@inneranimalmedia/agentsam-sdk 2.6.3 → 2.6.4

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.
Files changed (233) hide show
  1. package/AGENTSAM.md +6 -0
  2. package/README.md +16 -1
  3. package/bin/agentsam +16 -1
  4. package/docs/BRAND_INTELLIGENCE.md +1 -1
  5. package/docs/architecture/AGENTSAM_DISTRIBUTION_OWNERSHIP.md +176 -0
  6. package/docs/architecture/AGENTSAM_GO_RUNTIME.md +282 -0
  7. package/docs/architecture/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  8. package/docs/architecture/FS_E2E_CLOSURE_RECEIPT.md +59 -0
  9. package/docs/architecture/LOCAL_FS_AUTHORITY.md +38 -0
  10. package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +28 -0
  11. package/docs/architecture/PLAN_CLI_AND_LOCAL_STUDIO_DESKTOP.md +96 -0
  12. package/docs/architecture/SAM_ACTIVITY_RECOVERY_RECEIPT.md +39 -0
  13. package/docs/architecture/SAM_DECISION_WORK_RECEIPT.md +54 -0
  14. package/docs/architecture/SAM_KERNEL.md +181 -0
  15. package/docs/architecture/SAM_MACHINE_NORMALIZATION_PRECOMMIT_REPORT.md +208 -0
  16. package/docs/architecture/SLASH_SKILLS_PORTABLE.md +116 -0
  17. package/docs/architecture/fs-e2e-receipt.latest.json +42 -0
  18. package/docs/architecture/previews/codebaseindex-guided-path/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  19. package/docs/architecture/previews/codebaseindex-guided-path/index.html +321 -0
  20. package/migrations/d1/0010_portable_tickets_memory.sql +140 -0
  21. package/migrations/d1/0011_agentsam_skill_v2.sql +185 -0
  22. package/migrations/d1/0011b_agentsam_skill_v2_cutover.sql +22 -0
  23. package/migrations/d1/0011c_agentsam_skill_v2_backfill.sql +76 -0
  24. package/migrations/d1/0011d_agentsam_skill_v2_retrieval_revisions.sql +50 -0
  25. package/migrations/d1/0012_agentsam_tools_required_seed.sql +67 -0
  26. package/migrations/d1/0013_identity_oauth_states.sql +15 -0
  27. package/migrations/d1/0014_auth_event_log.sql +20 -0
  28. package/migrations/d1/0015_identity_oauth_state_app_id.sql +3 -0
  29. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +16 -0
  30. package/migrations/sqlite/agentsam_skill_retrieval.portable.sql +42 -0
  31. package/package.json +19 -4
  32. package/packages/agentsam-contracts/src/errors.ts +16 -0
  33. package/packages/agentsam-errors/src/envelope.js +53 -0
  34. package/packages/agentsam-errors/src/index.js +1 -0
  35. package/packages/agentsam-errors/src/recovery.js +301 -0
  36. package/packages/agentsam-knowledge/src/providers/index.js +18 -6
  37. package/packages/connectors/cloudflare/src/routes.js +9 -0
  38. package/packages/connectors/cloudflare/tests/connector.test.mjs +26 -1
  39. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
  40. package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +11 -2
  41. package/packages/identity/docs/PORTABLE_IDENTITY_ARCHITECTURE.md +50 -0
  42. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +31 -0
  43. package/packages/identity/migrations/sqlite/001_identity_core.sql +99 -0
  44. package/packages/identity/migrations/sqlite/002_identity_oauth_client.sql +38 -0
  45. package/packages/identity/migrations/sqlite/003_identity_oauth_server.sql +64 -0
  46. package/packages/identity/package.json +2 -2
  47. package/packages/identity/src/adapters/cloudflare-d1/index.js +122 -22
  48. package/packages/identity/src/adapters/sqlite/index.js +319 -0
  49. package/packages/identity/src/app/verify-app.js +95 -0
  50. package/packages/identity/src/contracts/identity-store.js +115 -0
  51. package/packages/identity/src/contracts/route-ids.js +30 -0
  52. package/packages/identity/src/contracts/route-projection.js +218 -0
  53. package/packages/identity/src/contracts/routes.js +11 -0
  54. package/packages/identity/src/core/browser-paths.js +4 -5
  55. package/packages/identity/src/core/constants.js +13 -8
  56. package/packages/identity/src/core/session-policy.js +32 -0
  57. package/packages/identity/src/frontend/auth-portal/pages/login.html +10 -10
  58. package/packages/identity/src/frontend/auth-portal/pages/reset.html +3 -3
  59. package/packages/identity/src/frontend/auth-portal/pages/signup.html +3 -3
  60. package/packages/identity/src/frontend/auth-portal/preview/dashboard-stub.html +1 -1
  61. package/packages/identity/src/index.js +25 -0
  62. package/packages/identity/src/oauth/README.md +10 -4
  63. package/packages/identity/src/oauth/credentials.js +20 -13
  64. package/packages/identity/src/oauth/finalize-inbound.js +1 -1
  65. package/packages/identity/src/oauth/iam-platform.js +8 -7
  66. package/packages/identity/src/oauth/redirect-paths.js +27 -36
  67. package/packages/identity/src/server/identity-service.js +30 -13
  68. package/packages/identity/src/server/mount-policy.js +30 -0
  69. package/packages/identity/src/server/post-auth.js +79 -0
  70. package/packages/identity/src/server/worker-router.js +104 -72
  71. package/packages/identity/tests/finalize-inbound-oauth.test.mjs +6 -6
  72. package/packages/identity/tests/iam-provider.test.mjs +1 -1
  73. package/packages/identity/tests/identity-service.test.mjs +36 -5
  74. package/packages/identity/tests/oauth-credentials.test.mjs +3 -1
  75. package/packages/identity/tests/portable-identity-architecture.test.mjs +157 -0
  76. package/packages/identity/tests/session-routes-policy.test.mjs +21 -0
  77. package/packages/theme-church-site/package.json +2 -1
  78. package/packages/theme-church-site/src/index.js +1 -0
  79. package/packages/theme-companions-site/package.json +2 -1
  80. package/packages/theme-companions-site/src/index.js +1 -0
  81. package/packages/theme-floors-site/package.json +2 -1
  82. package/packages/theme-floors-site/src/index.js +1 -0
  83. package/packages/theme-fuelnfree-site/package.json +2 -1
  84. package/packages/theme-fuelnfree-site/src/index.js +1 -0
  85. package/packages/theme-handyman-site/package.json +2 -1
  86. package/packages/theme-handyman-site/src/index.js +1 -0
  87. package/packages/theme-insurance-site/package.json +2 -1
  88. package/packages/theme-insurance-site/src/index.js +1 -0
  89. package/packages/theme-shinshu-site/package.json +2 -1
  90. package/packages/theme-shinshu-site/src/index.js +1 -0
  91. package/protocol/apps/agentsam.app.v1.schema.json +51 -0
  92. package/protocol/brand/brandpack.v1.schema.json +43 -0
  93. package/protocol/credentials/issue.v1.schema.json +38 -0
  94. package/protocol/database/connection.v1.schema.json +41 -0
  95. package/protocol/embeddings/embedding-profile.v1.schema.json +20 -0
  96. package/protocol/errors/error-envelope.schema.json +135 -1
  97. package/protocol/errors/recovery.v1.schema.json +50 -0
  98. package/protocol/runtime/workspace-fs.v1.schema.json +71 -0
  99. package/protocol/sam/activity.v1.schema.json +48 -0
  100. package/protocol/sam/answer.v1.schema.json +35 -0
  101. package/protocol/sam/calibration.v1.schema.json +21 -0
  102. package/protocol/sam/decision-receipt.v1.schema.json +29 -0
  103. package/protocol/sam/evaluation.v1.schema.json +19 -0
  104. package/protocol/sam/operation.schema.json +66 -0
  105. package/protocol/sam/outcome.v1.schema.json +36 -0
  106. package/protocol/sam/question.v1.schema.json +26 -0
  107. package/protocol/sam/registry.seed.json +153 -0
  108. package/protocol/sam/result.schema.json +53 -0
  109. package/protocol/sam/state.v1.schema.json +23 -0
  110. package/protocol/skills/agentsam.interaction.v1.schema.json +50 -0
  111. package/protocol/skills/agentsam.skill.v1.schema.json +57 -0
  112. package/protocol/ui/icon-registry.mjs +226 -0
  113. package/protocol/ui/icon.v1.schema.json +51 -0
  114. package/skills/README.md +22 -9
  115. package/skills/agentsam-codebaseindex/SKILL.md +225 -0
  116. package/skills/catalog.json +14 -0
  117. package/src/cli/command-catalog.js +130 -0
  118. package/src/cli/dispatch.js +48 -0
  119. package/src/cli.js +43 -1
  120. package/src/commands/api-key.js +244 -0
  121. package/src/commands/app.js +60 -28
  122. package/src/commands/brand.js +17 -19
  123. package/src/commands/codebaseindex.js +688 -0
  124. package/src/commands/env.js +152 -25
  125. package/src/commands/go.js +366 -53
  126. package/src/commands/interaction-clack.js +115 -0
  127. package/src/commands/models.js +1 -1
  128. package/src/commands/providers.js +62 -14
  129. package/src/commands/shell.js +43 -2
  130. package/src/commands/skill.js +248 -0
  131. package/src/commands/skills.js +1 -1
  132. package/src/commands/start-local.js +4 -0
  133. package/src/commands/whoami.js +90 -18
  134. package/src/go/build.js +229 -39
  135. package/src/go/cloudflare.js +506 -105
  136. package/src/go/container.js +120 -0
  137. package/src/go/contract.js +9 -4
  138. package/src/go/discover.js +149 -33
  139. package/src/go/index.js +15 -3
  140. package/src/go/native-probe-runner.mjs +119 -0
  141. package/src/go/{registry.js → official-registry.js} +64 -7
  142. package/src/go/official-release.js +10 -0
  143. package/src/go/receipts.js +77 -10
  144. package/src/go/verify.js +9 -2
  145. package/src/index.js +27 -0
  146. package/src/indexing/ingest/discover-models.js +298 -0
  147. package/src/indexing/ingest/inventory.js +243 -0
  148. package/src/indexing/ingest/job-graph.js +181 -0
  149. package/src/indexing/ingest/materials.js +210 -0
  150. package/src/lib/provider-credentials.js +63 -21
  151. package/src/lib/slash-commands.js +1 -0
  152. package/src/local-fs/capability.js +121 -0
  153. package/src/local-fs/freshness.js +75 -0
  154. package/src/local-fs/index.js +385 -0
  155. package/src/local-fs/paths.js +100 -0
  156. package/src/local-pty/server.js +295 -19
  157. package/src/mcp/client.js +2 -2
  158. package/src/models/ai-access-onboarding.js +112 -0
  159. package/src/models/discovery.js +10 -2
  160. package/src/models/inventory-core.js +9 -1
  161. package/src/sam/activity/index.js +183 -0
  162. package/src/sam/client.js +252 -0
  163. package/src/sam/decision/calibration.js +109 -0
  164. package/src/sam/decision/confidence.js +126 -0
  165. package/src/sam/decision/evaluate.js +157 -0
  166. package/src/sam/decision/evaluators/deterministic.js +341 -0
  167. package/src/sam/decision/evaluators/heuristic.js +61 -0
  168. package/src/sam/decision/evaluators/select.js +50 -0
  169. package/src/sam/decision/evaluators/semantic.js +149 -0
  170. package/src/sam/decision/hierarchical.js +61 -0
  171. package/src/sam/decision/index.js +53 -0
  172. package/src/sam/decision/policy.js +86 -0
  173. package/src/sam/decision/questions.js +120 -0
  174. package/src/sam/decision/receipt.js +148 -0
  175. package/src/sam/decision/state.js +117 -0
  176. package/src/sam/decision/types.js +22 -0
  177. package/src/sam/decision/validate.js +200 -0
  178. package/src/sam/define.js +51 -0
  179. package/src/sam/index.js +65 -0
  180. package/src/sam/operations/brand-scan.js +62 -0
  181. package/src/sam/operations/cad-blender-inspect.js +36 -0
  182. package/src/sam/operations/codebaseindex-ingest.js +49 -0
  183. package/src/sam/operations/decision-evaluate.js +59 -0
  184. package/src/sam/operations/planning-astar.js +77 -0
  185. package/src/sam/operations/planning-goap.js +60 -0
  186. package/src/sam/operations/repository-inspect.js +72 -0
  187. package/src/sam/operations/security-scan.js +33 -0
  188. package/src/sam/operations/terminal-exec.js +29 -0
  189. package/src/sam/planning/astar.js +311 -0
  190. package/src/sam/planning/goap.js +177 -0
  191. package/src/sam/planning/index.js +21 -0
  192. package/src/sam/planning/state.js +84 -0
  193. package/src/sam/registry.js +48 -0
  194. package/src/sam/result.js +77 -0
  195. package/src/sam/seed.js +44 -0
  196. package/src/sam/types.js +91 -0
  197. package/src/skills/catalog.js +64 -0
  198. package/src/skills/content-resolver.js +124 -0
  199. package/src/skills/hosted-store.js +37 -0
  200. package/src/skills/index.js +29 -64
  201. package/src/skills/interaction.js +102 -0
  202. package/src/skills/local-store.js +228 -0
  203. package/src/skills/manifest.js +104 -0
  204. package/src/skills/metrics.js +31 -0
  205. package/src/skills/registry.js +184 -0
  206. package/src/skills/runtime.js +287 -0
  207. package/src/skills/slash.js +44 -0
  208. package/src/ui/cli/help.js +94 -101
  209. package/test/cli/api-key-env-whoami.test.mjs +129 -0
  210. package/test/cli/codebaseindex-plan-ux.test.mjs +37 -0
  211. package/test/cli/go.test.mjs +62 -5
  212. package/test/cli/skill-npm-and-env.test.mjs +52 -0
  213. package/test/cli/wireframes-go-registry.test.mjs +87 -2
  214. package/test/go/build-source-identity.test.mjs +31 -0
  215. package/test/go/cloudflare-probe.test.mjs +274 -10
  216. package/test/go/distribution.test.mjs +28 -0
  217. package/test/integration/ai-access-onboarding.test.mjs +47 -0
  218. package/test/integration/cli-help.test.mjs +1 -1
  219. package/test/integration/cms-site-tenancy-contract.test.mjs +6 -6
  220. package/test/integration/codebaseindex-ingest.test.mjs +166 -0
  221. package/test/integration/icon-registry.test.mjs +67 -0
  222. package/test/integration/ingest-discover-models.test.mjs +30 -0
  223. package/test/integration/install-script.test.mjs +12 -9
  224. package/test/integration/local-fs.test.mjs +113 -0
  225. package/test/integration/provider-env-cli.test.mjs +2 -1
  226. package/test/integration/sam-activity-recovery.test.mjs +147 -0
  227. package/test/integration/sam-decision.test.mjs +584 -0
  228. package/test/integration/sam-kernel.test.mjs +99 -0
  229. package/test/integration/sam-planning-astar.test.mjs +279 -0
  230. package/test/integration/skill-runtime.test.mjs +240 -0
  231. package/test/integration/studio-fs-pty-e2e.test.mjs +294 -0
  232. package/test/models.test.mjs +14 -7
  233. package/test/shell.test.mjs +4 -4
@@ -0,0 +1,120 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { probeGoDeploymentWithRetry } from './cloudflare.js';
3
+
4
+ function runDocker(args, { productRoot, spawn = spawnSync } = {}) {
5
+ const res = spawn('docker', args, {
6
+ cwd: productRoot,
7
+ encoding: 'utf8',
8
+ maxBuffer: 16 * 1024 * 1024,
9
+ });
10
+ return {
11
+ status: res.status,
12
+ stdout: res.stdout || '',
13
+ stderr: res.stderr || '',
14
+ output: ((res.stdout || '') + '\n' + (res.stderr || '')).trim(),
15
+ };
16
+ }
17
+
18
+ export async function verifyGoContainer({
19
+ productRoot,
20
+ product = 'agentsam-go-worker',
21
+ expectedSource,
22
+ expectedSourceCommit,
23
+ expectedBuiltAt = '',
24
+ spawn = spawnSync,
25
+ fetchImpl = globalThis.fetch,
26
+ } = {}) {
27
+ const tag = product + ':agentsam-verify';
28
+ const build = runDocker(['build', '--platform', 'linux/amd64', '-t', tag, '.'], { productRoot, spawn });
29
+ if (build.status !== 0) {
30
+ const err = new Error('go_container_build_failed');
31
+ err.detail = build.output.slice(-4000);
32
+ throw err;
33
+ }
34
+
35
+ const inspected = runDocker(['image', 'inspect', tag], { productRoot, spawn });
36
+ if (inspected.status !== 0) throw new Error('go_container_inspect_failed');
37
+ let image = null;
38
+ try { image = JSON.parse(inspected.stdout)?.[0] || null; } catch {}
39
+ if (!image) throw new Error('go_container_inspect_invalid');
40
+ if (image.Architecture !== 'amd64') throw new Error('go_container_architecture_invalid');
41
+ const imageUser = String(image.Config?.User || '');
42
+ if (!imageUser || imageUser === '0' || imageUser === 'root' || imageUser.startsWith('0:')) {
43
+ throw new Error('go_container_root_user_forbidden');
44
+ }
45
+
46
+ const name = product + '-verify-' + process.pid + '-' + Date.now();
47
+ const start = runDocker([
48
+ 'run', '-d', '--name', name,
49
+ '-p', '127.0.0.1::8080',
50
+ '-e', 'AGENTSAM_TARGET=container',
51
+ '-e', 'AGENTSAM_BUILD_SOURCE=' + (expectedSource || ''),
52
+ '-e', 'AGENTSAM_BUILD_COMMIT=' + (expectedSourceCommit || ''),
53
+ '-e', 'AGENTSAM_BUILT_AT=' + expectedBuiltAt,
54
+ tag,
55
+ ], { productRoot, spawn });
56
+ if (start.status !== 0) {
57
+ const err = new Error('go_container_start_failed');
58
+ err.detail = start.output.slice(-3000);
59
+ throw err;
60
+ }
61
+
62
+ const containerId = start.stdout.trim();
63
+ let stopped = false;
64
+ let cleaned = false;
65
+ try {
66
+ let port = null;
67
+ for (let attempt = 0; attempt < 30; attempt += 1) {
68
+ const mapped = runDocker(['port', containerId, '8080/tcp'], { productRoot, spawn });
69
+ const match = mapped.stdout.match(/:(\d+)\s*$/m);
70
+ if (mapped.status === 0 && match) {
71
+ port = Number(match[1]);
72
+ break;
73
+ }
74
+ await new Promise((resolve) => setTimeout(resolve, 100));
75
+ }
76
+ if (!port) throw new Error('go_container_port_missing');
77
+
78
+ const origin = 'http://127.0.0.1:' + port;
79
+ const probe = await probeGoDeploymentWithRetry(origin, {
80
+ fetchImpl,
81
+ expectedSource,
82
+ expectedSourceCommit,
83
+ expectedTarget: 'container',
84
+ edge: false,
85
+ attempts: 20,
86
+ delayMs: 250,
87
+ });
88
+ if (!probe.ok) {
89
+ const err = new Error('go_container_probe_failed');
90
+ err.detail = probe;
91
+ throw err;
92
+ }
93
+
94
+ const stop = runDocker(['stop', '-t', '5', containerId], { productRoot, spawn });
95
+ stopped = stop.status === 0;
96
+ if (!stopped) throw new Error('go_container_stop_failed');
97
+ const cleanup = runDocker(['container', 'rm', containerId], { productRoot, spawn });
98
+ cleaned = cleanup.status === 0;
99
+ if (!cleaned) throw new Error('go_container_cleanup_failed');
100
+
101
+ return {
102
+ ok: true,
103
+ tag,
104
+ name,
105
+ image_digest: image.Id || null,
106
+ architecture: image.Architecture,
107
+ os: image.Os || null,
108
+ user: imageUser,
109
+ container_id: containerId,
110
+ clean_shutdown: true,
111
+ clean_cleanup: true,
112
+ probe,
113
+ retained_stopped_container: false,
114
+ build_output: build.output.slice(-2000),
115
+ };
116
+ } finally {
117
+ if (!stopped) runDocker(['stop', '-t', '1', containerId], { productRoot, spawn });
118
+ if (!cleaned) runDocker(['container', 'rm', containerId], { productRoot, spawn });
119
+ }
120
+ }
@@ -15,15 +15,23 @@ const PACKAGE_TEMPLATE = {
15
15
  worker: './worker/src/index.js',
16
16
  },
17
17
  capabilities: ['hash', 'inspect', 'runtime', 'capabilities'],
18
+ distribution: {
19
+ package: '@inneranimalmedia/agentsam-go-worker',
20
+ normal_user: 'official-hosted-service',
21
+ self_host: 'advanced-opt-in',
22
+ },
18
23
  deployment: {
19
24
  adapter: 'cloudflare',
20
25
  mode: 'worker-container',
21
26
  wrangler_config: './wrangler.jsonc',
27
+ authority: 'explicit-cloudflare-account',
22
28
  },
23
29
  product: {
24
30
  slug: DEFAULT_PRODUCT,
25
31
  kind: 'service',
26
- registry: 'agentsam_products',
32
+ registry: 'local-by-default',
33
+ official_registry: 'agentsam_products',
34
+ official_registry_only: true,
27
35
  },
28
36
  };
29
37
 
@@ -111,9 +119,6 @@ export function preflightToolchain({ requireDocker = false, productRoot = null }
111
119
  push('docker', false, e.message);
112
120
  }
113
121
 
114
- const token = Boolean(process.env.CLOUDFLARE_API_TOKEN || process.env.CF_API_TOKEN);
115
- push('cloudflare_auth', token || Boolean(process.env.CLOUDFLARE_ACCOUNT_ID), token ? 'token_present' : 'account_or_token_missing');
116
-
117
122
  const failed = checks.filter((c) => {
118
123
  if (c.ok) return false;
119
124
  if (c.id === 'docker' && !requireDocker) return false;
@@ -1,45 +1,132 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { createRequire } from 'node:module';
3
4
  import { fileURLToPath } from 'node:url';
4
5
  import { execFileSync } from 'node:child_process';
5
6
  import { repositoryRoot, gitEvidence } from '../knowledge/config.js';
6
7
 
7
8
  const HERE = path.dirname(fileURLToPath(import.meta.url));
9
+ const MODULE_REQUIRE = createRequire(import.meta.url);
8
10
  export const SDK_ROOT = path.resolve(HERE, '../..');
9
11
  export const DEFAULT_PRODUCT = 'agentsam-go-worker';
10
12
  export const DEFAULT_PRODUCT_REL = path.join('apps', DEFAULT_PRODUCT);
13
+ export const GO_WORKER_PACKAGE = '@inneranimalmedia/agentsam-go-worker';
14
+
15
+ function readJSON(file) {
16
+ try { return JSON.parse(fs.readFileSync(file, 'utf8')); } catch { return null; }
17
+ }
18
+
19
+ function normalizeExplicitProductRoot(value) {
20
+ if (!value) return null;
21
+ const resolved = path.resolve(value);
22
+ if (!fs.existsSync(resolved)) return null;
23
+ if (path.basename(resolved) === 'runtime' && fs.existsSync(path.join(resolved, 'go.mod'))) {
24
+ return path.dirname(resolved);
25
+ }
26
+ return resolved;
27
+ }
28
+
29
+ function packageRootFrom(requireFn) {
30
+ try {
31
+ return path.dirname(requireFn.resolve(GO_WORKER_PACKAGE + '/package.json'));
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ function cwdRequire(cwd) {
38
+ try {
39
+ return createRequire(path.join(path.resolve(cwd), 'package.json'));
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ function runtimeCandidate(productRoot, origin) {
46
+ if (!productRoot) return null;
47
+ const runtimeRoot = path.join(productRoot, 'runtime');
48
+ const modPath = path.join(runtimeRoot, 'go.mod');
49
+ if (!fs.existsSync(modPath)) return null;
50
+ const mod = fs.readFileSync(modPath, 'utf8');
51
+ const moduleMatch = mod.match(/^module\s+(\S+)/m);
52
+ const serverMain = path.join(runtimeRoot, 'cmd', 'server', 'main.go');
53
+ const packageJson = path.join(productRoot, 'package.json');
54
+ return {
55
+ origin,
56
+ runtimeRoot,
57
+ module: moduleMatch?.[1] || null,
58
+ goMod: modPath,
59
+ entry: fs.existsSync(serverMain) ? serverMain : findFirstGoMain(runtimeRoot),
60
+ productRoot,
61
+ packageManifest: path.join(productRoot, 'agentsam.package.json'),
62
+ packageJson,
63
+ package: readJSON(packageJson),
64
+ };
65
+ }
66
+
67
+ function legacyRuntimeCandidate(runtimeRoot, origin) {
68
+ const modPath = path.join(runtimeRoot, 'go.mod');
69
+ if (!fs.existsSync(modPath)) return null;
70
+ const mod = fs.readFileSync(modPath, 'utf8');
71
+ const moduleMatch = mod.match(/^module\s+(\S+)/m);
72
+ const productRoot = path.basename(runtimeRoot) === 'runtime' ? path.dirname(runtimeRoot) : runtimeRoot;
73
+ return {
74
+ origin,
75
+ runtimeRoot,
76
+ module: moduleMatch?.[1] || null,
77
+ goMod: modPath,
78
+ entry: findFirstGoMain(runtimeRoot),
79
+ productRoot,
80
+ packageManifest: path.join(productRoot, 'agentsam.package.json'),
81
+ packageJson: path.join(productRoot, 'package.json'),
82
+ package: readJSON(path.join(productRoot, 'package.json')),
83
+ };
84
+ }
11
85
 
12
86
  /**
13
- * Locate AgentSam Go runtime source without inventing a second implementation.
14
- * Prefers apps/agentsam-go-worker/runtime; otherwise any go.mod that declares agentsam-go-worker.
87
+ * Locate the one AgentSam Go service implementation without assuming the SDK
88
+ * development checkout ships inside the root npm package.
89
+ *
90
+ * Resolution order:
91
+ * 1. explicit AGENTSAM_GO_WORKER_ROOT
92
+ * 2. current repository apps/agentsam-go-worker (maintainer/contributor mode)
93
+ * 3. installed @inneranimalmedia/agentsam-go-worker package (distribution mode)
94
+ * 4. SDK development tree when present
95
+ * 5. narrow legacy runtime candidates
15
96
  */
16
97
  export function discoverGoRuntime(cwd = process.cwd()) {
17
98
  const root = repositoryRoot(cwd);
18
- const candidates = [
19
- path.join(root, DEFAULT_PRODUCT_REL, 'runtime'),
20
- path.join(SDK_ROOT, DEFAULT_PRODUCT_REL, 'runtime'),
21
- path.join(root, 'runtime'),
22
- path.join(root, 'cmd', 'agentsam'),
99
+ const req = cwdRequire(cwd);
100
+ const productCandidates = [
101
+ [normalizeExplicitProductRoot(process.env.AGENTSAM_GO_WORKER_ROOT), 'explicit'],
102
+ [path.join(root, DEFAULT_PRODUCT_REL), 'repository'],
103
+ [req ? packageRootFrom(req) : null, 'installed_package'],
104
+ [packageRootFrom(MODULE_REQUIRE), 'installed_package'],
105
+ [path.join(SDK_ROOT, DEFAULT_PRODUCT_REL), 'sdk_development_tree'],
23
106
  ];
24
107
 
25
108
  const found = [];
26
- for (const runtimeRoot of candidates) {
27
- const modPath = path.join(runtimeRoot, 'go.mod');
28
- if (!fs.existsSync(modPath)) continue;
29
- const mod = fs.readFileSync(modPath, 'utf8');
30
- const moduleMatch = mod.match(/^module\s+(\S+)/m);
31
- const serverMain = path.join(runtimeRoot, 'cmd', 'server', 'main.go');
32
- const entry = fs.existsSync(serverMain)
33
- ? serverMain
34
- : findFirstGoMain(runtimeRoot);
35
- found.push({
36
- runtimeRoot,
37
- module: moduleMatch?.[1] || null,
38
- goMod: modPath,
39
- entry,
40
- productRoot: path.dirname(runtimeRoot),
41
- packageManifest: path.join(path.dirname(runtimeRoot), 'agentsam.package.json'),
42
- });
109
+ const seen = new Set();
110
+ for (const [productRoot, origin] of productCandidates) {
111
+ if (!productRoot) continue;
112
+ let real;
113
+ try { real = fs.realpathSync(productRoot); } catch { continue; }
114
+ if (seen.has(real)) continue;
115
+ seen.add(real);
116
+ const candidate = runtimeCandidate(real, origin);
117
+ if (candidate) found.push(candidate);
118
+ }
119
+
120
+ for (const [runtimeRoot, origin] of [
121
+ [path.join(root, 'runtime'), 'legacy_repository_runtime'],
122
+ [path.join(root, 'cmd', 'agentsam'), 'legacy_repository_cmd'],
123
+ ]) {
124
+ let real;
125
+ try { real = fs.realpathSync(runtimeRoot); } catch { continue; }
126
+ if (seen.has(real)) continue;
127
+ seen.add(real);
128
+ const candidate = legacyRuntimeCandidate(real, origin);
129
+ if (candidate) found.push(candidate);
43
130
  }
44
131
 
45
132
  const preferred = found.find((row) => row.module?.includes('agentsam-go-worker')) || found[0] || null;
@@ -47,7 +134,7 @@ export function discoverGoRuntime(cwd = process.cwd()) {
47
134
  const git = gitEvidence(root);
48
135
 
49
136
  return {
50
- schema: 'agentsam.go-discovery.v1',
137
+ schema: 'agentsam.go-discovery.v2',
51
138
  repository_root: root,
52
139
  sdk_root: SDK_ROOT,
53
140
  go: goTool,
@@ -55,6 +142,14 @@ export function discoverGoRuntime(cwd = process.cwd()) {
55
142
  runtime: preferred,
56
143
  candidates: found,
57
144
  product_exists: Boolean(preferred && fs.existsSync(preferred.packageManifest)),
145
+ distribution: preferred
146
+ ? {
147
+ origin: preferred.origin,
148
+ package_name: preferred.package?.name || null,
149
+ package_version: preferred.package?.version || null,
150
+ product_root: preferred.productRoot,
151
+ }
152
+ : null,
58
153
  };
59
154
  }
60
155
 
@@ -65,7 +160,7 @@ function findFirstGoMain(dir) {
65
160
  let ents;
66
161
  try { ents = fs.readdirSync(cur, { withFileTypes: true }); } catch { continue; }
67
162
  for (const ent of ents) {
68
- if (ent.name === 'vendor' || ent.name === '.git') continue;
163
+ if (ent.name === 'vendor' || ent.name === '.git' || ent.name === 'node_modules') continue;
69
164
  const full = path.join(cur, ent.name);
70
165
  if (ent.isDirectory()) stack.push(full);
71
166
  else if (ent.name === 'main.go') return full;
@@ -84,13 +179,34 @@ export function probeGoToolchain() {
84
179
  }
85
180
  }
86
181
 
87
- export function resolveProductRoot(discovery, productName = DEFAULT_PRODUCT) {
88
- if (discovery?.runtime?.productRoot && path.basename(discovery.runtime.productRoot) === productName) {
182
+ export function resolveGoStateRoot(discovery, cwd = process.cwd()) {
183
+ const origin = discovery?.runtime?.origin || null;
184
+ if (origin === 'repository' || origin === 'sdk_development_tree') {
89
185
  return discovery.runtime.productRoot;
90
186
  }
91
- const fromSdk = path.join(SDK_ROOT, 'apps', productName);
92
- if (fs.existsSync(fromSdk)) return fromSdk;
93
- const fromRepo = path.join(discovery.repository_root, 'apps', productName);
94
- if (fs.existsSync(fromRepo)) return fromRepo;
95
- return fromSdk;
187
+ return repositoryRoot(cwd);
188
+ }
189
+
190
+ export function resolveProductRoot(discovery, productName = DEFAULT_PRODUCT) {
191
+ const runtime = discovery?.runtime;
192
+ if (
193
+ runtime?.productRoot
194
+ && (
195
+ path.basename(runtime.productRoot) === productName
196
+ || runtime.package?.name === GO_WORKER_PACKAGE
197
+ )
198
+ ) {
199
+ return runtime.productRoot;
200
+ }
201
+
202
+ const fromCandidates = discovery?.candidates?.find((row) => (
203
+ path.basename(row.productRoot || '') === productName
204
+ || row.package?.name === GO_WORKER_PACKAGE
205
+ ));
206
+ if (fromCandidates?.productRoot) return fromCandidates.productRoot;
207
+
208
+ const err = new Error('go_product_not_discovered:' + productName);
209
+ err.code = 'go_product_not_discovered';
210
+ err.hint = 'Install ' + GO_WORKER_PACKAGE + ' for self-host deployment or run from the AgentSam SDK maintainer checkout.';
211
+ throw err;
96
212
  }
package/src/go/index.js CHANGED
@@ -1,13 +1,25 @@
1
- export { discoverGoRuntime, resolveProductRoot, probeGoToolchain, DEFAULT_PRODUCT, SDK_ROOT } from './discover.js';
1
+ export { discoverGoRuntime, resolveProductRoot, resolveGoStateRoot, probeGoToolchain, DEFAULT_PRODUCT, SDK_ROOT } from './discover.js';
2
2
  export { ensureProductContract, readProductManifest, preflightToolchain } from './contract.js';
3
3
  export { buildGoProduct, runGoBuild, runGoTests, runGoVet } from './build.js';
4
- export { deployGoCloudflare, probeGoDeployment } from './cloudflare.js';
4
+ export { deployGoCloudflare, resolveWranglerIdentity, probeGoDeployment, probeGoDeploymentWithRetry, readLatestWranglerDeployment } from './cloudflare.js';
5
+ export { verifyGoContainer } from './container.js';
5
6
  export { verifyGoProduct } from './verify.js';
6
- export { applyGoProductRegistry, buildGoProductRegistrySql } from './registry.js';
7
+ export {
8
+ applyInnerAnimalMediaOfficialGoProductRegistry,
9
+ applyIamOfficialGoProductRegistry,
10
+ buildGoProductRegistrySql,
11
+ } from './official-registry.js';
12
+ export {
13
+ INNERANIMALMEDIA_OFFICIAL_RELEASE_ENV,
14
+ LEGACY_IAM_OFFICIAL_RELEASE_ENV,
15
+ innerAnimalMediaOfficialReleaseEnabled,
16
+ } from './official-release.js';
7
17
  export {
8
18
  writeGoBuildReceipt,
9
19
  writeDeploymentReceipt,
20
+ writeDeploymentValidationReceipt,
10
21
  writeProductRegistryLocal,
22
+ writeProductValidationLocal,
11
23
  readLatestStatus,
12
24
  buildProductRow,
13
25
  } from './receipts.js';
@@ -0,0 +1,119 @@
1
+ import { spawn } from 'node:child_process';
2
+ import net from 'node:net';
3
+
4
+ const binary = process.argv[2];
5
+ const expectedSource = process.argv[3] || '';
6
+ const expectedCommit = process.argv[4] || '';
7
+ const expectedHash = '2e60bba13dc2bc37d75dd2ce5deb25466f19cb2994e20889388948879875eae9';
8
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
9
+
10
+ const port = await new Promise((resolve, reject) => {
11
+ const server = net.createServer();
12
+ server.unref();
13
+ server.on('error', reject);
14
+ server.listen(0, '127.0.0.1', () => {
15
+ const value = server.address().port;
16
+ server.close(() => resolve(value));
17
+ });
18
+ });
19
+
20
+ const child = spawn(binary, [], {
21
+ env: { ...process.env, PORT: String(port), AGENTSAM_TARGET: 'local' },
22
+ stdio: ['ignore', 'ignore', 'pipe'],
23
+ });
24
+ let stderr = '';
25
+ child.stderr.on('data', (chunk) => { stderr += String(chunk); });
26
+ const base = 'http://127.0.0.1:' + port;
27
+ const results = {};
28
+
29
+ async function request(name, pathname, init = {}) {
30
+ const res = await fetch(base + pathname, init);
31
+ let body = null;
32
+ try { body = await res.json(); } catch {}
33
+ results[name] = { status: res.status, ok: res.ok, body };
34
+ return results[name];
35
+ }
36
+
37
+ let ready = false;
38
+ for (let attempt = 0; attempt < 100 && child.exitCode == null; attempt += 1) {
39
+ try {
40
+ const health = await request('health', '/health', { headers: { Accept: 'application/json' } });
41
+ if (health.ok) { ready = true; break; }
42
+ } catch {}
43
+ await sleep(50);
44
+ }
45
+
46
+ let error = null;
47
+ if (!ready) {
48
+ error = 'runtime_not_ready';
49
+ } else {
50
+ try {
51
+ await request('runtime', '/v1/runtime');
52
+ await request('capabilities', '/v1/capabilities');
53
+ await request('hash', '/v1/hash', {
54
+ method: 'POST',
55
+ headers: { 'Content-Type': 'application/json' },
56
+ body: JSON.stringify({ input: 'agentsam', algorithm: 'sha256' }),
57
+ });
58
+ await request('inspect', '/v1/inspect', {
59
+ method: 'POST',
60
+ headers: { 'Content-Type': 'application/json' },
61
+ body: JSON.stringify({ files: [{ path: 'demo.css', content: '.button { color: #2563eb; }' }] }),
62
+ });
63
+ await request('malformed', '/v1/inspect', {
64
+ method: 'POST',
65
+ headers: { 'Content-Type': 'application/json' },
66
+ body: JSON.stringify({ not_files: true }),
67
+ });
68
+ } catch (cause) {
69
+ error = cause.message;
70
+ }
71
+ }
72
+
73
+ const health = results.health?.body;
74
+ const runtime = results.runtime?.body;
75
+ const capabilities = results.capabilities?.body;
76
+ const malformed = results.malformed?.body;
77
+ const checks = {
78
+ health: results.health?.status === 200 && health?.ok === true && health?.target === 'local',
79
+ source_identity: Boolean(expectedSource) && health?.build?.source === expectedSource,
80
+ source_commit: expectedCommit ? health?.build?.commit === expectedCommit : true,
81
+ runtime: results.runtime?.status === 200 && runtime?.schema === 'agentsam.go-runtime.v1',
82
+ capabilities: results.capabilities?.status === 200
83
+ && capabilities?.schema === 'agentsam.go-capabilities.v1'
84
+ && ['hash', 'inspect', 'runtime', 'capabilities'].every((name) => capabilities?.capabilities?.includes(name)),
85
+ hash: results.hash?.status === 200 && results.hash?.body?.hash === expectedHash,
86
+ inspect: results.inspect?.status === 200
87
+ && results.inspect?.body?.findings?.some((finding) => finding.kind === 'hardcoded_color' && finding.value === '#2563eb'),
88
+ error_envelope: results.malformed?.status === 400
89
+ && malformed?.ok === false
90
+ && malformed?.schema_version === 1
91
+ && malformed?.reason === 'input_invalid'
92
+ && malformed?.code === 'INVALID_ARGUMENT',
93
+ };
94
+
95
+ const exitPromise = new Promise((resolve) => {
96
+ const timer = setTimeout(() => {
97
+ child.kill('SIGKILL');
98
+ resolve({ code: child.exitCode, signal: 'SIGKILL', timeout: true });
99
+ }, 5000);
100
+ child.once('exit', (code, signal) => {
101
+ clearTimeout(timer);
102
+ resolve({ code, signal, timeout: false });
103
+ });
104
+ });
105
+ child.kill('SIGTERM');
106
+ const exit = await exitPromise;
107
+ checks.clean_shutdown = exit.code === 0 && !exit.timeout;
108
+
109
+ const ok = !error && Object.values(checks).every(Boolean);
110
+ process.stdout.write(JSON.stringify({
111
+ ok,
112
+ origin: base,
113
+ checks,
114
+ results,
115
+ exit,
116
+ stderr: stderr.slice(-2000),
117
+ error,
118
+ }));
119
+ process.exit(ok ? 0 : 1);
@@ -5,6 +5,7 @@ import { spawnSync } from 'node:child_process';
5
5
  import { createHash, randomBytes } from 'node:crypto';
6
6
  import { SDK_ROOT } from './discover.js';
7
7
  import { writeProductRegistryLocal } from './receipts.js';
8
+ import { innerAnimalMediaOfficialReleaseEnabled } from './official-release.js';
8
9
 
9
10
  const DEFAULT_DB = 'inneranimalmedia-business';
10
11
  const DEFAULT_WRANGLER = 'apps/local-studio/backend/wrangler.jsonc';
@@ -22,7 +23,7 @@ function json(value) {
22
23
 
23
24
  export function buildGoProductRegistrySql({
24
25
  product = 'agentsam-go-worker',
25
- status = 'wired',
26
+ status = 'deployed',
26
27
  version = '0.1.0',
27
28
  repositoryId = DEFAULT_REPOSITORY_ID,
28
29
  canonicalPath = 'apps/agentsam-go-worker',
@@ -30,6 +31,10 @@ export function buildGoProductRegistrySql({
30
31
  url = null,
31
32
  commit = null,
32
33
  health = null,
34
+ workerDeploymentId = null,
35
+ workerVersionId = null,
36
+ artifactDigest = null,
37
+ containerDigest = null,
33
38
  description = 'AgentSam Go runtime (Worker edge + native Cloudflare Container)',
34
39
  } = {}) {
35
40
  const metadata = {
@@ -40,6 +45,10 @@ export function buildGoProductRegistrySql({
40
45
  mode: 'worker-container',
41
46
  url: url || null,
42
47
  health: health || null,
48
+ worker_deployment_id: workerDeploymentId,
49
+ worker_version_id: workerVersionId,
50
+ artifact_digest: artifactDigest,
51
+ container_image_digest: containerDigest,
43
52
  },
44
53
  source: { commit: commit || null },
45
54
  capabilities: ['hash', 'inspect', 'runtime', 'capabilities'],
@@ -101,7 +110,12 @@ ON CONFLICT(slug) DO UPDATE SET
101
110
  target_type: 'cloudflare_worker',
102
111
  target_id: product,
103
112
  relationship_type: 'deployed_as',
104
- metadata: { origin: 'agentsam.go.cloudflare', url: url || null },
113
+ metadata: {
114
+ origin: 'agentsam.go.cloudflare',
115
+ url: url || null,
116
+ worker_deployment_id: workerDeploymentId,
117
+ worker_version_id: workerVersionId,
118
+ },
105
119
  },
106
120
  {
107
121
  target_type: 'cli_command',
@@ -127,25 +141,52 @@ DO UPDATE SET metadata = excluded.metadata;`,
127
141
  return statements.join('\n');
128
142
  }
129
143
 
130
- export function applyGoProductRegistry({
144
+ export function applyInnerAnimalMediaOfficialGoProductRegistry({
131
145
  productRoot,
132
146
  product = 'agentsam-go-worker',
147
+ officialRelease = false,
133
148
  cwd = SDK_ROOT,
134
- status = 'wired',
149
+ status = 'deployed',
135
150
  url = null,
136
151
  commit = null,
137
152
  health = null,
153
+ workerDeploymentId = null,
154
+ workerVersionId = null,
155
+ artifactDigest = null,
156
+ containerDigest = null,
138
157
  dryRun = false,
139
158
  skipRemote = false,
140
159
  spawn = spawnSync,
141
160
  repositoryId = DEFAULT_REPOSITORY_ID,
142
161
  } = {}) {
162
+ if (!officialRelease || !innerAnimalMediaOfficialReleaseEnabled()) {
163
+ const err = new Error('inneranimalmedia_registry_official_release_required');
164
+ err.code = 'inneranimalmedia_registry_official_release_required';
165
+ err.legacy_code = 'iam_registry_official_release_required';
166
+ err.hint = 'InnerAnimalMedia D1 registration is restricted to the explicit official release path.';
167
+ throw err;
168
+ }
169
+
170
+ const officialStatus = status === 'deployed' ? 'production' : status;
171
+ const allowedStatuses = new Set(['prototype', 'scaffolded', 'wired', 'production', 'deprecated']);
172
+ if (!allowedStatuses.has(officialStatus)) {
173
+ const err = new Error('inneranimalmedia_registry_status_invalid');
174
+ err.code = 'inneranimalmedia_registry_status_invalid';
175
+ err.legacy_code = 'iam_registry_status_invalid';
176
+ err.detail = { received: status, normalized: officialStatus };
177
+ throw err;
178
+ }
179
+
143
180
  const sql = buildGoProductRegistrySql({
144
181
  product,
145
- status,
182
+ status: officialStatus,
146
183
  url,
147
184
  commit,
148
185
  health,
186
+ workerDeploymentId,
187
+ workerVersionId,
188
+ artifactDigest,
189
+ containerDigest,
149
190
  repositoryId,
150
191
  });
151
192
 
@@ -153,13 +194,22 @@ export function applyGoProductRegistry({
153
194
  slug: product,
154
195
  kind: 'service',
155
196
  name: product,
156
- status,
197
+ status: officialStatus,
157
198
  repository_id: repositoryId,
158
199
  canonical_path: 'apps/agentsam-go-worker',
159
200
  package_name: '@inneranimalmedia/agentsam-go-worker',
160
201
  metadata: {
161
202
  runtime: 'go',
162
- deployment: { provider: 'cloudflare', mode: 'worker-container', url, health },
203
+ deployment: {
204
+ provider: 'cloudflare',
205
+ mode: 'worker-container',
206
+ url,
207
+ health,
208
+ worker_deployment_id: workerDeploymentId,
209
+ worker_version_id: workerVersionId,
210
+ artifact_digest: artifactDigest,
211
+ container_image_digest: containerDigest,
212
+ },
163
213
  source: { commit },
164
214
  },
165
215
  };
@@ -221,3 +271,10 @@ export function applyGoProductRegistry({
221
271
  try { fs.unlinkSync(tmpFile); } catch { /* ignore */ }
222
272
  }
223
273
  }
274
+
275
+ /**
276
+ * Backward-compatible SDK export. New code should use
277
+ * applyInnerAnimalMediaOfficialGoProductRegistry.
278
+ */
279
+ export const applyIamOfficialGoProductRegistry =
280
+ applyInnerAnimalMediaOfficialGoProductRegistry;