@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
@@ -1,7 +1,7 @@
1
1
  import assert from 'node:assert/strict';
2
2
  import test from 'node:test';
3
3
  import { renderArchitectureExplorer, renderOperationInspector, drawBox } from '../../src/ui/wireframes.js';
4
- import { buildGoProductRegistrySql } from '../../src/go/registry.js';
4
+ import { applyInnerAnimalMediaOfficialGoProductRegistry, buildGoProductRegistrySql } from '../../src/go/official-registry.js';
5
5
 
6
6
  test('architecture explorer is boxed reasoning scenery', () => {
7
7
  const view = renderArchitectureExplorer({
@@ -38,7 +38,7 @@ test('drawBox pads visible ANSI width', () => {
38
38
  test('buildGoProductRegistrySql upserts product + relationships without inventing tables', () => {
39
39
  const sql = buildGoProductRegistrySql({
40
40
  product: 'agentsam-go-worker',
41
- status: 'wired',
41
+ status: 'deployed',
42
42
  url: 'https://agentsam-go-worker.example.workers.dev',
43
43
  commit: 'abc123',
44
44
  health: 'healthy',
@@ -52,3 +52,88 @@ test('buildGoProductRegistrySql upserts product + relationships without inventin
52
52
  assert.doesNotMatch(sql, /CREATE TABLE/);
53
53
  assert.doesNotMatch(sql, /account_id/);
54
54
  });
55
+
56
+
57
+ test('InnerAnimalMedia remote registry requires the explicit official-release guard', () => {
58
+ const preferred = process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE;
59
+ const legacy = process.env.AGENTSAM_IAM_OFFICIAL_RELEASE;
60
+
61
+ delete process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE;
62
+ delete process.env.AGENTSAM_IAM_OFFICIAL_RELEASE;
63
+
64
+ try {
65
+ assert.throws(
66
+ () => applyInnerAnimalMediaOfficialGoProductRegistry({
67
+ productRoot: '/tmp/agentsam-test-state',
68
+ officialRelease: true,
69
+ skipRemote: true,
70
+ }),
71
+ /inneranimalmedia_registry_official_release_required/,
72
+ );
73
+ } finally {
74
+ if (preferred == null) {
75
+ delete process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE;
76
+ } else {
77
+ process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE = preferred;
78
+ }
79
+
80
+ if (legacy == null) {
81
+ delete process.env.AGENTSAM_IAM_OFFICIAL_RELEASE;
82
+ } else {
83
+ process.env.AGENTSAM_IAM_OFFICIAL_RELEASE = legacy;
84
+ }
85
+ }
86
+ });
87
+
88
+ test('InnerAnimalMedia official registry normalizes deployed lifecycle status to D1 production', () => {
89
+ const prior = process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE;
90
+ process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE = '1';
91
+ try {
92
+ const result = applyInnerAnimalMediaOfficialGoProductRegistry({
93
+ productRoot: null,
94
+ officialRelease: true,
95
+ status: 'deployed',
96
+ dryRun: true,
97
+ skipRemote: true,
98
+ });
99
+ assert.match(result.sql, /'production'/);
100
+ assert.doesNotMatch(result.sql, /'deployed',\n 'AgentSam Go runtime/);
101
+ } finally {
102
+ if (prior == null) delete process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE;
103
+ else process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE = prior;
104
+ }
105
+ });
106
+
107
+
108
+ test('legacy AGENTSAM_IAM_OFFICIAL_RELEASE guard remains backward compatible', () => {
109
+ const preferred = process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE;
110
+ const legacy = process.env.AGENTSAM_IAM_OFFICIAL_RELEASE;
111
+
112
+ delete process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE;
113
+ process.env.AGENTSAM_IAM_OFFICIAL_RELEASE = '1';
114
+
115
+ try {
116
+ const result = applyInnerAnimalMediaOfficialGoProductRegistry({
117
+ productRoot: null,
118
+ officialRelease: true,
119
+ status: 'deployed',
120
+ dryRun: true,
121
+ skipRemote: true,
122
+ });
123
+
124
+ assert.equal(result.ok, true);
125
+ assert.match(result.sql, /'production'/);
126
+ } finally {
127
+ if (preferred == null) {
128
+ delete process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE;
129
+ } else {
130
+ process.env.AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE = preferred;
131
+ }
132
+
133
+ if (legacy == null) {
134
+ delete process.env.AGENTSAM_IAM_OFFICIAL_RELEASE;
135
+ } else {
136
+ process.env.AGENTSAM_IAM_OFFICIAL_RELEASE = legacy;
137
+ }
138
+ }
139
+ });
@@ -0,0 +1,31 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ import {
5
+ repositoryIdFromGitContext,
6
+ } from '../../src/go/build.js';
7
+
8
+ test('Go build source canonicalizes GitHub repository identity', () => {
9
+ assert.equal(
10
+ repositoryIdFromGitContext({
11
+ remoteHost: 'github.com',
12
+ repoFullName: 'SamPrimeaux/agentsam-sdk',
13
+ }),
14
+ 'github:samprimeaux/agentsam-sdk',
15
+ );
16
+ });
17
+
18
+ test('Go build source preserves provider-qualified non-GitHub identity', () => {
19
+ assert.equal(
20
+ repositoryIdFromGitContext({
21
+ remoteHost: 'gitlab.example.com',
22
+ repoFullName: 'Owner/Repo',
23
+ }),
24
+ 'gitlab.example.com:Owner/Repo',
25
+ );
26
+ });
27
+
28
+ test('Go build source returns null when remote identity is unavailable', () => {
29
+ assert.equal(repositoryIdFromGitContext(null), null);
30
+ assert.equal(repositoryIdFromGitContext({}), null);
31
+ });
@@ -1,53 +1,317 @@
1
1
  import assert from 'node:assert/strict';
2
+ import path from 'node:path';
2
3
  import test from 'node:test';
3
- import { extractWorkersDevUrl, probeGoDeployment } from '../../src/go/cloudflare.js';
4
+ import { fileURLToPath } from 'node:url';
5
+ import {
6
+ deployGoCloudflare,
7
+ extractWorkersDevUrl,
8
+ probeGoDeployment,
9
+ readLatestWranglerDeployment,
10
+ resolveWranglerIdentity,
11
+ resolveConfiguredDeploymentUrl,
12
+ } from '../../src/go/cloudflare.js';
4
13
  import { buildProductRow } from '../../src/go/receipts.js';
5
14
 
15
+ const SDK_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
16
+ const PRODUCT_ROOT = path.join(SDK_ROOT, 'apps/agentsam-go-worker');
17
+ const EXPECTED_HASH = '2e60bba13dc2bc37d75dd2ce5deb25466f19cb2994e20889388948879875eae9';
18
+
19
+
20
+ test('configured custom domain is canonical Go deployment URL', () => {
21
+ assert.equal(
22
+ resolveConfiguredDeploymentUrl(PRODUCT_ROOT),
23
+ 'https://runtime.inneranimalmedia.com',
24
+ );
25
+ });
26
+
6
27
  test('extractWorkersDevUrl parses wrangler output', () => {
7
28
  const url = extractWorkersDevUrl('Published agentsam-go-worker\n https://agentsam-go-worker.example.workers.dev\n');
8
29
  assert.equal(url, 'https://agentsam-go-worker.example.workers.dev');
9
30
  });
10
31
 
11
- test('probeGoDeployment requires deterministic Go capabilities', async () => {
32
+ test('probeGoDeployment requires edge, source identity, capabilities, deterministic functions and ErrorEnvelope', async () => {
12
33
  const responses = new Map([
13
- ['/health', { status: 200, body: { ok: true, service: 'agentsam-go-worker', runtime: 'go' } }],
14
- ['/v1/runtime', { status: 200, body: { schema: 'agentsam.go-runtime.v1', capabilities: ['hash'] } }],
15
- ['/v1/hash', { status: 200, body: { hash: 'a'.repeat(64), algorithm: 'sha256' } }],
34
+ ['/', { status: 200, body: { ok: true, edge: 'worker', runtime: 'go/native-container', source: 'git:abc123' } }],
35
+ ['/edge/health', { status: 200, body: { ok: true, edge: 'worker', runtime: 'go/native-container', source: 'git:abc123' } }],
36
+ ['/health', {
37
+ status: 200,
38
+ body: {
39
+ ok: true,
40
+ service: 'agentsam-go-worker',
41
+ runtime: 'go',
42
+ target: 'cloudflare',
43
+ build: { source: 'git:abc123', commit: 'abc123' },
44
+ },
45
+ }],
46
+ ['/v1/runtime', {
47
+ status: 200,
48
+ body: { schema: 'agentsam.go-runtime.v1', os: 'linux', capabilities: ['hash', 'inspect', 'runtime', 'capabilities'] },
49
+ }],
50
+ ['/v1/capabilities', {
51
+ status: 200,
52
+ body: { schema: 'agentsam.go-capabilities.v1', capabilities: ['hash', 'inspect', 'runtime', 'capabilities'] },
53
+ }],
54
+ ['/v1/hash', { status: 200, body: { hash: EXPECTED_HASH, algorithm: 'sha256' } }],
16
55
  ['/v1/inspect', { status: 200, body: { findings: [{ kind: 'hardcoded_color', value: '#2563eb' }] } }],
17
56
  ]);
18
57
  let inspectCalls = 0;
19
- const fetchImpl = async (url, init = {}) => {
58
+ const fetchImpl = async (url) => {
20
59
  const pathname = new URL(url).pathname;
21
60
  if (pathname === '/v1/inspect') {
22
61
  inspectCalls += 1;
23
62
  if (inspectCalls === 2) {
24
63
  return {
25
64
  status: 400,
26
- async json() { return { ok: false, error: 'files_required' }; },
65
+ async json() {
66
+ return {
67
+ ok: false,
68
+ schema_version: 1,
69
+ code: 'INVALID_ARGUMENT',
70
+ reason: 'input_invalid',
71
+ };
72
+ },
27
73
  };
28
74
  }
29
75
  }
30
76
  const row = responses.get(pathname);
77
+ assert.ok(row, 'unexpected probe path: ' + pathname);
31
78
  return {
32
79
  status: row.status,
33
80
  async json() { return row.body; },
34
81
  };
35
82
  };
36
- const result = await probeGoDeployment('https://example.workers.dev', { fetchImpl });
83
+
84
+ const result = await probeGoDeployment('https://example.workers.dev', {
85
+ fetchImpl,
86
+ expectedSource: 'git:abc123',
87
+ expectedSourceCommit: 'abc123',
88
+ expectedTarget: 'cloudflare',
89
+ });
37
90
  assert.equal(result.ok, true);
91
+ assert.equal(result.checks.edge_root, true);
92
+ assert.equal(result.checks.edge_health, true);
93
+ assert.equal(result.checks.source_identity, true);
94
+ assert.equal(result.checks.source_commit, true);
95
+ assert.equal(result.checks.capabilities, true);
96
+ assert.equal(result.results.deterministic_hash.ok, true);
38
97
  assert.equal(result.results.deterministic_inspect.ok, true);
39
98
  assert.equal(result.results.malformed_rejected.ok, true);
40
99
  });
41
100
 
42
- test('buildProductRow stays on agentsam_products projection', () => {
101
+ test('readLatestWranglerDeployment normalizes authoritative deployment/version identity', () => {
102
+ const spawn = () => ({
103
+ status: 0,
104
+ stdout: JSON.stringify([
105
+ {
106
+ id: 'dep_old',
107
+ created_on: '2026-09-24T00:00:00Z',
108
+ versions: [{ version_id: 'ver_old', percentage: 100 }],
109
+ },
110
+ {
111
+ id: 'dep_new',
112
+ created_on: '2026-09-25T00:00:00Z',
113
+ versions: [{ version_id: 'ver_new', percentage: 100 }],
114
+ },
115
+ ]),
116
+ stderr: '',
117
+ });
118
+ const result = readLatestWranglerDeployment(PRODUCT_ROOT, 'agentsam-go-worker', { spawn });
119
+ assert.equal(result.ok, true);
120
+ assert.equal(result.deployment_id, 'dep_new');
121
+ assert.equal(result.version_id, 'ver_new');
122
+ });
123
+
124
+ test('resolveWranglerIdentity fails closed when authentication is unavailable', () => {
125
+ const spawn = () => ({ status: 1, stdout: '', stderr: 'not logged in' });
126
+ const result = resolveWranglerIdentity(PRODUCT_ROOT, { spawn });
127
+ assert.equal(result.ok, false);
128
+ assert.equal(result.authenticated, false);
129
+ assert.equal(result.error, 'cloudflare_not_authenticated');
130
+ });
131
+
132
+ test('resolveWranglerIdentity requires an explicit account when multiple are available', () => {
133
+ const spawn = () => ({
134
+ status: 0,
135
+ stdout: JSON.stringify({
136
+ loggedIn: true,
137
+ authType: 'OAuth Token',
138
+ accounts: [
139
+ { id: 'acc_a', name: 'Account A', type: 'standard' },
140
+ { id: 'acc_b', name: 'Account B', type: 'standard' },
141
+ ],
142
+ }),
143
+ stderr: '',
144
+ });
145
+ const ambiguous = resolveWranglerIdentity(PRODUCT_ROOT, { spawn });
146
+ assert.equal(ambiguous.ok, false);
147
+ assert.equal(ambiguous.error, 'cloudflare_account_ambiguous');
148
+
149
+ const selected = resolveWranglerIdentity(PRODUCT_ROOT, {
150
+ spawn,
151
+ requestedAccountId: 'acc_b',
152
+ });
153
+ assert.equal(selected.ok, true);
154
+ assert.equal(selected.account.id, 'acc_b');
155
+ });
156
+
157
+ test('Cloudflare self-host dry run binds the resolved account and never mutates InnerAnimalMedia D1', async () => {
158
+ const calls = [];
159
+ const cloudflareIdentity = {
160
+ ok: true,
161
+ authenticated: true,
162
+ auth_type: 'OAuth Token',
163
+ account: { id: 'acc_user', name: 'User Cloudflare', type: 'standard' },
164
+ accounts: [{ id: 'acc_user', name: 'User Cloudflare', type: 'standard' }],
165
+ };
166
+ const spawn = (command, args = [], options = {}) => {
167
+ calls.push({ command, args, env: options.env || {} });
168
+ if (command === 'docker' && args[0] === 'info') {
169
+ return { status: 0, stdout: 'ok', stderr: '' };
170
+ }
171
+ if (args.includes('deploy') && args.includes('--dry-run')) {
172
+ assert.equal(options.env.CLOUDFLARE_ACCOUNT_ID, 'acc_user');
173
+ assert.ok(args.includes('AGENTSAM_BUILD_SOURCE:npm:@inneranimalmedia/agentsam-go-worker@0.1.0'));
174
+ return { status: 0, stdout: 'Total Upload: 1 KiB', stderr: '' };
175
+ }
176
+ throw new Error('unexpected spawn: ' + [command, ...args].join(' '));
177
+ };
178
+
179
+ const result = await deployGoCloudflare({
180
+ productRoot: PRODUCT_ROOT,
181
+ product: 'agentsam-go-worker',
182
+ dryRun: true,
183
+ accountId: 'acc_user',
184
+ cloudflareIdentity,
185
+ source: {
186
+ identity: 'npm:@inneranimalmedia/agentsam-go-worker@0.1.0',
187
+ commit: null,
188
+ package_name: '@inneranimalmedia/agentsam-go-worker',
189
+ package_version: '0.1.0',
190
+ },
191
+ builtAt: '2026-09-25T00:00:00.000Z',
192
+ spawn,
193
+ });
194
+
195
+ assert.equal(result.deployed, false);
196
+ assert.equal(result.dryRunValidated, true);
197
+ assert.equal(result.receipt.dry_run, true);
198
+ assert.equal(result.receipt.skipped_deploy, false);
199
+ assert.equal(result.receipt.registry_mode, 'self_host_local');
200
+ assert.equal(result.receipt.cloudflare.account_id, 'acc_user');
201
+ assert.equal(result.registry.remote, false);
202
+ assert.equal(result.registry.reason, 'self_host_registry_isolated');
203
+ assert.ok(calls.some((call) => call.args.includes('deploy') && call.args.includes('--dry-run')));
204
+ });
205
+
206
+
207
+ test('buildProductRow stays on agentsam_products projection with deployment identity', () => {
43
208
  const row = buildProductRow({
44
209
  product: 'agentsam-go-worker',
45
- repositoryId: 'agentsam-sdk',
210
+ repositoryId: 'github:samprimeaux/agentsam-sdk',
46
211
  commit: 'abc',
47
212
  url: 'https://x.workers.dev',
48
213
  health: 'healthy',
214
+ workerDeploymentId: 'dep_1',
215
+ workerVersionId: 'ver_1',
216
+ artifactDigest: 'sha256:binary',
217
+ containerDigest: 'sha256:image',
49
218
  });
50
219
  assert.equal(row.slug, 'agentsam-go-worker');
51
220
  assert.equal(row.kind, 'service');
221
+ assert.equal(row.status, 'deployed');
222
+ assert.equal(row.canonical_path, 'apps/agentsam-go-worker');
223
+ assert.equal(row.package_name, '@inneranimalmedia/agentsam-go-worker');
52
224
  assert.equal(row.metadata.runtime, 'go');
225
+ assert.equal(row.metadata.deployment.worker_deployment_id, 'dep_1');
226
+ assert.equal(row.metadata.deployment.worker_version_id, 'ver_1');
227
+ });
228
+
229
+ test('source identity produces a source-keyed Container instance', async () => {
230
+ const { runtimeInstanceKey } = await import('../../apps/agentsam-go-worker/worker/src/identity.js');
231
+ const first = runtimeInstanceKey('git:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
232
+ const second = runtimeInstanceKey('git:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
233
+ assert.equal(first, 'runtime:git:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
234
+ assert.equal(second, 'runtime:git:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
235
+ assert.notEqual(first, second);
236
+ assert.equal(runtimeInstanceKey('npm:@inneranimalmedia/agentsam-go-worker@0.1.0'), 'runtime:npm:@inneranimalmedia/agentsam-go-worker@0.1.0');
237
+ });
238
+
239
+
240
+ test('validation-only Cloudflare runs do not replace production receipts', async () => {
241
+ const fs = await import('node:fs');
242
+ const os = await import('node:os');
243
+
244
+ const stateRoot = fs.mkdtempSync(
245
+ path.join(os.tmpdir(), 'agentsam-go-receipt-isolation-'),
246
+ );
247
+
248
+ const goDir = path.join(stateRoot, '.agentsam', 'go');
249
+ fs.mkdirSync(goDir, { recursive: true });
250
+
251
+ const production = {
252
+ schema: 'agentsam.deployment-receipt.v1',
253
+ product: 'agentsam-go-worker',
254
+ provider: 'cloudflare',
255
+ url: 'https://runtime.inneranimalmedia.com',
256
+ health: 'healthy',
257
+ deployed_at: '2026-09-25T17:05:13.618296Z',
258
+ worker_deployment_id: 'dep_prod',
259
+ worker_version_id: 'ver_prod',
260
+ official_release: true,
261
+ };
262
+
263
+ fs.writeFileSync(
264
+ path.join(goDir, 'latest.deployment-receipt.json'),
265
+ JSON.stringify(production, null, 2) + '\n',
266
+ );
267
+
268
+ const cloudflareIdentity = {
269
+ ok: true,
270
+ authenticated: true,
271
+ auth_type: 'OAuth Token',
272
+ account: { id: 'acc_test', name: 'Test', type: 'standard' },
273
+ accounts: [{ id: 'acc_test', name: 'Test', type: 'standard' }],
274
+ };
275
+
276
+ const spawn = (command, args = []) => {
277
+ if (command === 'docker' && args[0] === 'info') {
278
+ return { status: 0, stdout: 'ok', stderr: '' };
279
+ }
280
+ if (args.includes('deploy') && args.includes('--dry-run')) {
281
+ return { status: 0, stdout: 'dry run', stderr: '' };
282
+ }
283
+ throw new Error('unexpected spawn: ' + [command, ...args].join(' '));
284
+ };
285
+
286
+ await deployGoCloudflare({
287
+ productRoot: PRODUCT_ROOT,
288
+ stateRoot,
289
+ product: 'agentsam-go-worker',
290
+ dryRun: true,
291
+ accountId: 'acc_test',
292
+ cloudflareIdentity,
293
+ source: {
294
+ identity: 'git:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
295
+ commit: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
296
+ package_name: '@inneranimalmedia/agentsam-go-worker',
297
+ package_version: '0.1.0',
298
+ },
299
+ artifactDigest: 'sha256:artifact',
300
+ containerDigest: 'sha256:container',
301
+ spawn,
302
+ });
303
+
304
+ const after = JSON.parse(
305
+ fs.readFileSync(
306
+ path.join(goDir, 'latest.deployment-receipt.json'),
307
+ 'utf8',
308
+ ),
309
+ );
310
+
311
+ assert.deepEqual(after, production);
312
+ assert.ok(
313
+ fs.existsSync(
314
+ path.join(goDir, 'latest.deployment-validation-receipt.json'),
315
+ ),
316
+ );
53
317
  });
@@ -0,0 +1,28 @@
1
+ import assert from 'node:assert/strict';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import test from 'node:test';
6
+ import { fileURLToPath } from 'node:url';
7
+ import {
8
+ GO_WORKER_PACKAGE,
9
+ discoverGoRuntime,
10
+ resolveProductRoot,
11
+ } from '../../src/go/discover.js';
12
+
13
+ const SDK_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
14
+ const PRODUCT_ROOT = path.join(SDK_ROOT, 'apps', 'agentsam-go-worker');
15
+
16
+ test('installed Go Worker package is discovered outside the monorepo', () => {
17
+ const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-go-distribution-'));
18
+ const packageRoot = path.join(temp, 'node_modules', ...GO_WORKER_PACKAGE.split('/'));
19
+ fs.mkdirSync(path.dirname(packageRoot), { recursive: true });
20
+ fs.symlinkSync(PRODUCT_ROOT, packageRoot, 'dir');
21
+
22
+ const discovery = discoverGoRuntime(temp);
23
+ assert.equal(discovery.schema, 'agentsam.go-discovery.v2');
24
+ assert.equal(discovery.runtime?.origin, 'installed_package');
25
+ assert.equal(discovery.distribution?.package_name, GO_WORKER_PACKAGE);
26
+ assert.equal(discovery.distribution?.package_version, '0.1.0');
27
+ assert.equal(fs.realpathSync(resolveProductRoot(discovery)), fs.realpathSync(PRODUCT_ROOT));
28
+ });
@@ -0,0 +1,47 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import {
4
+ assessAiAccess,
5
+ formatAiAccessOnboarding,
6
+ CF_OAUTH_REQUIRED_REDIRECTS,
7
+ LOCAL_STUDIO_LOGIN,
8
+ } from '../../src/models/ai-access-onboarding.js';
9
+ import { listModelCatalog } from '../../src/models/catalog.js';
10
+ import { getModelRecord, mergeModelReference, listModelCatalog as listFromIndex } from '../../src/models/index.js';
11
+
12
+ describe('listModelCatalog import surface', () => {
13
+ it('is defined from catalog and models/index', () => {
14
+ assert.equal(typeof listModelCatalog, 'function');
15
+ assert.equal(typeof listFromIndex, 'function');
16
+ assert.ok(listModelCatalog().length > 0);
17
+ assert.equal(typeof getModelRecord, 'function');
18
+ assert.equal(typeof mergeModelReference, 'function');
19
+ });
20
+ });
21
+
22
+ describe('ai access onboarding', () => {
23
+ it('marks ready when a provider credential is configured', () => {
24
+ const access = assessAiAccess({
25
+ inventory: { providers: [{ id: 'openai', configured: true }] },
26
+ ollama: { online: false, models: [] },
27
+ options: [{ value: 'none' }],
28
+ });
29
+ assert.equal(access.ready, true);
30
+ assert.equal(access.hasProviderKeys, true);
31
+ });
32
+
33
+ it('marks not ready and formats setup paths', () => {
34
+ const access = assessAiAccess({
35
+ inventory: { providers: [{ id: 'openai', configured: false }] },
36
+ ollama: { online: false, models: [] },
37
+ options: [{ value: 'none' }],
38
+ });
39
+ assert.equal(access.ready, false);
40
+ const text = formatAiAccessOnboarding(access, { wantCloudAi: true });
41
+ assert.match(text, /ollama\.com\/download/);
42
+ assert.match(text, /agentsam providers/);
43
+ assert.match(text, /api\/oauth\/cloudflare\/start/);
44
+ assert.ok(CF_OAUTH_REQUIRED_REDIRECTS.some((u) => u.includes('/api/oauth/cloudflare/callback')));
45
+ assert.match(LOCAL_STUDIO_LOGIN, /next=\/agentsam/);
46
+ });
47
+ });
@@ -14,7 +14,7 @@ test('agentsam help is concise, topic-aware, and deterministic outside a TTY', (
14
14
  assert.equal(help.status, 0, help.stderr);
15
15
  assert.doesNotMatch(help.stderr, /Unknown command/);
16
16
  assert.match(help.stdout, /Agent Sam/);
17
- assert.match(help.stdout, /Type normally to work with Agent Sam/);
17
+ assert.match(help.stdout, /SAM = Systematic Autonomous Machinery/);
18
18
  assert.match(help.stdout, /agentsam help <topic>/);
19
19
  assert.match(help.stdout, /press \/ for the command picker/i);
20
20
  assert.doesNotMatch(help.stdout, /Inspect options:/);
@@ -143,13 +143,13 @@ test('homepage.html is decomposed into reusable site partials with relative link
143
143
  assert.ok(header.length > 500, 'header.html must contain full header content');
144
144
  assert.ok(footer.length > 500, 'footer.html must contain full footer content');
145
145
 
146
- // Relative navigation links (R2 partial SSOT)
147
- assert.match(header, /href="\/work"/);
148
- assert.match(header, /href="\/about"/);
149
- assert.match(header, /href="\/services"/);
150
- assert.match(header, /href="\/contact"/);
146
+ // AgentSam public header navigation is relative and product-specific (R2 partial SSOT).
147
+ assert.match(header, /href="\/"/);
148
+ assert.match(header, /href="\/learn\/"/);
149
+ assert.match(header, /href="\/themes\/"/);
150
+ assert.match(header, /href="\/packages\/sdk\/help\/"/);
151
151
  assert.match(header, /href="\/auth\/login\?next=\/agentsam"/);
152
- assert.doesNotMatch(header, /href="https:\/\/inneranimalmedia\.com\/(work|about|services|contact)"/);
152
+ assert.doesNotMatch(header, /href="https:\/\/inneranimalmedia\.com\/(learn|themes|packages\/sdk|agentsam)"/);
153
153
 
154
154
  assert.match(footer, /href="\/work"/);
155
155
  assert.match(footer, /href="\/about"/);