@asm-agent/coding-agent 0.8.8 → 0.9.0
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 +15 -0
- package/README.md +2 -7
- package/dist/asm-agent-runtime/src/__pycache__/asm_cm_driver.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/__pycache__/phase76_address_head.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__init__.py +1 -1
- package/dist/asm-agent-runtime/src/rlm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/bash.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/bash.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp_base.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/repl.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/repl.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/skill.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/bash.py +94 -31
- package/dist/asm-agent-runtime/src/rlm/repl.md +3 -3
- package/dist/asm-agent-runtime/src/rlm/repl.py +46 -45
- package/dist/asm-agent-runtime/test/__pycache__/test_bash.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_repl.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/test_bash.py +74 -19
- package/dist/asm-agent-runtime/test/test_repl.py +67 -3
- package/dist/asm-agent-runtime/uv.lock +446 -155
- package/dist/bundle/{anthropic-OFECORE7.js → anthropic-ZOZNPFXS.js} +2 -2
- package/dist/bundle/{azure-openai-responses-AOVTLR6N.js → azure-openai-responses-TDHCU647.js} +2 -2
- package/dist/bundle/{bundled-modules-JQCJDEIY.js → bundled-modules-Q2YODC4B.js} +3 -3
- package/dist/bundle/{chunk-M67RGWDQ.js → chunk-AMKLNEAK.js} +25 -44
- package/dist/bundle/{chunk-7TB7CGPV.js → chunk-FPY7FFJS.js} +978 -1821
- package/dist/bundle/{chunk-JC2TT4MZ.js → chunk-G6SC4YYW.js} +4942 -1916
- package/dist/bundle/{chunk-A65OM3TZ.js → chunk-QLHAP3FT.js} +1 -1
- package/dist/bundle/{cli-main-FNHDQGQD.js → cli-main-277AG2BR.js} +3 -3
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/{google-RVJL6RIQ.js → google-Q3AJWUOY.js} +1 -1
- package/dist/bundle/{google-vertex-EZTRRRH6.js → google-vertex-2CSNOUBS.js} +1 -1
- package/dist/bundle/{main-IYXIIAJN.js → main-TNXWJXIU.js} +3 -3
- package/dist/bundle/{mistral-FSGKSMA7.js → mistral-XRYJGLLG.js} +1 -1
- package/dist/bundle/{openai-codex-responses-VM5Y564D.js → openai-codex-responses-C6BRO2BN.js} +2 -2
- package/dist/bundle/{openai-completions-X46FOQDN.js → openai-completions-DNXCK2JW.js} +3 -3
- package/dist/bundle/{openai-responses-SOQNEPBE.js → openai-responses-BEMWVIXE.js} +2 -2
- package/dist/config.d.ts +0 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-config.d.ts +1 -2
- package/dist/core/agent-session-config.d.ts.map +1 -1
- package/dist/core/agent-session-config.js +0 -3
- package/dist/core/agent-session-config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +0 -8
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +0 -2
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +0 -22
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +8 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +100 -22
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/kernel/bootstrap.d.ts.map +1 -1
- package/dist/core/kernel/bootstrap.js +1 -1
- package/dist/core/kernel/bootstrap.js.map +1 -1
- package/dist/core/kernel/repl-manager.d.ts +32 -8
- package/dist/core/kernel/repl-manager.d.ts.map +1 -1
- package/dist/core/kernel/repl-manager.js +401 -102
- package/dist/core/kernel/repl-manager.js.map +1 -1
- package/dist/core/kernel/shared.d.ts +11 -7
- package/dist/core/kernel/shared.d.ts.map +1 -1
- package/dist/core/kernel/shared.js +2 -5
- package/dist/core/kernel/shared.js.map +1 -1
- package/dist/core/mcp/mcp-manager.d.ts +4 -2
- package/dist/core/mcp/mcp-manager.d.ts.map +1 -1
- package/dist/core/mcp/mcp-manager.js +9 -7
- package/dist/core/mcp/mcp-manager.js.map +1 -1
- package/dist/core/prime-inference-auth.d.ts +0 -9
- package/dist/core/prime-inference-auth.d.ts.map +1 -1
- package/dist/core/prime-inference-auth.js +0 -50
- package/dist/core/prime-inference-auth.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +0 -1
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/session-manager.d.ts +0 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +0 -22
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +4 -16
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +13 -43
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +0 -5
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/acp-mcp.d.ts +6 -0
- package/dist/core/tools/acp-mcp.d.ts.map +1 -0
- package/dist/core/tools/acp-mcp.js +86 -0
- package/dist/core/tools/acp-mcp.js.map +1 -0
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ipython.d.ts.map +1 -1
- package/dist/core/tools/ipython.js +9 -4
- package/dist/core/tools/ipython.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -11
- package/dist/main.js.map +1 -1
- package/dist/modes/acp/acp-mode.d.ts.map +1 -1
- package/dist/modes/acp/acp-mode.js +1 -1
- package/dist/modes/acp/acp-mode.js.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts +0 -2
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js +0 -2
- package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
- package/dist/modes/agents-view/agents-view-mode.d.ts.map +1 -1
- package/dist/modes/agents-view/agents-view-mode.js +0 -19
- package/dist/modes/agents-view/agents-view-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-mode.d.ts +1 -10
- package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-mode.js +134 -274
- package/dist/modes/daemon/daemon-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-protocol.d.ts +11 -5
- package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-protocol.js +6 -8
- package/dist/modes/daemon/daemon-protocol.js.map +1 -1
- package/dist/modes/daemon/daemon-supervisor.d.ts +0 -3
- package/dist/modes/daemon/daemon-supervisor.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-supervisor.js +18 -52
- package/dist/modes/daemon/daemon-supervisor.js.map +1 -1
- package/dist/modes/daemon/daemon-worker-protocol.d.ts +1 -6
- package/dist/modes/daemon/daemon-worker-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-worker-protocol.js +0 -2
- package/dist/modes/daemon/daemon-worker-protocol.js.map +1 -1
- package/dist/modes/interactive/auth-flows.d.ts +0 -2
- package/dist/modes/interactive/auth-flows.d.ts.map +1 -1
- package/dist/modes/interactive/auth-flows.js +1 -101
- package/dist/modes/interactive/auth-flows.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +6 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +13 -3
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +2 -2
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts +12 -0
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
- package/dist/modes/interactive/components/mermaid.js +63 -0
- package/dist/modes/interactive/components/mermaid.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/feature-hints.d.ts.map +1 -1
- package/dist/modes/interactive/feature-hints.js +0 -4
- package/dist/modes/interactive/feature-hints.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -7
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +23 -279
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/settings.md +1 -31
- package/docs/usage.md +1 -4
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +6 -5
- package/dist/core/agent-traces.d.ts +0 -130
- package/dist/core/agent-traces.d.ts.map +0 -1
- package/dist/core/agent-traces.js +0 -746
- package/dist/core/agent-traces.js.map +0 -1
- package/dist/core/telemetry.d.ts +0 -92
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js +0 -633
- package/dist/core/telemetry.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAoDD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAcpG;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAM/F;AAyBD,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAqCtC;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAU9F","sourcesContent":["import { getPiUserAgent } from \"./pi-user-agent.js\";\n\nconst DEFAULT_ASM_AGENT_DOWNLOAD_BASE_URL = \"https://pub-
|
|
1
|
+
{"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAoDD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAcpG;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAM/F;AAyBD,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAqCtC;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAU9F","sourcesContent":["import { getPiUserAgent } from \"./pi-user-agent.js\";\n\nconst DEFAULT_ASM_AGENT_DOWNLOAD_BASE_URL = \"https://pub-ca377e94504d4b9cb997babbbc998159.r2.dev\";\nconst STABLE_VERSION_MANIFEST_PATH = \"latest.json\";\nconst BETA_VERSION_MANIFEST_PATH = \"beta.json\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tinstallSpec?: string;\n}\n\ninterface ParsedVersion {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n\tprerelease?: string;\n}\n\nfunction comparePrereleaseIdentifiers(leftPrerelease: string, rightPrerelease: string): number {\n\tconst leftIdentifiers = leftPrerelease.split(\".\");\n\tconst rightIdentifiers = rightPrerelease.split(\".\");\n\tconst length = Math.max(leftIdentifiers.length, rightIdentifiers.length);\n\n\tfor (let index = 0; index < length; index += 1) {\n\t\tconst left = leftIdentifiers[index];\n\t\tconst right = rightIdentifiers[index];\n\t\tif (left === right) continue;\n\t\tif (left === undefined) return -1;\n\t\tif (right === undefined) return 1;\n\n\t\tconst leftIsNumeric = /^\\d+$/.test(left);\n\t\tconst rightIsNumeric = /^\\d+$/.test(right);\n\t\tif (leftIsNumeric && rightIsNumeric) {\n\t\t\tconst leftNumber = left.replace(/^0+(?=\\d)/, \"\");\n\t\t\tconst rightNumber = right.replace(/^0+(?=\\d)/, \"\");\n\t\t\tif (leftNumber.length !== rightNumber.length) return leftNumber.length - rightNumber.length;\n\t\t\tconst comparison = leftNumber.localeCompare(rightNumber);\n\t\t\tif (comparison !== 0) return comparison;\n\t\t\tcontinue;\n\t\t}\n\t\tif (leftIsNumeric) return -1;\n\t\tif (rightIsNumeric) return 1;\n\t\treturn left.localeCompare(right);\n\t}\n\n\treturn 0;\n}\n\nfunction parsePackageVersion(version: string): ParsedVersion | undefined {\n\tconst match = version.trim().match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+.*)?$/);\n\tif (!match) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tmajor: Number.parseInt(match[1], 10),\n\t\tminor: Number.parseInt(match[2], 10),\n\t\tpatch: Number.parseInt(match[3], 10),\n\t\tprerelease: match[4],\n\t};\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = parsePackageVersion(leftVersion);\n\tconst right = parsePackageVersion(rightVersion);\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\n\tif (left.major !== right.major) return left.major - right.major;\n\tif (left.minor !== right.minor) return left.minor - right.minor;\n\tif (left.patch !== right.patch) return left.patch - right.patch;\n\tif (left.prerelease === right.prerelease) return 0;\n\tif (!left.prerelease) return 1;\n\tif (!right.prerelease) return -1;\n\treturn comparePrereleaseIdentifiers(left.prerelease, right.prerelease);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nfunction getAsmAgentDownloadBaseUrl(): string {\n\treturn (process.env.ASM_AGENT_DOWNLOAD_BASE_URL?.trim() || DEFAULT_ASM_AGENT_DOWNLOAD_BASE_URL).replace(/\\/+$/, \"\");\n}\n\nfunction normalizeReleaseVersion(version: string): string {\n\treturn version.trim().replace(/^v/, \"\");\n}\n\nfunction getReleaseManifestPath(currentVersion: string): string {\n\tconst prerelease = parsePackageVersion(currentVersion)?.prerelease;\n\treturn prerelease?.match(/^beta(?:\\.|$)/) ? BETA_VERSION_MANIFEST_PATH : STABLE_VERSION_MANIFEST_PATH;\n}\n\nfunction resolveReleaseUrl(baseUrl: string, pathOrUrl: string): string | undefined {\n\tconst trimmed = pathOrUrl.trim();\n\tif (!trimmed) return undefined;\n\ttry {\n\t\treturn new URL(trimmed).toString();\n\t} catch {\n\t\treturn `${baseUrl}/${trimmed.replace(/^\\/+/, \"\")}`;\n\t}\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK || process.env.PI_OFFLINE) return undefined;\n\n\tconst baseUrl = getAsmAgentDownloadBaseUrl();\n\tconst response = await fetch(`${baseUrl}/${getReleaseManifestPath(currentVersion)}`, {\n\t\theaders: {\n\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\taccept: \"application/json\",\n\t\t},\n\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),\n\t});\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tpackage?: unknown;\n\t\tpackageName?: unknown;\n\t\ttarball?: unknown;\n\t\tversion?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.package === \"string\" && data.package.trim()\n\t\t\t? data.package.trim()\n\t\t\t: typeof data.packageName === \"string\" && data.packageName.trim()\n\t\t\t\t? data.packageName.trim()\n\t\t\t\t: undefined;\n\tconst installSpec = typeof data.tarball === \"string\" ? resolveReleaseUrl(baseUrl, data.tarball) : undefined;\n\tconst release: LatestPiRelease = { version: normalizeReleaseVersion(data.version) };\n\tif (packageName) {\n\t\trelease.packageName = packageName;\n\t}\n\tif (installSpec) {\n\t\trelease.installSpec = installSpec;\n\t}\n\treturn release;\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<string | undefined> {\n\ttry {\n\t\tconst latestVersion = await getLatestPiVersion(currentVersion);\n\t\tif (latestVersion && isNewerPackageVersion(latestVersion, currentVersion)) {\n\t\t\treturn latestVersion;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getPiUserAgent } from "./pi-user-agent.js";
|
|
2
|
-
const DEFAULT_ASM_AGENT_DOWNLOAD_BASE_URL = "https://pub-
|
|
2
|
+
const DEFAULT_ASM_AGENT_DOWNLOAD_BASE_URL = "https://pub-ca377e94504d4b9cb997babbbc998159.r2.dev";
|
|
3
3
|
const STABLE_VERSION_MANIFEST_PATH = "latest.json";
|
|
4
4
|
const BETA_VERSION_MANIFEST_PATH = "beta.json";
|
|
5
5
|
const DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"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","sourcesContent":["import { getPiUserAgent } from \"./pi-user-agent.js\";\n\nconst DEFAULT_ASM_AGENT_DOWNLOAD_BASE_URL = \"https://pub-728493de92a943e2a9b2d17b4719f318.r2.dev\";\nconst STABLE_VERSION_MANIFEST_PATH = \"latest.json\";\nconst BETA_VERSION_MANIFEST_PATH = \"beta.json\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tinstallSpec?: string;\n}\n\ninterface ParsedVersion {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n\tprerelease?: string;\n}\n\nfunction comparePrereleaseIdentifiers(leftPrerelease: string, rightPrerelease: string): number {\n\tconst leftIdentifiers = leftPrerelease.split(\".\");\n\tconst rightIdentifiers = rightPrerelease.split(\".\");\n\tconst length = Math.max(leftIdentifiers.length, rightIdentifiers.length);\n\n\tfor (let index = 0; index < length; index += 1) {\n\t\tconst left = leftIdentifiers[index];\n\t\tconst right = rightIdentifiers[index];\n\t\tif (left === right) continue;\n\t\tif (left === undefined) return -1;\n\t\tif (right === undefined) return 1;\n\n\t\tconst leftIsNumeric = /^\\d+$/.test(left);\n\t\tconst rightIsNumeric = /^\\d+$/.test(right);\n\t\tif (leftIsNumeric && rightIsNumeric) {\n\t\t\tconst leftNumber = left.replace(/^0+(?=\\d)/, \"\");\n\t\t\tconst rightNumber = right.replace(/^0+(?=\\d)/, \"\");\n\t\t\tif (leftNumber.length !== rightNumber.length) return leftNumber.length - rightNumber.length;\n\t\t\tconst comparison = leftNumber.localeCompare(rightNumber);\n\t\t\tif (comparison !== 0) return comparison;\n\t\t\tcontinue;\n\t\t}\n\t\tif (leftIsNumeric) return -1;\n\t\tif (rightIsNumeric) return 1;\n\t\treturn left.localeCompare(right);\n\t}\n\n\treturn 0;\n}\n\nfunction parsePackageVersion(version: string): ParsedVersion | undefined {\n\tconst match = version.trim().match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+.*)?$/);\n\tif (!match) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tmajor: Number.parseInt(match[1], 10),\n\t\tminor: Number.parseInt(match[2], 10),\n\t\tpatch: Number.parseInt(match[3], 10),\n\t\tprerelease: match[4],\n\t};\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = parsePackageVersion(leftVersion);\n\tconst right = parsePackageVersion(rightVersion);\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\n\tif (left.major !== right.major) return left.major - right.major;\n\tif (left.minor !== right.minor) return left.minor - right.minor;\n\tif (left.patch !== right.patch) return left.patch - right.patch;\n\tif (left.prerelease === right.prerelease) return 0;\n\tif (!left.prerelease) return 1;\n\tif (!right.prerelease) return -1;\n\treturn comparePrereleaseIdentifiers(left.prerelease, right.prerelease);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nfunction getAsmAgentDownloadBaseUrl(): string {\n\treturn (process.env.ASM_AGENT_DOWNLOAD_BASE_URL?.trim() || DEFAULT_ASM_AGENT_DOWNLOAD_BASE_URL).replace(/\\/+$/, \"\");\n}\n\nfunction normalizeReleaseVersion(version: string): string {\n\treturn version.trim().replace(/^v/, \"\");\n}\n\nfunction getReleaseManifestPath(currentVersion: string): string {\n\tconst prerelease = parsePackageVersion(currentVersion)?.prerelease;\n\treturn prerelease?.match(/^beta(?:\\.|$)/) ? BETA_VERSION_MANIFEST_PATH : STABLE_VERSION_MANIFEST_PATH;\n}\n\nfunction resolveReleaseUrl(baseUrl: string, pathOrUrl: string): string | undefined {\n\tconst trimmed = pathOrUrl.trim();\n\tif (!trimmed) return undefined;\n\ttry {\n\t\treturn new URL(trimmed).toString();\n\t} catch {\n\t\treturn `${baseUrl}/${trimmed.replace(/^\\/+/, \"\")}`;\n\t}\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK || process.env.PI_OFFLINE) return undefined;\n\n\tconst baseUrl = getAsmAgentDownloadBaseUrl();\n\tconst response = await fetch(`${baseUrl}/${getReleaseManifestPath(currentVersion)}`, {\n\t\theaders: {\n\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\taccept: \"application/json\",\n\t\t},\n\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),\n\t});\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tpackage?: unknown;\n\t\tpackageName?: unknown;\n\t\ttarball?: unknown;\n\t\tversion?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.package === \"string\" && data.package.trim()\n\t\t\t? data.package.trim()\n\t\t\t: typeof data.packageName === \"string\" && data.packageName.trim()\n\t\t\t\t? data.packageName.trim()\n\t\t\t\t: undefined;\n\tconst installSpec = typeof data.tarball === \"string\" ? resolveReleaseUrl(baseUrl, data.tarball) : undefined;\n\tconst release: LatestPiRelease = { version: normalizeReleaseVersion(data.version) };\n\tif (packageName) {\n\t\trelease.packageName = packageName;\n\t}\n\tif (installSpec) {\n\t\trelease.installSpec = installSpec;\n\t}\n\treturn release;\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<string | undefined> {\n\ttry {\n\t\tconst latestVersion = await getLatestPiVersion(currentVersion);\n\t\tif (latestVersion && isNewerPackageVersion(latestVersion, currentVersion)) {\n\t\t\treturn latestVersion;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"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","sourcesContent":["import { getPiUserAgent } from \"./pi-user-agent.js\";\n\nconst DEFAULT_ASM_AGENT_DOWNLOAD_BASE_URL = \"https://pub-ca377e94504d4b9cb997babbbc998159.r2.dev\";\nconst STABLE_VERSION_MANIFEST_PATH = \"latest.json\";\nconst BETA_VERSION_MANIFEST_PATH = \"beta.json\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tinstallSpec?: string;\n}\n\ninterface ParsedVersion {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n\tprerelease?: string;\n}\n\nfunction comparePrereleaseIdentifiers(leftPrerelease: string, rightPrerelease: string): number {\n\tconst leftIdentifiers = leftPrerelease.split(\".\");\n\tconst rightIdentifiers = rightPrerelease.split(\".\");\n\tconst length = Math.max(leftIdentifiers.length, rightIdentifiers.length);\n\n\tfor (let index = 0; index < length; index += 1) {\n\t\tconst left = leftIdentifiers[index];\n\t\tconst right = rightIdentifiers[index];\n\t\tif (left === right) continue;\n\t\tif (left === undefined) return -1;\n\t\tif (right === undefined) return 1;\n\n\t\tconst leftIsNumeric = /^\\d+$/.test(left);\n\t\tconst rightIsNumeric = /^\\d+$/.test(right);\n\t\tif (leftIsNumeric && rightIsNumeric) {\n\t\t\tconst leftNumber = left.replace(/^0+(?=\\d)/, \"\");\n\t\t\tconst rightNumber = right.replace(/^0+(?=\\d)/, \"\");\n\t\t\tif (leftNumber.length !== rightNumber.length) return leftNumber.length - rightNumber.length;\n\t\t\tconst comparison = leftNumber.localeCompare(rightNumber);\n\t\t\tif (comparison !== 0) return comparison;\n\t\t\tcontinue;\n\t\t}\n\t\tif (leftIsNumeric) return -1;\n\t\tif (rightIsNumeric) return 1;\n\t\treturn left.localeCompare(right);\n\t}\n\n\treturn 0;\n}\n\nfunction parsePackageVersion(version: string): ParsedVersion | undefined {\n\tconst match = version.trim().match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+.*)?$/);\n\tif (!match) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tmajor: Number.parseInt(match[1], 10),\n\t\tminor: Number.parseInt(match[2], 10),\n\t\tpatch: Number.parseInt(match[3], 10),\n\t\tprerelease: match[4],\n\t};\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = parsePackageVersion(leftVersion);\n\tconst right = parsePackageVersion(rightVersion);\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\n\tif (left.major !== right.major) return left.major - right.major;\n\tif (left.minor !== right.minor) return left.minor - right.minor;\n\tif (left.patch !== right.patch) return left.patch - right.patch;\n\tif (left.prerelease === right.prerelease) return 0;\n\tif (!left.prerelease) return 1;\n\tif (!right.prerelease) return -1;\n\treturn comparePrereleaseIdentifiers(left.prerelease, right.prerelease);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nfunction getAsmAgentDownloadBaseUrl(): string {\n\treturn (process.env.ASM_AGENT_DOWNLOAD_BASE_URL?.trim() || DEFAULT_ASM_AGENT_DOWNLOAD_BASE_URL).replace(/\\/+$/, \"\");\n}\n\nfunction normalizeReleaseVersion(version: string): string {\n\treturn version.trim().replace(/^v/, \"\");\n}\n\nfunction getReleaseManifestPath(currentVersion: string): string {\n\tconst prerelease = parsePackageVersion(currentVersion)?.prerelease;\n\treturn prerelease?.match(/^beta(?:\\.|$)/) ? BETA_VERSION_MANIFEST_PATH : STABLE_VERSION_MANIFEST_PATH;\n}\n\nfunction resolveReleaseUrl(baseUrl: string, pathOrUrl: string): string | undefined {\n\tconst trimmed = pathOrUrl.trim();\n\tif (!trimmed) return undefined;\n\ttry {\n\t\treturn new URL(trimmed).toString();\n\t} catch {\n\t\treturn `${baseUrl}/${trimmed.replace(/^\\/+/, \"\")}`;\n\t}\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK || process.env.PI_OFFLINE) return undefined;\n\n\tconst baseUrl = getAsmAgentDownloadBaseUrl();\n\tconst response = await fetch(`${baseUrl}/${getReleaseManifestPath(currentVersion)}`, {\n\t\theaders: {\n\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\taccept: \"application/json\",\n\t\t},\n\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),\n\t});\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tpackage?: unknown;\n\t\tpackageName?: unknown;\n\t\ttarball?: unknown;\n\t\tversion?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.package === \"string\" && data.package.trim()\n\t\t\t? data.package.trim()\n\t\t\t: typeof data.packageName === \"string\" && data.packageName.trim()\n\t\t\t\t? data.packageName.trim()\n\t\t\t\t: undefined;\n\tconst installSpec = typeof data.tarball === \"string\" ? resolveReleaseUrl(baseUrl, data.tarball) : undefined;\n\tconst release: LatestPiRelease = { version: normalizeReleaseVersion(data.version) };\n\tif (packageName) {\n\t\trelease.packageName = packageName;\n\t}\n\tif (installSpec) {\n\t\trelease.installSpec = installSpec;\n\t}\n\treturn release;\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<string | undefined> {\n\ttry {\n\t\tconst latestVersion = await getLatestPiVersion(currentVersion);\n\t\tif (latestVersion && isNewerPackageVersion(latestVersion, currentVersion)) {\n\t\t\treturn latestVersion;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
package/docs/settings.md
CHANGED
|
@@ -48,7 +48,7 @@ Edit directly or use `/settings` for common options.
|
|
|
48
48
|
|
|
49
49
|
### Update Checks
|
|
50
50
|
|
|
51
|
-
Stable builds fetch the release manifest at `https://pub-
|
|
51
|
+
Stable builds fetch the release manifest at `https://pub-ca377e94504d4b9cb997babbbc998159.r2.dev/latest.json`. Beta builds fetch `beta.json` and continue following beta updates. Override the base URL with `ASM_AGENT_DOWNLOAD_BASE_URL`.
|
|
52
52
|
|
|
53
53
|
Set `PI_SKIP_VERSION_CHECK=1` to disable the ASM Agent version update check. Use `--offline` or `PI_OFFLINE=1` to disable startup network operations, including update checks and package update checks.
|
|
54
54
|
|
|
@@ -64,36 +64,6 @@ The stable `latest.json` and beta `beta.json` manifests use the same JSON shape:
|
|
|
64
64
|
|
|
65
65
|
`version` is required. `package` is optional and may also be named `packageName`; it defaults to the current package name. `tarball` is optional; when present, ASM Agent installs that tarball instead of the package name. Relative tarball paths resolve against `ASM_AGENT_DOWNLOAD_BASE_URL`.
|
|
66
66
|
|
|
67
|
-
### Pseudonymous usage analytics
|
|
68
|
-
|
|
69
|
-
ASM Agent sends pseudonymous, aggregate usage and performance events to Prime Intellect. These events include version and operating-system category, onboarding outcome and duration, execution mode (`interactive`, `print`, `json`, `rpc`, or `acp`), run outcomes, TTFT and latency, prompt and turn counts, token usage, tool success counts, retries, and compactions.
|
|
70
|
-
|
|
71
|
-
ASM Agent does not send prompts, responses, thinking, tool arguments or results, command text, filenames, paths, repository information, environment variables, credentials, raw error messages, hostnames, usernames, emails, or hardware identifiers. A random installation ID is stored as `telemetry.json` in the configured agent directory (normally `~/.asm-agent/`).
|
|
72
|
-
|
|
73
|
-
Telemetry can be disabled globally or for an individual project. Project settings can only further restrict telemetry: they cannot re-enable a global opt-out or suppress the global one-time disclosure.
|
|
74
|
-
|
|
75
|
-
| Setting | Type | Default | Description |
|
|
76
|
-
|---------|------|---------|-------------|
|
|
77
|
-
| `telemetry.enabled` | boolean | `true` | Send pseudonymous aggregate usage and performance events |
|
|
78
|
-
|
|
79
|
-
Disable analytics with any of:
|
|
80
|
-
|
|
81
|
-
```json
|
|
82
|
-
{
|
|
83
|
-
"telemetry": {
|
|
84
|
-
"enabled": false
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
ASM_AGENT_TELEMETRY=0 asm-agent
|
|
91
|
-
DO_NOT_TRACK=1 asm-agent
|
|
92
|
-
asm-agent --offline
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
`ASM_AGENT_TELEMETRY_ENDPOINT` overrides the ingestion endpoint for development and self-hosted deployments.
|
|
96
|
-
|
|
97
67
|
### Warnings
|
|
98
68
|
|
|
99
69
|
| Setting | Type | Default | Description |
|
package/docs/usage.md
CHANGED
|
@@ -46,7 +46,6 @@ Type `/` in the editor to open command completion. Extensions can register custo
|
|
|
46
46
|
| `/new` | Start a new session |
|
|
47
47
|
| `/name <name>` | Set session display name |
|
|
48
48
|
| `/session` | Show session file, ID, and message counts |
|
|
49
|
-
| `/traces [status\|on\|off\|preview\|upload-current\|upload-all\|login]` | Preview, upload, or manage opt-in trace sharing |
|
|
50
49
|
| `/usage`, `/context` | Show the parent and subagent context, token, and cost breakdown |
|
|
51
50
|
| `/tree` | Jump to any point in the session and continue from there |
|
|
52
51
|
| `/fork` | Create a new session from a previous user message |
|
|
@@ -359,9 +358,7 @@ asm-agent --tools ipython -p "Review the code"
|
|
|
359
358
|
| `PI_SKIP_VERSION_CHECK` | Skip the ASM Agent version update check at startup. This prevents the release manifest request |
|
|
360
359
|
| `ASM_AGENT_DOWNLOAD_BASE_URL` | Override the ASM Agent release manifest and tarball base URL |
|
|
361
360
|
| `PI_CACHE_RETENTION` | Set to `long` for extended prompt cache where supported |
|
|
362
|
-
| `PRIME_API_KEY` | Prime Inference API key
|
|
363
|
-
| `ASM_AGENT_TRACES_API_KEY` | Prime API key used only for opt-in trace sharing |
|
|
364
|
-
| `ASM_AGENT_TRACES_BASE_URL` | Override the ASM Agent trace upload API base URL |
|
|
361
|
+
| `PRIME_API_KEY` | Prime Inference API key |
|
|
365
362
|
| `ASM_AGENT_KERNEL_PYTHON` | Use an existing Python environment with `asm-agent-runtime` instead of bootstrapping `~/.asm-agent/kernel-venv` |
|
|
366
363
|
| `VISUAL`, `EDITOR` | External editor for Ctrl+G |
|
|
367
364
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-custom-provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-custom-provider",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.9.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.52.0"
|
|
12
12
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-sandbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-sandbox",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.9.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sandbox-runtime": "^0.0.55"
|
|
12
12
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-with-deps",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-with-deps",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.9.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "^2.1.3"
|
|
12
12
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asm-agent/coding-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Coding agent CLI with a persistent Python REPL kernel and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"asmAgentConfig": {
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@agentclientprotocol/sdk": "^1.3.0",
|
|
51
|
-
"@asm-agent/agent": "^0.
|
|
52
|
-
"@asm-agent/ai": "^0.
|
|
53
|
-
"@asm-agent/postgres": "^0.
|
|
54
|
-
"@asm-agent/tui": "^0.
|
|
51
|
+
"@asm-agent/agent": "^0.9.0",
|
|
52
|
+
"@asm-agent/ai": "^0.9.0",
|
|
53
|
+
"@asm-agent/postgres": "^0.9.0",
|
|
54
|
+
"@asm-agent/tui": "^0.9.0",
|
|
55
55
|
"@silvia-odwyer/photon-node": "^0.3.4",
|
|
56
56
|
"chalk": "^5.5.0",
|
|
57
57
|
"cli-highlight": "^2.1.11",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"extract-zip": "^2.0.1",
|
|
60
60
|
"file-type": "^21.1.1",
|
|
61
61
|
"glob": "^13.0.1",
|
|
62
|
+
"grok-mermaid": "0.2.3",
|
|
62
63
|
"hosted-git-info": "^9.0.2",
|
|
63
64
|
"ignore": "^7.0.5",
|
|
64
65
|
"jiti": "^2.7.0",
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import type { AuthStorage } from "./auth-storage.js";
|
|
2
|
-
import { type SessionHeader, type SessionManager } from "./session-manager.js";
|
|
3
|
-
import type { SettingsManager } from "./settings-manager.js";
|
|
4
|
-
export type AgentTraceCredentialSource = "environment" | "stored" | "prime-inference" | "prime-cli";
|
|
5
|
-
export interface AgentTraceCredential {
|
|
6
|
-
apiKey: string;
|
|
7
|
-
source: AgentTraceCredentialSource;
|
|
8
|
-
label: string;
|
|
9
|
-
}
|
|
10
|
-
export type AgentTraceUploadResult = {
|
|
11
|
-
status: "uploaded";
|
|
12
|
-
sessionId: string;
|
|
13
|
-
traceId: string;
|
|
14
|
-
bytesStored: number;
|
|
15
|
-
key?: string;
|
|
16
|
-
} | {
|
|
17
|
-
status: "disabled";
|
|
18
|
-
} | {
|
|
19
|
-
status: "missing_credentials";
|
|
20
|
-
} | {
|
|
21
|
-
status: "no_session_file";
|
|
22
|
-
} | {
|
|
23
|
-
status: "empty_session";
|
|
24
|
-
} | {
|
|
25
|
-
status: "invalid_session";
|
|
26
|
-
message: string;
|
|
27
|
-
} | {
|
|
28
|
-
status: "too_large";
|
|
29
|
-
size: number;
|
|
30
|
-
maxBytes: number;
|
|
31
|
-
} | {
|
|
32
|
-
status: "failed";
|
|
33
|
-
statusCode?: number;
|
|
34
|
-
message: string;
|
|
35
|
-
};
|
|
36
|
-
export interface AgentTraceUploadOptions {
|
|
37
|
-
sessionFile: string | undefined;
|
|
38
|
-
authStorage: AuthStorage;
|
|
39
|
-
settingsManager: SettingsManager;
|
|
40
|
-
/** Require the global automatic-sharing opt-in. Set false only for an explicit one-shot upload command. */
|
|
41
|
-
requireEnabled?: boolean;
|
|
42
|
-
baseUrl?: string;
|
|
43
|
-
configPath?: string;
|
|
44
|
-
fetchFn?: typeof fetch;
|
|
45
|
-
reloadConfig?: boolean;
|
|
46
|
-
requestTimeoutMs?: number;
|
|
47
|
-
signal?: AbortSignal;
|
|
48
|
-
}
|
|
49
|
-
export interface AgentTraceSessionUploadOptions extends Omit<AgentTraceUploadOptions, "sessionFile"> {
|
|
50
|
-
sessionManager: SessionManager;
|
|
51
|
-
}
|
|
52
|
-
export interface AgentTraceUploadInstallOptions {
|
|
53
|
-
authStorage: AuthStorage;
|
|
54
|
-
settingsManager: SettingsManager;
|
|
55
|
-
baseUrl?: string;
|
|
56
|
-
configPath?: string;
|
|
57
|
-
fetchFn?: typeof fetch;
|
|
58
|
-
requestTimeoutMs?: number;
|
|
59
|
-
}
|
|
60
|
-
export type AgentTracePreviewResult = {
|
|
61
|
-
status: "ready";
|
|
62
|
-
sessionFile: string;
|
|
63
|
-
sessionId: string;
|
|
64
|
-
traceId: string;
|
|
65
|
-
parentSessionId?: string;
|
|
66
|
-
cwd: string;
|
|
67
|
-
size: number;
|
|
68
|
-
maxBytes: number;
|
|
69
|
-
uploadable: boolean;
|
|
70
|
-
endpoint: string;
|
|
71
|
-
gitRepo?: string;
|
|
72
|
-
gitCommit?: string;
|
|
73
|
-
contentPreview: string;
|
|
74
|
-
truncated: boolean;
|
|
75
|
-
} | {
|
|
76
|
-
status: "no_session_file";
|
|
77
|
-
} | {
|
|
78
|
-
status: "empty_session";
|
|
79
|
-
} | {
|
|
80
|
-
status: "invalid_session";
|
|
81
|
-
message: string;
|
|
82
|
-
} | {
|
|
83
|
-
status: "failed";
|
|
84
|
-
message: string;
|
|
85
|
-
};
|
|
86
|
-
export interface AgentTracePreviewOptions {
|
|
87
|
-
sessionFile: string | undefined;
|
|
88
|
-
baseUrl?: string;
|
|
89
|
-
maxContentChars?: number;
|
|
90
|
-
}
|
|
91
|
-
export interface AgentTraceUploadAllProgress {
|
|
92
|
-
completed: number;
|
|
93
|
-
total: number;
|
|
94
|
-
sessionFile?: string;
|
|
95
|
-
result?: AgentTraceUploadResult;
|
|
96
|
-
}
|
|
97
|
-
export interface AgentTraceUploadAllOptions extends Omit<AgentTraceUploadOptions, "sessionFile"> {
|
|
98
|
-
sessionDir?: string;
|
|
99
|
-
concurrency?: number;
|
|
100
|
-
onProgress?: (progress: AgentTraceUploadAllProgress) => void;
|
|
101
|
-
}
|
|
102
|
-
export interface AgentTraceUploadAllResult {
|
|
103
|
-
total: number;
|
|
104
|
-
uploaded: number;
|
|
105
|
-
failed: number;
|
|
106
|
-
skipped: number;
|
|
107
|
-
bytesStored: number;
|
|
108
|
-
results: Array<{
|
|
109
|
-
sessionFile: string;
|
|
110
|
-
result: AgentTraceUploadResult;
|
|
111
|
-
}>;
|
|
112
|
-
}
|
|
113
|
-
/** Active-branch git for the indexing headers: walk leaf to root, not the last git_state in
|
|
114
|
-
* file order (which may belong to a sibling branch). */
|
|
115
|
-
export declare function activeGitContext(body: string, header: SessionHeader): {
|
|
116
|
-
repoUrl?: string;
|
|
117
|
-
commit?: string;
|
|
118
|
-
} | undefined;
|
|
119
|
-
export declare function previewAgentTraceFile(options: AgentTracePreviewOptions): Promise<AgentTracePreviewResult>;
|
|
120
|
-
export declare function findAgentTraceFiles(sessionDir?: string): Promise<string[]>;
|
|
121
|
-
export declare function uploadAllAgentTraces(options: AgentTraceUploadAllOptions): Promise<AgentTraceUploadAllResult>;
|
|
122
|
-
export declare function getAsmAgentTraceCredential(authStorage: AuthStorage, options?: {
|
|
123
|
-
reloadAuth?: boolean;
|
|
124
|
-
configPath?: string;
|
|
125
|
-
}): Promise<AgentTraceCredential | undefined>;
|
|
126
|
-
export declare function uploadAgentTraceFile(options: AgentTraceUploadOptions): Promise<AgentTraceUploadResult>;
|
|
127
|
-
export declare function uploadAgentTraceSession(options: AgentTraceSessionUploadOptions): Promise<AgentTraceUploadResult>;
|
|
128
|
-
export declare function installAgentTraceUpload(sessionManager: SessionManager, options: AgentTraceUploadInstallOptions): void;
|
|
129
|
-
export declare function flushAgentTraceUpload(sessionManager: SessionManager): Promise<AgentTraceUploadResult | undefined>;
|
|
130
|
-
//# sourceMappingURL=agent-traces.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"agent-traces.d.ts","sourceRoot":"","sources":["../../src/core/agent-traces.ts"],"names":[],"mappings":"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","sourcesContent":["import { Buffer } from \"node:buffer\";\nimport type { Dirent } from \"node:fs\";\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { appendRotatingLog, getAgentTracesLogPath, getSessionsDir, VERSION } from \"../config.js\";\nimport { readFirstLineSync } from \"../utils/file-lines.js\";\nimport type { AuthStorage } from \"./auth-storage.js\";\nimport {\n\tASM_AGENT_TRACES_PROVIDER_ID,\n\tloadPrimeCliConfig,\n\tPRIME_INFERENCE_PROVIDER_ID,\n\tresolveAsmAgentTracesBaseUrl,\n} from \"./prime-inference-auth.js\";\nimport { getSessionArtifactsRoot, type SessionHeader, type SessionManager } from \"./session-manager.js\";\nimport type { SettingsManager } from \"./settings-manager.js\";\n\nconst MAX_TRACE_BYTES = 20 * 1024 * 1024;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 15_000;\nconst TRACE_UPLOAD_DEBOUNCE_MS = 1_000;\nconst TRACE_UPLOAD_MIN_INTERVAL_MS = 60_000;\nconst TRACE_UPLOAD_RETRY_BASE_DELAY_MS = 500;\nconst TRACE_UPLOAD_RETRY_MAX_DELAY_MS = 10_000;\nconst TRACE_UPLOAD_MAX_RETRIES = 3;\nconst TRACE_UPLOAD_RETRY_JITTER = 0.2;\nconst TRACE_PREVIEW_MAX_CHARS = 8_000;\nconst TRACE_UPLOAD_ALL_CONCURRENCY = 4;\nconst TRACE_UPLOAD_RATE_LIMIT_REQUESTS = 5;\nconst TRACE_UPLOAD_RATE_LIMIT_WINDOW_MS = 60_000;\nconst TRACE_UPLOAD_RATE_LIMIT_SAFETY_MS = 100;\nconst TRACE_UPLOAD_ALL_MIN_REQUEST_INTERVAL_MS =\n\tMath.ceil(TRACE_UPLOAD_RATE_LIMIT_WINDOW_MS / TRACE_UPLOAD_RATE_LIMIT_REQUESTS) + TRACE_UPLOAD_RATE_LIMIT_SAFETY_MS;\n\nexport type AgentTraceCredentialSource = \"environment\" | \"stored\" | \"prime-inference\" | \"prime-cli\";\n\nexport interface AgentTraceCredential {\n\tapiKey: string;\n\tsource: AgentTraceCredentialSource;\n\tlabel: string;\n}\n\nexport type AgentTraceUploadResult =\n\t| {\n\t\t\tstatus: \"uploaded\";\n\t\t\tsessionId: string;\n\t\t\ttraceId: string;\n\t\t\tbytesStored: number;\n\t\t\tkey?: string;\n\t }\n\t| { status: \"disabled\" }\n\t| { status: \"missing_credentials\" }\n\t| { status: \"no_session_file\" }\n\t| { status: \"empty_session\" }\n\t| { status: \"invalid_session\"; message: string }\n\t| { status: \"too_large\"; size: number; maxBytes: number }\n\t| { status: \"failed\"; statusCode?: number; message: string };\n\nexport interface AgentTraceUploadOptions {\n\tsessionFile: string | undefined;\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\t/** Require the global automatic-sharing opt-in. Set false only for an explicit one-shot upload command. */\n\trequireEnabled?: boolean;\n\tbaseUrl?: string;\n\tconfigPath?: string;\n\tfetchFn?: typeof fetch;\n\treloadConfig?: boolean;\n\trequestTimeoutMs?: number;\n\tsignal?: AbortSignal;\n}\n\nexport interface AgentTraceSessionUploadOptions extends Omit<AgentTraceUploadOptions, \"sessionFile\"> {\n\tsessionManager: SessionManager;\n}\n\nexport interface AgentTraceUploadInstallOptions {\n\tauthStorage: AuthStorage;\n\tsettingsManager: SettingsManager;\n\tbaseUrl?: string;\n\tconfigPath?: string;\n\tfetchFn?: typeof fetch;\n\trequestTimeoutMs?: number;\n}\n\nexport type AgentTracePreviewResult =\n\t| {\n\t\t\tstatus: \"ready\";\n\t\t\tsessionFile: string;\n\t\t\tsessionId: string;\n\t\t\ttraceId: string;\n\t\t\tparentSessionId?: string;\n\t\t\tcwd: string;\n\t\t\tsize: number;\n\t\t\tmaxBytes: number;\n\t\t\tuploadable: boolean;\n\t\t\tendpoint: string;\n\t\t\tgitRepo?: string;\n\t\t\tgitCommit?: string;\n\t\t\tcontentPreview: string;\n\t\t\ttruncated: boolean;\n\t }\n\t| { status: \"no_session_file\" }\n\t| { status: \"empty_session\" }\n\t| { status: \"invalid_session\"; message: string }\n\t| { status: \"failed\"; message: string };\n\nexport interface AgentTracePreviewOptions {\n\tsessionFile: string | undefined;\n\tbaseUrl?: string;\n\tmaxContentChars?: number;\n}\n\nexport interface AgentTraceUploadAllProgress {\n\tcompleted: number;\n\ttotal: number;\n\tsessionFile?: string;\n\tresult?: AgentTraceUploadResult;\n}\n\nexport interface AgentTraceUploadAllOptions extends Omit<AgentTraceUploadOptions, \"sessionFile\"> {\n\tsessionDir?: string;\n\tconcurrency?: number;\n\tonProgress?: (progress: AgentTraceUploadAllProgress) => void;\n}\n\nexport interface AgentTraceUploadAllResult {\n\ttotal: number;\n\tuploaded: number;\n\tfailed: number;\n\tskipped: number;\n\tbytesStored: number;\n\tresults: Array<{ sessionFile: string; result: AgentTraceUploadResult }>;\n}\n\nfunction stringEnv(name: string): string | undefined {\n\tconst value = process.env[name];\n\treturn typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction describeError(error: unknown): string {\n\tif (!(error instanceof Error)) {\n\t\treturn String(error);\n\t}\n\tconst cause = (error as { cause?: unknown }).cause;\n\tif (isRecord(cause)) {\n\t\tconst code = typeof cause.code === \"string\" ? cause.code : undefined;\n\t\tconst causeMessage = typeof cause.message === \"string\" ? cause.message : undefined;\n\t\tconst detail = code ?? causeMessage;\n\t\tif (detail && detail !== error.message) {\n\t\t\treturn `${error.message} (${detail})`;\n\t\t}\n\t}\n\treturn error.message;\n}\n\nclass TraceUploadTimeoutError extends Error {\n\tconstructor(timeoutMs: number) {\n\t\tsuper(`Trace upload timed out after ${timeoutMs}ms`);\n\t\tthis.name = \"TraceUploadTimeoutError\";\n\t}\n}\n\nconst RETRIABLE_NETWORK_CODES = new Set([\n\t\"ECONNRESET\",\n\t\"ECONNREFUSED\",\n\t\"ECONNABORTED\",\n\t\"EPIPE\",\n\t\"ETIMEDOUT\",\n\t\"ENETUNREACH\",\n\t\"ENETDOWN\",\n\t\"EAI_AGAIN\",\n\t\"UND_ERR_SOCKET\",\n\t\"UND_ERR_CONNECT_TIMEOUT\",\n]);\n\nconst RETRIABLE_HTTP_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504]);\n\nfunction isRetriableNetworkError(error: unknown): boolean {\n\tif (error instanceof TraceUploadTimeoutError) {\n\t\treturn true;\n\t}\n\tif (!(error instanceof Error) || error.name === \"AbortError\") {\n\t\treturn false;\n\t}\n\tconst cause = (error as { cause?: unknown }).cause;\n\treturn isRecord(cause) && typeof cause.code === \"string\" && RETRIABLE_NETWORK_CODES.has(cause.code);\n}\n\nfunction stringField(data: Record<string, unknown>, key: string): string | undefined {\n\tconst value = data[key];\n\treturn typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n}\n\nfunction numberField(data: Record<string, unknown>, key: string): number | undefined {\n\tconst value = data[key];\n\treturn typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction isSessionHeader(value: unknown): value is SessionHeader {\n\treturn (\n\t\tisRecord(value) &&\n\t\tvalue.type === \"session\" &&\n\t\ttypeof value.id === \"string\" &&\n\t\ttypeof value.timestamp === \"string\" &&\n\t\ttypeof value.cwd === \"string\" &&\n\t\t(value.parentSession === undefined || typeof value.parentSession === \"string\")\n\t);\n}\n\nfunction readSessionHeader(sessionFile: string): SessionHeader | undefined {\n\ttry {\n\t\tconst firstLine = readFirstLineSync(sessionFile);\n\t\tif (!firstLine?.trim()) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst parsed = JSON.parse(firstLine) as unknown;\n\t\treturn isSessionHeader(parsed) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** Active-branch git for the indexing headers: walk leaf to root, not the last git_state in\n * file order (which may belong to a sibling branch). */\nexport function activeGitContext(\n\tbody: string,\n\theader: SessionHeader,\n): { repoUrl?: string; commit?: string } | undefined {\n\tconst byId = new Map<string, { parentId: string | null; type: string; git?: unknown }>();\n\tlet leafId: string | null = null;\n\tfor (const line of body.split(\"\\n\")) {\n\t\tif (!line.trim()) continue;\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(line);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (!isRecord(parsed) || parsed.type === \"session\" || typeof parsed.id !== \"string\") continue;\n\t\tbyId.set(parsed.id, {\n\t\t\tparentId: typeof parsed.parentId === \"string\" ? parsed.parentId : null,\n\t\t\ttype: typeof parsed.type === \"string\" ? parsed.type : \"\",\n\t\t\tgit: parsed.git,\n\t\t});\n\t\tleafId = parsed.id;\n\t}\n\n\tlet current = leafId ? byId.get(leafId) : undefined;\n\tfor (let depth = 0; current && depth < byId.size + 1; depth += 1) {\n\t\tif (current.type === \"git_state\" && isRecord(current.git)) {\n\t\t\treturn current.git as { repoUrl?: string; commit?: string };\n\t\t}\n\t\tcurrent = current.parentId ? byId.get(current.parentId) : undefined;\n\t}\n\treturn header.git;\n}\n\nfunction resolveParentSessionPath(sessionFile: string, parentSession: string): string {\n\treturn isAbsolute(parentSession) ? parentSession : resolve(dirname(sessionFile), parentSession);\n}\n\nfunction resolveTraceContext(\n\tsessionFile: string,\n\theader: SessionHeader,\n): { traceId: string; parentSessionId?: string } {\n\tlet traceId = header.id;\n\tlet parentSessionId: string | undefined;\n\tlet currentFile = sessionFile;\n\tlet currentHeader = header;\n\n\tfor (let depth = 0; depth < 32; depth += 1) {\n\t\tif (!currentHeader.parentSession) {\n\t\t\tbreak;\n\t\t}\n\n\t\tconst parentPath = resolveParentSessionPath(currentFile, currentHeader.parentSession);\n\t\tconst parentHeader = readSessionHeader(parentPath);\n\t\tif (!parentHeader) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif (depth === 0) {\n\t\t\tparentSessionId = parentHeader.id;\n\t\t}\n\t\ttraceId = parentHeader.id;\n\t\tcurrentFile = parentPath;\n\t\tcurrentHeader = parentHeader;\n\t}\n\n\treturn { traceId, parentSessionId };\n}\n\nfunction parseResponseObject(text: string): Record<string, unknown> | undefined {\n\tif (!text.trim()) {\n\t\treturn undefined;\n\t}\n\ttry {\n\t\tconst parsed = JSON.parse(text) as unknown;\n\t\treturn isRecord(parsed) ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nasync function readResponseMessage(response: Response): Promise<string> {\n\tconst text = await response.text().catch(() => \"\");\n\tif (!text.trim()) {\n\t\treturn response.statusText || \"Unknown error\";\n\t}\n\n\tconst parsed = parseResponseObject(text);\n\tif (parsed) {\n\t\tconst error = parsed.error;\n\t\tif (isRecord(error)) {\n\t\t\tconst message = stringField(error, \"message\");\n\t\t\tif (message) return message;\n\t\t}\n\t\tconst detail = stringField(parsed, \"detail\");\n\t\tif (detail) return detail;\n\t\tconst message = stringField(parsed, \"message\");\n\t\tif (message) return message;\n\t}\n\n\treturn text.trim();\n}\n\nasync function fetchWithTimeout(\n\tfetchFn: typeof fetch,\n\turl: string,\n\tinit: RequestInit,\n\ttimeoutMs: number,\n\tsignal?: AbortSignal,\n): Promise<Response> {\n\tconst controller = new AbortController();\n\tconst timeoutError = new TraceUploadTimeoutError(timeoutMs);\n\tlet timedOut = false;\n\tconst timeout = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort(timeoutError);\n\t}, timeoutMs);\n\tconst onAbort = () => controller.abort(signal?.reason);\n\tif (signal?.aborted) {\n\t\tonAbort();\n\t} else {\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t}\n\n\ttry {\n\t\treturn await fetchFn(url, { ...init, signal: controller.signal });\n\t} catch (error) {\n\t\tif (timedOut) {\n\t\t\tthrow timeoutError;\n\t\t}\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve) => {\n\t\tif (signal?.aborted) {\n\t\t\tresolve();\n\t\t\treturn;\n\t\t}\n\t\tconst timeout = setTimeout(finish, ms);\n\t\tconst onAbort = () => finish();\n\t\tfunction finish() {\n\t\t\tclearTimeout(timeout);\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve();\n\t\t}\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n}\n\nfunction traceUploadRetryDelay(retryIndex: number): number {\n\tconst exponentialDelay = Math.min(\n\t\tTRACE_UPLOAD_RETRY_MAX_DELAY_MS,\n\t\tTRACE_UPLOAD_RETRY_BASE_DELAY_MS * 2 ** retryIndex,\n\t);\n\tconst jitterMultiplier = 1 - TRACE_UPLOAD_RETRY_JITTER + Math.random() * TRACE_UPLOAD_RETRY_JITTER * 2;\n\treturn Math.max(0, Math.round(exponentialDelay * jitterMultiplier));\n}\n\nfunction retryAfterDelay(response: Response): number | undefined {\n\tconst value = response.headers.get(\"retry-after\")?.trim();\n\tif (!value) {\n\t\treturn undefined;\n\t}\n\tconst seconds = Number(value);\n\tif (Number.isFinite(seconds) && seconds >= 0) {\n\t\treturn Math.min(Math.ceil(seconds * 1_000), TRACE_UPLOAD_RATE_LIMIT_WINDOW_MS);\n\t}\n\tconst retryAt = Date.parse(value);\n\treturn Number.isFinite(retryAt)\n\t\t? Math.min(Math.max(0, retryAt - Date.now()), TRACE_UPLOAD_RATE_LIMIT_WINDOW_MS)\n\t\t: undefined;\n}\n\ntype BeforeTraceUploadRequest = () => Promise<void>;\n\nasync function fetchWithRetry(\n\tfetchFn: typeof fetch,\n\turl: string,\n\tinit: RequestInit,\n\ttimeoutMs: number,\n\tsignal?: AbortSignal,\n\tbeforeRequest?: BeforeTraceUploadRequest,\n): Promise<Response> {\n\tfor (let attempt = 0; ; attempt += 1) {\n\t\tlet retryDelayMs: number | undefined;\n\t\ttry {\n\t\t\tawait beforeRequest?.();\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow signal.reason ?? new Error(\"Trace upload cancelled\");\n\t\t\t}\n\t\t\tconst response = await fetchWithTimeout(fetchFn, url, init, timeoutMs, signal);\n\t\t\tif (attempt >= TRACE_UPLOAD_MAX_RETRIES || !RETRIABLE_HTTP_STATUSES.has(response.status)) {\n\t\t\t\treturn response;\n\t\t\t}\n\t\t\tif (response.status === 429) {\n\t\t\t\tretryDelayMs = retryAfterDelay(response) ?? TRACE_UPLOAD_RATE_LIMIT_WINDOW_MS;\n\t\t\t} else if (response.status === 503) {\n\t\t\t\tretryDelayMs = retryAfterDelay(response);\n\t\t\t}\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t} catch (error) {\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow signal.reason ?? error;\n\t\t\t}\n\t\t\tif (attempt >= TRACE_UPLOAD_MAX_RETRIES || !isRetriableNetworkError(error)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tawait delay(retryDelayMs ?? traceUploadRetryDelay(attempt), signal);\n\t\tif (signal?.aborted) {\n\t\t\tthrow signal.reason ?? new Error(\"Trace upload cancelled\");\n\t\t}\n\t}\n}\n\nfunction traceContentPreview(body: string, maxChars: number): { content: string; truncated: boolean } {\n\tif (body.length <= maxChars) {\n\t\treturn { content: body.trimEnd(), truncated: false };\n\t}\n\tconst marker = \"\\n... middle of trace omitted ...\\n\";\n\tconst available = Math.max(0, maxChars - marker.length);\n\tconst headChars = Math.ceil(available / 2);\n\tconst tailChars = Math.floor(available / 2);\n\treturn {\n\t\tcontent: `${body.slice(0, headChars).trimEnd()}${marker}${body.slice(body.length - tailChars).trimStart()}`,\n\t\ttruncated: true,\n\t};\n}\n\nexport async function previewAgentTraceFile(options: AgentTracePreviewOptions): Promise<AgentTracePreviewResult> {\n\tif (!options.sessionFile) {\n\t\treturn { status: \"no_session_file\" };\n\t}\n\n\tlet fileSize: number;\n\ttry {\n\t\tconst stats = await stat(options.sessionFile);\n\t\tif (!stats.isFile()) {\n\t\t\treturn { status: \"no_session_file\" };\n\t\t}\n\t\tfileSize = stats.size;\n\t} catch {\n\t\treturn { status: \"no_session_file\" };\n\t}\n\tif (fileSize === 0) {\n\t\treturn { status: \"empty_session\" };\n\t}\n\n\tconst header = readSessionHeader(options.sessionFile);\n\tif (!header) {\n\t\treturn { status: \"invalid_session\", message: \"Session file is missing a valid session header\" };\n\t}\n\n\tlet body = \"\";\n\tif (fileSize <= MAX_TRACE_BYTES) {\n\t\ttry {\n\t\t\tbody = await readFile(options.sessionFile, \"utf8\");\n\t\t} catch (error) {\n\t\t\treturn { status: \"failed\", message: describeError(error) };\n\t\t}\n\t\tif (!body.trim()) {\n\t\t\treturn { status: \"empty_session\" };\n\t\t}\n\t}\n\n\tconst traceContext = resolveTraceContext(options.sessionFile, header);\n\tconst baseUrl = resolveAsmAgentTracesBaseUrl(options.baseUrl);\n\tconst git = body ? activeGitContext(body, header) : header.git;\n\tconst preview = body\n\t\t? traceContentPreview(body, Math.max(256, options.maxContentChars ?? TRACE_PREVIEW_MAX_CHARS))\n\t\t: { content: \"\", truncated: true };\n\treturn {\n\t\tstatus: \"ready\",\n\t\tsessionFile: options.sessionFile,\n\t\tsessionId: header.id,\n\t\ttraceId: traceContext.traceId,\n\t\tparentSessionId: traceContext.parentSessionId,\n\t\tcwd: header.cwd,\n\t\tsize: fileSize,\n\t\tmaxBytes: MAX_TRACE_BYTES,\n\t\tuploadable: fileSize <= MAX_TRACE_BYTES,\n\t\tendpoint: `${baseUrl}/api/v1/agent-traces/sessions/${encodeURIComponent(header.id)}`,\n\t\tgitRepo: git?.repoUrl,\n\t\tgitCommit: git?.commit,\n\t\tcontentPreview: preview.content,\n\t\ttruncated: preview.truncated,\n\t};\n}\n\nasync function findSessionFilesUnder(root: string, files: Set<string>): Promise<void> {\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = await readdir(root, { withFileTypes: true });\n\t} catch {\n\t\treturn;\n\t}\n\n\tfor (const entry of entries) {\n\t\tconst entryPath = join(root, entry.name);\n\t\tif (entry.isDirectory()) {\n\t\t\tawait findSessionFilesUnder(entryPath, files);\n\t\t\tcontinue;\n\t\t}\n\t\tif (entry.isFile() && entry.name.endsWith(\".jsonl\") && readSessionHeader(entryPath)) {\n\t\t\tfiles.add(entryPath);\n\t\t}\n\t}\n}\n\nexport async function findAgentTraceFiles(sessionDir: string = getSessionsDir()): Promise<string[]> {\n\tconst files = new Set<string>();\n\tconst roots = new Set([resolve(sessionDir), resolve(getSessionArtifactsRoot(sessionDir))]);\n\tawait Promise.all([...roots].map((root) => findSessionFilesUnder(root, files)));\n\treturn [...files].sort();\n}\n\nfunction createTraceUploadAllRequestGate(signal?: AbortSignal): BeforeTraceUploadRequest {\n\tlet nextRequestAt = 0;\n\tlet queue = Promise.resolve();\n\treturn () => {\n\t\tconst slot = queue.then(async () => {\n\t\t\tconst waitMs = Math.max(0, nextRequestAt - Date.now());\n\t\t\tif (waitMs > 0) {\n\t\t\t\tawait delay(waitMs, signal);\n\t\t\t}\n\t\t\tif (!signal?.aborted) {\n\t\t\t\tnextRequestAt = Date.now() + TRACE_UPLOAD_ALL_MIN_REQUEST_INTERVAL_MS;\n\t\t\t}\n\t\t});\n\t\tqueue = slot.catch(() => undefined);\n\t\treturn slot;\n\t};\n}\n\nexport async function uploadAllAgentTraces(options: AgentTraceUploadAllOptions): Promise<AgentTraceUploadAllResult> {\n\tconst { sessionDir, concurrency, onProgress, ...uploadOptions } = options;\n\tconst sessionFiles = await findAgentTraceFiles(sessionDir);\n\ttype UploadResultItem = AgentTraceUploadAllResult[\"results\"][number];\n\tconst results: Array<UploadResultItem | undefined> = new Array(sessionFiles.length);\n\tlet cursor = 0;\n\tlet completed = 0;\n\tconst beforeRequest = createTraceUploadAllRequestGate(uploadOptions.signal);\n\tonProgress?.({ completed, total: sessionFiles.length });\n\n\tconst worker = async () => {\n\t\twhile (true) {\n\t\t\tif (uploadOptions.signal?.aborted) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst index = cursor;\n\t\t\tcursor += 1;\n\t\t\tconst sessionFile = sessionFiles[index];\n\t\t\tif (!sessionFile) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await uploadAgentTraceFileWithRequestGate(\n\t\t\t\t{\n\t\t\t\t\t...uploadOptions,\n\t\t\t\t\tsessionFile,\n\t\t\t\t\treloadConfig: false,\n\t\t\t\t},\n\t\t\t\tbeforeRequest,\n\t\t\t);\n\t\t\tif (uploadOptions.signal?.aborted && result.status === \"failed\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresults[index] = { sessionFile, result };\n\t\t\tcompleted += 1;\n\t\t\tonProgress?.({ completed, total: sessionFiles.length, sessionFile, result });\n\t\t}\n\t};\n\n\tconst requestedConcurrency = concurrency ?? TRACE_UPLOAD_ALL_CONCURRENCY;\n\tconst normalizedConcurrency =\n\t\tNumber.isFinite(requestedConcurrency) && requestedConcurrency > 0\n\t\t\t? Math.max(1, Math.floor(requestedConcurrency))\n\t\t\t: TRACE_UPLOAD_ALL_CONCURRENCY;\n\tconst workerCount = Math.min(sessionFiles.length, normalizedConcurrency);\n\tawait Promise.all(Array.from({ length: workerCount }, worker));\n\n\tconst completedResults = results.filter((item): item is UploadResultItem => item !== undefined);\n\tlet uploaded = 0;\n\tlet failed = 0;\n\tlet bytesStored = 0;\n\tfor (const item of completedResults) {\n\t\tif (item.result.status === \"uploaded\") {\n\t\t\tuploaded += 1;\n\t\t\tbytesStored += item.result.bytesStored;\n\t\t} else if (item.result.status === \"failed\") {\n\t\t\tfailed += 1;\n\t\t}\n\t}\n\treturn {\n\t\ttotal: sessionFiles.length,\n\t\tuploaded,\n\t\tfailed,\n\t\tskipped: sessionFiles.length - uploaded - failed,\n\t\tbytesStored,\n\t\tresults: completedResults,\n\t};\n}\n\nexport async function getAsmAgentTraceCredential(\n\tauthStorage: AuthStorage,\n\toptions: { reloadAuth?: boolean; configPath?: string } = {},\n): Promise<AgentTraceCredential | undefined> {\n\tconst traceEnvKey = stringEnv(\"ASM_AGENT_TRACES_API_KEY\");\n\tif (traceEnvKey) {\n\t\treturn { apiKey: traceEnvKey, source: \"environment\", label: \"ASM_AGENT_TRACES_API_KEY\" };\n\t}\n\n\tif (options.reloadAuth !== false) {\n\t\tauthStorage.reload();\n\t}\n\n\tconst traceKey = await authStorage.getApiKey(ASM_AGENT_TRACES_PROVIDER_ID, { includeFallback: false });\n\tif (traceKey) {\n\t\treturn { apiKey: traceKey, source: \"stored\", label: \"ASM Agent Traces credential\" };\n\t}\n\n\tconst primeEnvKey = stringEnv(\"PRIME_API_KEY\");\n\tif (primeEnvKey) {\n\t\treturn { apiKey: primeEnvKey, source: \"environment\", label: \"PRIME_API_KEY\" };\n\t}\n\n\tconst primeCredential = authStorage.get(PRIME_INFERENCE_PROVIDER_ID);\n\tif (primeCredential) {\n\t\tconst primeKey = await authStorage.getApiKey(PRIME_INFERENCE_PROVIDER_ID, { includeFallback: false });\n\t\tif (primeKey) {\n\t\t\treturn { apiKey: primeKey, source: \"prime-inference\", label: \"Prime Inference credential\" };\n\t\t}\n\t}\n\n\tconst primeCliKey = loadPrimeCliConfig(options.configPath).apiKey;\n\tif (primeCliKey) {\n\t\treturn { apiKey: primeCliKey, source: \"prime-cli\", label: \"Prime CLI credential\" };\n\t}\n\n\treturn undefined;\n}\n\nasync function getAgentTracesEnabled(\n\toptions: Pick<AgentTraceUploadOptions, \"reloadConfig\" | \"settingsManager\">,\n): Promise<boolean> {\n\tif (options.reloadConfig !== false) {\n\t\tawait options.settingsManager.reload().catch(() => undefined);\n\t}\n\treturn options.settingsManager.getAgentTracesEnabled();\n}\n\nasync function uploadAgentTraceFileWithRequestGate(\n\toptions: AgentTraceUploadOptions,\n\tbeforeRequest?: BeforeTraceUploadRequest,\n): Promise<AgentTraceUploadResult> {\n\tconst result = await performAgentTraceUpload(options, beforeRequest);\n\tlogAgentTraceOutcome(options.sessionFile, result);\n\treturn result;\n}\n\nexport function uploadAgentTraceFile(options: AgentTraceUploadOptions): Promise<AgentTraceUploadResult> {\n\treturn uploadAgentTraceFileWithRequestGate(options);\n}\n\nfunction logAgentTraceOutcome(sessionFile: string | undefined, result: AgentTraceUploadResult): void {\n\tlet line: string | undefined;\n\tswitch (result.status) {\n\t\tcase \"uploaded\":\n\t\t\tline = `uploaded session ${result.sessionId} (${result.bytesStored} bytes)`;\n\t\t\tbreak;\n\t\tcase \"failed\":\n\t\t\tline = `upload failed${result.statusCode ? ` (HTTP ${result.statusCode})` : \"\"}: ${result.message}`;\n\t\t\tbreak;\n\t\tcase \"too_large\":\n\t\t\tline = `upload skipped: session is ${result.size} bytes (limit ${result.maxBytes})`;\n\t\t\tbreak;\n\t\tcase \"invalid_session\":\n\t\t\tline = `upload skipped: ${result.message}`;\n\t\t\tbreak;\n\t\tcase \"missing_credentials\":\n\t\t\tline = \"upload skipped: no Prime credential configured (run /traces login)\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn;\n\t}\n\tconst suffix = sessionFile ? ` [${sessionFile}]` : \"\";\n\tappendRotatingLog(getAgentTracesLogPath(), `[${new Date().toISOString()}] ${line}${suffix}`);\n}\n\nasync function performAgentTraceUpload(\n\toptions: AgentTraceUploadOptions,\n\tbeforeRequest?: BeforeTraceUploadRequest,\n): Promise<AgentTraceUploadResult> {\n\tconst requireEnabled = options.requireEnabled !== false;\n\tif (requireEnabled && !(await getAgentTracesEnabled(options))) {\n\t\treturn { status: \"disabled\" };\n\t}\n\tif (!options.sessionFile) {\n\t\treturn { status: \"no_session_file\" };\n\t}\n\n\tlet fileSize: number;\n\ttry {\n\t\tconst stats = await stat(options.sessionFile);\n\t\tif (!stats.isFile()) {\n\t\t\treturn { status: \"no_session_file\" };\n\t\t}\n\t\tfileSize = stats.size;\n\t} catch {\n\t\treturn { status: \"no_session_file\" };\n\t}\n\tif (fileSize === 0) {\n\t\treturn { status: \"empty_session\" };\n\t}\n\tif (fileSize > MAX_TRACE_BYTES) {\n\t\treturn { status: \"too_large\", size: fileSize, maxBytes: MAX_TRACE_BYTES };\n\t}\n\n\tconst header = readSessionHeader(options.sessionFile);\n\tif (!header) {\n\t\treturn { status: \"invalid_session\", message: \"Session file is missing a valid session header\" };\n\t}\n\n\tconst credential = await getAsmAgentTraceCredential(options.authStorage, {\n\t\tconfigPath: options.configPath,\n\t\treloadAuth: options.reloadConfig !== false,\n\t});\n\tif (!credential) {\n\t\treturn { status: \"missing_credentials\" };\n\t}\n\n\tif (requireEnabled && !(await getAgentTracesEnabled(options))) {\n\t\treturn { status: \"disabled\" };\n\t}\n\n\tlet body: string;\n\ttry {\n\t\tbody = await readFile(options.sessionFile, \"utf8\");\n\t} catch (error) {\n\t\treturn { status: \"failed\", message: describeError(error) };\n\t}\n\tif (!body.trim()) {\n\t\treturn { status: \"empty_session\" };\n\t}\n\n\tconst traceContext = resolveTraceContext(options.sessionFile, header);\n\tconst bodyBytes = Buffer.byteLength(body, \"utf8\");\n\tconst headers: Record<string, string> = {\n\t\tAuthorization: `Bearer ${credential.apiKey}`,\n\t\t\"Content-Type\": \"application/x-ndjson\",\n\t\tAccept: \"application/json\",\n\t\t\"X-Trace-Id\": traceContext.traceId,\n\t\t\"X-Cwd\": header.cwd,\n\t\t\"X-Agent-Version\": VERSION,\n\t};\n\tif (traceContext.parentSessionId) {\n\t\theaders[\"X-Parent-Session\"] = traceContext.parentSessionId;\n\t}\n\tconst git = activeGitContext(body, header);\n\tif (git?.repoUrl) {\n\t\theaders[\"X-Git-Repo\"] = git.repoUrl;\n\t}\n\tif (git?.commit) {\n\t\theaders[\"X-Git-Commit\"] = git.commit;\n\t}\n\n\tif (requireEnabled && !(await getAgentTracesEnabled(options))) {\n\t\treturn { status: \"disabled\" };\n\t}\n\n\tconst baseUrl = resolveAsmAgentTracesBaseUrl(options.baseUrl);\n\tconst url = `${baseUrl}/api/v1/agent-traces/sessions/${encodeURIComponent(header.id)}`;\n\tconst fetchFn = options.fetchFn ?? fetch;\n\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetchWithRetry(\n\t\t\tfetchFn,\n\t\t\turl,\n\t\t\t{\n\t\t\t\tmethod: \"PUT\",\n\t\t\t\theaders,\n\t\t\t\tbody,\n\t\t\t},\n\t\t\toptions.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,\n\t\t\toptions.signal,\n\t\t\tbeforeRequest,\n\t\t);\n\t} catch (error) {\n\t\treturn { status: \"failed\", message: describeError(error) };\n\t}\n\n\tif (!response.ok) {\n\t\treturn {\n\t\t\tstatus: \"failed\",\n\t\t\tstatusCode: response.status,\n\t\t\tmessage: await readResponseMessage(response),\n\t\t};\n\t}\n\n\tconst responseText = await response.text().catch(() => \"\");\n\tconst responseData = parseResponseObject(responseText);\n\treturn {\n\t\tstatus: \"uploaded\",\n\t\tsessionId: responseData ? (stringField(responseData, \"session_id\") ?? header.id) : header.id,\n\t\ttraceId: responseData ? (stringField(responseData, \"trace_id\") ?? traceContext.traceId) : traceContext.traceId,\n\t\tbytesStored: responseData ? (numberField(responseData, \"bytes_stored\") ?? bodyBytes) : bodyBytes,\n\t\tkey: responseData ? stringField(responseData, \"key\") : undefined,\n\t};\n}\n\nexport function uploadAgentTraceSession(options: AgentTraceSessionUploadOptions): Promise<AgentTraceUploadResult> {\n\treturn uploadAgentTraceFile({\n\t\t...options,\n\t\tsessionFile: options.sessionManager.getSessionFile(),\n\t});\n}\n\nclass AgentTraceUploadController {\n\tprivate timeout: NodeJS.Timeout | undefined;\n\tprivate pending = false;\n\tprivate inFlight: Promise<AgentTraceUploadResult> | undefined;\n\tprivate flushPromise: Promise<AgentTraceUploadResult | undefined> | undefined;\n\tprivate lastUploadStartedAt: number | undefined;\n\tprivate lastUploadedSignature: string | undefined;\n\n\tconstructor(\n\t\tprivate readonly sessionManager: SessionManager,\n\t\tprivate options: AgentTraceUploadInstallOptions,\n\t) {}\n\n\tupdate(options: AgentTraceUploadInstallOptions): void {\n\t\tthis.options = options;\n\t}\n\n\tschedule = (): void => {\n\t\tthis.pending = true;\n\t\tif (this.timeout) {\n\t\t\tclearTimeout(this.timeout);\n\t\t}\n\t\tconst elapsed = this.lastUploadStartedAt === undefined ? 0 : Date.now() - this.lastUploadStartedAt;\n\t\tconst throttleDelay =\n\t\t\tthis.lastUploadStartedAt === undefined ? 0 : Math.max(0, TRACE_UPLOAD_MIN_INTERVAL_MS - elapsed);\n\t\tthis.timeout = setTimeout(\n\t\t\t() => {\n\t\t\t\tthis.timeout = undefined;\n\t\t\t\tvoid this.flush().catch(() => undefined);\n\t\t\t},\n\t\t\tMath.max(TRACE_UPLOAD_DEBOUNCE_MS, throttleDelay),\n\t\t);\n\t};\n\n\tprivate async getCurrentFileSignature(): Promise<string | undefined> {\n\t\tconst sessionFile = this.sessionManager.getSessionFile();\n\t\tif (!sessionFile) {\n\t\t\treturn undefined;\n\t\t}\n\t\ttry {\n\t\t\tconst stats = await stat(sessionFile);\n\t\t\treturn `${sessionFile}:${stats.size}:${stats.mtimeMs}`;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tasync flush(): Promise<AgentTraceUploadResult | undefined> {\n\t\tif (this.flushPromise) {\n\t\t\tconst result = await this.flushPromise;\n\t\t\tif (!this.pending) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\treturn (await this.flush()) ?? result;\n\t\t}\n\n\t\tthis.flushPromise = this.runFlush();\n\t\ttry {\n\t\t\treturn await this.flushPromise;\n\t\t} finally {\n\t\t\tthis.flushPromise = undefined;\n\t\t}\n\t}\n\n\tprivate async runFlush(): Promise<AgentTraceUploadResult | undefined> {\n\t\tif (this.timeout) {\n\t\t\tclearTimeout(this.timeout);\n\t\t\tthis.timeout = undefined;\n\t\t}\n\t\tif (this.inFlight) {\n\t\t\tawait this.inFlight.catch(() => undefined);\n\t\t}\n\t\tif (!this.pending) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst signature = await this.getCurrentFileSignature();\n\t\tif (signature && signature === this.lastUploadedSignature) {\n\t\t\tthis.pending = false;\n\t\t\treturn undefined;\n\t\t}\n\n\t\tthis.pending = false;\n\t\tthis.lastUploadStartedAt = Date.now();\n\t\tthis.inFlight = uploadAgentTraceSession({\n\t\t\t...this.options,\n\t\t\tsessionManager: this.sessionManager,\n\t\t});\n\t\ttry {\n\t\t\tconst result = await this.inFlight;\n\t\t\tif (result.status === \"uploaded\" && signature) {\n\t\t\t\tthis.lastUploadedSignature = signature;\n\t\t\t}\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tthis.inFlight = undefined;\n\t\t}\n\t}\n}\n\nconst traceUploadControllers = new WeakMap<SessionManager, AgentTraceUploadController>();\n\nexport function installAgentTraceUpload(sessionManager: SessionManager, options: AgentTraceUploadInstallOptions): void {\n\tlet controller = traceUploadControllers.get(sessionManager);\n\tif (controller) {\n\t\tcontroller.update(options);\n\t\treturn;\n\t}\n\n\tcontroller = new AgentTraceUploadController(sessionManager, options);\n\ttraceUploadControllers.set(sessionManager, controller);\n\tsessionManager.onPersist(controller.schedule);\n}\n\nexport async function flushAgentTraceUpload(\n\tsessionManager: SessionManager,\n): Promise<AgentTraceUploadResult | undefined> {\n\treturn traceUploadControllers.get(sessionManager)?.flush();\n}\n"]}
|