@code-yeongyu/senpi 2026.7.25-2 → 2026.7.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -29
- package/dist/core/agent-session.d.ts +0 -13
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -23
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/builtin/config-reload/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/config-reload/index.js +17 -20
- package/dist/core/extensions/builtin/config-reload/index.js.map +1 -1
- package/dist/core/extensions/builtin/config-reload/log.d.ts +1 -4
- package/dist/core/extensions/builtin/config-reload/log.d.ts.map +1 -1
- package/dist/core/extensions/builtin/config-reload/log.js +0 -3
- package/dist/core/extensions/builtin/config-reload/log.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.d.ts +0 -48
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +64 -88
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/index.js +4 -2
- package/dist/core/extensions/builtin/websearch/index.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/config.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/config.js +1 -4
- package/dist/core/extensions/builtin/websearch/websearch/config.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/native.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/native.js +4 -2
- package/dist/core/extensions/builtin/websearch/websearch/native.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/renderers.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/renderers.js +8 -20
- package/dist/core/extensions/builtin/websearch/websearch/renderers.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/search.d.ts +1 -6
- package/dist/core/extensions/builtin/websearch/websearch/search.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/search.js +11 -15
- package/dist/core/extensions/builtin/websearch/websearch/search.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/tool.js +10 -5
- package/dist/core/extensions/builtin/websearch/websearch/tool.js.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/types.d.ts +0 -1
- package/dist/core/extensions/builtin/websearch/websearch/types.d.ts.map +1 -1
- package/dist/core/extensions/builtin/websearch/websearch/types.js.map +1 -1
- package/dist/core/extensions/types.d.ts +0 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-resolver.d.ts +0 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +3 -13
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +1 -19
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +0 -3
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/retry-fallback/controller.d.ts +0 -7
- package/dist/core/retry-fallback/controller.d.ts.map +1 -1
- package/dist/core/retry-fallback/controller.js +0 -13
- package/dist/core/retry-fallback/controller.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -7
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +0 -10
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/thinking-levels.d.ts.map +1 -1
- package/dist/core/thinking-levels.js +2 -9
- package/dist/core/thinking-levels.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +0 -6
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +1 -3
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +2 -9
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +2 -9
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +0 -11
- package/dist/package-manager-cli.js.map +1 -1
- package/docs/extensions.md +2 -2
- package/docs/settings.md +0 -11
- package/examples/extensions/message-renderer.ts +2 -2
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +0 -12
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +0 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +22 -87
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js +7 -15
- package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +16 -38
- package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js +2 -9
- package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js +2 -12
- package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +11 -19
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +23 -121
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +7 -12
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js +0 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.d.ts +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.js +35 -37
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +1 -11
- package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +0 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js +0 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models-store.d.ts +0 -5
- package/node_modules/@earendil-works/pi-ai/dist/models-store.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models-store.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.js +1 -5
- package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +0 -9
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js +3 -8
- package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +6 -6
- package/dist/beta/omo-local-update.d.ts +0 -207
- package/dist/beta/omo-local-update.d.ts.map +0 -1
- package/dist/beta/omo-local-update.js +0 -708
- package/dist/beta/omo-local-update.js.map +0 -1
- package/dist/core/extensions/builtin/config-reload/routine-settings.d.ts +0 -15
- package/dist/core/extensions/builtin/config-reload/routine-settings.d.ts.map +0 -1
- package/dist/core/extensions/builtin/config-reload/routine-settings.js +0 -102
- package/dist/core/extensions/builtin/config-reload/routine-settings.js.map +0 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/server-fallback-receipt.d.ts +0 -30
- package/node_modules/@earendil-works/pi-ai/dist/utils/server-fallback-receipt.d.ts.map +0 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/server-fallback-receipt.js +0 -70
- package/node_modules/@earendil-works/pi-ai/dist/utils/server-fallback-receipt.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"omo-local-update.js","sourceRoot":"","sources":["../../src/beta/omo-local-update.ts"],"names":[],"mappings":"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","sourcesContent":["// BETA(omo-local-update): removable beta module - delete this file, all test/omo-local-update*\n// files to drop the feature.\n//\n// Beta: on bare `senpi update`, compare a locally-installed OMO plugin (omo-senpi +\n// senpi-task) against origin/dev of its source checkout and replace the LOCAL PLUGIN\n// INSTALL only when different. The user's checkout receives ZERO git mutations: this module\n// never runs checkout/branch/commit/merge/reset/clean/stash/push against the user's repo.\n// Its only git writes are `git fetch origin dev` (remote-tracking ref update) plus\n// worktree add/remove/prune registering the FEATURE-OWNED persistent build worktree under\n// <agentDir>/omo-local-update/. `checkout --detach --force` is used exactly once and only\n// inside that feature-owned worktree, which this module creates and owns exclusively.\n// Builds run there; the install target (pluginPath) is swapped atomically by rename.\n//\n// Export policy: `runOmoLocalUpdateBeta` is the ONLY production API and the only symbol the\n// CLI may import. Every other export in this module is /** exported for tests only */ so the\n// single test file (test/omo-local-update.test.ts) can exercise helpers directly - no\n// CLI-side helper imports, no logic duplication.\n\nimport { randomUUID } from \"node:crypto\";\nimport {\n\tcpSync,\n\ttype Dirent,\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trenameSync,\n\trmSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport chalk from \"chalk\";\nimport type { PackageSource } from \"../core/settings-manager.ts\";\nimport { spawnProcess, waitForChildProcess } from \"../utils/child-process.ts\";\nimport { canonicalizePath, isLocalPath, resolvePath } from \"../utils/paths.ts\";\nimport { killProcessTree } from \"../utils/shell.ts\";\n\n/** Result of one spawned command, with output captured and timeout enforced. */\nexport interface OmoLocalRunResult {\n\tcode: number | null;\n\tstdout: string;\n\tstderr: string;\n\ttimedOut: boolean;\n}\n\nexport interface OmoLocalRunOptions {\n\tcwd?: string;\n\ttimeoutMs?: number;\n\t/** Merged over process.env (callers inject the isolated git env from the fixture contract). */\n\tenv?: Record<string, string | undefined>;\n}\n\n/** exported for tests only */\nexport type OmoLocalRun = (command: string, args: string[], options: OmoLocalRunOptions) => Promise<OmoLocalRunResult>;\n\n/**\n * exported for tests only\n *\n * Shared process seam for the whole module. spawnProcess/waitForChildProcess neither capture\n * output nor enforce timeouts; this adds both. The child is spawned detached on POSIX so it\n * owns a process group, and the timeout kill goes through killProcessTree (SIGKILL to the\n * whole group) - without that, bun/git descendants would keep mutating the build worktree\n * after the direct child died.\n */\nexport async function defaultRun(\n\tcommand: string,\n\targs: string[],\n\toptions: OmoLocalRunOptions,\n): Promise<OmoLocalRunResult> {\n\tconst child = spawnProcess(command, args, {\n\t\tcwd: options.cwd,\n\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\tenv: { ...process.env, ...options.env },\n\t\tdetached: process.platform !== \"win32\",\n\t\twindowsHide: true,\n\t});\n\tlet stdout = \"\";\n\tlet stderr = \"\";\n\tchild.stdout.on(\"data\", (chunk: Buffer) => {\n\t\tstdout += chunk.toString();\n\t});\n\tchild.stderr.on(\"data\", (chunk: Buffer) => {\n\t\tstderr += chunk.toString();\n\t});\n\tconst abort = new AbortController();\n\tlet timedOut = false;\n\tconst pid = child.pid;\n\tconst timer =\n\t\toptions.timeoutMs === undefined\n\t\t\t? undefined\n\t\t\t: setTimeout(() => {\n\t\t\t\t\ttimedOut = true;\n\t\t\t\t\tif (pid !== undefined) {\n\t\t\t\t\t\tkillProcessTree(pid);\n\t\t\t\t\t}\n\t\t\t\t\tabort.abort();\n\t\t\t\t}, options.timeoutMs);\n\ttry {\n\t\tconst code = await waitForChildProcess(child, { signal: abort.signal });\n\t\treturn { code, stdout, stderr, timedOut };\n\t} finally {\n\t\tif (timer !== undefined) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t}\n}\n\n/** exported for tests only */\nexport function isKillSwitched(env: Record<string, string | undefined>): boolean {\n\treturn env.SENPI_OMO_LOCAL_UPDATE === \"0\";\n}\n\n/** A detected locally-installed OMO plugin and its enclosing omo monorepo checkout. */\nexport interface OmoLocalInstall {\n\tpluginPath: string;\n\trepoRoot: string;\n}\n\n/** exported for tests only */\nexport interface DetectOmoLocalInstallOptions {\n\tpackages: PackageSource[] | undefined;\n\tagentDir: string;\n\trun: OmoLocalRun;\n\treadJson?: (path: string) => unknown;\n\texists?: (path: string) => boolean;\n}\n\nfunction defaultReadJson(path: string): unknown {\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\"));\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction packageNameOf(json: unknown): string | undefined {\n\tif (typeof json !== \"object\" || json === null) {\n\t\treturn undefined;\n\t}\n\tconst name = (json as { name?: unknown }).name;\n\treturn typeof name === \"string\" ? name : undefined;\n}\n\n/** Same semantics as package-manager.ts's private getHomeDir (HOME env wins over os.homedir). */\nfunction homeDir(): string {\n\treturn process.env.HOME || homedir();\n}\n\n/**\n * exported for tests only\n *\n * Three-part detection gate (ALL must hold, else silent no-op):\n * 1. A global settings `packages` entry (string or object form) is a local path whose resolved\n * dir's package.json name is `@code-yeongyu/omo-senpi`.\n * 2. The derived repo root (pluginPath/../../..) contains both workspace packages\n * `@oh-my-opencode/omo-senpi` and `@oh-my-opencode/senpi-task`.\n * 3. `git -C <repoRoot> rev-parse --show-toplevel` succeeds AND its canonicalized output equals\n * the canonicalized repo root - a mismatched toplevel would mean the derived root is not\n * the checkout it claims to be.\n */\nexport async function detectOmoLocalInstall(\n\toptions: DetectOmoLocalInstallOptions,\n): Promise<OmoLocalInstall | undefined> {\n\tconst readJson = options.readJson ?? defaultReadJson;\n\tconst exists = options.exists ?? existsSync;\n\tif (!options.packages) {\n\t\treturn undefined;\n\t}\n\tfor (const entry of options.packages) {\n\t\tconst source = typeof entry === \"string\" ? entry : entry.source;\n\t\tif (!isLocalPath(source)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst pluginPath = resolvePath(source, options.agentDir, { homeDir: homeDir(), trim: true });\n\t\tif (packageNameOf(readJson(join(pluginPath, \"package.json\"))) !== \"@code-yeongyu/omo-senpi\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst repoRoot = resolve(pluginPath, \"..\", \"..\", \"..\");\n\t\tconst omoSenpiPkgPath = join(repoRoot, \"packages\", \"omo-senpi\", \"package.json\");\n\t\tconst senpiTaskPkgPath = join(repoRoot, \"packages\", \"senpi-task\", \"package.json\");\n\t\tif (!exists(omoSenpiPkgPath) || packageNameOf(readJson(omoSenpiPkgPath)) !== \"@oh-my-opencode/omo-senpi\") {\n\t\t\tcontinue;\n\t\t}\n\t\tif (!exists(senpiTaskPkgPath) || packageNameOf(readJson(senpiTaskPkgPath)) !== \"@oh-my-opencode/senpi-task\") {\n\t\t\tcontinue;\n\t\t}\n\t\tlet topLevel: string;\n\t\ttry {\n\t\t\tconst result = await options.run(\"git\", [\"-C\", repoRoot, \"rev-parse\", \"--show-toplevel\"], {});\n\t\t\tif (result.code !== 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttopLevel = result.stdout.trim();\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (topLevel === \"\" || canonicalizePath(topLevel) !== canonicalizePath(repoRoot)) {\n\t\t\tcontinue;\n\t\t}\n\t\treturn { pluginPath, repoRoot };\n\t}\n\treturn undefined;\n}\n\n/** State stamp written after a successful install: `<agentDir>/omo-local-update-state.json`. */\nexport interface OmoLocalUpdateStamp {\n\trepoRoot: string;\n\t/** Frozen origin/dev sha the installed plugin was built from. */\n\tsha: string;\n\t/** `git rev-parse origin/dev:packages/omo-senpi` at install time. */\n\tomoSenpiTree: string;\n\t/** `git rev-parse origin/dev:packages/senpi-task` at install time. */\n\tsenpiTaskTree: string;\n\tinstalledAt: string;\n\t/** Post-install inventory: relative paths of every installed artifact present at stamp time. */\n\tartifacts: string[];\n}\n\n/** exported for tests only */\nexport function omoLocalUpdateStampPath(agentDir: string): string {\n\treturn join(agentDir, \"omo-local-update-state.json\");\n}\n\n/** exported for tests only */\nexport function readStamp(agentDir: string): OmoLocalUpdateStamp | undefined {\n\tconst json = defaultReadJson(omoLocalUpdateStampPath(agentDir));\n\tif (typeof json !== \"object\" || json === null) {\n\t\treturn undefined;\n\t}\n\tconst candidate = json as {\n\t\trepoRoot?: unknown;\n\t\tsha?: unknown;\n\t\tomoSenpiTree?: unknown;\n\t\tsenpiTaskTree?: unknown;\n\t\tinstalledAt?: unknown;\n\t\tartifacts?: unknown;\n\t};\n\tif (\n\t\ttypeof candidate.repoRoot !== \"string\" ||\n\t\ttypeof candidate.sha !== \"string\" ||\n\t\ttypeof candidate.omoSenpiTree !== \"string\" ||\n\t\ttypeof candidate.senpiTaskTree !== \"string\" ||\n\t\ttypeof candidate.installedAt !== \"string\" ||\n\t\t!Array.isArray(candidate.artifacts)\n\t) {\n\t\treturn undefined;\n\t}\n\tconst artifacts: string[] = [];\n\tfor (const artifact of candidate.artifacts as unknown[]) {\n\t\tif (typeof artifact !== \"string\") {\n\t\t\treturn undefined;\n\t\t}\n\t\tartifacts.push(artifact);\n\t}\n\treturn {\n\t\trepoRoot: candidate.repoRoot,\n\t\tsha: candidate.sha,\n\t\tomoSenpiTree: candidate.omoSenpiTree,\n\t\tsenpiTaskTree: candidate.senpiTaskTree,\n\t\tinstalledAt: candidate.installedAt,\n\t\tartifacts,\n\t};\n}\n\n/** exported for tests only */\nexport function writeStamp(agentDir: string, stamp: OmoLocalUpdateStamp): void {\n\tmkdirSync(agentDir, { recursive: true });\n\twriteFileSync(omoLocalUpdateStampPath(agentDir), `${JSON.stringify(stamp, null, 2)}\\n`, \"utf-8\");\n}\n\n/** exported for tests only */\nexport interface ShouldSkipUpdateOptions {\n\tstamp: OmoLocalUpdateStamp | undefined;\n\trepoRoot: string;\n\tremoteSha: string;\n\t/** True only when every path recorded in stamp.artifacts still exists on disk. */\n\tstampArtifactsExist: boolean;\n\tforce: boolean;\n}\n\n/**\n * exported for tests only\n *\n * Skip decision (taken BEFORE any worktree op, install, or write): skip only when the stamp\n * belongs to this repo root, was installed at the frozen remote sha, recorded a non-empty\n * artifact inventory, and every inventoried path still exists. A repoRoot mismatch always\n * updates; an empty/absent inventory never skips; force always updates.\n */\nexport function shouldSkipUpdate(options: ShouldSkipUpdateOptions): boolean {\n\tif (options.force) {\n\t\treturn false;\n\t}\n\tconst stamp = options.stamp;\n\tif (!stamp) {\n\t\treturn false;\n\t}\n\tif (stamp.repoRoot !== options.repoRoot) {\n\t\treturn false;\n\t}\n\tif (stamp.sha !== options.remoteSha) {\n\t\treturn false;\n\t}\n\tif (stamp.artifacts.length === 0) {\n\t\treturn false;\n\t}\n\treturn options.stampArtifactsExist;\n}\n\n/**\n * exported for tests only\n *\n * Failure of one orchestrator-owned step (fetch/worktree/install/build/artifacts/swap/stamp).\n * The stage feeds `OMO local plugin update failed (<stage>): ...`; `output` (combined\n * stdout+stderr of the failed step) is echoed dim, last 40 lines.\n */\nexport class OmoLocalStepError extends Error {\n\treadonly stage: string;\n\treadonly output: string | undefined;\n\tconstructor(stage: string, message: string, output?: string) {\n\t\tsuper(message);\n\t\tthis.name = \"OmoLocalStepError\";\n\t\tthis.stage = stage;\n\t\tthis.output = output;\n\t}\n}\n\nfunction firstErrorLine(result: OmoLocalRunResult): string {\n\tfor (const text of [result.stderr, result.stdout]) {\n\t\tfor (const line of text.split(\"\\n\")) {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (trimmed !== \"\") {\n\t\t\t\treturn trimmed;\n\t\t\t}\n\t\t}\n\t}\n\treturn \"unknown error\";\n}\n\n/** The frozen state of origin/dev: commit sha, subject, and both package tree hashes. */\nexport interface OmoRemoteState {\n\tsha: string;\n\tsubject: string;\n\tomoSenpiTree: string;\n\tsenpiTaskTree: string;\n}\n\n/** exported for tests only */\nexport interface ComputeRemoteStateOptions {\n\trepoRoot: string;\n\trun: OmoLocalRun;\n}\n\n/**\n * exported for tests only\n *\n * Inspect the two packages' state ON ORIGIN/DEV: ONE `git fetch origin dev` (120s, read-only\n * - the ONLY network/ref operation in the module), then rev-parse/log reads against the\n * frozen `origin/dev` ref. A fetch failure throws an OmoLocalStepError with stage \"fetch\"\n * before anything else is touched.\n */\nexport async function computeRemoteState(options: ComputeRemoteStateOptions): Promise<OmoRemoteState> {\n\tconst { repoRoot, run } = options;\n\tconst git = (args: string[], timeoutMs?: number) => run(\"git\", args, { cwd: repoRoot, timeoutMs });\n\tconst requireOk = async (args: string[], timeoutMs?: number): Promise<string> => {\n\t\tconst result = await git(args, timeoutMs);\n\t\tif (result.timedOut) {\n\t\t\tthrow new OmoLocalStepError(\"fetch\", `git ${args.join(\" \")} timed out`);\n\t\t}\n\t\tif (result.code !== 0) {\n\t\t\tthrow new OmoLocalStepError(\n\t\t\t\t\"fetch\",\n\t\t\t\t`git ${args.join(\" \")}: ${firstErrorLine(result)}`,\n\t\t\t\t`${result.stdout}${result.stderr}`,\n\t\t\t);\n\t\t}\n\t\treturn result.stdout.trim();\n\t};\n\tawait requireOk([\"fetch\", \"origin\", \"dev\"], 120_000);\n\tconst sha = await requireOk([\"rev-parse\", \"origin/dev\"]);\n\tif (sha === \"\") {\n\t\tthrow new OmoLocalStepError(\"fetch\", \"git rev-parse origin/dev: empty output\");\n\t}\n\tconst subject = await requireOk([\"log\", \"-1\", \"--format=%s\", \"origin/dev\"]);\n\tconst omoSenpiTree = await requireOk([\"rev-parse\", \"origin/dev:packages/omo-senpi\"]);\n\tconst senpiTaskTree = await requireOk([\"rev-parse\", \"origin/dev:packages/senpi-task\"]);\n\treturn { sha, subject, omoSenpiTree, senpiTaskTree };\n}\n\n/** exported for tests only */\nexport function omoLocalUpdateLockPath(agentDir: string): string {\n\treturn join(agentDir, \"omo-local-update.lock\");\n}\n\n/** exported for tests only */\nexport function omoLocalUpdateBuildWorktreePath(agentDir: string): string {\n\treturn join(agentDir, \"omo-local-update\", \"build-worktree\");\n}\n\ninterface OmoLocalLock {\n\tpath: string;\n\tpid: number;\n\tnonce: string;\n}\n\nfunction readLockFile(path: string): { pid: number; nonce: string } | undefined {\n\ttry {\n\t\tconst json = JSON.parse(readFileSync(path, \"utf-8\")) as { pid?: unknown; nonce?: unknown };\n\t\tif (typeof json.pid !== \"number\" || typeof json.nonce !== \"string\") {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn { pid: json.pid, nonce: json.nonce };\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction pidIsAlive(pid: number): boolean {\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\t// EPERM: the process exists but belongs to another user.\n\t\treturn (error as NodeJS.ErrnoException).code === \"EPERM\";\n\t}\n}\n\n/**\n * Atomic lock acquisition (concurrency guard): `wx` create writing {pid, nonce, startedAt}.\n * On EEXIST: a LIVE pid wins unconditionally - dim line, NEVER take over regardless of age.\n * A dead pid (or an unreadable lock) is unlinked and the `wx` create retried ONCE; a\n * concurrent winner's fresh lock then loses us the retry, which is correct. Synchronous\n * throughout, so in-process contenders cannot interleave mid-check.\n */\nfunction acquireOmoLocalLock(agentDir: string, log: (message: string) => void): OmoLocalLock | undefined {\n\tmkdirSync(agentDir, { recursive: true });\n\tconst path = omoLocalUpdateLockPath(agentDir);\n\tconst lock: OmoLocalLock = { path, pid: process.pid, nonce: randomUUID() };\n\tconst payload = JSON.stringify({ pid: lock.pid, nonce: lock.nonce, startedAt: new Date().toISOString() });\n\tconst tryCreate = (): boolean => {\n\t\ttry {\n\t\t\twriteFileSync(path, payload, { flag: \"wx\" });\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t};\n\tconst reportBusy = (): undefined => {\n\t\tconst existing = readLockFile(path);\n\t\tlog(chalk.dim(`OMO local plugin update already running (pid ${existing?.pid ?? \"unknown\"}); skipping.`));\n\t\treturn undefined;\n\t};\n\tif (tryCreate()) {\n\t\treturn lock;\n\t}\n\tconst existing = readLockFile(path);\n\tif (existing !== undefined && pidIsAlive(existing.pid)) {\n\t\treturn reportBusy();\n\t}\n\ttry {\n\t\trmSync(path);\n\t} catch {\n\t\t// Another process reclaimed first; the single retry below loses correctly.\n\t}\n\tif (tryCreate()) {\n\t\treturn lock;\n\t}\n\treturn reportBusy();\n}\n\n/** Owner-checked unlink: re-read and match our own pid+nonce before deleting. */\nfunction releaseOmoLocalLock(lock: OmoLocalLock): void {\n\ttry {\n\t\tconst existing = readLockFile(lock.path);\n\t\tif (existing !== undefined && existing.pid === lock.pid && existing.nonce === lock.nonce) {\n\t\t\trmSync(lock.path);\n\t\t}\n\t} catch {\n\t\t// Lock release must never throw.\n\t}\n}\n\n/** Post-build completeness set: five files plus a non-empty skills glob. */\nconst REQUIRED_BUILD_ARTIFACTS = [\n\t\"extensions/omo.js\",\n\t\"runtime/lsp-daemon/dist/cli.js\",\n\t\"runtime/lsp-daemon/dist/index.js\",\n\t\"runtime/lsp-daemon/dist/.omo-runtime-manifest.json\",\n\t\"scripts/install.mjs\",\n] as const;\n\nfunction walkFiles(rootDir: string): string[] {\n\tconst files: string[] = [];\n\tconst pending = [rootDir];\n\twhile (pending.length > 0) {\n\t\tconst dir = pending.pop();\n\t\tif (dir === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tlet entries: Dirent[];\n\t\ttry {\n\t\t\tentries = readdirSync(dir, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const entry of entries) {\n\t\t\tconst full = join(dir, entry.name);\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tpending.push(full);\n\t\t\t} else if (entry.isFile()) {\n\t\t\t\tfiles.push(full);\n\t\t\t}\n\t\t}\n\t}\n\treturn files;\n}\n\n/**\n * Post-install inventory for the stamp: every file under plugin/extensions/ and\n * plugin/runtime/lsp-daemon/dist/, every SKILL.md under plugin/skills/, plus\n * plugin/scripts/install.mjs - paths relative to the plugin dir, posix-separated, sorted.\n */\nfunction collectArtifactInventory(pluginPath: string): string[] {\n\tconst inventory: string[] = [];\n\tconst collectUnder = (relativeDir: string, filter?: (posixPath: string) => boolean): void => {\n\t\tfor (const filePath of walkFiles(join(pluginPath, relativeDir))) {\n\t\t\tconst posixPath = relative(pluginPath, filePath).split(sep).join(\"/\");\n\t\t\tif (filter === undefined || filter(posixPath)) {\n\t\t\t\tinventory.push(posixPath);\n\t\t\t}\n\t\t}\n\t};\n\tcollectUnder(\"extensions\");\n\tcollectUnder(join(\"runtime\", \"lsp-daemon\", \"dist\"));\n\tcollectUnder(\"skills\", (posixPath) => posixPath.endsWith(\"/SKILL.md\"));\n\tif (existsSync(join(pluginPath, \"scripts\", \"install.mjs\"))) {\n\t\tinventory.push(\"scripts/install.mjs\");\n\t}\n\tinventory.sort();\n\treturn inventory;\n}\n\n/** Post-build completeness check: the five required files + >=1 skills/<name>/SKILL.md. */\nfunction findMissingBuildArtifacts(pluginPath: string): string[] {\n\tconst missing: string[] = [];\n\tfor (const required of REQUIRED_BUILD_ARTIFACTS) {\n\t\tif (!existsSync(join(pluginPath, required))) {\n\t\t\tmissing.push(required);\n\t\t}\n\t}\n\tlet skillCount = 0;\n\ttry {\n\t\tfor (const entry of readdirSync(join(pluginPath, \"skills\"), { withFileTypes: true })) {\n\t\t\tif (entry.isDirectory() && existsSync(join(pluginPath, \"skills\", entry.name, \"SKILL.md\"))) {\n\t\t\t\tskillCount++;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// A missing skills dir counts as zero skills.\n\t}\n\tif (skillCount === 0) {\n\t\tmissing.push(\"skills/*/SKILL.md\");\n\t}\n\treturn missing;\n}\n\n/** Marker error: the bun binary is missing from PATH (spawn ENOENT). */\nclass OmoLocalBunMissingError extends Error {\n\tconstructor() {\n\t\tsuper(\"bun not found on PATH\");\n\t\tthis.name = \"OmoLocalBunMissingError\";\n\t}\n}\n\n/**\n * One bun step through the shared run seam, run INSIDE the build worktree (never the user's\n * checkout). A missing binary (spawn ENOENT) gets the dedicated marker so the orchestrator\n * can render the single yellow bun warning; any other failed start, non-zero exit, or\n * timeout becomes an OmoLocalStepError carrying the combined output for the dim dump.\n */\nasync function runBunStep(\n\tstage: \"install\" | \"build\",\n\targs: string[],\n\tworktree: string,\n\trun: OmoLocalRun,\n\ttimeoutMs: number,\n): Promise<void> {\n\tlet result: OmoLocalRunResult;\n\ttry {\n\t\tresult = await run(\"bun\", args, { cwd: worktree, timeoutMs });\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\tthrow new OmoLocalBunMissingError();\n\t\t}\n\t\tthrow new OmoLocalStepError(\n\t\t\tstage,\n\t\t\t`bun ${args.join(\" \")} failed to start: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\tconst output = `${result.stdout}${result.stderr}`;\n\tif (result.timedOut) {\n\t\tthrow new OmoLocalStepError(\n\t\t\tstage,\n\t\t\t`bun ${args.join(\" \")} timed out after ${Math.round(timeoutMs / 1000)}s`,\n\t\t\toutput,\n\t\t);\n\t}\n\tif (result.code !== 0) {\n\t\tthrow new OmoLocalStepError(stage, `bun ${args.join(\" \")} exited with code ${result.code ?? \"unknown\"}`, output);\n\t}\n}\n\n/** exported for tests only */\nexport interface EnsureBuildWorktreeOptions {\n\t/** Feature-owned persistent worktree path (inside agentDir). */\n\tworktree: string;\n\trepoRoot: string;\n\t/** Frozen origin/dev sha to check out detached. */\n\tsha: string;\n\trun: OmoLocalRun;\n}\n\n/**\n * exported for tests only\n *\n * Validate/reuse the FEATURE-OWNED persistent build worktree:\n * - present AND owned by this repo (`git -C <wt> rev-parse --git-common-dir` realpath-equals\n * realpath(repoRoot/.git)) -> reuse: `git -C <wt> checkout --detach --force <sha>`. The\n * --force is SAFE here: this worktree is exclusively feature-owned, so it only discards\n * our own previous build outputs, and untracked node_modules survives for incremental\n * installs.\n * - present but foreign/invalid -> `git -C repoRoot worktree remove --force <wt>` (fs rm\n * fallback), then re-add.\n * - absent -> `git -C repoRoot worktree add --detach <wt> <sha>`.\n * These are the ONLY git mutations in the module besides `git fetch`, and they touch only\n * the feature-owned worktree registration - never the user's checkout state.\n */\nexport async function ensureBuildWorktree(options: EnsureBuildWorktreeOptions): Promise<void> {\n\tconst { worktree, repoRoot, sha, run } = options;\n\tif (existsSync(worktree)) {\n\t\tconst commonDir = await run(\"git\", [\"-C\", worktree, \"rev-parse\", \"--git-common-dir\"], {});\n\t\tconst owned =\n\t\t\tcommonDir.code === 0 &&\n\t\t\tcommonDir.stdout.trim() !== \"\" &&\n\t\t\tcanonicalizePath(resolve(worktree, commonDir.stdout.trim())) === canonicalizePath(join(repoRoot, \".git\"));\n\t\tif (owned) {\n\t\t\tconst checkout = await run(\"git\", [\"-C\", worktree, \"checkout\", \"--detach\", \"--force\", sha], {});\n\t\t\tif (checkout.code !== 0) {\n\t\t\t\tthrow new OmoLocalStepError(\n\t\t\t\t\t\"worktree\",\n\t\t\t\t\t`git checkout --detach --force: ${firstErrorLine(checkout)}`,\n\t\t\t\t\t`${checkout.stdout}${checkout.stderr}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\t// Foreign or invalid directory at the feature-owned path: remove it (registered\n\t\t// worktree or not) and fall through to a fresh add.\n\t\tconst remove = await run(\"git\", [\"-C\", repoRoot, \"worktree\", \"remove\", \"--force\", worktree], {});\n\t\tif (remove.code !== 0 || existsSync(worktree)) {\n\t\t\trmSync(worktree, { recursive: true, force: true });\n\t\t}\n\t}\n\tmkdirSync(dirname(worktree), { recursive: true });\n\tconst add = await run(\"git\", [\"-C\", repoRoot, \"worktree\", \"add\", \"--detach\", worktree, sha], {});\n\tif (add.code === 0) {\n\t\treturn;\n\t}\n\t// A stale registration whose directory vanished blocks the add; prune metadata and retry once.\n\tawait run(\"git\", [\"-C\", repoRoot, \"worktree\", \"prune\"], {});\n\tconst retry = await run(\"git\", [\"-C\", repoRoot, \"worktree\", \"add\", \"--detach\", worktree, sha], {});\n\tif (retry.code !== 0) {\n\t\tthrow new OmoLocalStepError(\n\t\t\t\"worktree\",\n\t\t\t`git worktree add: ${firstErrorLine(retry)}`,\n\t\t\t`${add.stdout}${add.stderr}${retry.stdout}${retry.stderr}`,\n\t\t);\n\t}\n}\n\n/** exported for tests only: injectable fs seam for the atomic swap. */\nexport interface OmoLocalFsSeam {\n\tcpSync: (source: string, destination: string) => void;\n\trenameSync: (oldPath: string, newPath: string) => void;\n\trmSync: (path: string) => void;\n}\n\nconst defaultFsSeam: OmoLocalFsSeam = {\n\tcpSync: (source, destination) => {\n\t\tcpSync(source, destination, { recursive: true });\n\t},\n\trenameSync: (oldPath, newPath) => {\n\t\trenameSync(oldPath, newPath);\n\t},\n\trmSync: (path) => {\n\t\trmSync(path, { recursive: true, force: true });\n\t},\n};\n\n/** exported for tests only */\nexport interface SwapPluginDirOptions {\n\tpluginPath: string;\n\t/** The freshly built plugin dir inside the build worktree. */\n\tsourceDir: string;\n\tfs?: OmoLocalFsSeam;\n}\n\nlet swapCounter = 0;\n\n/**\n * exported for tests only\n *\n * ATOMIC SWAP of the install target. staging/prev are siblings of pluginPath (same parent\n * => same filesystem => atomic renames): copy the built tree to staging, move pluginPath\n * aside to prev, move staging into place. If the staging rename fails, prev is restored\n * and staging removed before the error propagates - the local install is never left\n * half-swapped. On success prev is removed.\n */\nexport function swapPluginDir(options: SwapPluginDirOptions): void {\n\tconst seam = options.fs ?? defaultFsSeam;\n\tswapCounter += 1;\n\tconst tag = `${Date.now()}-${process.pid}-${swapCounter}`;\n\tconst staging = `${options.pluginPath}.staging-${tag}`;\n\tconst prev = `${options.pluginPath}.prev-${tag}`;\n\tseam.cpSync(options.sourceDir, staging);\n\tseam.renameSync(options.pluginPath, prev);\n\ttry {\n\t\tseam.renameSync(staging, options.pluginPath);\n\t} catch (error) {\n\t\tseam.renameSync(prev, options.pluginPath);\n\t\tseam.rmSync(staging);\n\t\tthrow error;\n\t}\n\tseam.rmSync(prev);\n}\n\nfunction firstLine(text: string): string {\n\tfor (const line of text.split(\"\\n\")) {\n\t\tconst trimmed = line.trim();\n\t\tif (trimmed !== \"\") {\n\t\t\treturn trimmed;\n\t\t}\n\t}\n\treturn \"unknown error\";\n}\n\nfunction lastNonEmptyLines(text: string, count: number): string[] {\n\tconst lines: string[] = [];\n\tfor (const line of text.split(\"\\n\")) {\n\t\tif (line.trim() !== \"\") {\n\t\t\tlines.push(line);\n\t\t}\n\t}\n\treturn lines.slice(-count);\n}\n\nexport interface RunOmoLocalUpdateBetaOptions {\n\tenv: Record<string, string | undefined>;\n\tagentDir: string;\n\tsettings?: { packages?: PackageSource[] };\n\tforce?: boolean;\n\tlog?: (message: string) => void;\n\trun?: OmoLocalRun;\n}\n\n/**\n * Beta hook entry point, called from bare `senpi update` before the self-update.\n *\n * SINGLE owner of the ORDERED state machine: gate chain (kill-switch -> detection) ->\n * atomic lock acquisition (held through fetch, worktree, build, swap, stamp AND notify;\n * owner-checked unlink in `finally`) -> computeRemoteState (ONE read-only fetch + frozen\n * rev-parse reads of origin/dev) -> skip decision BEFORE any worktree op, install, or\n * write -> ensureBuildWorktree (feature-owned persistent worktree, reuse-or-recreate) ->\n * `bun install` (600s, cwd = build worktree) -> `bun run build:senpi-plugin` (900s, cwd =\n * build worktree) -> completeness check in the WORKTREE plugin dir -> atomic swap of the\n * install target -> writeStamp (inventory from the NEW plugin dir) -> notify (green line\n * + dim per-package tree comparison when an old stamp existed).\n *\n * HARD GUARANTEES: the user's checkout receives ZERO git mutations (no\n * checkout/branch/commit/merge/reset/clean/stash/push anywhere; only `git fetch` and\n * feature-owned worktree add/remove). Only pluginPath content is replaced. This hook NEVER\n * throws and NEVER sets process.exitCode: every failure downgrades to a yellow warning +\n * dim manual hint so the senpi self-update continues untouched.\n */\nexport async function runOmoLocalUpdateBeta(options: RunOmoLocalUpdateBetaOptions): Promise<void> {\n\tconst log =\n\t\toptions.log ??\n\t\t((message: string) => {\n\t\t\tconsole.log(message);\n\t\t});\n\tconst run = options.run ?? defaultRun;\n\tlet repoRoot: string | undefined;\n\ttry {\n\t\tif (isKillSwitched(options.env)) {\n\t\t\treturn;\n\t\t}\n\t\tconst install = await detectOmoLocalInstall({\n\t\t\tpackages: options.settings?.packages,\n\t\t\tagentDir: options.agentDir,\n\t\t\trun,\n\t\t});\n\t\tif (!install) {\n\t\t\treturn;\n\t\t}\n\t\trepoRoot = install.repoRoot;\n\t\tconst { pluginPath } = install;\n\n\t\tconst lock = acquireOmoLocalLock(options.agentDir, log);\n\t\tif (lock === undefined) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tlog(chalk.dim(\"Updating OMO local plugins: fetching origin/dev...\"));\n\t\t\tconst remoteState = await computeRemoteState({ repoRoot, run });\n\n\t\t\t// Skip decision FIRST: a skip touches NOTHING (no worktree ops, no install, no writes).\n\t\t\tconst stamp = readStamp(options.agentDir);\n\t\t\tconst stampArtifactsExist =\n\t\t\t\tstamp?.artifacts.every((artifact) => existsSync(join(pluginPath, artifact))) ?? false;\n\t\t\tif (\n\t\t\t\tshouldSkipUpdate({\n\t\t\t\t\tstamp,\n\t\t\t\t\trepoRoot,\n\t\t\t\t\tremoteSha: remoteState.sha,\n\t\t\t\t\tstampArtifactsExist,\n\t\t\t\t\tforce: options.force ?? false,\n\t\t\t\t})\n\t\t\t) {\n\t\t\t\tlog(\n\t\t\t\t\tchalk.dim(`OMO local plugins already at origin/dev @${remoteState.sha.slice(0, 7)}; skipping rebuild.`),\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Build in the feature-owned persistent worktree - never in the user's checkout.\n\t\t\tconst worktree = omoLocalUpdateBuildWorktreePath(options.agentDir);\n\t\t\tawait ensureBuildWorktree({ worktree, repoRoot, sha: remoteState.sha, run });\n\t\t\ttry {\n\t\t\t\tlog(chalk.dim(\"Updating OMO local plugins: installing deps...\"));\n\t\t\t\tawait runBunStep(\"install\", [\"install\"], worktree, run, 600_000);\n\t\t\t\tlog(chalk.dim(\"Updating OMO local plugins: building plugin...\"));\n\t\t\t\tawait runBunStep(\"build\", [\"run\", \"build:senpi-plugin\"], worktree, run, 900_000);\n\t\t\t} catch (stepError) {\n\t\t\t\tif (stepError instanceof OmoLocalBunMissingError) {\n\t\t\t\t\tlog(\n\t\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t\t\"OMO local plugin update skipped: bun is required to install and build the plugin but was not found on PATH. Install bun and re-run `senpi update`.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthrow stepError;\n\t\t\t}\n\t\t\tconst worktreePluginDir = join(worktree, relative(repoRoot, pluginPath));\n\t\t\tconst missing = findMissingBuildArtifacts(worktreePluginDir);\n\t\t\tif (missing.length > 0) {\n\t\t\t\tthrow new OmoLocalStepError(\"artifacts\", `build incomplete - missing: ${missing.join(\", \")}`);\n\t\t\t}\n\n\t\t\t// Atomic swap of the install target, then stamp from the NEW plugin dir inventory.\n\t\t\ttry {\n\t\t\t\tswapPluginDir({ pluginPath, sourceDir: worktreePluginDir });\n\t\t\t} catch (swapError) {\n\t\t\t\tthrow new OmoLocalStepError(\n\t\t\t\t\t\"swap\",\n\t\t\t\t\t`atomic swap failed: ${swapError instanceof Error ? swapError.message : String(swapError)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\twriteStamp(options.agentDir, {\n\t\t\t\trepoRoot,\n\t\t\t\tsha: remoteState.sha,\n\t\t\t\tomoSenpiTree: remoteState.omoSenpiTree,\n\t\t\t\tsenpiTaskTree: remoteState.senpiTaskTree,\n\t\t\t\tinstalledAt: new Date().toISOString(),\n\t\t\t\tartifacts: collectArtifactInventory(pluginPath),\n\t\t\t});\n\n\t\t\tconst short = remoteState.sha.slice(0, 7);\n\t\t\tlog(\n\t\t\t\tchalk.green(\n\t\t\t\t\t`Updated OMO local plugins (omo-senpi + senpi-task) to origin/dev @${short} - ${remoteState.subject}`,\n\t\t\t\t),\n\t\t\t);\n\t\t\tif (stamp !== undefined) {\n\t\t\t\tconst omoLine = stamp.omoSenpiTree === remoteState.omoSenpiTree ? \"unchanged\" : \"updated\";\n\t\t\t\tconst taskLine = stamp.senpiTaskTree === remoteState.senpiTaskTree ? \"unchanged\" : \"updated\";\n\t\t\t\tlog(chalk.dim(`omo-senpi: ${omoLine}, senpi-task: ${taskLine}`));\n\t\t\t}\n\t\t} finally {\n\t\t\treleaseOmoLocalLock(lock);\n\t\t}\n\t} catch (error) {\n\t\t// The hook NEVER throws and NEVER sets process.exitCode: render the yellow failure\n\t\t// line (+ dim failed-step output tail + dim manual hint) and let the senpi\n\t\t// self-update continue.\n\t\tconst stage = error instanceof OmoLocalStepError ? error.stage : \"unknown\";\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tlog(chalk.yellow(`OMO local plugin update failed (${stage}): ${firstLine(message)}`));\n\t\tif (error instanceof OmoLocalStepError && error.output !== undefined) {\n\t\t\tfor (const line of lastNonEmptyLines(error.output, 40)) {\n\t\t\t\tlog(chalk.dim(line));\n\t\t\t}\n\t\t}\n\t\tif (repoRoot !== undefined) {\n\t\t\tlog(\n\t\t\t\tchalk.dim(\n\t\t\t\t\t`To update manually: git -C ${repoRoot} pull origin dev && bun install && bun run build:senpi-plugin`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { ConfigReloadLogger } from "./log.ts";
|
|
2
|
-
export declare function joinConfigDir(cwd: string): string;
|
|
3
|
-
export declare function isSettingsPath(path: string, agentDir: string, cwd: string): boolean;
|
|
4
|
-
export declare function updateSettingsContentSnapshot(contents: Map<string, string>, path: string): void;
|
|
5
|
-
export declare function refreshSettingsContentSnapshots(contents: Map<string, string>, agentDir: string, cwd: string): void;
|
|
6
|
-
/**
|
|
7
|
-
* Drops settings.json changes whose top-level diff is limited to routine keys
|
|
8
|
-
* (ROUTINE_SETTINGS_KEYS). The content diff works across processes, unlike the
|
|
9
|
-
* process-local self-write tracker: /model in one session no longer hot-reloads
|
|
10
|
-
* every other session. The snapshot base advances for every observed settings
|
|
11
|
-
* path, suppressed or not, so each event is classified against the previous
|
|
12
|
-
* event's content. Missing or unparseable content is never suppressed.
|
|
13
|
-
*/
|
|
14
|
-
export declare function excludeRoutineOnlySettingsChanges(paths: readonly string[], contents: Map<string, string>, agentDir: string, cwd: string, logger: ConfigReloadLogger): string[];
|
|
15
|
-
//# sourceMappingURL=routine-settings.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"routine-settings.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/config-reload/routine-settings.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAgBnD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAKnF;AAMD,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAO/F;AAED,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAIlH;AA6BD;;;;;;;GAOG;AACH,wBAAgB,iCAAiC,CAChD,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,kBAAkB,GACxB,MAAM,EAAE,CAeV"}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
import { CONFIG_DIR_NAME } from "../../../../config.js";
|
|
4
|
-
/**
|
|
5
|
-
* Settings keys a running session already applies live (model/thinking picks)
|
|
6
|
-
* or never reads back (changelog bookkeeping). A settings.json change limited
|
|
7
|
-
* to these keys — typically /model or a thinking-level change in another
|
|
8
|
-
* session or a background CLI run — must not hot-reload this session. Any
|
|
9
|
-
* other key change keeps the full validate-and-reload flow.
|
|
10
|
-
*/
|
|
11
|
-
const ROUTINE_SETTINGS_KEYS = new Set([
|
|
12
|
-
"defaultModel",
|
|
13
|
-
"defaultProvider",
|
|
14
|
-
"defaultThinkingLevel",
|
|
15
|
-
"lastChangelogVersion",
|
|
16
|
-
]);
|
|
17
|
-
export function joinConfigDir(cwd) {
|
|
18
|
-
return resolve(cwd, CONFIG_DIR_NAME);
|
|
19
|
-
}
|
|
20
|
-
export function isSettingsPath(path, agentDir, cwd) {
|
|
21
|
-
return (resolve(path) === resolve(agentDir, "settings.json") ||
|
|
22
|
-
resolve(path) === resolve(joinConfigDir(cwd), "settings.json"));
|
|
23
|
-
}
|
|
24
|
-
function settingsSnapshotKey(path) {
|
|
25
|
-
return resolve(path);
|
|
26
|
-
}
|
|
27
|
-
export function updateSettingsContentSnapshot(contents, path) {
|
|
28
|
-
const key = settingsSnapshotKey(path);
|
|
29
|
-
try {
|
|
30
|
-
contents.set(key, readFileSync(path, "utf-8"));
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
contents.delete(key);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
export function refreshSettingsContentSnapshots(contents, agentDir, cwd) {
|
|
37
|
-
contents.clear();
|
|
38
|
-
updateSettingsContentSnapshot(contents, resolve(agentDir, "settings.json"));
|
|
39
|
-
updateSettingsContentSnapshot(contents, resolve(joinConfigDir(cwd), "settings.json"));
|
|
40
|
-
}
|
|
41
|
-
function parseSettingsObject(content) {
|
|
42
|
-
try {
|
|
43
|
-
const parsed = JSON.parse(content);
|
|
44
|
-
return isPlainObject(parsed) ? parsed : undefined;
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
function changedTopLevelKeys(previous, next) {
|
|
51
|
-
const keys = new Set([...Object.keys(previous), ...Object.keys(next)]);
|
|
52
|
-
const changed = [];
|
|
53
|
-
for (const key of keys) {
|
|
54
|
-
if (JSON.stringify(previous[key]) !== JSON.stringify(next[key]))
|
|
55
|
-
changed.push(key);
|
|
56
|
-
}
|
|
57
|
-
return changed.sort();
|
|
58
|
-
}
|
|
59
|
-
function isRoutineOnlySettingsChange(previousContent, nextContent) {
|
|
60
|
-
if (previousContent === undefined || nextContent === undefined)
|
|
61
|
-
return false;
|
|
62
|
-
const previous = parseSettingsObject(previousContent);
|
|
63
|
-
const next = parseSettingsObject(nextContent);
|
|
64
|
-
if (previous === undefined || next === undefined)
|
|
65
|
-
return false;
|
|
66
|
-
const changedKeys = changedTopLevelKeys(previous, next);
|
|
67
|
-
return changedKeys.length > 0 && changedKeys.every((key) => ROUTINE_SETTINGS_KEYS.has(key));
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Drops settings.json changes whose top-level diff is limited to routine keys
|
|
71
|
-
* (ROUTINE_SETTINGS_KEYS). The content diff works across processes, unlike the
|
|
72
|
-
* process-local self-write tracker: /model in one session no longer hot-reloads
|
|
73
|
-
* every other session. The snapshot base advances for every observed settings
|
|
74
|
-
* path, suppressed or not, so each event is classified against the previous
|
|
75
|
-
* event's content. Missing or unparseable content is never suppressed.
|
|
76
|
-
*/
|
|
77
|
-
export function excludeRoutineOnlySettingsChanges(paths, contents, agentDir, cwd, logger) {
|
|
78
|
-
return paths.filter((path) => {
|
|
79
|
-
if (!isSettingsPath(path, agentDir, cwd))
|
|
80
|
-
return true;
|
|
81
|
-
const previousContent = contents.get(settingsSnapshotKey(path));
|
|
82
|
-
let nextContent;
|
|
83
|
-
try {
|
|
84
|
-
nextContent = readFileSync(path, "utf-8");
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
nextContent = undefined;
|
|
88
|
-
}
|
|
89
|
-
updateSettingsContentSnapshot(contents, path);
|
|
90
|
-
if (!isRoutineOnlySettingsChange(previousContent, nextContent))
|
|
91
|
-
return true;
|
|
92
|
-
logger.debug("routine_settings_change_suppressed", { path });
|
|
93
|
-
return false;
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
function isPlainObject(value) {
|
|
97
|
-
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
98
|
-
return false;
|
|
99
|
-
const prototype = Object.getPrototypeOf(value);
|
|
100
|
-
return prototype === Object.prototype || prototype === null;
|
|
101
|
-
}
|
|
102
|
-
//# sourceMappingURL=routine-settings.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"routine-settings.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/config-reload/routine-settings.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { CONFIG_DIR_NAME } from \"../../../../config.ts\";\nimport type { ConfigReloadLogger } from \"./log.ts\";\n\n/**\n * Settings keys a running session already applies live (model/thinking picks)\n * or never reads back (changelog bookkeeping). A settings.json change limited\n * to these keys — typically /model or a thinking-level change in another\n * session or a background CLI run — must not hot-reload this session. Any\n * other key change keeps the full validate-and-reload flow.\n */\nconst ROUTINE_SETTINGS_KEYS: ReadonlySet<string> = new Set([\n\t\"defaultModel\",\n\t\"defaultProvider\",\n\t\"defaultThinkingLevel\",\n\t\"lastChangelogVersion\",\n]);\n\nexport function joinConfigDir(cwd: string): string {\n\treturn resolve(cwd, CONFIG_DIR_NAME);\n}\n\nexport function isSettingsPath(path: string, agentDir: string, cwd: string): boolean {\n\treturn (\n\t\tresolve(path) === resolve(agentDir, \"settings.json\") ||\n\t\tresolve(path) === resolve(joinConfigDir(cwd), \"settings.json\")\n\t);\n}\n\nfunction settingsSnapshotKey(path: string): string {\n\treturn resolve(path);\n}\n\nexport function updateSettingsContentSnapshot(contents: Map<string, string>, path: string): void {\n\tconst key = settingsSnapshotKey(path);\n\ttry {\n\t\tcontents.set(key, readFileSync(path, \"utf-8\"));\n\t} catch {\n\t\tcontents.delete(key);\n\t}\n}\n\nexport function refreshSettingsContentSnapshots(contents: Map<string, string>, agentDir: string, cwd: string): void {\n\tcontents.clear();\n\tupdateSettingsContentSnapshot(contents, resolve(agentDir, \"settings.json\"));\n\tupdateSettingsContentSnapshot(contents, resolve(joinConfigDir(cwd), \"settings.json\"));\n}\n\nfunction parseSettingsObject(content: string): Record<string, unknown> | undefined {\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(content);\n\t\treturn isPlainObject(parsed) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction changedTopLevelKeys(previous: Record<string, unknown>, next: Record<string, unknown>): string[] {\n\tconst keys = new Set([...Object.keys(previous), ...Object.keys(next)]);\n\tconst changed: string[] = [];\n\tfor (const key of keys) {\n\t\tif (JSON.stringify(previous[key]) !== JSON.stringify(next[key])) changed.push(key);\n\t}\n\treturn changed.sort();\n}\n\nfunction isRoutineOnlySettingsChange(previousContent: string | undefined, nextContent: string | undefined): boolean {\n\tif (previousContent === undefined || nextContent === undefined) return false;\n\tconst previous = parseSettingsObject(previousContent);\n\tconst next = parseSettingsObject(nextContent);\n\tif (previous === undefined || next === undefined) return false;\n\tconst changedKeys = changedTopLevelKeys(previous, next);\n\treturn changedKeys.length > 0 && changedKeys.every((key) => ROUTINE_SETTINGS_KEYS.has(key));\n}\n\n/**\n * Drops settings.json changes whose top-level diff is limited to routine keys\n * (ROUTINE_SETTINGS_KEYS). The content diff works across processes, unlike the\n * process-local self-write tracker: /model in one session no longer hot-reloads\n * every other session. The snapshot base advances for every observed settings\n * path, suppressed or not, so each event is classified against the previous\n * event's content. Missing or unparseable content is never suppressed.\n */\nexport function excludeRoutineOnlySettingsChanges(\n\tpaths: readonly string[],\n\tcontents: Map<string, string>,\n\tagentDir: string,\n\tcwd: string,\n\tlogger: ConfigReloadLogger,\n): string[] {\n\treturn paths.filter((path) => {\n\t\tif (!isSettingsPath(path, agentDir, cwd)) return true;\n\t\tconst previousContent = contents.get(settingsSnapshotKey(path));\n\t\tlet nextContent: string | undefined;\n\t\ttry {\n\t\t\tnextContent = readFileSync(path, \"utf-8\");\n\t\t} catch {\n\t\t\tnextContent = undefined;\n\t\t}\n\t\tupdateSettingsContentSnapshot(contents, path);\n\t\tif (!isRoutineOnlySettingsChange(previousContent, nextContent)) return true;\n\t\tlogger.debug(\"routine_settings_change_suppressed\", { path });\n\t\treturn false;\n\t});\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n"]}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { AssistantMessage } from "../types.ts";
|
|
2
|
-
export declare const SERVER_FALLBACK_ABORTED_DIAGNOSTIC = "server_fallback_aborted";
|
|
3
|
-
export declare const BILLING_INCOMPLETE_DIAGNOSTIC = "billing_incomplete_after_client_abort";
|
|
4
|
-
export interface ServerFallbackReceipt {
|
|
5
|
-
readonly from: string;
|
|
6
|
-
readonly to: string;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Anthropic marks a classifier handoff with `{type:"fallback", from:{model}, to:{model}}`
|
|
10
|
-
* (`server-side-fallback-*` betas). Returns undefined for anything else, so an
|
|
11
|
-
* unrelated or malformed provider-native block falls through to normal handling.
|
|
12
|
-
*/
|
|
13
|
-
export declare function parseServerFallbackReceipt(block: unknown): ServerFallbackReceipt | undefined;
|
|
14
|
-
/**
|
|
15
|
-
* Sticky routing serves later turns of a fallen-back conversation from the
|
|
16
|
-
* substitute model with no `fallback` block at all; a `fallback_message` entry
|
|
17
|
-
* in `usage.iterations` is the documented signal. A served-model string
|
|
18
|
-
* comparison is deliberately NOT used: gateways and Bedrock-style endpoints
|
|
19
|
-
* rewrite model ids, so a mismatch is not evidence of a fallback.
|
|
20
|
-
*/
|
|
21
|
-
export declare function parseStickyFallbackReceipt(usage: unknown, requestedModel: string, servedModel?: string): ServerFallbackReceipt | undefined;
|
|
22
|
-
export declare function serverFallbackRefusalExplanation(receipt: ServerFallbackReceipt): string;
|
|
23
|
-
/**
|
|
24
|
-
* Rewrites an aborted turn into the same shape a pre-output classifier refusal
|
|
25
|
-
* has, so `isClassifierRefusal()` routes it through the caller's fallback chain.
|
|
26
|
-
* Content is dropped: the substitute model's partial output was never requested,
|
|
27
|
-
* and replaying a half-turn containing a fallback marker breaks Anthropic replay.
|
|
28
|
-
*/
|
|
29
|
-
export declare function applyServerFallbackAbort(message: AssistantMessage, receipt: ServerFallbackReceipt): void;
|
|
30
|
-
//# sourceMappingURL=server-fallback-receipt.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server-fallback-receipt.d.ts","sourceRoot":"","sources":["../../src/utils/server-fallback-receipt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,eAAO,MAAM,kCAAkC,4BAA4B,CAAC;AAC5E,eAAO,MAAM,6BAA6B,0CAA0C,CAAC;AAErF,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACpB;AAWD;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,qBAAqB,GAAG,SAAS,CAK5F;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACzC,KAAK,EAAE,OAAO,EACd,cAAc,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,MAAM,GAClB,qBAAqB,GAAG,SAAS,CAUnC;AAED,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAEvF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAgBxG"}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { appendAssistantMessageDiagnostic } from "./diagnostics.js";
|
|
2
|
-
export const SERVER_FALLBACK_ABORTED_DIAGNOSTIC = "server_fallback_aborted";
|
|
3
|
-
export const BILLING_INCOMPLETE_DIAGNOSTIC = "billing_incomplete_after_client_abort";
|
|
4
|
-
function isRecord(value) {
|
|
5
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
-
}
|
|
7
|
-
function readModel(value) {
|
|
8
|
-
if (!isRecord(value))
|
|
9
|
-
return undefined;
|
|
10
|
-
return typeof value.model === "string" && value.model.length > 0 ? value.model : undefined;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Anthropic marks a classifier handoff with `{type:"fallback", from:{model}, to:{model}}`
|
|
14
|
-
* (`server-side-fallback-*` betas). Returns undefined for anything else, so an
|
|
15
|
-
* unrelated or malformed provider-native block falls through to normal handling.
|
|
16
|
-
*/
|
|
17
|
-
export function parseServerFallbackReceipt(block) {
|
|
18
|
-
if (!isRecord(block) || block.type !== "fallback")
|
|
19
|
-
return undefined;
|
|
20
|
-
const from = readModel(block.from);
|
|
21
|
-
const to = readModel(block.to);
|
|
22
|
-
return from !== undefined && to !== undefined ? { from, to } : undefined;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Sticky routing serves later turns of a fallen-back conversation from the
|
|
26
|
-
* substitute model with no `fallback` block at all; a `fallback_message` entry
|
|
27
|
-
* in `usage.iterations` is the documented signal. A served-model string
|
|
28
|
-
* comparison is deliberately NOT used: gateways and Bedrock-style endpoints
|
|
29
|
-
* rewrite model ids, so a mismatch is not evidence of a fallback.
|
|
30
|
-
*/
|
|
31
|
-
export function parseStickyFallbackReceipt(usage, requestedModel, servedModel) {
|
|
32
|
-
if (!isRecord(usage) || !Array.isArray(usage.iterations))
|
|
33
|
-
return undefined;
|
|
34
|
-
for (let index = usage.iterations.length - 1; index >= 0; index--) {
|
|
35
|
-
const entry = usage.iterations[index];
|
|
36
|
-
if (!isRecord(entry) || entry.type !== "fallback_message")
|
|
37
|
-
continue;
|
|
38
|
-
const entryModel = typeof entry.model === "string" && entry.model.length > 0 ? entry.model : undefined;
|
|
39
|
-
const to = entryModel ?? servedModel;
|
|
40
|
-
return to !== undefined ? { from: requestedModel, to } : undefined;
|
|
41
|
-
}
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
export function serverFallbackRefusalExplanation(receipt) {
|
|
45
|
-
return `Server-side fallback (${receipt.from} -> ${receipt.to}) aborted by client policy`;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Rewrites an aborted turn into the same shape a pre-output classifier refusal
|
|
49
|
-
* has, so `isClassifierRefusal()` routes it through the caller's fallback chain.
|
|
50
|
-
* Content is dropped: the substitute model's partial output was never requested,
|
|
51
|
-
* and replaying a half-turn containing a fallback marker breaks Anthropic replay.
|
|
52
|
-
*/
|
|
53
|
-
export function applyServerFallbackAbort(message, receipt) {
|
|
54
|
-
const explanation = serverFallbackRefusalExplanation(receipt);
|
|
55
|
-
message.content = [];
|
|
56
|
-
message.stopReason = "error";
|
|
57
|
-
message.stopDetails = { type: "refusal", explanation };
|
|
58
|
-
message.errorMessage = explanation;
|
|
59
|
-
appendAssistantMessageDiagnostic(message, {
|
|
60
|
-
type: SERVER_FALLBACK_ABORTED_DIAGNOSTIC,
|
|
61
|
-
timestamp: Date.now(),
|
|
62
|
-
details: { from: receipt.from, to: receipt.to },
|
|
63
|
-
});
|
|
64
|
-
appendAssistantMessageDiagnostic(message, {
|
|
65
|
-
type: BILLING_INCOMPLETE_DIAGNOSTIC,
|
|
66
|
-
timestamp: Date.now(),
|
|
67
|
-
details: { reason: "per-attempt usage does not arrive after a client abort" },
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
//# sourceMappingURL=server-fallback-receipt.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server-fallback-receipt.js","sourceRoot":"","sources":["../../src/utils/server-fallback-receipt.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\nimport { appendAssistantMessageDiagnostic } from \"./diagnostics.ts\";\n\nexport const SERVER_FALLBACK_ABORTED_DIAGNOSTIC = \"server_fallback_aborted\";\nexport const BILLING_INCOMPLETE_DIAGNOSTIC = \"billing_incomplete_after_client_abort\";\n\nexport interface ServerFallbackReceipt {\n\treadonly from: string;\n\treadonly to: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction readModel(value: unknown): string | undefined {\n\tif (!isRecord(value)) return undefined;\n\treturn typeof value.model === \"string\" && value.model.length > 0 ? value.model : undefined;\n}\n\n/**\n * Anthropic marks a classifier handoff with `{type:\"fallback\", from:{model}, to:{model}}`\n * (`server-side-fallback-*` betas). Returns undefined for anything else, so an\n * unrelated or malformed provider-native block falls through to normal handling.\n */\nexport function parseServerFallbackReceipt(block: unknown): ServerFallbackReceipt | undefined {\n\tif (!isRecord(block) || block.type !== \"fallback\") return undefined;\n\tconst from = readModel(block.from);\n\tconst to = readModel(block.to);\n\treturn from !== undefined && to !== undefined ? { from, to } : undefined;\n}\n\n/**\n * Sticky routing serves later turns of a fallen-back conversation from the\n * substitute model with no `fallback` block at all; a `fallback_message` entry\n * in `usage.iterations` is the documented signal. A served-model string\n * comparison is deliberately NOT used: gateways and Bedrock-style endpoints\n * rewrite model ids, so a mismatch is not evidence of a fallback.\n */\nexport function parseStickyFallbackReceipt(\n\tusage: unknown,\n\trequestedModel: string,\n\tservedModel?: string,\n): ServerFallbackReceipt | undefined {\n\tif (!isRecord(usage) || !Array.isArray(usage.iterations)) return undefined;\n\tfor (let index = usage.iterations.length - 1; index >= 0; index--) {\n\t\tconst entry: unknown = usage.iterations[index];\n\t\tif (!isRecord(entry) || entry.type !== \"fallback_message\") continue;\n\t\tconst entryModel = typeof entry.model === \"string\" && entry.model.length > 0 ? entry.model : undefined;\n\t\tconst to = entryModel ?? servedModel;\n\t\treturn to !== undefined ? { from: requestedModel, to } : undefined;\n\t}\n\treturn undefined;\n}\n\nexport function serverFallbackRefusalExplanation(receipt: ServerFallbackReceipt): string {\n\treturn `Server-side fallback (${receipt.from} -> ${receipt.to}) aborted by client policy`;\n}\n\n/**\n * Rewrites an aborted turn into the same shape a pre-output classifier refusal\n * has, so `isClassifierRefusal()` routes it through the caller's fallback chain.\n * Content is dropped: the substitute model's partial output was never requested,\n * and replaying a half-turn containing a fallback marker breaks Anthropic replay.\n */\nexport function applyServerFallbackAbort(message: AssistantMessage, receipt: ServerFallbackReceipt): void {\n\tconst explanation = serverFallbackRefusalExplanation(receipt);\n\tmessage.content = [];\n\tmessage.stopReason = \"error\";\n\tmessage.stopDetails = { type: \"refusal\", explanation };\n\tmessage.errorMessage = explanation;\n\tappendAssistantMessageDiagnostic(message, {\n\t\ttype: SERVER_FALLBACK_ABORTED_DIAGNOSTIC,\n\t\ttimestamp: Date.now(),\n\t\tdetails: { from: receipt.from, to: receipt.to },\n\t});\n\tappendAssistantMessageDiagnostic(message, {\n\t\ttype: BILLING_INCOMPLETE_DIAGNOSTIC,\n\t\ttimestamp: Date.now(),\n\t\tdetails: { reason: \"per-attempt usage does not arrive after a client abort\" },\n\t});\n}\n"]}
|