@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,244 @@
1
+ import os from 'node:os';
2
+ import { getJson, postJson } from '../lib/core-client.js';
3
+ import { resolveAccountAuthority } from '../lib/auth.js';
4
+ import { setProviderCredential, ensureAgentEnvLoader } from '../lib/provider-credentials.js';
5
+
6
+ function writeLine(write, value = '') {
7
+ write(`${value}\n`);
8
+ }
9
+
10
+ function parseArgs(argv = []) {
11
+ const out = {
12
+ command: 'help',
13
+ name: '',
14
+ id: '',
15
+ store: 'keychain',
16
+ activate: false,
17
+ active: false,
18
+ json: false,
19
+ positionals: [],
20
+ };
21
+ const [command = 'help', ...rest] = argv;
22
+ out.command = command;
23
+ for (let i = 0; i < rest.length; i += 1) {
24
+ const arg = rest[i];
25
+ if (arg === '--name') out.name = String(rest[++i] || '').trim();
26
+ else if (arg === '--id') out.id = String(rest[++i] || '').trim();
27
+ else if (arg === '--store') out.store = String(rest[++i] || 'keychain').trim().toLowerCase();
28
+ else if (arg === '--activate') out.activate = true;
29
+ else if (arg === '--active') out.active = true;
30
+ else if (arg === '--json') out.json = true;
31
+ else if (String(arg).startsWith('-')) throw new Error(`unexpected api-key argument: ${arg}`);
32
+ else out.positionals.push(arg);
33
+ }
34
+ if (!out.id && out.positionals[0]) out.id = out.positionals[0];
35
+ if (!out.name) {
36
+ try {
37
+ out.name = os.hostname() || 'local';
38
+ } catch {
39
+ out.name = 'local';
40
+ }
41
+ }
42
+ return out;
43
+ }
44
+
45
+ async function requireAuthority(options = {}) {
46
+ const authority = await (options.authorityLoader || resolveAccountAuthority)({
47
+ env: options.env || process.env,
48
+ home: options.home,
49
+ explicit: options.token || '',
50
+ fetchImpl: options.fetchImpl,
51
+ refreshImpl: options.refreshImpl,
52
+ nowMs: options.nowMs,
53
+ skewMs: options.skewMs,
54
+ signal: options.signal,
55
+ });
56
+ if (!authority?.value) {
57
+ throw new Error(authority?.error || 'Run agentsam login first (OAuth session required to mint API keys).');
58
+ }
59
+ return authority;
60
+ }
61
+
62
+ function storeSecretLocally(secret, options = {}) {
63
+ const store = String(options.store || 'keychain').toLowerCase();
64
+ if (store === 'none' || store === 'print') {
65
+ return { storage: 'none', source_command: null };
66
+ }
67
+ // keychain | vault — setSecureProviderKey tries OS keychain then encrypted vault
68
+ const result = setProviderCredential('inneranimalmedia', secret, {
69
+ ...options,
70
+ exportProfile: false,
71
+ writeEnvProfile: false,
72
+ });
73
+ ensureAgentEnvLoader(options);
74
+ return {
75
+ storage: store === 'vault' ? 'local_vault' : 'os_keychain',
76
+ provider: result.provider,
77
+ source_command: 'source ~/.agentsam/load-agent-env.sh',
78
+ };
79
+ }
80
+
81
+ function renderCreate(result) {
82
+ const lines = [
83
+ '',
84
+ ' ✓ AgentSam API credential created',
85
+ '',
86
+ ` Name ${result.credential?.name || ''}`,
87
+ ` Prefix ${result.credential?.prefix || ''}`,
88
+ ` Owner current account`,
89
+ ` Storage ${result.storage_label || 'not stored'}`,
90
+ ` Status active`,
91
+ '',
92
+ ];
93
+ if (result.activated) {
94
+ lines.push(' ✓ AGENTSAM_API_KEY is available to AgentSam environments');
95
+ lines.push('');
96
+ lines.push(' source ~/.agentsam/load-agent-env.sh');
97
+ lines.push(' agentsam whoami');
98
+ lines.push('');
99
+ } else if (result.secret_once) {
100
+ lines.push(' Copy this key now. It cannot be displayed again.');
101
+ lines.push(` ${result.secret_once}`);
102
+ lines.push('');
103
+ }
104
+ return lines.join('\n');
105
+ }
106
+
107
+ export async function runApiKey(argv = [], options = {}) {
108
+ const write = options.write || ((text) => process.stdout.write(text));
109
+ const parsed = parseArgs(argv);
110
+ const env = options.env || process.env;
111
+
112
+ if (parsed.command === 'help' || parsed.command === '--help' || parsed.command === '-h') {
113
+ writeLine(write, 'agentsam api-key create [--name <label>] [--store keychain|vault|none] [--activate]');
114
+ writeLine(write, 'agentsam api-key list [--json]');
115
+ writeLine(write, 'agentsam api-key rotate [--id <credential_id>|--active] [--store keychain] [--activate]');
116
+ writeLine(write, 'agentsam api-key revoke --id <credential_id>');
117
+ return;
118
+ }
119
+
120
+ if (parsed.command === 'create') {
121
+ const authority = await requireAuthority(options);
122
+ const post = options.postJsonImpl || postJson;
123
+ const response = await post(
124
+ '/api/sdk/api-keys',
125
+ { action: 'create', name: parsed.name, client_type: 'cli' },
126
+ { env, home: options.home, bearer: authority.value, fetchImpl: options.fetchImpl, refreshImpl: options.refreshImpl },
127
+ );
128
+ const secret = response?.secret_once;
129
+ if (!secret) throw new Error('host_did_not_return_secret_once');
130
+
131
+ let storage = { storage: 'none' };
132
+ let activated = false;
133
+ if (parsed.activate || parsed.store !== 'none') {
134
+ storage = storeSecretLocally(secret, { ...options, store: parsed.store });
135
+ activated = parsed.activate || parsed.store !== 'none';
136
+ }
137
+
138
+ const result = {
139
+ ok: true,
140
+ credential: response.credential,
141
+ secret_once: activated ? undefined : secret,
142
+ storage: storage.storage,
143
+ storage_label:
144
+ storage.storage === 'os_keychain'
145
+ ? process.platform === 'darwin'
146
+ ? 'macOS Keychain'
147
+ : process.platform === 'win32'
148
+ ? 'Windows Credential Manager'
149
+ : 'OS credential store'
150
+ : storage.storage === 'local_vault'
151
+ ? 'local encrypted vault'
152
+ : 'not stored',
153
+ activated,
154
+ };
155
+ if (parsed.json) writeLine(write, JSON.stringify({ ...result, secret_once: secret }, null, 2));
156
+ else write(renderCreate(result));
157
+ return result;
158
+ }
159
+
160
+ if (parsed.command === 'list') {
161
+ const authority = await requireAuthority(options);
162
+ const get = options.getJsonImpl || getJson;
163
+ const response = await get('/api/sdk/api-keys', {
164
+ env,
165
+ home: options.home,
166
+ bearer: authority.value,
167
+ fetchImpl: options.fetchImpl,
168
+ refreshImpl: options.refreshImpl,
169
+ });
170
+ const rows = response?.credentials || [];
171
+ if (parsed.json) {
172
+ writeLine(write, JSON.stringify({ ok: true, credentials: rows }, null, 2));
173
+ } else {
174
+ writeLine(write, '');
175
+ writeLine(write, ' AgentSam API keys');
176
+ if (!rows.length) writeLine(write, ' (none)');
177
+ for (const row of rows) {
178
+ writeLine(
179
+ write,
180
+ ` ${(row.name || row.id || '').padEnd(28)} ${(row.prefix || '').padEnd(14)} ${row.status || 'unknown'}`,
181
+ );
182
+ }
183
+ writeLine(write, '');
184
+ }
185
+ return { ok: true, credentials: rows };
186
+ }
187
+
188
+ if (parsed.command === 'rotate') {
189
+ const authority = await requireAuthority(options);
190
+ let id = parsed.id;
191
+ if (!id || parsed.active) {
192
+ const get = options.getJsonImpl || getJson;
193
+ const listed = await get('/api/sdk/api-keys', {
194
+ env,
195
+ home: options.home,
196
+ bearer: authority.value,
197
+ fetchImpl: options.fetchImpl,
198
+ refreshImpl: options.refreshImpl,
199
+ });
200
+ const active = (listed?.credentials || []).find((row) => row.status === 'active');
201
+ if (!active?.id) throw new Error('no_active_credential_to_rotate');
202
+ id = active.id;
203
+ }
204
+ const post = options.postJsonImpl || postJson;
205
+ const response = await post(
206
+ '/api/sdk/api-keys',
207
+ { action: 'rotate', id, name: parsed.name || undefined },
208
+ { env, home: options.home, bearer: authority.value, fetchImpl: options.fetchImpl, refreshImpl: options.refreshImpl },
209
+ );
210
+ const secret = response?.secret_once;
211
+ if (!secret) throw new Error('host_did_not_return_secret_once');
212
+ const storage = storeSecretLocally(secret, { ...options, store: parsed.store === 'none' ? 'keychain' : parsed.store });
213
+ const result = {
214
+ ok: true,
215
+ credential: response.credential,
216
+ storage: storage.storage,
217
+ storage_label: 'OS keychain / vault',
218
+ activated: true,
219
+ };
220
+ if (parsed.json) writeLine(write, JSON.stringify({ ...result, secret_once: secret }, null, 2));
221
+ else write(renderCreate({ ...result, secret_once: undefined }));
222
+ return result;
223
+ }
224
+
225
+ if (parsed.command === 'revoke') {
226
+ if (!parsed.id) throw new Error('api-key revoke requires --id <credential_id>');
227
+ const authority = await requireAuthority(options);
228
+ const post = options.postJsonImpl || postJson;
229
+ const response = await post(
230
+ '/api/sdk/api-keys',
231
+ { action: 'revoke', id: parsed.id },
232
+ { env, home: options.home, bearer: authority.value, fetchImpl: options.fetchImpl, refreshImpl: options.refreshImpl },
233
+ );
234
+ if (parsed.json) writeLine(write, JSON.stringify(response, null, 2));
235
+ else {
236
+ writeLine(write, '');
237
+ writeLine(write, response?.ok ? ' ✓ credential revoked' : ' revoke failed');
238
+ writeLine(write, '');
239
+ }
240
+ return response;
241
+ }
242
+
243
+ throw new Error(`unknown api-key command: ${parsed.command}`);
244
+ }
@@ -9,38 +9,56 @@ function clean(value) {
9
9
  return value == null ? '' : String(value).trim();
10
10
  }
11
11
 
12
+ function readManifest(manifestPath, fallbackId) {
13
+ try {
14
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
15
+ return {
16
+ id: manifest.id || fallbackId,
17
+ name: manifest.name || fallbackId,
18
+ dir: path.dirname(manifestPath),
19
+ manifestPath,
20
+ bin: manifest.bin || null,
21
+ commands: manifest.commands || {},
22
+ manifest,
23
+ };
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+
12
29
  export function listAppManifests(root = REPO_ROOT) {
13
- const appsRoot = path.join(root, 'apps');
14
- if (!fs.existsSync(appsRoot)) return [];
15
- return fs.readdirSync(appsRoot, { withFileTypes: true })
16
- .filter((entry) => entry.isDirectory())
17
- .map((entry) => {
18
- const dir = path.join(appsRoot, entry.name);
19
- const manifestPath = path.join(dir, 'agentsam.app.json');
20
- if (!fs.existsSync(manifestPath)) return null;
21
- try {
22
- const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
23
- return {
24
- id: manifest.id || entry.name,
25
- name: manifest.name || entry.name,
26
- dir,
27
- manifestPath,
28
- bin: manifest.bin || null,
29
- commands: manifest.commands || {},
30
- manifest,
31
- };
32
- } catch {
33
- return null;
34
- }
35
- })
36
- .filter(Boolean)
37
- .sort((a, b) => a.id.localeCompare(b.id));
30
+ const out = [];
31
+ const seen = new Set();
32
+
33
+ function addFromDir(parent, entryName) {
34
+ const dir = path.join(parent, entryName);
35
+ const manifestPath = path.join(dir, 'agentsam.app.json');
36
+ if (!fs.existsSync(manifestPath)) return;
37
+ const row = readManifest(manifestPath, entryName);
38
+ if (!row || seen.has(row.id)) return;
39
+ seen.add(row.id);
40
+ out.push(row);
41
+ }
42
+
43
+ for (const parentName of ['apps', 'packages']) {
44
+ const parent = path.join(root, parentName);
45
+ if (!fs.existsSync(parent)) continue;
46
+ for (const entry of fs.readdirSync(parent, { withFileTypes: true })) {
47
+ if (!entry.isDirectory()) continue;
48
+ addFromDir(parent, entry.name);
49
+ }
50
+ }
51
+
52
+ return out.sort((a, b) => a.id.localeCompare(b.id));
38
53
  }
39
54
 
40
55
  function resolveApp(id, root = REPO_ROOT) {
41
56
  const apps = listAppManifests(root);
42
57
  const hit = apps.find((row) => row.id === id || path.basename(row.dir) === id);
43
- if (!hit) throw new Error(`unknown AgentSam app: ${id}`);
58
+ if (!hit) {
59
+ const available = apps.map((a) => a.id).join(', ') || '(none)';
60
+ throw new Error(`unknown AgentSam app: ${id}. Available: ${available}`);
61
+ }
44
62
  return hit;
45
63
  }
46
64
 
@@ -63,6 +81,7 @@ export async function runApp(argv = [], options = {}) {
63
81
  write([
64
82
  'agentsam app list',
65
83
  'agentsam app info <id>',
84
+ 'agentsam app install <id>',
66
85
  'agentsam app doctor <id>',
67
86
  'agentsam app preview <id>',
68
87
  'agentsam app scaffold <id> <dir>',
@@ -75,7 +94,7 @@ export async function runApp(argv = [], options = {}) {
75
94
  const apps = listAppManifests(options.root || REPO_ROOT);
76
95
  write('\n AgentSam apps\n\n');
77
96
  for (const app of apps) {
78
- write(` • ${app.id.padEnd(20)} ${app.name}\n`);
97
+ write(` • ${app.id.padEnd(24)} ${app.name}\n`);
79
98
  }
80
99
  write('\n');
81
100
  return apps;
@@ -88,6 +107,19 @@ export async function runApp(argv = [], options = {}) {
88
107
  write(`${JSON.stringify(app.manifest, null, 2)}\n`);
89
108
  return app.manifest;
90
109
  }
110
+ if (command === 'install') {
111
+ const curl =
112
+ app.manifest?.install?.curl ||
113
+ `curl -fsSL https://agentsam.inneranimalmedia.com/install | bash -s -- --app-id ${app.id}`;
114
+ const npmCmd =
115
+ app.manifest?.install?.command ||
116
+ (app.manifest?.package ? `npm install ${app.manifest.package}` : null);
117
+ write(`\n Install ${app.id}\n\n`);
118
+ if (npmCmd) write(` ${npmCmd}\n`);
119
+ write(` ${curl}\n\n`);
120
+ write(' app_id is stable product identity. Pass --app-id explicitly; no AGENTSAM_DEFAULT_APP.\n\n');
121
+ return { id: app.id, curl, command: npmCmd };
122
+ }
91
123
  if (command === 'doctor' || command === 'preview') {
92
124
  runAppBin(app, [command, ...rest], options);
93
125
  return;
@@ -100,7 +132,7 @@ export async function runApp(argv = [], options = {}) {
100
132
  }
101
133
 
102
134
  export function appCommandHelp() {
103
- return 'agentsam app list|info|doctor|preview|scaffold';
135
+ return 'agentsam app list|info|install|doctor|preview|scaffold';
104
136
  }
105
137
 
106
138
  export { clean };
@@ -10,6 +10,7 @@ import {
10
10
  brandWorldFromPlan,
11
11
  brandGoalFromPlan,
12
12
  } from '../../packages/agentsam-brand/src/index.js';
13
+ import { planGoap, GOAP_ENGINE } from '../sam/planning/goap.js';
13
14
  import { suggestNextActions } from '../progression/index.js';
14
15
  import { createRuntimeActivity } from '../ui/runtime-activity.js';
15
16
 
@@ -218,26 +219,23 @@ async function runBrandPlanInner({ scan, resolved, opts }) {
218
219
  const world = brandWorldFromPlan(plan);
219
220
  const goal = brandGoalFromPlan(plan);
220
221
  const actions = brandGoapActions();
221
- const sequence = [];
222
- const state = { ...world };
223
- // greedy applicable actions by cost until goal satisfied or stuck
224
- for (let guard = 0; guard < 20; guard += 1) {
225
- const done = Object.entries(goal).every(([k, v]) => state[k] === v);
226
- if (done) break;
227
- const candidates = actions
228
- .filter((a) => Object.entries(a.preconditions || {}).every(([k, v]) => state[k] === v))
229
- .filter((a) => !sequence.includes(a.id))
230
- .sort((a, b) => (a.cost || 1) - (b.cost || 1));
231
- if (!candidates.length) break;
232
- const next = candidates[0];
233
- sequence.push(next.id);
234
- Object.assign(state, next.effects || {});
235
- }
222
+ const planned = planGoap({
223
+ initialState: world,
224
+ goal,
225
+ actions,
226
+ maxExpansions: 10_000,
227
+ });
236
228
  goap = {
237
- ok: sequence.length > 0,
238
- plan: sequence,
239
- cost: sequence.reduce((n, id) => n + (actions.find((a) => a.id === id)?.cost || 0), 0),
240
- engine: 'brand-goap-greedy',
229
+ ok: planned.ok,
230
+ plan: planned.plan,
231
+ cost: planned.total_cost ?? planned.cost,
232
+ engine: planned.engine || GOAP_ENGINE,
233
+ status: planned.status,
234
+ expanded_states: planned.expanded_states,
235
+ generated_states: planned.generated_states,
236
+ frontier_peak: planned.frontier_peak,
237
+ elapsed_ms: planned.elapsed_ms,
238
+ error: planned.error,
241
239
  };
242
240
  }
243
241
  const enriched = attachProgression('brand.plan', plan, opts.json);