Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ coverage/
.DS_Store

.release/
dist-browser/
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ verify` rebuilds the CLI and fails when the committed reference is stale. Regene
it whenever public command metadata or the package version changes. No timestamp
or local path is included.

## Browser build

Build the CLI module for a browser, then check the emitted artifact:

npm run build:browser
npm run verify:browser

The registry comes from the real command files. Commands needing the installed CLI remain in that inventory with an unsupported reason. Agent setup is refused before loading its implementation or reading local client configuration; the installer is excluded from the bundle. Verification checks the emitted dependency graph and runs a synthetic text send with no network access. Package and Docs publication remain separate steps.

## Authentication profiles

Until the backend exposes a revocable CLI device-authorization flow, login
Expand Down
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default tseslint.config(
'.release/**',
'coverage/**',
'dist/**',
'dist-browser/**',
'node_modules/**',
],
},
Expand Down
17 changes: 17 additions & 0 deletions internal/agent-sessions/cli90-accepted-cli85-20261028.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# CLI #90 integration after accepted CLI #85

Collaborator: purpshell. Agent: gpt-6.1-sol, xhigh, T3 Code. Thread: 7793bd59-7f5e-4ad0-bcf2-8da9ea202931. Selected hand-authored evidence is recorded here with a full-transcript capture gap; no credentials, customer content or hidden reasoning is included.

## Source and preservation

Release accepted CLI85 main 637f9991342279133bb000a7db01574bcffaf174, source 541f9a01. CLI90 old 8b42b62cc18391567da0d786beff34c529b73d3c on base a9a19cd68eecf7f33eae495665c1f389b6906a5e was actually rebased with --rebase-merges onto live main 637f9991342279133bb000a7db01574bcffaf174. Rebased source: ae827188d429b1fc15a778107e39036a50d4c81a. The four feature commits and prior checkpoint retain their authored history/dates; original patches, bundle, index, conflict stages and range-diff are retained under backup/rebase-20261028-cli90-8b42b62c-after-cli85. JSON fields were reconciled semantically; the fixed Zod 4.6.7 floor, current graph and both script families remain. Installed dependencies match lock version/resolved/integrity, with foreign optional platforms explicitly excluded. No install ran.

## Verification

The pre-load tripwire failed before the guard and passed after shared unsupported metadata was applied. Loader/module, filesystem/configuration and installer tripwires prevent local effects. An independent artifact check failed while the old producer still bundled installer modules, then passed when the genuine producer used the same literal typed policy. Unsupported command IDs stay in the inventory with rejecting loaders. No generated inventory was hand-edited or old count hard-coded. The emitted artifact refuses setup before environment/fetch access, excludes installer/native module inputs, and preserves the real text-send POST/path/body/output using synthetic fetch only.

Fresh serial Node 24: 1164 tests in 118 files passed; format/lint/types/build/reference/metadata/browser artifact/pack/audit and installed Actionlint on both unchanged workflows passed. The targeted artifact build/recorder runs again after commit because its embedded Git identity changes. Exact metrics, artifact input graph and final source proof are retained privately and linked from the PR. Natural rewritten-head hosted jobs and review remain required; old-head green is not reused.

## Impact and gates

CLI source/producers and its README change. Accepted CLI85 process/helper/consent/native fixture and both workflows remain byte-identical. API and all six SDK wire/version/package pins are unchanged; the existing opaque-key SDK limitation remains. Docs #888 keeps its older source-bound bundle until its sole Opus owner accepts a new one. No Admin/MCP, runner, Temporal, audit, Inspector, Console, Connect, Help Center, marketing, ZK custody, QuickLink or browser pairing tunnel runtime changed. No UI/browser action, real installer, network API, registry, provider, migration or deployment effect occurred. Release owns merge; staging/availability gates remain and trackers were not synchronized.
11 changes: 11 additions & 0 deletions internal/agent-sessions/cli90-current-main-rebase-20261028.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# CLI90 current-main rebase

Collaborator: purpshell. Agent: gpt-6.1-sol, xhigh, through T3 Code. Thread: 7793bd59-7f5e-4ad0-bcf2-8da9ea202931. This is a hand-authored selected checkpoint with a full-transcript capture gap. No credentials, customer content or hidden reasoning is included.

The user authorized guarded rebases of existing PRs. Old fde26bbee054101b20f71f9525d75acb4719a5c0 on 58e91a18d1a4afc108eb3119db0830340bb2a926 was actually rebased with --rebase-merges onto live main a9a19cd68eecf7f33eae495665c1f389b6906a5e. Rebased source: 826b87f9751f0ae6c7896b6744fabde0af2ab064. Durable backup: backup/rebase-20261028-cli90-fde26bbe. Old patch, bundle, index, author records, range-diff and each conflict stage are retained privately. Only divergent root Zod constraint fields were selected semantically at the authored 4.6.7 floor; current main and authored lock graph values otherwise merge field by field. No install or dependency download ran.

The browser registry was regenerated from actual command files. Agent setup is not present in this accepted main source. CLI85 must land before the next combined registry refresh; this head does not claim its unpublished parent is accepted.

Fresh serial Node 24 checks passed: full CLI suite, formatting, lint, typecheck, Node build, browser build, release metadata, package dry-run, production audit and an emitted browser module recording the real text-send command against a synthetic in-memory transport. No request reached a network API. New hosted checks and review remain required; old-head evidence does not qualify this head. A real browser, native agent installers and package publication were not checked in this task.

Impact: CLI runner/source and browser registry are qualified against the same accepted main revision. SDK package/API contract pins are unchanged; opaque-key support still depends on the pinned SDK, and client-token acceptance here is synthetic. Docs888 retains its existing source-bound browser bundle until its sole Opus owner accepts a new binding. API/Admin authority, runners, Temporal, audit, Inspector, Console, Connect, Help Center and marketing runtime are unchanged by this CLI-only delta. ZK custody, QuickLink and the browser pairing tunnel are unaffected: no credential-exchange or pairing code changed, and the recorder performs only a synthetic message request. Feature/registry/environment availability remains gated, staging deferred, Release owns merge. Roadmap records were not synchronized.
25 changes: 13 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 34 additions & 31 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,55 +1,40 @@
{
"name": "@polymorfa/cli",
"version": "0.1.0-dev.0",
"description": "The official command-line interface for Polymorfa",
"type": "module",
"license": "MIT",
"engines": {
"node": ">=22"
},
"bin": {
"polymorfa": "./bin/run.js"
},
"files": [
"bin/run.js",
"dist",
"skills",
"README.md",
"LICENSE"
],
"scripts": {
"audit:prod": "npm audit --omit=dev",
"build": "npm run clean && tsc -p tsconfig.build.json",
"clean": "node scripts/clean-dist.js",
"format": "prettier --write .",
"format:check": "prettier --check .",
"lint": "eslint .",
"prepare": "npm run build",
"test": "vitest run",
"typecheck": "tsc -p tsconfig.json --noEmit",
"verify": "npm run format:check && npm run lint && npm run typecheck && npm test && npm run build && node --test scripts/cli-reference.test.mjs && node scripts/cli-reference.mjs --check && npm pack --dry-run --ignore-scripts && npm run audit:prod",
"docs:reference": "npm run build && node scripts/cli-reference.mjs",
"docs:reference:check": "npm run build && node scripts/cli-reference.mjs --check"
},
"dependencies": {
"@modelcontextprotocol/server": "2.3.1",
"@napi-rs/keyring": "1.3.0",
"@oclif/core": "^4.13.5",
"@polymorfa/sdk": "0.1.0-dev.20261004024706",
"jq-wasm": "3.0.0-jq-1.8.2",
"zod": "^4.6.6"
"zod": "4.6.7"
},
"description": "The official command-line interface for Polymorfa",
"devDependencies": {
"@eslint/js": "^9.39.5",
"@oclif/test": "^4.1.22",
"@types/node": "^24.0.0",
"esbuild": "^0.28.2",
"eslint": "^9.39.5",
"prettier": "^3.9.6",
"tsx": "^4.20.6",
"typescript": "^6.0.3",
"typescript-eslint": "^8.67.0",
"vitest": "3.2.7"
},
"engines": {
"node": ">=22"
},
"files": [
"bin/run.js",
"dist",
"skills",
"README.md",
"LICENSE"
],
"license": "MIT",
"name": "@polymorfa/cli",
"oclif": {
"bin": "polymorfa",
"dirname": "polymorfa",
Expand Down Expand Up @@ -349,5 +334,23 @@
"repository": {
"type": "git",
"url": "git+https://github.com/polymorfa/cli.git"
}
},
"scripts": {
"audit:prod": "npm audit --omit=dev",
"build": "npm run clean && tsc -p tsconfig.build.json",
"build:browser": "node scripts/gen-browser-registry.mjs && node scripts/build-browser.mjs",
"clean": "node scripts/clean-dist.js",
"format": "prettier --write .",
"format:check": "prettier --check .",
"lint": "eslint .",
"prepare": "npm run build",
"test": "vitest run",
"typecheck": "tsc -p tsconfig.json --noEmit",
"verify": "npm run format:check && npm run lint && npm run typecheck && npm test && npm run build && node --test scripts/cli-reference.test.mjs && node scripts/cli-reference.mjs --check && npm run verify:browser && npm pack --dry-run --ignore-scripts && npm run audit:prod",
"docs:reference": "npm run build && node scripts/cli-reference.mjs",
"docs:reference:check": "npm run build && node scripts/cli-reference.mjs --check",
"verify:browser": "node scripts/verify-browser.mjs"
},
"type": "module",
"version": "0.1.0-dev.0"
}
110 changes: 110 additions & 0 deletions scripts/build-browser.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Builds dist-browser/: the CLI's commands as a browser module (src/browser/index.ts).
// Node built-ins and local-only packages resolve to src/browser/stubs; each command loads on demand.
import console from 'node:console'
import process from 'node:process'
import {URL, fileURLToPath} from 'node:url'
import {execFileSync} from 'node:child_process'
import {readFileSync, writeFileSync, rmSync} from 'node:fs'
import {builtinModules} from 'node:module'
import {build} from 'esbuild'
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const pkg = JSON.parse(
readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
)
const stub = (name) =>
fileURLToPath(new URL(`../src/browser/stubs/${name}.ts`, import.meta.url))
const NODE = {
fs: stub('fs'),
'fs/promises': stub('fs-promises'),
path: stub('path'),
'path/posix': stub('path'),
os: stub('os'),
crypto: stub('crypto'),
events: stub('events'),
buffer: stub('buffer'),
child_process: stub('unavailable'),
net: stub('unavailable'),
dns: stub('unavailable'),
'dns/promises': stub('unavailable'),
http: stub('unavailable'),
https: stub('unavailable'),
readline: stub('unavailable'),
'readline/promises': stub('unavailable'),
}
const PACKAGES = new Set([
'@napi-rs/keyring',
'@modelcontextprotocol/server',
'@modelcontextprotocol/server/stdio',
'jq-wasm',
'@polymorfa/sdk/node',
])
const escape = (value) => value.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&')
const builtins = new RegExp(`^(${builtinModules.map(escape).join('|')})$`)

const stubs = {
name: 'browser-stubs',
setup(builder) {
builder.onResolve({filter: /^node:/}, (args) => ({
path: NODE[args.path.slice(5)] ?? stub('misc'),
}))
builder.onResolve({filter: builtins}, (args) => ({
path: NODE[args.path] ?? stub('misc'),
}))
builder.onResolve(
{
filter:
/^(@napi-rs\/keyring|@modelcontextprotocol\/server(\/stdio)?|jq-wasm|@polymorfa\/sdk\/node)$/,
},
(args) =>
PACKAGES.has(args.path) ? {path: stub('packages')} : undefined,
)
},
}

const commit = execFileSync('git', ['rev-parse', 'HEAD'], {
encoding: 'utf8',
}).trim()
rmSync(new URL('../dist-browser', import.meta.url), {
recursive: true,
force: true,
})
const result = await build({
entryPoints: ['src/browser/index.ts'],
bundle: true,
splitting: true,
format: 'esm',
platform: 'browser',
target: 'es2022',
outdir: 'dist-browser',
entryNames: 'polymorfa-cli',
chunkNames: 'chunks/[name]-[hash]',
inject: [stub('process'), stub('buffer-global')],
define: {
__CLI_VERSION__: JSON.stringify(pkg.version),
__CLI_COMMIT__: JSON.stringify(commit),
global: 'globalThis',
},
plugins: [stubs],
mainFields: ['browser', 'module', 'main'],
conditions: ['browser', 'import', 'default'],
minify: process.env.BROWSER_MINIFY !== '0',
legalComments: 'linked',
metafile: true,
logLevel: 'warning',
})
if (process.env.BROWSER_METAFILE)
writeFileSync(
process.env.BROWSER_METAFILE,
JSON.stringify(result.metafile, null, 2) + '\n',
)
const bytes = Object.values(result.metafile.outputs).reduce(
(sum, output) => sum + output.bytes,
0,
)
writeFileSync(
new URL('../dist-browser/manifest.json', import.meta.url),
`${JSON.stringify({package: pkg.name, version: pkg.version, commit, entry: 'polymorfa-cli.js', files: Object.keys(result.metafile.outputs).length, bytes}, null, 2)}\n`,
)
console.log(
`dist-browser: ${Object.keys(result.metafile.outputs).length} files, ${(bytes / 1024 / 1024).toFixed(2)} MiB, commit ${commit.slice(0, 10)}`,
)
Loading
Loading