diff --git a/README.md b/README.md index c1c3957..1018dda 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,219 @@ # MainSequence developer tooling -One TypeScript package owns the shared action models, browser authentication, machine session, repository resolution, project dispatch, the `ms-devtools` command runner and the project MCP client. Both SDK repositories remain unchanged. Host integrations live in their own repositories and consume only this package's public API: [VS Code](https://github.com/mainsequence-sdk/ms-vscode-extension), [Claude Desktop](https://github.com/mainsequence-sdk/mainsequence-claude-desktop) and, since 0.3.0, the [Codex plugin](https://github.com/mainsequence-sdk/mainsequence-codex-plugin) ([ADR 0003](docs/adr/0003-codex-plugin-extraction.md)). Since 0.3.12 both plugins register saved project MCP tools through the [shared project-tool registry](#shared-project-tool-registry-0312) ([ADR 0004](docs/adr/0004-shared-project-tool-registry.md)). There are no runtime npm dependencies or LLM API calls in the runner. The MCP client calls the existing platform directory and selected project MCP endpoints; the developer actions retain their deterministic execution. +`@dev-mainsequence/devtools` is the shared TypeScript package behind MainSequence's +developer integrations: browser sign-in and the machine session, repository and project +operations, the project MCP client, the platform agent client, the shared project-tool +registry and the `ms-devtools` command line. It has no runtime npm dependencies and makes +no LLM API calls; developer actions run deterministically. The host integrations live in +their own repositories and use only this package's public API. + +## Which MainSequence tool do I install? + +| Host | What you get | Install | Repository | +| --- | --- | --- | --- | +| **VS Code** | A MainSequence panel: sign in, browse repositories and projects, set them up locally, open signed terminals, run SDK actions | Install **MainSequence** from the VS Code Marketplace, or `code --install-extension mainsequencegmbh.vscode-mainsequence` | [ms-vscode-extension](https://github.com/mainsequence-sdk/ms-vscode-extension) | +| **Codex** (desktop and CLI) | The MainSequence panel (Home, Code, Projects, Agents, Tools), agent messaging in chat, project MCP tools, `/ms` commands | `codex plugin marketplace add mainsequence-sdk/mainsequence-codex-plugin`, then `codex plugin add mainsequence@mainsequence` | [mainsequence-codex-plugin](https://github.com/mainsequence-sdk/mainsequence-codex-plugin) | +| **Claude Desktop** (Code) | The MainSequence pane (Home, Code, Projects, Agents, Tools), agent conversations with `/ms @agent`, project MCP tools, deployments | **Customize → Plugins → Add marketplace → Add from repository**, enter `https://github.com/mainsequence-sdk/mainsequence-claude-desktop.git`, install **MainSequence** from `mainsequence-desktop` | [mainsequence-claude-desktop](https://github.com/mainsequence-sdk/mainsequence-claude-desktop) | +| **Terminal or CI** | The `ms-devtools` command line | `npx -p @dev-mainsequence/devtools ms-devtools --help`, or `npm install -g @dev-mainsequence/devtools` | this repository | + +All of them need Node 22 or newer and share one sign-in per backend, kept in the operating +system's credential store (the login Keychain on macOS, Secret Service through +`secret-tool` on Linux). The `mainsequence` (Python) and `command-center-sdk` (Node) +command lines read the same record, so signing in anywhere signs in everywhere. Windows +has no persistent store in this package: the VS Code extension keeps its own session +there, and the Codex and Claude Desktop plugins are not supported on Windows yet. Each +host's README explains its own setup; the Command Center's **Settings → Account → +Developer tools** page gives the same steps with your deployment's backend URL. + +## The `ms-devtools` command line -## Build and run +```sh +npx -p @dev-mainsequence/devtools ms-devtools --help +ms-devtools login --backend https://api.main-sequence.app +ms-devtools auth-status --backend https://api.main-sequence.app --check --json +ms-devtools refresh-token --backend https://api.main-sequence.app +ms-devtools repositories --backend https://api.main-sequence.app --json +ms-devtools status --path "/path/to/project" --json +ms-devtools sync --path "/path/to/project" +``` -VS Code and Claude use the shared [MainSequence Projects API and local workspace setup](docs/organization-projects.md). Projects are environment-scoped collections of repository branches; the existing repository operations API retains its compatible names and storage layout. +### Sign in -Requires Node 22 or newer. Install build dependencies and build once: +`login` opens the hosted browser authorization flow with PKCE and a loopback callback; +account creation is part of that hosted flow. Login and `auth-status` work before either +SDK is installed. The runner checks the store before opening a browser and reads back the +saved pair before reporting success. The saved record is the SDKs' existing +`MainSequenceCLI.auth` service, backend-scoped account and version-1 JSON format; there +is no separate credential record and no token file. `refresh-token` renews the saved +machine session; it does not replace a token exported into another shell. `logout` +removes this backend's local record and separately reports whether remote revocation +completed. -```sh -npm ci -npm run build -node dist/runner.js --help +A deliberately supplied `MAINSEQUENCE_ACCESS_TOKEN` with its matching +`MAINSEQUENCE_ENDPOINT` is a process or CI identity. A rejected process identity never +falls back to another saved identity. Runtime credentials are a separate application lane +and are not accepted for developer actions. + +### Project actions + +Backend selection uses an explicit `--backend`, then `MAINSEQUENCE_ENDPOINT`, the Git-root +`.env` endpoint, the existing CLI configuration, then the standard backend. Project +selection validates the real Git root, attached branch, full HEAD SHA and canonical remote +identity. Ambiguous Python/frontend projects require `--type python` or `--type vite_react`. + +| Command | Behavior | +| --- | --- | +| `status` | Local Git context, session metadata, and installed command capabilities. | +| `resolve` | Backend Git-context resolution with identity/branch/ref/commit validation. | +| `setup --uid UID --branch BRANCH --base-dir DIR [--install]` | Fetch the registered binding; reuse/register the repository SSH key; verify access; clone into `//projects/-`; write an endpoint-only `.env`; optionally install dependencies. Existing checkout folders are never replaced. | +| `install` | `uv sync` for Python; `npm ci` for frontend projects. | +| `sync` | Refresh the project's dependency files with its installed SDK: Python `code-repository sync` runs `uv lock`, `uv sync` and the locked `requirements.txt` export (`mainsequence` 9.0.5 or later); Node `code-repository sync` refreshes `package-lock.json` and runs `npm ci` (`@dev-mainsequence/command-center-sdk` 0.5.13 or later). No commit message, dry run, Git command or backend request: review the changes, then commit and push them yourself. An installed SDK that still has the retired release sync (`--dry-run`/`--message` in its sync help) is reported unavailable without running it; run `update-sdk`. | +| `sdk-status` | Isolated Python distribution metadata plus stable source version, or Node `application sdk-status`. A source version does not prove registry publication. | +| `update-sdk [--dry-run]` | Python `code-repository update-sdk` or Node `application update-sdk`; retains the project's existing dependency policy. | +| `update-agents` | Python SDK's packaged `AGENTS.md` managed-block update. | +| `install-skills [--dry-run]` | Node SDK's packaged skills installation. Python's combined skills command requires MCP and is unsupported here. | +| `env-cleanup` | Remove legacy project credentials and keep the endpoint and unrelated settings; refuse tracked or symlink `.env` files. | +| `skills-sync` | Reports unsupported: backend-owned skills require MainSequence MCP. | +| `open-folder`, `signed-terminal` | Host capabilities exposed by the library; the terminal runner reports them as unsupported. | + +Python dispatch uses `.venv/bin/mainsequence` (`Scripts/mainsequence.exe` on Windows). +Node dispatch executes the project's installed +`@dev-mainsequence/command-center-sdk/cli/command-center-sdk.mjs` with the runner's Node +executable. No global SDK or sibling source path is a fallback. Command help is checked +before dispatch; missing or older capabilities produce a structured error. + +Versions and release tags of a CodeRepository are repository code, for example a GitHub +Actions workflow; the platform deploys from Git pushes, so `sync` only refreshes +dependency files and there is no `freeze-env`. For existing library callers, a sync +request that still carries `message` is accepted and the message ignored, a `freeze-env` +request reports `UNSUPPORTED_ACTION`, and the deprecated `sanitizeCommitMessage` export +and `freezeEnv` CLI action name remain but build no command. + +If `.env` still contains credentials, run `env-cleanup` explicitly before SDK dispatch. +It removes canonical tokens, runtime credentials, the unsupported legacy token and the +runtime credential auth-mode assignment, including `export` and whitespace forms. It +preserves unrelated application settings, keeps the endpoint in the VS Code extension's +block (`# BEGIN MAINSEQUENCE AUTH (managed by VS Code)` … `# END MAINSEQUENCE AUTH`) as +the extension writes it, excludes `.env` from Git, and writes it atomically with private +permissions. A file already in that form is not written again. + +Mutations hold a repository lock in the Git common directory, also covering linked +worktrees. Before a clone exists, setup locks `..mainsequence-devtools.lock` in +its canonical parent directory. Cancellation stops the child process; failures after +execution begins report partial or uncertain effects. A failed sync is never +automatically retried or rolled back. After an abrupt process kill, inspect running +actions before removing a stale lock (`mainsequence-devtools.lock` in the Git common +directory, or the named setup lock). + +Raw SDK output is private and is not included in results or hook output. Progress +reports command lifecycle; supported structured status metadata is filtered. Run the SDK +directly in a private terminal when its detailed diagnostic output is needed. Raw +credentials are never arguments, public results, or model context. + +### Project MCPs + +`mcp-discover`, `mcp-add`, `mcp-list`, `mcp-remove`, `mcp-tools`, `mcp-call` and +`mcp-catalog [--refresh]` discover the platform's MCP directory, remember a selected +release, read its tools and invoke them through a local MCP client, using the developer +session and short-lived release credentials. Connections are saved in +`mcp-connections.json` beside the CLI configuration (hosts may inject +`mcpConnectionsPath`). `mcp-add` stores the release's name, its repository's name and +its repository branch with the connection (`name`, `display_name`, +`code_repository_branch_uid`), so `mcp-list` labels a saved connection without a backend +request; a label that cannot be read is left out rather than making the MCP unavailable. +The conversational use of these connections in Codex is described in +[the Codex plugin's guide](https://github.com/mainsequence-sdk/mainsequence-codex-plugin/blob/main/docs/conversational-mcp.md). + +## Library API + +```ts +import { createDevTools, createNodeHost } from '@dev-mainsequence/devtools'; + +const tools = createDevTools({ host: createNodeHost() }); +const result = await tools.dispatch({ action: 'sync', root: '/path/to/project' }); ``` -Run directly in a terminal for deterministic execution without invoking a model: +The same dispatcher serves the library, the CLI and the host runners. `parseArguments`, +`tokenizeCommand` and `HELP` are exported so a host can parse the same command line as +`ms-devtools`. `HostServices` supplies browser and process execution, safe progress, +cancellation, and optional native folder and terminal operations. Shared code imports no +host API. Public types include `ActionRequest`, `ActionResult`, `ProjectContext`, +`ActionCapability` and `SessionStatus`. Credentials stay private to the session service. + +`createSessionService` owns browser authorization, authenticated HTTP, refresh and +revocation; `RepositoryClient` owns the canonical backend response and Git-resolution +contracts; `createDevTools` owns project actions and cancellation. `HostAuthSession` is an +opt-in compatibility adapter for asynchronous host SecretStorage, machine-session adoption +and the host projection/migration policy; its `get`, `save`, `environment` and +`persistence` methods are privileged credential bridges and must never reach webview +state, progress, logs, hook output or action results. The VS Code extension uses it where +no native store is reachable; Codex and Claude Desktop use native persistence only. + +### Discovery and account binding + +`dispatch()` infers typed payloads for session status, environments, agent directories, +MCP discovery, saved connections and tool catalogs; the exports include `McpConnection`, +`McpTool`, `McpCatalog`, `McpDiscoveryPage`, `AgentDirectory` and `DiscoveryResultMap`. +Backend response validation stays here; host applications own their view state. -```sh -node dist/runner.js login --backend https://api.main-sequence.app -node dist/runner.js auth-status --backend https://api.main-sequence.app --check --json -node dist/runner.js refresh-token --backend https://api.main-sequence.app -node dist/runner.js repositories --backend https://api.main-sequence.app --json -node dist/runner.js status --path "/path/to/project" --json -node dist/runner.js sync --path "/path/to/project" +```ts +const verified = await devtools.dispatch({ action: 'auth-status', backend, check: true }); +if (verified.status !== 'success' || !verified.data?.username) throw new Error('Sign in first'); +const scope = { backend, expectedAccount: verified.data.username, environmentUid }; +const saved = await devtools.dispatch({ action: 'mcp-list', ...scope, readOnly: true }); +const available = await devtools.dispatch({ action: 'mcp-discover', ...scope, enrichNames: true, limit: 20 }); ``` -Login and session status work before either SDK is installed. Login opens the existing hosted browser authorization flow with PKCE and a loopback callback; account creation remains part of that hosted flow. The runner checks the store before opening a browser and reads back the saved pair before reporting success. - -Persistent login uses macOS Keychain or Linux Secret Service (`secret-tool` from libsecret). Windows has no native persistent Node store in this extracted implementation. A deliberately supplied `MAINSEQUENCE_ACCESS_TOKEN` with its matching `MAINSEQUENCE_ENDPOINT` supports a process/CI identity. A rejected process identity never falls back to another saved identity. Runtime credentials are a separate application lane and are not accepted for these developer actions. - -The machine record is the SDKs' existing `MainSequenceCLI.auth` service, backend-scoped account, and version-1 JSON format. There is no Codex-specific credential record and no token file. `refresh-token` renews the saved machine session; it does not replace a token exported into another shell. `logout` removes this backend's local record and separately reports whether remote revocation completed. - -## Project MCP client - -In 0.3.6, remote tool failures use `MCP_TOOL_ERROR` and retain the sanitized MCP -`content`/`structuredContent` in `ActionResult.data`, separately from transport/API -errors. Hosts must preserve that result and any `effects` warning. Calls are never -automatically replayed. - -Since 0.3.7, a persistent client reuses verified release metadata, the release grant -and its tool catalog in memory for at most 60 seconds (never beyond credential -expiry). A prepared `mcp-call` sends only the business `tools/call` HTTP request. -`mcp-tools` explicitly refreshes schemas without repeating valid connection setup. -Cold setup verifies the account remotely at entry and completion; warm calls reread -the shared credential selection locally before and after execution. Logout, a -changed credential pair or saved endpoint, removal, expiry and transport failures -invalidate reuse. The server continues to enforce authorization for each call. -Tool results and credentials are never written to connection metadata; failed calls -are never replayed automatically, including after Stop. - -`createDevTools()` owns a cache by default. Hosts that create a new dispatcher per -request can pass the same opaque `createMcpConnectionCache()` handle as `mcpCache`; -devtools owns validation and expiry, while each request retains its own cancellation -signal. A session adapter without `selectionIdentity()` always uses fresh setup. -Separate CLI processes do not share this memory cache. - -Version 0.3.3 adds the public `AgentDelivery` service for durable host conversations. -It stages immutable requests, records native submission acknowledgements separately -from agent delivery, and reuses saved receipts on recovery. It uses the same session, -agent and readiness APIs as other consumers; no host UI code is included. See -[the delivery contract](docs/agent-conversations.md#durable-host-delivery-033). - -The `mcp-discover`, `mcp-add`, `mcp-list`, `mcp-remove`, `mcp-tools` and `mcp-call` actions discover the platform's MCP directory, remember a selected release and invoke its tools through a local MCP client, using the existing developer session and short-lived release credentials. They are available from `ms-devtools` and from `createDevTools().dispatch()`; hosts may inject `mcpConnectionsPath`. Since 0.3.1, `mcp-add` reads the release's name, its repository's name and its repository branch from the release directory and stores them with the connection as `name`, `display_name` and `code_repository_branch_uid`, so `mcp-list` labels a saved connection without a backend request; a record saved by an earlier version is completed by the first listing that can read them, and a label that cannot be read is left out rather than making the MCP unavailable. Discovery rows carry `name` and `code_repository_branch_uid` as the platform directory reports them. The conversational `mainsequence-mcp` skill that lets Codex use them without `/ms` ships with the [Codex plugin](https://github.com/mainsequence-sdk/mainsequence-codex-plugin), together with [its user guide](https://github.com/mainsequence-sdk/mainsequence-codex-plugin/blob/main/docs/conversational-mcp.md) and [ADR 0002](https://github.com/mainsequence-sdk/mainsequence-codex-plugin/blob/main/docs/adr/0002-conversational-project-mcp-client.md). - -A cold project MCP (a scaled-to-zero FastAPI release) is slow. Measured against the -Production CRM on 2026-10-23, a first `mcp-call` took 53–71 s (release detail and -exchange-launch about 2 s each, the project's `initialize` 9 s to over 60 s, `tools/call` -10–39 s); a warm one 7–10 s. Since 0.3.12 project requests have their own budget, -`projectRequestTimeoutMs` (default 120 s; `requestTimeoutMs` keeps governing backend -requests, default 30 s), and a `tools/call` honours the tool's advertised +- `mcp-list` with `readOnly: true` reads saved metadata without label lookups, locks or + connection-file writes; without it, a record saved without labels is completed by the + first listing that can read them. +- `mcp-discover` with `enrichNames: true` resolves optional repository names once per + branch, at most four at a time, with no connection writes. +- `mcp-environments` and `organization-environments` share one bounded `listEnvironments` + loader: duplicate rows, changing totals, premature empty pages and directories over + 10,000 entries are refused. +- MCP, agent and organization-project actions accept `expectedAccount`. The built-in + session verifies the credential actually used for requests and retries, rejects a + different account and discards responses when the selected credentials change during a + read. `bindSessionAccount(session, backend, expectedAccount)` gives public domain + clients the same contract; a custom `SessionService` implements the optional + `withAccount` method, and account checks fail with `UNSUPPORTED_ACTION` when it lacks + one. The scoped session cannot log in, log out or change authentication. Hosts still + invalidate stale selections when their configured backend or environment changes. + +### Project MCP client + +A remote tool failure is `MCP_TOOL_ERROR` and keeps the sanitized MCP `content` and +`structuredContent` in `ActionResult.data`, apart from transport and API errors; hosts +preserve that result and any `effects` warning, and calls are never replayed +automatically. A persistent client reuses verified release metadata, the release grant and +its tool catalog in memory for at most 60 seconds, never beyond credential expiry: a +prepared `mcp-call` sends only the business `tools/call` request, `mcp-tools` refreshes +schemas explicitly, cold setup verifies the account remotely at entry and completion, and +warm calls reread the shared credential selection locally before and after execution. +Logout, a changed credential pair or saved endpoint, removal, expiry and transport +failures invalidate reuse; the server still authorizes every call. `createDevTools()` +owns a cache by default; hosts that create a dispatcher per request pass one opaque +`createMcpConnectionCache()` handle as `mcpCache`. A session adapter without +`selectionIdentity()` always uses fresh setup. Separate CLI processes share no cache. + +A cold project MCP (a scaled-to-zero FastAPI release) is slow: measured against the +Production CRM, a first `mcp-call` took 53–71 s and a warm one 7–10 s. Project requests +have their own budget, `projectRequestTimeoutMs` (default 120 s; `requestTimeoutMs`, default +30 s, governs backend requests), and a `tools/call` honours the tool's advertised `_meta["mainsequence.ai/timeout-seconds/v1"]` when it is larger, capped at 300 s. Hosts set -their outer limit above this (Codex `tool_timeout_sec`, the Claude Desktop worker budget). -Error messages say which endpoint answered which request (`The project MCP https://… returned -HTTP 503 for tools/call crm_contacts_list.`), tell a timeout (`timed out after 120 s`) apart -from a connection failure (`failed before a response arrived (ECONNREFUSED)`), and keep a -JSON-RPC error's own message, redacted. The error codes are unchanged. +their outer limit above this. Error messages say which endpoint answered which request +(`The project MCP https://… returned HTTP 503 for tools/call crm_contacts_list.`), tell a +timeout (`timed out after 120 s`) apart from a connection failure (`failed before a +response arrived (ECONNREFUSED)`), and keep a JSON-RPC error's own message, redacted. -## Shared project-tool registry (0.3.12) +### Shared project-tool registry -Both host plugins present every saved project MCP connection's tools as first-class tools of -the host, named `ms__` (for example `ms_crm_contacts_list_183f8138`), so a model -calls `crm_contacts_list` like any other tool instead of walking a discovery protocol. Since -0.3.12 this package owns that registry ([ADR 0004](docs/adr/0004-shared-project-tool-registry.md)) -and the plugins keep only what is specific to their host. +Both host plugins present every saved project MCP connection's tools as first-class tools +of the host, named `ms__` (for example `ms_crm_contacts_list_183f8138`), so a +model calls `crm_contacts_list` like any other tool. This package owns that registry +([ADR 0004](docs/adr/0004-shared-project-tool-registry.md)); the plugins keep only what +is specific to their host. - `projectToolName(backend, environmentUid, releaseUid, tool)`: `ms_` + the remote name (characters outside `[a-zA-Z0-9_-]` replaced by `_`, cut to 32) + `_` + the lower-case @@ -90,9 +221,9 @@ and the plugins keep only what is specific to their host. one name in every host; the CRM vector above is a frozen test. - `projectToolDefinition(connection, tool)` and `projectToolDefinitions(connection, tools)` (80 per connection, duplicates and invalid tools dropped): `{ name, title, description, - inputSchema, annotations }` with the description `MainSequence []: - `, an object schema (`type: 'object'` added when the server omitted it) - and the four boolean hints, open-world by default. + inputSchema, annotations }` with the description `MainSequence + []: `, an object schema and the four boolean hints, + open-world by default. - `projectToolResult(actionResult)`: what a host returns for a forwarded call: the remote content blocks, then one JSON text block with `summary`, `effects`, `error` and `structuredContent` when the call failed, returned structured content or no blocks; @@ -100,154 +231,82 @@ and the plugins keep only what is specific to their host. - `readProjectToolCatalog(dispatch, { backend?, environmentUid?, previous?, signal? })`: `mcp-list` (read-only), then one `mcp-tools` per saved connection, two at a time. A connection whose catalog cannot be read keeps its previous tools and is named in - `unavailable`; a removed connection loses them; connections outside the scope are carried - over. No account snapshot is attached: the session for a connection's backend is verified - when its tool is called. + `unavailable`; a removed connection loses them; connections outside the scope are + carried over. The session for a connection's backend is verified when its tool is called. - `createProjectToolCatalog({ dispatch, file?, staleMs?, notify?, disabled? })`: the shared on-disk catalog, `project-tool-catalog.json` beside `mcp-connections.json` - (`mainSequenceStateDirectory(env)` names that directory). `list()` answers from the file at - once, scoped to the current account's backend once a refresh has learned it; `refresh()` - re-reads under a lock, so one process reads catalogs at a time while the others pick its - result up from the file; `update()`, `dispose()` and `notify` serve a long-lived host such as - the Codex MCP server. The file holds schemas and labels only, never credentials, tool - results or tokens. -- The `mcp-catalog` action returns the same definitions, bindings and state for a host that - dispatches actions instead of importing (the Claude Desktop hook reaches this package only - through a worker process): without `refresh` from the file, with `refresh: true` re-reading - a stale cache, with `'force'` always, waiting up to two minutes for another process's - refresh to end. `mcp-tool-call` is `mcp-call` answered in the `projectToolResult` shape. - `ms-devtools mcp-catalog [--refresh]` is the command-line form. + (`mainSequenceStateDirectory(env)` names that directory). `list()` answers from the file + at once, scoped to the current account's backend once a refresh has learned it; + `refresh()` re-reads under a lock, so one process reads catalogs at a time while the + others pick its result up from the file; `update()`, `dispose()` and `notify` serve a + long-lived host such as the Codex MCP server. The file holds schemas and labels only. +- The `mcp-catalog` action returns the same definitions, bindings and state for a host + that dispatches actions instead of importing: without `refresh` from the file, with + `refresh: true` re-reading a stale cache, with `'force'` always, waiting up to two + minutes for another process's refresh to end. `mcp-tool-call` is `mcp-call` answered in + the `projectToolResult` shape. What stays host-specific: the Codex server merges the definitions into its `tools/list`, -sends `tools/list_changed`, keeps its `contextId` discovery layer and shared transport, and -forwards an `ms_*` call through `mcp-call` and `projectToolResult`; the Claude Desktop hook -registers the definitions with `$.tool.register`, asks `$.ui.ask` before every call, -converts the result's blocks to Messages API blocks and spawns one worker per action. +sends `tools/list_changed` and forwards an `ms_*` call through `mcp-call`; the Claude +Desktop hook registers the definitions, asks before every call, converts the result's +blocks to Messages API blocks and spawns one worker per action. -## Shared discovery API (0.3.2) +### Agents, projects, workspaces and transport -`createDevTools().dispatch()` now infers typed payloads for session status, environments, -agent directories, MCP discovery, saved connections and tool catalogs. `ActionResult` -defaults to `unknown` for compatibility; the public exports include `McpConnection`, -`McpTool`, `McpCatalog`, `McpDiscoveryPage`, `AgentDirectory` and `DiscoveryResultMap`. -Backend response validation stays in devtools; host applications own their view state. +- [Platform agent conversations](docs/agent-conversations.md): agent discovery, sessions, + readiness, sends, tasks and the durable `AgentDelivery` coordinator for host chats. +- [Organization projects](docs/organization-projects.md): environment-scoped project + listing and repeatable local workspace setup. +- [Shared project operations](docs/shared-project-operations.md): local repository + discovery, deletion, Docker builds and devcontainer edits for host adapters. +- [Workspace defaults and environments](docs/workspace-environments.md): backend and + repositories-folder resolution and environment-scoped MCP actions. +- [Shared desktop transport](docs/shared-desktop-transport.md): the per-user worker that + hosts with one process per chat use to share HTTP connections, reads and token renewal. -```ts -const verified = await devtools.dispatch({ action: 'auth-status', backend, check: true }); -if (verified.status !== 'success' || !verified.data?.username) throw new Error('Sign in first'); -const scope = { backend, expectedAccount: verified.data.username, environmentUid }; -const saved = await devtools.dispatch({ action: 'mcp-list', ...scope, readOnly: true }); -const available = await devtools.dispatch({ action: 'mcp-discover', ...scope, enrichNames: true, limit: 20 }); -``` +Decisions are recorded in [ADR 0001](docs/adr/0001-shared-developer-tooling-and-codex.md) +(shared tooling), [ADR 0002](docs/adr/0002-conversational-project-mcp-client.md) (the MCP +client), [ADR 0003](docs/adr/0003-codex-plugin-extraction.md) (host repositories) and +[ADR 0004](docs/adr/0004-shared-project-tool-registry.md) (the project-tool registry). -- `mcp-list` with `readOnly: true` reads saved metadata without label lookups, locks or - connection-file writes. Missing stores remain absent; corrupt files are preserved and - reported. Omit the option (or explicitly use `false`) to retain the legacy label-backfill - behavior. Normal authentication renewal is independent of connection metadata writes. -- `mcp-discover` with `enrichNames: true` resolves optional repository names once per branch, - with at most four concurrent lookups and no connection writes. Missing optional metadata - leaves usable endpoints visible. Cancellation and account changes still fail the action. -- `mcp-environments` and `organization-environments` use the same bounded `listEnvironments` - loader. Short pages advance by their actual length; duplicate rows, changing totals, - premature empty pages and directories over 10,000 entries are refused. The existing MCP - result retains `isProduction`; the Projects result retains `{uid, name}`. -- MCP and organization-project actions accept optional `expectedAccount`. The built-in - session verifies the actual credential used for requests and retries, rejects a different - account and discards responses when the selected credentials change during a read. Agent - operations also use this binding when the session supports it. This does not make remote - mutations atomic with account changes or roll back work already dispatched. - -`bindSessionAccount(session, backend, expectedAccount)` is available for public domain -clients. Custom `SessionService` implementations can implement the optional `withAccount` -method to provide that contract. New opt-in MCP/Projects account checks fail with -`UNSUPPORTED_ACTION` when the custom transport lacks it; existing unscoped callers and -legacy custom agent transports retain their prior behavior. The built-in scoped session -cannot log in, log out or change authentication. Hosts still invalidate stale selections -when their configured backend/environment changes. - -## Project actions - -Backend selection uses an explicit `--backend`, process `MAINSEQUENCE_ENDPOINT`, the Git-root `.env` endpoint, existing CLI configuration, then the standard backend. Project selection validates the real Git root, attached branch, full HEAD SHA, and canonical remote identity. Ambiguous Python/frontend projects require `--type python` or `--type vite_react`. +## Development -| Command | Behavior | -| --- | --- | -| `status` | Local Git context, session metadata, and installed command capabilities. | -| `resolve` | Existing backend Git-context resolution with identity/branch/ref/commit validation. | -| `setup --uid UID --branch BRANCH --base-dir DIR [--install]` | Fetch the registered binding; reuse/register the repository SSH key; verify access; clone into `//projects/-`; write endpoint-only `.env`; optionally install dependencies. Existing checkout folders are never replaced. | -| `install` | `uv sync` for Python; `npm ci` for frontend projects. | -| `sync` | Refresh the project's dependency files with its installed SDK: Python `code-repository sync` runs `uv lock`, `uv sync` and the locked `requirements.txt` export (`mainsequence` 9.0.5 or later); Node `code-repository sync` refreshes `package-lock.json` and runs `npm ci` (`@dev-mainsequence/command-center-sdk` 0.5.13 or later). No commit message, dry run, Git command or backend request: review the changes, then commit and push them yourself. An installed SDK that still has the retired release sync (`--dry-run`/`--message` in its sync help) is reported unavailable without running it; run `update-sdk`. | -| `sdk-status` | Isolated Python distribution metadata plus stable source version, or Node `application sdk-status`. A source version does not prove registry publication. | -| `update-sdk [--dry-run]` | Python `code-repository update-sdk` or Node `application update-sdk`; retains the project's existing dependency policy. | -| `update-agents` | Python SDK's packaged `AGENTS.md` managed-block update. | -| `install-skills [--dry-run]` | Node SDK's packaged skills installation. Python's current combined skills command requires MCP and is unsupported here. | -| `env-cleanup` | Remove legacy project credentials and keep the endpoint and unrelated settings; refuse tracked or symlink `.env` files. | -| `skills-sync` | Reports unsupported: backend-owned skills currently require MainSequence MCP. | -| `open-folder`, `signed-terminal` | Host capabilities exposed by the library. The initial Codex/terminal runner reports these as unsupported. | - -Python dispatch uses `.venv/bin/mainsequence` (`Scripts/mainsequence.exe` on Windows). Node dispatch executes the project's installed `@dev-mainsequence/command-center-sdk/cli/command-center-sdk.mjs` with the runner's Node executable. No global SDK or sibling source path is a fallback. Command help is checked before dispatch; missing/older capabilities produce a structured error. - -Versions and release tags of a CodeRepository are repository code, for example a GitHub Actions workflow; the platform deploys from Git pushes. `freeze-env` was removed because `sync` now writes the locked `requirements.txt`. For existing library callers, a sync request that still carries `message` is accepted and the message ignored, a `freeze-env` request reports `UNSUPPORTED_ACTION`, and the deprecated `sanitizeCommitMessage` export and `freezeEnv` CLI action name remain but build no command. - -If `.env` still contains credentials, run `env-cleanup` explicitly before SDK dispatch. It removes canonical tokens, runtime credentials, the unsupported legacy token, and the runtime credential auth-mode assignment, including `export` and whitespace forms. It preserves unrelated application settings, keeps the endpoint in the VS Code extension's block (`# BEGIN MAINSEQUENCE AUTH (managed by VS Code)` … `# END MAINSEQUENCE AUTH`) as the extension writes it, excludes `.env` from Git, and writes it atomically with private permissions. A file already in that form is not written again. - -Mutations hold a repository lock in the Git common directory, also covering linked worktrees. Before a clone exists, setup locks `..mainsequence-devtools.lock` in its canonical parent directory. Cancellation stops the child process; failures after execution begins report partial or uncertain effects. A failed sync is never automatically retried or rolled back; the lock file, environment or exported requirements may have changed. After an abrupt process kill, inspect running actions before manually removing the stale lock (`mainsequence-devtools.lock` in the Git common directory, or the named setup lock). - -Raw SDK output is private and is not included in results or hook output. Progress reports command lifecycle; supported structured status metadata is filtered. Run the SDK directly in a private terminal when its detailed diagnostic output is needed. Raw credentials are never arguments, public results, or model context. - -## Codex plugin - -The Codex plugin (`mainsequence` in the `mainsequence` marketplace, npm package `@dev-mainsequence/codex-plugin`) is built, verified and released from [mainsequence-codex-plugin](https://github.com/mainsequence-sdk/mainsequence-codex-plugin). It vendors the exact pinned devtools package into its artifact, so an installed plugin needs neither this checkout nor an npm download at execution time. Its hook runs the `/ms` slash-menu commands before inference, and its `mainsequence-mcp` skill exposes the MCP client above in conversation. - -The Codex marketplace is maintained in the Codex plugin repository. This shared library -repository does not host a plugin catalog. Follow the [Codex installation and source -migration instructions](https://github.com/mainsequence-sdk/mainsequence-codex-plugin#install). - -## Reusable API - -```ts -import { createDevTools, createNodeHost } from '@dev-mainsequence/devtools'; - -const tools = createDevTools({ host: createNodeHost() }); -const result = await tools.dispatch({ - action: 'sync', root: '/path/to/project' -}); -``` - -The same dispatcher serves the library, the CLI and the host runners (the Claude Desktop worker and the Codex hook). `parseArguments`, `tokenizeCommand` and `HELP` are exported so a host runner can parse the same command line as `ms-devtools`. `HostServices` supplies browser/process execution, safe progress, cancellation, and optional native folder/terminal operations. Shared code imports no host API. Public types include `ActionRequest`, `ActionResult`, `ProjectContext`, `ActionCapability`, and `SessionStatus`. Credentials stay private to the session service. - -Version 0.3.0 publishes the library and the `ms-devtools` runner only: the npm archive contains `dist`, `README.md`, `LICENSE` and `NOTICE`. VS Code and Claude Desktop pin exact published versions; the Codex plugin does the same from its own repository. See [release and installation](docs/phase-2-release.md) for the publishing procedure, which is unchanged. VS Code's existing SecretStorage fallback remains in that extension; no host introduces fallback project-token projection. - -## Verification +Requires Node 22 or newer. ```sh +npm ci +npm run build +node dist/runner.js --help npm run release:check node scripts/verify-sdk-interop.cjs /path/to/mainsequence-sdk /path/to/command-center-sdk ``` -`release:check` type-checks, builds, runs the tests, checks release metadata and the absence of host/plugin catalogs, packs the npm archive into `artifacts/` and verifies it from an isolated consumer. The Codex host checks moved to the plugin repository with the plugin. - -Tests use a loopback fixture backend, synthetic in-memory store entries, stand-ins for native store programs, installed-CLI fixtures, and temporary Git repositories. They never log in to a real backend or read/write the user's credentials. Loopback networking must be permitted to run the browser tests. The parser, tokenizer and terminal runner have their own suite in `tests/arguments.test.cjs`, since host runners depend on them. - -The optional SDK compatibility script checks the **actual provided SDK source implementations** against synthetic in-memory records in both directions, with an isolated temporary Python home. It imports the SDK private session implementation only for compatibility verification, never as a product dependency, and loads its dependencies from the specified checkout without running the SDK initializer. Set `MAINSEQUENCE_TEST_PYTHON=/path/to/sdk/.venv/bin/python` when its CLI dependencies are unavailable to `python3`. Native-store behavior is tested using the extracted macOS/Linux program fixtures; live OS-store and backend refresh-rotation interoperability require a separate release check. - -See [ADR 0001](docs/adr/0001-shared-developer-tooling-and-codex.md), [ADR 0004](docs/adr/0004-shared-project-tool-registry.md), [Phase-1 verification](docs/phase-1-verification.md) and [Phase-2 verification](docs/phase-2-verification.md) for boundaries and outstanding checks. - -## Phase 2 host integration - -`createSessionService` owns browser authorization, authenticated HTTP, refresh and revocation. `RepositoryClient` owns the canonical backend response and Git-resolution contracts. `createDevTools` owns project actions and cancellation. Hosts import only `@dev-mainsequence/devtools`; no private paths or sibling SDK source imports are used. - -`HostAuthSession` is an opt-in compatibility adapter for asynchronous host SecretStorage, machine-session adoption, and the existing host projection/migration policy. Its `get`, `save`, `environment` and `persistence` methods are privileged credential bridges for host internals: never put their values in webview state, progress, logs, hook output, or action results. Codex uses native persistence directly and does not enable this fallback. - -## Shared operations and integration ownership - -Version 0.2.2 adds the [public project operations API](docs/shared-project-operations.md). -Claude Desktop is maintained in [its own repository](https://github.com/mainsequence-sdk/mainsequence-claude-desktop). -The Codex plugin is maintained in [its own repository](https://github.com/mainsequence-sdk/mainsequence-codex-plugin) since 0.3.0. -See the [integration roadmap](docs/integration-roadmap.md) for ownership and the deferred OpenCode extraction. - -Workspace defaults and environment-scoped MCP host APIs are documented in -[workspace settings and environments](docs/workspace-environments.md). - -Version 0.2.4 adds the reusable [agent directory and conversation API](docs/agent-conversations.md), -using existing platform MCP contracts and the selected organization environment. -Claude's pane and prompt integration remain in its own repository. +`release:check` type-checks, builds, runs the tests, checks the release metadata and the +documentation, packs the npm archive into `artifacts/` and verifies it from an isolated +consumer. Tests use a loopback fixture backend, synthetic in-memory store entries, +stand-ins for the native store programs, installed-CLI fixtures and temporary Git +repositories; they never log in to a real backend or read or write the user's +credentials. Loopback networking must be permitted for the browser tests. The parser, +tokenizer and terminal runner have their own suite in `tests/arguments.test.cjs`, since +host runners depend on them. + +The optional SDK compatibility script checks the actual SDK source implementations +against synthetic in-memory records in both directions, with an isolated temporary Python +home. It imports the SDK private session implementation only for that check and loads its +dependencies from the given checkout without running the SDK initializer. Set +`MAINSEQUENCE_TEST_PYTHON=/path/to/sdk/.venv/bin/python` when its CLI dependencies are +unavailable to `python3`. Live OS-store and backend refresh-rotation interoperability are a +separate release check. + +## Release + +The npm archive contains `dist`, `README.md`, `LICENSE` and `NOTICE`; host adapters, +manifests and marketplaces are released from their own repositories. To release: set the +new version in `package.json` and `package-lock.json`, run `npm run release:check`, merge, +and push the tag `v`. The release workflow (`release.yml`, GitHub environment +`npm`) repeats the checks and publishes the verified archive with provenance through npm +trusted publishing. Published versions are immutable; never republish a rebuilt archive +under an existing version. Write the release notes on the GitHub release of that tag. +After publishing, read the archive's integrity from the registry +(`npm view @dev-mainsequence/devtools@ dist.integrity`; a local `npm pack` has +another) before a host pins the new version in its lockfile. diff --git a/docs/adr/0001-shared-developer-tooling-and-codex.md b/docs/adr/0001-shared-developer-tooling-and-codex.md index 9a5d1a0..f5e86f0 100644 --- a/docs/adr/0001-shared-developer-tooling-and-codex.md +++ b/docs/adr/0001-shared-developer-tooling-and-codex.md @@ -13,7 +13,7 @@ Amended 2026-10-09 by owner request to extend the Codex plugin with conversation - **Amended 2026-10-21:** the Codex adapter, manifests, skills, host checks and releases moved to [mainsequence-codex-plugin](https://github.com/mainsequence-sdk/mainsequence-codex-plugin) ([ADR 0003](0003-codex-plugin-extraction.md)). From 0.3.0 this package is the shared library and the `ms-devtools` terminal CLI; `parseArguments`, `tokenizeCommand` and `HELP` are public exports for host runners, and the `--codex-hook` entry point lives in the plugin's own runner. The npm archive no longer carries `.codex-plugin`, `hooks`, `skills`, `assets`, `build-info.json` or `docs`. -Phase 1 and the Phase 2 package/VS Code migration are implemented, and npm 0.2.0 is published. VS Code pins the published archive. Subsequent Codex fixes are installed in the local development plugin and require a new version for their npm release. See [usage and packaging](../../README.md), [Phase-1 verification](../phase-1-verification.md) and [Phase-2 verification](../phase-2-verification.md). Actual Codex app-server turns verify zero inference requests for handled actions, and CLI results/trust review are verified. Desktop rendering remains experimental pending manual verification. Live store/refresh-rotation and full backend/Git deployment checks remain release validation items. +Phase 1 and the Phase 2 package/VS Code migration are implemented, and npm 0.2.0 is published. VS Code pins the published archive. Subsequent Codex fixes are installed in the local development plugin and require a new version for their npm release. See [usage and packaging](../../README.md); the Phase-1 and Phase-2 verification records were removed on 2026-10-24 and remain in Git history. Actual Codex app-server turns verify zero inference requests for handled actions, and CLI results/trust review are verified. Desktop rendering remains experimental pending manual verification. Live store/refresh-rotation and full backend/Git deployment checks remain release validation items. ## Context diff --git a/docs/adr/0003-codex-plugin-extraction.md b/docs/adr/0003-codex-plugin-extraction.md index 1f8a387..e532476 100644 --- a/docs/adr/0003-codex-plugin-extraction.md +++ b/docs/adr/0003-codex-plugin-extraction.md @@ -18,7 +18,7 @@ library pinned by VS Code and Claude Desktop, and the installable Codex plugin. The Claude Desktop integration already lives in [mainsequence-claude-desktop](https://github.com/mainsequence-sdk/mainsequence-claude-desktop), consuming only the public package API and bundling the pinned package into its own -artifact. The [integration roadmap](../integration-roadmap.md) deferred the same move for +artifact. The integration roadmap (since removed) deferred the same move for Codex: "extract adapter, manifests, host tests and releases into an independent repository. Preserve plugin identity and installation compatibility." diff --git a/docs/agent-conversations.md b/docs/agent-conversations.md index 3d5bc7d..3e73954 100644 --- a/docs/agent-conversations.md +++ b/docs/agent-conversations.md @@ -1,6 +1,6 @@ # Shared platform agent conversations -The additive 0.2.6 API discovers agents and exchanges messages through the existing +This package discovers agents and exchanges messages through the existing MainSequence `/mcp` gateway. No backend routes, schemas, account handling, or provider configuration change. Claude UI, native draft/command handling and conversation controls belong to `mainsequence-claude-desktop`; this package contains only the reusable @@ -56,7 +56,7 @@ Set `waitForReady: true` on `agent-send` to use the same readiness gate immediat before dispatch, including task continuation. A readiness failure has no uncertain message effect; a failure after dispatch retains the existing uncertain-send marker. This option defaults off for compatibility with existing adapters, whose gateway -sender continues to own readiness. Claude 0.4.5 opts in. No UI package, Python SDK +sender continues to own readiness. The Claude Desktop plugin opts in. No UI package, Python SDK or direct runtime HTTP transport is added. A send may use that resolved `sessionUid`, or a stable handle for legacy clients. @@ -78,7 +78,7 @@ sixth request argument accepts a per-request `timeoutMs` up to 300,000 milliseco Agent replies are external data. Consumers must not treat returned text or card descriptions as instructions that override user requests or permission checks. -## Durable host delivery (0.3.3) +## Durable host delivery `AgentDelivery` is a public, host-independent coordinator. Construct it with `createDispatch(signal)` returning the existing `createDevTools(...).dispatch`, @@ -126,23 +126,6 @@ session allocation/resolution without messaging, timeout metadata, session conti behavior using a synthetic MCP transport. These are contract tests, not evidence of live agent availability. Existing authentication and project tests remain in the suite. -Version 0.2.4 was published on 2026-10-15 from commit `57bb311` through the existing -[trusted-publisher workflow](https://github.com/mainsequence-sdk/mainsequence-devtools/actions/runs/38732377231). -The public registry archive is verified with integrity -`sha512-RgU8NALWU6XjCMC297pVcfjyM5xEQlZjnxdTKXkgBSWF1MX8HHreGMxA7xbdxs+SjWJczJ3bhBYmxsqJGxLQkQ==`. -Claude's consumer lockfile pins that archive. Publication does not update the Claude -marketplace or existing VS Code/Codex pins. See the [release procedure](phase-2-release.md); -do not republish a rebuilt archive under an existing npm version. - -Version 0.2.5 adds session allocation/resolution without a message and validated -platform tool deadlines. Claude 0.4.4 consumes this additive API. Release through -the existing trusted-publisher workflow, verify the public archive integrity, and -then pin that archive in the consumer. Existing Codex marketplace and VS Code pins -are unchanged by this shared-library release. - -Version 0.2.6 adds readiness preparation and opt-in send-time revalidation for Claude -0.4.5. Existing session allocation and other adapter behavior remain unchanged. - Agent list, search and detail results include `defaults: { provider, model, thinking }`, projected only from existing `llm_provider`, `llm_model` and `llm_thinking` fields. Empty or absent fields remain empty strings. These are Agent defaults for new sessions, not a claim about a resumed session’s resolved configuration. Runtime configuration and credential fields are excluded. diff --git a/docs/conversational-mcp.md b/docs/conversational-mcp.md deleted file mode 100644 index 8701093..0000000 --- a/docs/conversational-mcp.md +++ /dev/null @@ -1,19 +0,0 @@ -# Conversational project MCP connections - -The user guide moved on 2026-10-21 to the Codex plugin repository: -[mainsequence-codex-plugin/docs/conversational-mcp.md](https://github.com/mainsequence-sdk/mainsequence-codex-plugin/blob/main/docs/conversational-mcp.md). - -This package keeps the client and its command-line form. `ms-devtools mcp-discover`, -`mcp-add`, `mcp-list`, `mcp-remove`, `mcp-tools` and `mcp-call` are listed by -`ms-devtools --help`, and `createDevTools().dispatch()` accepts the same `mcp-*` -actions through `ActionRequest`. Hosts may inject `mcpConnectionsPath` for their own -metadata location. See [ADR 0002](adr/0002-conversational-project-mcp-client.md). - -Since 0.3.12 the saved connections' tools are also available as a host registers them, -`ms__`, through `ms-devtools mcp-catalog [--refresh]` and the `mcp-catalog` -action, from the shared `project-tool-catalog.json` beside `mcp-connections.json`; see the -[shared project-tool registry](../README.md#shared-project-tool-registry-0312) and -[ADR 0004](adr/0004-shared-project-tool-registry.md). A cold project MCP has taken over a -minute to answer `initialize`: project requests get 120 s by default -(`projectRequestTimeoutMs`), and a tool's advertised -`_meta["mainsequence.ai/timeout-seconds/v1"]` is honoured when larger, capped at 300 s. diff --git a/docs/integration-roadmap.md b/docs/integration-roadmap.md deleted file mode 100644 index a14e682..0000000 --- a/docs/integration-roadmap.md +++ /dev/null @@ -1,32 +0,0 @@ -# Integration ownership and deferred extraction - -The shared package is `@dev-mainsequence/devtools`. Each integration consumes its -public API, pins a compatible version, and owns its host-specific implementation. - -| Integration | Current ownership | Follow-up | -| --- | --- | --- | -| VS Code | [ms-vscode-extension](https://github.com/mainsequence-sdk/ms-vscode-extension) already owns the extension and pins devtools; inspected version 0.1.47 uses 0.2.1. | No repository move or pin update in this migration. Adoption of new shared operations is separate work. | -| Claude Desktop | [mainsequence-claude-desktop](https://github.com/mainsequence-sdk/mainsequence-claude-desktop) owns all Claude UI, lifecycle, account switching, worker transport, tests, docs, marketplace and releases. | Depends on the released devtools package; no sibling checkout or private imports. | -| Codex | Extracted on 2026-10-21: [mainsequence-codex-plugin](https://github.com/mainsequence-sdk/mainsequence-codex-plugin) owns the hook adapter, presentation, manifests, skills, host checks, tests, docs, marketplace and releases of the `mainsequence` plugin ([ADR 0003](adr/0003-codex-plugin-extraction.md)). | Depends on the released devtools package; no sibling checkout or private imports. The Codex marketplace moved into its host repository on 2026-10-24; this shared repository has no plugin catalog. | -| OpenCode | Existing implementation remains in the development checkout. | Deferred: extract server/TUI/RPC integration, manifests, host tests and releases into an independent repository. Preserve plugin identity and configuration. | - -The Codex extraction is implemented by devtools 0.3.0; the plugin is renamed from -`mainsequence-devtools` to `mainsequence`, so existing installs migrate by installing -the new entry (see the Codex repository's README). The OpenCode extraction remains -deferred: it needs a separately agreed repository destination, compatibility plan, -package pin, host verification and release. - -The 0.2.2 core release adds reusable project operations without publishing pending -OpenCode changes from the development checkout. That checkout retains its planned -0.3.0 version and existing changes. Both current repositories are public; no -visibility change is required. Claude 0.3.1 independently consumes devtools 0.2.2. -Previously published Claude 0.3.0 remains an immutable preview. - -Publication verified on 2026-10-14: devtools 0.2.2 is available from public npm, -and [Claude migration PR #1](https://github.com/mainsequence-sdk/mainsequence-claude-desktop/pull/1) -is merged. The [Claude 0.3.1 preview](https://github.com/mainsequence-sdk/mainsequence-claude-desktop/releases/tag/v0.3.1) -uses a registry lockfile and passed a fresh dependency install, Linux/macOS CI, -anonymous archive/checksum download and isolated native-engine installation. -Its marketplace advertises the verified 0.3.1 ZIP. The existing Codex marketplace -and VS Code dependency remain on 0.2.1; this release does not migrate those hosts. -Live Claude GUI/account acceptance remains tracked in the Claude repository. diff --git a/docs/organization-projects.md b/docs/organization-projects.md index e29fb7d..8691349 100644 --- a/docs/organization-projects.md +++ b/docs/organization-projects.md @@ -21,7 +21,7 @@ whose backward-compatible API still handles local repository operations. No new backend route, schema or grant is introduced; runtime/workload credentials remain outside the human Project API. -Links revalidate membership and use canonical Foundry URLs when the host supplies +Links revalidate membership and use Command Center URLs when the host supplies `commandCenterUrl`. Otherwise repository/branch links use the authorized GitHub binding. Missing/inaccessible bindings are reported, not guessed. Only HTTP(S) URLs without credentials are opened. diff --git a/docs/phase-1-verification.md b/docs/phase-1-verification.md deleted file mode 100644 index 895d745..0000000 --- a/docs/phase-1-verification.md +++ /dev/null @@ -1,42 +0,0 @@ -# Phase-1 implementation and verification - -Implemented on 2026-09-30 from ADR 0001. One private npm package contains shared TypeScript contracts/actions, extracted browser and native machine authentication, repository/project orchestration, the deterministic CLI, and the Codex prompt adapter. SDK and VS Code repositories remain unchanged. - -## Source baseline - -| Repository | Inspected source | -| --- | --- | -| Python SDK | `development`, `66f11a48`, next source version `8.1.28` | -| Command Center SDK | `main`, `6c083af`, prepared source version `0.5.11` | -| VS Code extension | `main`, `4bb107e`, version `0.1.45`, including the user's existing uncommitted dispatcher/metadata changes | - -Extraction provenance is recorded in `NOTICE`. The copied native store retains the existing service, backend hash, version-1 ASCII record, macOS entry mark/stdin guard, and Linux Secret Service attributes. This implementation also refuses future record versions and avoids deleting an unscoped legacy session associated with another backend. - -## Automated checks - -Local suite result: **42 tests passed, 0 failed**. Build, SDK source compatibility, and isolated public npm consumer checks also passed. - -- TypeScript strict compilation/type checking. -- Fixture browser login against the existing PKCE/token endpoints, state verification, durable save/read-back, profile lookup, renewal, logout, timeout/cancellation, and token-free results. -- Synthetic native macOS/Linux store program tests, foreign entry protection, missing/unavailable stores, backend isolation, and refresh-only records. -- Current SDK source interoperability using explicit checkout paths: common records read by both SDKs; Python records read by common/Node; Node records read by common/Python; exact backend identity checked across two backends. Python runs with an isolated temporary home and synthetic store; it imports no application auth bootstrap. -- Installed-CLI fixtures validate Python/Node argv, local CLI selection, capability probing, dependency/source policy, explicit credential/backend association, safe status filtering, cancellation/timeouts, and unsupported MCP skills. -- Sync fixtures create real Git commits and tags in temporary projects. They verify paths with spaces, literal shell syntax in messages, dry-run dispatch, partial failure without retry/rollback, and repository lock cleanup. -- Setup uses a temporary home, synthetic SSH keypair, fixture backend contracts, and a local clone; verifies key registration, canonical folder layout, endpoint-only `.env`, and existing-folder protection. -- Project cleanup covers exported/spaced assignments, unrelated settings, private permissions, Git-tracked files, and symlinks. -- Built plugin copied outside this checkout runs without `node_modules` or sibling repositories; ordinary prompts pass through and explicit actions return blocking hook JSON. -- Plugin tarball and local npm tarball are built without publication. The npm consumer check uses only its public export. - -Tests were run locally on macOS with Node `25.2.0`. CI is configured for Node 22 on macOS and Linux; those hosted jobs have not been run in this local task. - -## Remaining release checks - -These are explicitly unverified and are not implied by fixture success: - -1. Desktop app interception before inference, visible hook results, trust review, and host timeout behavior. The chat hook remains experimental; the direct runner is the supported zero-LLM path. -2. Live macOS/Linux credential-store round trips across all three tools and simultaneous Python/Node renewal against the real backend's refresh-token rotation policy. No cross-language renewal lock is claimed. -3. Full installed-SDK sync through a real backend and Git remote, including server deployment-tag selection and atomic push. Fixtures exercise orchestration and Git changes, not that external deployment path. No longer applicable since 2026-10-02: sync only refreshes dependency files and contacts no backend. -4. Windows native machine persistence, which the extracted Node implementation does not support. -5. An existing non-MCP API for backend-owned skills. Until verified, these commands are unsupported here. - -No real login, logout, token refresh, credential-store mutation, SDK update, user-project sync, or deployment was performed during verification. diff --git a/docs/phase-2-release.md b/docs/phase-2-release.md deleted file mode 100644 index cdcb886..0000000 --- a/docs/phase-2-release.md +++ /dev/null @@ -1,60 +0,0 @@ -# Phase 2 release and installation - -> Historical record of the 0.2.x releases. Since devtools 0.3.0 the Codex plugin is built, verified and released from [mainsequence-codex-plugin](https://github.com/mainsequence-sdk/mainsequence-codex-plugin); the Codex artifact, local marketplace and `verify-codex-*` scripts named below no longer exist in this repository. See [ADR 0003](adr/0003-codex-plugin-extraction.md). - -One repository, one npm package, one lockfile. Both SDKs remain unchanged. - -## Artifacts - -The additive 0.2.2 release is now published on public npm. It exposes shared -project operations for independent integrations. Claude Desktop 0.3.1 pins that -registry archive; its source, lockfile, marketplace and releases live in -[mainsequence-claude-desktop](https://github.com/mainsequence-sdk/mainsequence-claude-desktop). -The existing Codex marketplace and VS Code pin remain on 0.2.1. See -[integration ownership](integration-roadmap.md) and the -[shared project API](shared-project-operations.md). - -`@dev-mainsequence/devtools@0.2.1` contains the public TypeScript/JavaScript API, `ms-devtools` runner, `.codex-plugin/plugin.json`, the explicit-only `ms` skill registration, hooks and version metadata. The npm registry can therefore serve both VS Code's build dependency and Codex's marketplace package source. No package is downloaded when an action executes. The supported Codex compatibility manifest is required here: the tested 0.159.2 runtime recognized a root Agent Plugins manifest but skipped its hooks. Shipping both selected the root format and suppressed the hook, so this package deliberately omits root `plugin.json`. The installed 0.2.1 plugin also passes the actual-host checks on Codex 0.162.0-alpha.2. - -The same build produces `artifacts/codex/mainsequence-devtools/`, the standalone plugin archive, and a local marketplace at `artifacts/local-marketplace/`. VS Code pins the package and copies the compiled distribution into `out/vendor/devtools` during compile; its VSIX includes that copy with version metadata. No new shared repository or npm workspace is needed. - -## Verify and publish - -1. Assign a new release version consistently across the package and built plugin manifest; published npm versions are immutable. Keep the public marketplace on its last published version during preparation. Run `npm ci --ignore-scripts`, then `npm run release:check`. -2. Verify VS Code against that packed npm archive, including its lockfile integrity and VSIX contents. Keep the exact archive used to generate the consumer lockfile. -3. Authenticate with `npm login` or the configured trusted publisher, then publish the exact verified archive for the new version with `--ignore-scripts --access public`. Do not publish a development rebuild under an existing release version. -4. Configure npm trusted publishing for `mainsequence-sdk/mainsequence-devtools`, workflow `release.yml`, GitHub environment `npm`, allowing direct `npm publish`. Subsequent version tags run checks, upload archives and publish that checked npm artifact through OIDC. A manual workflow run defaults to checks/artifacts only. -5. Verify the new version is available from the public registry and matches the checked artifact before advancing the public marketplace or consumer dependency pins. `scripts/check-release.cjs` checks producer metadata and release tags; it permits the public marketplace to remain on an older release. The consumer lockfile identifies the exact npm archive, not an arbitrary local checkout. - -The public npm registry serves 0.2.1, and VS Code 0.1.47 pins that registry archive with integrity `sha512-7cYZN5fUJi4347BO38LES6Uvi+p+szR+SqLiv9ngsnC91S/6vcoKIfRr38xCcSJ0LmG4vlx+namtLqmDSzxt7g==`. This release includes line-ending and readable-output fixes, dependency-only sync and removal of `freeze-env`. Local builds and installations do not update the published archive. Verify registry integrity before updating a consumer pin. - -Trusted publishing needs npm 11.5.1+ and Node 22.14+; the release workflow uses Node 22 and npm 11.6.2. See [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/). - -## Install Codex locally - -```sh -npm run build -codex plugin marketplace add /absolute/path/mainsequence-devtools/artifacts/local-marketplace -codex plugin add mainsequence-devtools@mainsequence-local -``` - -Review and trust the current hook definition in Codex (`/hooks` in the CLI). Start a new session after installation. For an existing desktop chat, toggle MainSequence Developer Tools off and on in Plugins settings after the current agent turn ends; this uses the supported configuration hot reload. External CLI installation alone does not update a loaded thread's hooks. Installation itself does not trust hooks. The local catalog loads the built artifact, while the installed plugin runs from Codex's cache. This machine's `mainsequence-devtools@mainsequence-local` installation is enabled and its exact hook definition has been reviewed and trusted. - -After installation, run `node scripts/verify-codex-host.cjs` for an opt-in host integration check. It creates ephemeral Codex sessions, disables the MainSequence MCP server for those sessions, and directs inference to a local counted HTTP fixture. It verifies native `ms` skill registration and exercises help, failures, and valid SDK sync commands that refresh dependency files in temporary repositories without changing their Git state or contacting the backend. Handled commands make zero model requests, including while sync is running; ordinary prompts pass through to the offline fixture. The default check uses no live MainSequence authentication. Optionally set `MAINSEQUENCE_CODEX_SYNC_PROJECT=/absolute/project/path` to check, with the read-only `status` command, that a real project's installed SDK offers the dependency-only sync; this changes nothing in that project. No check contacts a real model endpoint. - -## Install the published Codex release - -Current installation instructions and the public marketplace are maintained in -[mainsequence-codex-plugin](https://github.com/mainsequence-sdk/mainsequence-codex-plugin#install). -The former Codex marketplace in this shared repository was removed on 2026-10-24. -Use the Codex repository’s instructions to replace an existing marketplace source. -The historical 0.2.x package details elsewhere in this document are not current -installation instructions. - -See [Codex plugin packaging and npm sources](https://developers.openai.com/plugins/build/plugins) and [plugin commands](https://learn.chatgpt.com/docs/developer-commands). - -## Execution and limits - -In Codex desktop, type `/ms`, select the native `ms` slash-menu entry, append arguments such as `--help`, and submit. The skill registers the interface; its linked mention is intercepted by the trusted hook and executed by the bundled runner. Ordinary prompts pass through. Handled actions return a blocking hook result, with credentials excluded from results and logs. Installed registration and zero inference requests, including valid Python and Node dependency syncs, are verified in actual Codex 0.162.0-alpha.2 app-server turns. The desktop menu/renderer and long-operation UI still need manual verification. Codex CLI 0.159.2 rejected custom `/ms` before submission; use the `ms-devtools` terminal runner there. See [Phase-2 verification](phase-2-verification.md). - -Native machine mode shares the SDK record and leaves repository `.env` files endpoint-only, the endpoint in the VS Code extension's block. VS Code explicitly supplies its existing SecretStorage fallback/projection policy where native persistence is unavailable, and opts into its SDK-owned MCP skills workflow. Codex enables neither option. SDK project operations retain their existing implementations; no SDK depends on this npm package. diff --git a/docs/phase-2-verification.md b/docs/phase-2-verification.md deleted file mode 100644 index e834275..0000000 --- a/docs/phase-2-verification.md +++ /dev/null @@ -1,106 +0,0 @@ -# Phase 2 verification — updated 2026-10-08 - -> Historical record of the 0.2.x releases. Since devtools 0.3.0 the Codex plugin is built, verified and released from [mainsequence-codex-plugin](https://github.com/mainsequence-sdk/mainsequence-codex-plugin); the Codex artifact, local marketplace and `verify-codex-*` scripts named below no longer exist in this repository. See [ADR 0003](adr/0003-codex-plugin-extraction.md). - -The shared package and VS Code migration are implemented. The public npm registry serves `@dev-mainsequence/devtools@0.2.1`; its downloaded archive matches VS Code's lockfile integrity `sha512-7cYZN5fUJi4347BO38LES6Uvi+p+szR+SqLiv9ngsnC91S/6vcoKIfRr38xCcSJ0LmG4vlx+namtLqmDSzxt7g==`. This release includes the Codex line-ending and readable-output fixes and dependency-only sync. `mainsequence-devtools@mainsequence-local` is installed, enabled and trusted in the local Codex plugin cache (`~/.codex/plugins/cache/mainsequence-local/mainsequence-devtools/0.2.1`). All 50 compiled runner, plugin, hook, skill and asset files match the repository build. Published archives remain immutable. - -## Compatibility audit — 2026-10-08 - -All four repositories' remote refs were fetched. These are the integration baselines checked: - -| Repository | Ref | Commit | Version | -| --- | --- | --- | --- | -| Developer tools | `origin/main` | `e46888e` | 0.2.1 | -| VS Code extension | `origin/main` | `48ddfc3` | 0.1.47; pins devtools 0.2.1 | -| Python SDK | `origin/development` | `5ebcd264` | 9.0.20 declared as the next release; publication not checked | -| Command Center SDK | `origin/main` | `519008a` | 0.5.16 | - -Developer tools, VS Code and Command Center SDK matched their fetched main branches. The local Python SDK `development` checkout was four commits behind; the entire difference was version declarations in `pyproject.toml` and `uv.lock`. Its CLI and authentication source used in the interoperability check is identical to fetched `origin/development`. - -Recent Python SDK changes add projected workload identity tokens for runtime credentials and exclude credentials from diagnostic representations. Developer browser authorization, refresh endpoints and the version-1 machine-session record remain compatible with the shared tooling. Synthetic record interoperability passed in all directions between developer tools and both SDKs, for two backend identities. The verification script now isolates the requested Python source package so a new CLI dependency cannot accidentally import and initialize an older globally installed SDK. Both the SDK virtual-environment interpreter and default `python3` passed. - -VS Code's package and lockfile already pinned 0.2.1, but its local `node_modules` still held 0.2.0. The verified published archive replaced that dependency using `scripts/use-local-devtools.cjs`; a fresh compile regenerated `out/vendor/devtools` at 0.2.1 and all 43 tests passed. No VS Code source or lockfile change was required. Neither SDK was modified. - -Codex 0.162.0-alpha.2 passed 13 help/error/pass-through cases and two valid dependency-sync cases against the installed plugin. Python and Node SDK fixtures executed with zero backend requests, zero model requests both during execution and afterward, refreshed dependency files, unchanged Git HEAD/tags and released locks. The isolated existing-chat reload regression also passed on this host: an external enable alone does not reload an existing chat, while a new chat or supported configuration hot reload intercepts commands with zero model requests. These checks exercise the actual host API, not the desktop composer or a live project's dependency installation. - -## Shared package and consumer - -- Strict TypeScript compilation and 62 shared tests pass. Fixtures cover the canonical credential record, browser authorization, refresh rotation, rejection/identity boundaries, host fallback, repository resolution, dependency-only SDK sync, rejection of retired SDK sync capabilities, cancellation and hook packaging. -- The migrated `ms-vscode-extension` compiles and its 43 tests pass, including Python distribution status with `MAINSEQUENCE_TEST_PYTHON` set to the SDK virtual environment. New adapter checks cover shared session renewal, native versus fallback credential handoff, literal SDK arguments, Electron's Node mode, cancellation and workspace trust. Existing user changes were retained. -- The public npm archive works from an isolated ESM consumer without SDKs or runtime npm dependencies. Private deep imports are rejected by package exports. -- VS Code pins the published 0.2.1 archive and bundles its installed public distribution into `out/vendor/devtools`. Earlier Phase 2 VSIX checks established that packaging includes the vendored distribution and version metadata without runtime `node_modules`, sibling checkouts or private package imports. The October 8 audit rebuilt the vendor directory and ran the consumer tests; it did not install a new VSIX. The lockfile integrity identifies the registry archive rather than a later development build with the same version. -- Synthetic interoperability checks pass in both directions against the actual Python SDK `development` and Command Center SDK `main` session implementations. Both SDK repositories remain unchanged. These checks do not access the user's credential store or log in to a live backend. - -## Installed Codex host - -Codex 0.159.2 recognized the initial root Agent Plugins manifest but returned no hook from `hooks/list` or `plugin/read`. The supported `.codex-plugin/plugin.json` entry point exposes the hook correctly. The package now ships only that entry point, and packaging checks reject a root `plugin.json` that would take precedence and suppress hooks. - -The CLI `/hooks` review showed the exact installed runner command, synchronous mode and 600-second host timeout. Only MainSequence's hook was trusted. A subsequent app-server query returned `trustStatus: "trusted"`, `enabled: true`, and the installed plugin's source path. The original implementation tested only a text prefix; that did not register a Codex interface. It has been replaced by an explicit-only `ms` skill for native desktop slash-menu registration and a hook that recognizes its linked mention. `skills/list` now returns an enabled `mainsequence-devtools:ms` entry with display name `ms`, and `plugin/read` exposes both the skill and hook. Duplicate result warnings were removed after observing host presentation. - -`scripts/verify-codex-host.cjs` tests actual app-server turns using an ephemeral session and a counted loopback model fixture, with the MainSequence MCP server disabled for that session. It verifies the installed skill registry and submits the native linked mention together with an explicit skill input item. The following current cases passed on Codex 0.162.0-alpha.2 on October 8. No real inference endpoint is used: - -| Prompt | Action result | Host hook status | Model requests | -| --- | --- | --- | --- | -| selected `ms` + `--help` | success | blocked | 0 | -| selected `ms` + `--help --json` | success, structured output requested explicitly | blocked | 0 | -| literal `/ms --help --all` | success, complete command menu | blocked | 0 | -| literal `/ms sync --help` | success, command-specific options | blocked | 0 | -| selected `ms` + `--help` with the desktop's trailing newline | success | blocked | 0 | -| selected `ms` without arguments, with a trailing newline | success, help | blocked | 0 | -| selected `ms` + `invalid-action` | failure | blocked | 0 | -| selected `ms` + `sync --message "retired option"` | failure, retired option explained | blocked | 0 | -| literal `/ms --help` ending in LF or CRLF | success | blocked | 0 | -| literal `/ms --help` followed by `status` on another line | failure, invalid request | blocked | 0 | -| literal `/ms sync` in Python fixture | success, dependency files refreshed | blocked | 0, including in flight | -| selected `ms` + `sync` in Node fixture | success, dependency files refreshed | blocked | 0, including in flight | -| ordinary fixture prompt | passes through | completed | 1, to the offline fixture | -| `:ms --help` | passes through | completed | 1, to the offline fixture | - -The hook result is present in the host event stream on success and failure. The fixture intentionally rejects the ordinary prompt's model request; it proves pass-through without consuming inference. This check is opt-in and requires an installed, enabled, reviewed hook; it never bypasses hook trust. It does not operate the desktop composer. Static inspection of the installed desktop code confirms that enabled skills register slash entries using their display name and selecting one inserts a linked mention. A live CLI composer check confirms that Codex CLI 0.159.2 rejects custom `/ms` input before submission; the app-server literal-input test does not establish CLI slash support. Use the terminal runner in the CLI. - -## Existing-chat reload regression — 2026-10-01 - -The user's selected native `ms` entry with `--help` reached the model in this pre-existing desktop chat. Menu registration was demonstrated by the linked skill mention, but interception did not occur. The plugin configuration was enabled and its exact hook hash was trusted; that alone does not establish that a loaded chat has adopted the hook. - -`scripts/verify-codex-reload.cjs` reproduces this in a temporary Codex home with this repository's plugin artifact and a counted offline model fixture. It starts a thread while the plugin is disabled, enables the plugin externally, and compares that loaded thread with a new thread and a supported configuration hot reload: - -| Case | Hook runs | Model requests | -| --- | --- | --- | -| Existing thread after external enable | none | 1, rejected by offline fixture | -| New thread in the same backend | blocked | 0 | -| Existing thread after `config/batchWrite` with `reloadUserConfig: true` | blocked | 0 | - -The fixture copies only this exact previously reviewed MainSequence hook definition's trust hash; it uses no live authentication and configures no MCP server. Assertions require completed turns and the above results. The regression was rerun on 2026-10-08 with Codex 0.162.0-alpha.2 and passed with the same behavior. - -A terminal installation does not hot-reload a chat that was already running. Toggle MainSequence Developer Tools off and on in the desktop Plugins settings; the installed app's plugin setting code sends `config/batchWrite` with `reloadUserConfig: true`. Alternatively, start a new Codex chat after installation. - -The user's subsequent screenshot shows the hook blocking the native entry in this chat. Its failure exposed a second issue: the desktop composer appends a newline to submitted text, which the single-line parser rejected. The adapter now removes trailing layout whitespace before parsing while retaining rejection of embedded newlines. Adapter tests and installed-host checks accept the exact trailing-newline form with zero model requests. The user subsequently supplied the successful help result from the desktop. - -## Readable Codex output — 2026-10-01 - -That successful help result was displayed as compact JSON with escaped newlines. The first presentation fix removed the envelope but still dumped each command's `data` object and reused the dense terminal help. The Codex adapter now has its own presentation layer: a short getting-started menu, a full menu at `/ms --help --all`, command-specific options, named repository entries, account summaries and readable project/SDK fields. Default output contains no serialized data objects or internal store/lock metadata. Clear failure messages include next steps where appropriate; partial-effect warnings remain visible. Explicit `--json` retains the unchanged versioned action result and error codes, and a literal `--json` message value does not select export mode. - -The installed-host fixture asserts actual line breaks, the command menus, absence of a JSON envelope, and zero model requests; it separately checks explicit JSON output. Formatter fixtures cover repository lists, empty results, machine-session status, project capabilities and SDK source-versus-registry distinctions. Codex still marks the hook as blocked because it stops the prompt before inference, including after successful actions. This changes the text presentation rather than replacing the host-owned card or adding interactive components. The subsequent desktop screenshot confirms the compact getting-started menu; runtime API tests verify the other field layouts. - -## Historical release-sync regression — 2026-10-02 - -A sync submission displayed the desktop's generic “Thinking” placeholder without a result. The hook had acquired the repository action lock at the submission time, but the SDK's backend lookup stalled. The saved CLI backend was an unavailable localhost service. A direct read-only SDK preflight continued retrying until it was stopped at 45 seconds; the original Codex turn was interrupted after 30 seconds, leaving a stale lock and no new commit. The lock was removed only after checking that its owner had exited and no SDK sync, Git, or dependency operation remained. - -At that time, a temporary Codex preflight used an unauthenticated HEAD request with a five-second deadline to report `BACKEND_UNREACHABLE` before running the SDK. A shared optional `prepareProjectAction` callback supplied it. Both were subsequently removed when SDK sync became a local dependency refresh, as described below. They are not part of 0.2.1. - -The original release-sync host fixtures deliberately paused before creating commits and tags. They established zero model requests while the SDK was running and afterward, and lock cleanup. Those fixtures have been replaced by dependency-only sync checks that require unchanged Git state and zero backend requests. Earlier help-only host checks did not establish valid SDK execution. - -Historical opt-in checks of the affected project returned `BACKEND_UNREACHABLE` in approximately 1.3 seconds and, after the backend came online, completed a read-only SDK sync preflight in approximately four seconds. Both made zero model requests and did not commit, tag or push the project's changes. The unavailable-project check and sync dry run no longer exist; the current opt-in real-project check uses `status` only. - -## Dependency-only sync — 2026-10-02 - -Sync no longer commits, tags, pushes or contacts the backend (see the ADR amendment of 2026-10-02). The stall above came from the SDK's backend lookup, which the dependency-only sync no longer makes, so the Codex backend preflight and the shared `prepareProjectAction` host callback added for it were removed; neither was in the published 0.2.0 archive. Sync dispatches exactly `code-repository sync --path .`. An installed SDK whose sync help still offers `--dry-run` or `--message` is reported unavailable with `update-sdk` as the repair, and its sync is not run. `freeze-env` was removed. - -The shared suite's SDK fixtures now model the released CLIs: Python prints the selected command's help, Node prints one usage text, sync refuses any argument but `--path` with exit 2 and writes only dependency files, and a second fixture advertises the retired release sync. Tests assert the exact argv, unchanged `HEAD` and tags, zero backend requests from a Codex sync, the unavailable report for the retired sync without executing it, and the `UNSUPPORTED_ACTION` answer for `freeze-env`. `scripts/verify-codex-host.cjs` expects the dependency refresh, zero backend and model requests, and an unchanged Git state; these cases passed against installed 0.2.1 on October 8. Its opt-in real-project check runs the read-only `status` and requires the `sync` capability to be available; that optional check was not run in the October 8 audit. - -## Remaining release checks - -- Verify trusted-publishing configuration before the next release, align package/plugin/catalog versions, and confirm the new registry archive's integrity. Do not republish an existing version. -- Manually verify the desktop renderer after restarting/reloading the app. Computer-use tooling refuses access to the Codex app, so GUI validation could not be completed automatically. The installed host runtime, event stream and CLI presentation were tested directly. -- Check the long-operation progress, cancellation and timeout UI in the desktop host. The runner's timeout and cancellation contracts have fixture coverage, but a full-duration desktop operation was not run. -- Validate live OS-store refresh rotation across all supported platforms and a real backend/Git setup. The automated suites use synthetic identities, loopback backends and temporary repositories. diff --git a/docs/shared-project-operations.md b/docs/shared-project-operations.md index 64c5334..5ac0fdc 100644 --- a/docs/shared-project-operations.md +++ b/docs/shared-project-operations.md @@ -5,7 +5,7 @@ repository/SDK/dependency workflows, MCP and project filesystem operations. Consumers import the package's public API. They implement their native UI, process bridge, lifecycle, application-specific credentials and distribution. -The additive 0.2.2 API exports `createProjectOperations`, +The package exports `createProjectOperations`, `PROJECT_OPERATION_ACTIONS`, `ProjectOperationRequest`, `ProjectOperationOptions`, `validateDockerImage`, `validateDockerPlatform` and `updateDevcontainerJsonc`. diff --git a/package-lock.json b/package-lock.json index 51e731b..52f4e34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@dev-mainsequence/devtools", - "version": "0.3.12", + "version": "0.3.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@dev-mainsequence/devtools", - "version": "0.3.12", + "version": "0.3.13", "license": "MIT", "bin": { "ms-devtools": "dist/runner.js" diff --git a/package.json b/package.json index 0bc0173..eded788 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dev-mainsequence/devtools", - "version": "0.3.12", + "version": "0.3.13", "description": "Shared MainSequence developer actions, project operations, MCP client and command runner", "license": "MIT", "engines": { @@ -29,7 +29,8 @@ "test": "npm run build && node --test tests/*.test.cjs", "prepack": "npm run build", "verify:package": "node scripts/verify-package.cjs", - "release:check": "npm run typecheck && npm test && node scripts/check-release.cjs && npm pack --ignore-scripts --pack-destination artifacts && npm run verify:package" + "release:check": "npm run typecheck && npm test && node scripts/check-release.cjs && node scripts/check-docs.cjs && npm pack --ignore-scripts --pack-destination artifacts && npm run verify:package", + "check:docs": "node scripts/check-docs.cjs" }, "devDependencies": { "@types/node": "18.19.130", diff --git a/scripts/check-docs.cjs b/scripts/check-docs.cjs new file mode 100644 index 0000000..87bfe56 --- /dev/null +++ b/scripts/check-docs.cjs @@ -0,0 +1,29 @@ +// Documentation stays current: links resolve, named npm scripts exist, and the README and +// guides carry no version numbers (versions live in package.json and GitHub releases). +// The two SDK minimums that `sync` requires are the only versions the README may name. +const fs = require('node:fs'); +const path = require('node:path'); +const assert = require('node:assert/strict'); +const root = path.resolve(__dirname, '..'); +const pkg = require(path.join(root, 'package.json')); +const guides = fs.readdirSync(path.join(root, 'docs')).filter(name => name.endsWith('.md')).map(name => `docs/${name}`); +const adrs = fs.readdirSync(path.join(root, 'docs/adr')).filter(name => name.endsWith('.md')).map(name => `docs/adr/${name}`); +const allowedVersions = new Set(['9.0.5', '0.5.13']); +for (const filename of ['README.md', ...guides, ...adrs]) { + const source = fs.readFileSync(path.join(root, filename), 'utf8'); + for (const match of source.matchAll(/\[[^\]]+\]\(([^)]+)\)/g)) { + const target = match[1].split('#')[0]; + if (!target || /^[a-z]+:/.test(target)) continue; + assert.ok(fs.existsSync(path.resolve(root, path.dirname(filename), target)), `${filename}: missing link ${target}`); + } + for (const [, script] of source.matchAll(/npm run ([a-z:-]+)/g)) assert.ok(pkg.scripts[script], `${filename}: unknown npm script ${script}`); +} +for (const filename of ['README.md', ...guides]) { + const source = fs.readFileSync(path.join(root, filename), 'utf8'); + const versions = [...source.matchAll(/\b\d+\.\d+\.\d+\b/g)].map(match => match[0]).filter(version => !allowedVersions.has(version)); + assert.deepEqual(versions, [], `${filename} must not name versions; found ${versions.join(', ')}`); +} +const readme = fs.readFileSync(path.join(root, 'README.md'), 'utf8'); +for (const host of ['ms-vscode-extension', 'mainsequence-codex-plugin', 'mainsequence-claude-desktop']) assert.ok(readme.includes(`https://github.com/mainsequence-sdk/${host}`), `README must link ${host}`); +for (const guide of guides) assert.ok(readme.includes(`(${guide})`), `README must link ${guide}`); +console.log('Documentation links, npm scripts and version-free guides verified.');