@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,117 @@
1
+ /**
2
+ * Shared SAM decision state — minimal projection for a question set.
3
+ */
4
+
5
+ import { createHash } from 'node:crypto';
6
+ import { DECISION_STATE_SCHEMA } from './types.js';
7
+
8
+ /**
9
+ * @param {object} [partial]
10
+ * @returns {object}
11
+ */
12
+ export function buildDecisionState(partial = {}) {
13
+ const state = {
14
+ schema: DECISION_STATE_SCHEMA,
15
+ intent: partial.intent ?? null,
16
+ goal: partial.goal ?? null,
17
+ repository: partial.repository
18
+ ? {
19
+ repository_id: partial.repository.repository_id ?? null,
20
+ root: partial.repository.root ?? null,
21
+ branch: partial.repository.branch ?? null,
22
+ dirty: partial.repository.dirty ?? null,
23
+ merkle_root: partial.repository.merkle_root ?? null,
24
+ }
25
+ : null,
26
+ code: partial.code
27
+ ? {
28
+ relevant_nodes: Array.isArray(partial.code.relevant_nodes) ? [...partial.code.relevant_nodes] : [],
29
+ dependency_nodes: Array.isArray(partial.code.dependency_nodes) ? [...partial.code.dependency_nodes] : [],
30
+ affected_packages: Array.isArray(partial.code.affected_packages) ? [...partial.code.affected_packages] : [],
31
+ }
32
+ : null,
33
+ runtime: partial.runtime
34
+ ? {
35
+ terminal_lanes: partial.runtime.terminal_lanes ?? null,
36
+ connection_health: partial.runtime.connection_health ?? null,
37
+ capabilities: Array.isArray(partial.runtime.capabilities) ? [...partial.runtime.capabilities] : [],
38
+ }
39
+ : null,
40
+ tools: partial.tools ?? null,
41
+ skills: partial.skills ?? null,
42
+ models: partial.models ?? null,
43
+ constraints: partial.constraints
44
+ ? {
45
+ budget: partial.constraints.budget ?? null,
46
+ latency: partial.constraints.latency ?? null,
47
+ approval: partial.constraints.approval ?? null,
48
+ security: partial.constraints.security ?? null,
49
+ production_write: partial.constraints.production_write ?? null,
50
+ isolation_required: partial.constraints.isolation_required ?? null,
51
+ requires_local_files: partial.constraints.requires_local_files ?? null,
52
+ }
53
+ : null,
54
+ evidence: Array.isArray(partial.evidence) ? [...partial.evidence] : [],
55
+ history: partial.history ?? null,
56
+ metadata: partial.metadata && typeof partial.metadata === 'object' ? { ...partial.metadata } : {},
57
+ facts: partial.facts && typeof partial.facts === 'object' ? { ...partial.facts } : {},
58
+ };
59
+ return Object.freeze(deepFreezeShallow(state));
60
+ }
61
+
62
+ /**
63
+ * Stable hash of decision state for receipts.
64
+ * @param {object} state
65
+ */
66
+ export function hashDecisionState(state) {
67
+ return createHash('sha256').update(stableStringify(state)).digest('hex');
68
+ }
69
+
70
+ /**
71
+ * Project only the keys needed for a question set (does not mutate input).
72
+ * @param {object} state
73
+ * @param {string[]} paths
74
+ */
75
+ export function projectState(state, paths = []) {
76
+ if (!paths.length) return buildDecisionState(state);
77
+ const out = { schema: DECISION_STATE_SCHEMA, facts: {}, evidence: [], metadata: {} };
78
+ for (const p of paths) {
79
+ const value = getPath(state, p);
80
+ if (value !== undefined) setPath(out, p, value);
81
+ }
82
+ if (state.evidence) out.evidence = [...state.evidence];
83
+ return buildDecisionState({ ...state, ...out });
84
+ }
85
+
86
+ function getPath(obj, dotted) {
87
+ const parts = String(dotted).split('.');
88
+ let cur = obj;
89
+ for (const part of parts) {
90
+ if (cur == null || typeof cur !== 'object') return undefined;
91
+ cur = cur[part];
92
+ }
93
+ return cur;
94
+ }
95
+
96
+ function setPath(obj, dotted, value) {
97
+ const parts = String(dotted).split('.');
98
+ let cur = obj;
99
+ for (let i = 0; i < parts.length - 1; i += 1) {
100
+ const p = parts[i];
101
+ if (cur[p] == null || typeof cur[p] !== 'object') cur[p] = {};
102
+ cur = cur[p];
103
+ }
104
+ cur[parts[parts.length - 1]] = value;
105
+ }
106
+
107
+ function deepFreezeShallow(value) {
108
+ if (!value || typeof value !== 'object') return value;
109
+ return value;
110
+ }
111
+
112
+ function stableStringify(value) {
113
+ if (value === null || typeof value !== 'object') return JSON.stringify(value);
114
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`;
115
+ const keys = Object.keys(value).sort();
116
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(',')}}`;
117
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * SAM decision contracts — Systematic Autonomous Machinery.
3
+ * choose / score / check — AgentSam-native, no vendor terminology.
4
+ */
5
+
6
+ export const DECISION_STATE_SCHEMA = 'agentsam.decision-state.v1';
7
+ export const DECISION_QUESTION_SCHEMA = 'agentsam.decision-question.v1';
8
+ export const DECISION_ANSWER_SCHEMA = 'agentsam.decision-answer.v1';
9
+ export const DECISION_EVALUATION_SCHEMA = 'agentsam.decision-evaluation.v1';
10
+ export const DECISION_RECEIPT_SCHEMA = 'agentsam.decision-receipt.v1';
11
+ export const DECISION_OUTCOME_SCHEMA = 'agentsam.decision-outcome.v1';
12
+ export const DECISION_CALIBRATION_SCHEMA = 'agentsam.decision-calibration.v1';
13
+
14
+ /** @typedef {'choose'|'score'|'check'} QuestionType */
15
+ /** @typedef {'deterministic'|'heuristic'|'graph'|'semantic'|'calibrated-statistical'} EvaluatorKind */
16
+
17
+ /**
18
+ * Confidence semantics:
19
+ * - confidence_estimate / support: raw evaluator concentration or proposition support
20
+ * - probabilities: ONLY when evaluator has a defined probabilistic interpretation
21
+ * - calibrated_probability: ONLY after empirical calibration with calibration_id
22
+ */
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Question builders + validation for choose / score / check.
3
+ */
4
+
5
+ import { DECISION_QUESTION_SCHEMA } from './types.js';
6
+
7
+ /**
8
+ * @param {object} def
9
+ */
10
+ export function defineChoose(def) {
11
+ return validateQuestion({
12
+ schema: DECISION_QUESTION_SCHEMA,
13
+ id: def.id,
14
+ type: 'choose',
15
+ version: def.version ?? 1,
16
+ instructions: def.instructions ?? null,
17
+ criteria: def.criteria ?? null,
18
+ options: def.options,
19
+ evaluator_hint: def.evaluator_hint ?? null,
20
+ });
21
+ }
22
+
23
+ /**
24
+ * @param {object} def
25
+ */
26
+ export function defineScore(def) {
27
+ return validateQuestion({
28
+ schema: DECISION_QUESTION_SCHEMA,
29
+ id: def.id,
30
+ type: 'score',
31
+ version: def.version ?? 1,
32
+ instructions: def.instructions ?? null,
33
+ criteria: def.criteria ?? null,
34
+ levels: def.levels,
35
+ evaluator_hint: def.evaluator_hint ?? null,
36
+ });
37
+ }
38
+
39
+ /**
40
+ * @param {object} def
41
+ */
42
+ export function defineCheck(def) {
43
+ return validateQuestion({
44
+ schema: DECISION_QUESTION_SCHEMA,
45
+ id: def.id,
46
+ type: 'check',
47
+ version: def.version ?? 1,
48
+ instructions: def.instructions ?? null,
49
+ criteria: def.criteria ?? null,
50
+ evaluator_hint: def.evaluator_hint ?? null,
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Fail-closed validation.
56
+ * @param {object} question
57
+ */
58
+ export function validateQuestion(question) {
59
+ if (!question || typeof question !== 'object') {
60
+ throw fail('invalid_question', 'question must be an object');
61
+ }
62
+ if (typeof question.id !== 'string' || !question.id.trim()) {
63
+ throw fail('invalid_question_id', 'question.id is required');
64
+ }
65
+ if (!['choose', 'score', 'check'].includes(question.type)) {
66
+ throw fail('invalid_question_type', `unsupported type: ${question.type}`);
67
+ }
68
+ if (question.instructions != null && !isAllowedInstructions(question.instructions)) {
69
+ throw fail('invalid_instructions', 'instructions must be string|object|array|null');
70
+ }
71
+ if (question.criteria != null && !isAllowedCriteria(question.criteria)) {
72
+ throw fail('invalid_criteria', 'criteria must be string|object|array|null');
73
+ }
74
+
75
+ if (question.type === 'choose') {
76
+ const options = normalizeOptions(question.options, question.criteria);
77
+ if (!options.length) {
78
+ throw fail('choose_options_required', 'choose requires a finite options set');
79
+ }
80
+ return Object.freeze({
81
+ ...question,
82
+ schema: DECISION_QUESTION_SCHEMA,
83
+ options,
84
+ version: question.version ?? 1,
85
+ });
86
+ }
87
+
88
+ if (question.type === 'score') {
89
+ const levels = normalizeLevels(question.levels ?? question.criteria);
90
+ if (levels.length < 2) {
91
+ throw fail('score_levels_required', 'score requires an ordered levels list (>=2)');
92
+ }
93
+ // Ensure strictly ordered by numeric index (and unique)
94
+ const seen = new Set();
95
+ for (let i = 0; i < levels.length; i += 1) {
96
+ if (seen.has(levels[i].index)) {
97
+ throw fail('score_levels_unordered', 'score levels must have unique strictly increasing indexes');
98
+ }
99
+ seen.add(levels[i].index);
100
+ if (i > 0 && !(levels[i].index > levels[i - 1].index)) {
101
+ throw fail('score_levels_unordered', 'score levels must be strictly increasing');
102
+ }
103
+ }
104
+ return Object.freeze({
105
+ ...question,
106
+ schema: DECISION_QUESTION_SCHEMA,
107
+ levels,
108
+ version: question.version ?? 1,
109
+ });
110
+ }
111
+
112
+ // check — single proposition; do not smuggle multi-dimensional scoring
113
+ return Object.freeze({
114
+ ...question,
115
+ schema: DECISION_QUESTION_SCHEMA,
116
+ version: question.version ?? 1,
117
+ });
118
+ }
119
+
120
+ /**
121
+ * @param {object[]} questions
122
+ */
123
+ export function validateQuestionBatch(questions) {
124
+ if (!Array.isArray(questions) || !questions.length) {
125
+ throw fail('empty_batch', 'questions must be a non-empty array');
126
+ }
127
+ const ids = new Set();
128
+ const validated = questions.map((q) => validateQuestion(q));
129
+ for (const q of validated) {
130
+ if (ids.has(q.id)) throw fail('duplicate_question_id', `duplicate question id: ${q.id}`);
131
+ ids.add(q.id);
132
+ }
133
+ return validated;
134
+ }
135
+
136
+ function normalizeOptions(options, criteria) {
137
+ if (Array.isArray(options)) {
138
+ return options.map((o) => {
139
+ if (typeof o === 'string') return o;
140
+ if (o && typeof o === 'object' && typeof o.id === 'string') return o.id;
141
+ throw fail('invalid_option', 'choose options must be strings or {id}');
142
+ });
143
+ }
144
+ if (criteria && typeof criteria === 'object' && !Array.isArray(criteria)) {
145
+ return Object.keys(criteria);
146
+ }
147
+ return [];
148
+ }
149
+
150
+ function normalizeLevels(levels) {
151
+ if (Array.isArray(levels)) {
152
+ return levels.map((level, i) => {
153
+ if (typeof level === 'string') return { index: i, label: level };
154
+ if (level && typeof level === 'object') {
155
+ const index = Number(level.index ?? level.value ?? i);
156
+ if (!Number.isFinite(index)) throw fail('invalid_level_index', 'level index must be numeric');
157
+ return {
158
+ index,
159
+ label: String(level.label ?? level.description ?? `level_${index}`),
160
+ description: level.description ?? null,
161
+ };
162
+ }
163
+ throw fail('invalid_level', 'score level must be string or object');
164
+ }).sort((a, b) => a.index - b.index);
165
+ }
166
+ if (levels && typeof levels === 'object') {
167
+ return Object.keys(levels)
168
+ .map((k) => {
169
+ const index = Number(k);
170
+ if (!Number.isFinite(index)) throw fail('invalid_level_key', 'object level keys must be numeric');
171
+ const v = levels[k];
172
+ return {
173
+ index,
174
+ label: typeof v === 'string' ? v : String(v?.label ?? k),
175
+ description: typeof v === 'object' ? v.description ?? null : null,
176
+ };
177
+ })
178
+ .sort((a, b) => a.index - b.index);
179
+ }
180
+ return [];
181
+ }
182
+
183
+ function isAllowedInstructions(value) {
184
+ return (
185
+ value === null
186
+ || typeof value === 'string'
187
+ || Array.isArray(value)
188
+ || (typeof value === 'object')
189
+ );
190
+ }
191
+
192
+ function isAllowedCriteria(value) {
193
+ return isAllowedInstructions(value);
194
+ }
195
+
196
+ function fail(code, message) {
197
+ const err = new Error(message);
198
+ err.code = code;
199
+ return err;
200
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @param {import('./types.js').SamOperationDef} def
3
+ * @returns {import('./types.js').SamOperationDef}
4
+ */
5
+ export function defineSamOperation(def) {
6
+ if (!def || typeof def !== 'object') {
7
+ throw new TypeError('defineSamOperation requires an operation definition object');
8
+ }
9
+ if (typeof def.id !== 'string' || !def.id.includes('.')) {
10
+ throw new TypeError('defineSamOperation: id must be a dotted operation id (e.g. brand.scan)');
11
+ }
12
+ if (typeof def.handler !== 'function') {
13
+ throw new TypeError(`defineSamOperation(${def.id}): handler must be a function`);
14
+ }
15
+ if (!def.module || !def.action) {
16
+ throw new TypeError(`defineSamOperation(${def.id}): module and action are required`);
17
+ }
18
+ if (!def.execution?.lanes?.length || !def.execution.model || !def.execution.network || !def.execution.sideEffects) {
19
+ throw new TypeError(`defineSamOperation(${def.id}): execution.{lanes,model,network,sideEffects} required`);
20
+ }
21
+ if (!def.risk) {
22
+ throw new TypeError(`defineSamOperation(${def.id}): risk is required`);
23
+ }
24
+ if (!def.summary) {
25
+ throw new TypeError(`defineSamOperation(${def.id}): summary is required`);
26
+ }
27
+
28
+ const skill = typeof def.skill === 'string'
29
+ ? { id: def.skill, help: true }
30
+ : def.skill === null
31
+ ? null
32
+ : (def.skill || undefined);
33
+
34
+ return {
35
+ ...def,
36
+ version: def.version ?? 1,
37
+ status: def.status ?? 'stable',
38
+ purpose: def.purpose || def.description || def.summary,
39
+ outcome: def.outcome || undefined,
40
+ accepts: Array.isArray(def.accepts) ? [...def.accepts] : [],
41
+ phases: Array.isArray(def.phases) ? [...def.phases] : [],
42
+ artifacts: Array.isArray(def.artifacts) ? [...def.artifacts] : [],
43
+ skill,
44
+ execution: {
45
+ embedding: 'never',
46
+ provider_spend: def.execution.model === 'never' ? 'none' : 'possible',
47
+ ...def.execution,
48
+ lanes: [...def.execution.lanes],
49
+ },
50
+ };
51
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * SAM — Systematic Autonomous Machinery
3
+ *
4
+ * AgentSam = product / SDK / CLI
5
+ * SAM = execution architecture underneath AgentSam
6
+ * sam = conventional AgentSamClient variable (machinery, not a person)
7
+ *
8
+ * @see docs/architecture/SAM_KERNEL.md
9
+ */
10
+
11
+ export { SAM_RESULT_SCHEMA, SAM_EXPANSION } from './types.js';
12
+ export { defineSamOperation } from './define.js';
13
+ export {
14
+ registerSamOperation,
15
+ getSamOperation,
16
+ listSamOperations,
17
+ toSamOperationCard,
18
+ clearSamRegistryForTests,
19
+ } from './registry.js';
20
+ export { buildSamResult, hashJson } from './result.js';
21
+ export { AgentSamClient, createAgentSamClient } from './client.js';
22
+ export { ensureSeedOperations, SEED_OPERATIONS, resetSeedFlagForTests } from './seed.js';
23
+ export {
24
+ planAStar,
25
+ planGoap,
26
+ ASTAR_ENGINE,
27
+ GOAP_ENGINE,
28
+ stableStateKey,
29
+ cloneState,
30
+ applyEffects,
31
+ goalSatisfied,
32
+ preconditionsMet,
33
+ } from './planning/index.js';
34
+ export {
35
+ evaluate as evaluateDecisions,
36
+ evaluateDependentStages,
37
+ buildDecisionState,
38
+ defineChoose,
39
+ defineScore,
40
+ defineCheck,
41
+ applyDecisionPolicy,
42
+ composeUtility,
43
+ createDecisionReceipt,
44
+ appendOutcome,
45
+ attachAction,
46
+ QUESTION_REGISTRY,
47
+ getRegisteredQuestion,
48
+ brierScore,
49
+ logLoss,
50
+ expectedCalibrationError,
51
+ hierarchicalChoose,
52
+ beamRetain,
53
+ createSemanticEvaluator,
54
+ DECISION_STATE_SCHEMA,
55
+ DECISION_RECEIPT_SCHEMA,
56
+ } from './decision/index.js';
57
+ export {
58
+ createActivityEvent,
59
+ createActivityStore,
60
+ activityFromDecision,
61
+ ACTIVITY_SCHEMA,
62
+ ACTIVITY_PHASES,
63
+ ACTIVITY_EVENTS,
64
+ DECISION_ACTIVITY_LABELS,
65
+ } from './activity/index.js';
@@ -0,0 +1,62 @@
1
+ import { defineSamOperation } from '../define.js';
2
+ import { repositorySnapshot } from '../../capabilities/index.js';
3
+ import { brandScan } from '../../../packages/agentsam-brand/src/index.js';
4
+
5
+ /**
6
+ * Brand intelligence — evidence-backed BrandPack candidate chain (scan remains read-only).
7
+ * Preview/export are separate operations with local_write side effects.
8
+ */
9
+ export const brandScanOp = defineSamOperation({
10
+ id: 'brand.scan',
11
+ version: 1,
12
+ module: 'brand',
13
+ action: 'scan',
14
+ summary: 'Audit materials into evidence-backed brand intelligence.',
15
+ purpose:
16
+ 'Audit a repository and supplied materials into evidence-backed brand intelligence.',
17
+ outcome:
18
+ 'Produce a BrandPack candidate describing observed brand assets, tokens, typography, themes, components, layouts, URLs, content references, conflicts and normalization opportunities.',
19
+ description:
20
+ 'Deterministic evidence extraction over repository.snapshot authority — tokens, assets, typography, components, conflicts. Does not mutate the source tree.',
21
+ skill: { id: 'agentsam-app-fundamentals', help: true },
22
+ accepts: [
23
+ 'repository', 'directory', 'html', 'css', 'javascript', 'typescript',
24
+ 'image', 'svg', 'archive', 'glb', 'gltf', 'text',
25
+ ],
26
+ phases: [
27
+ 'inventory',
28
+ 'evidence',
29
+ 'brand-observation',
30
+ 'normalization',
31
+ 'theme-proposal',
32
+ 'brandpack',
33
+ ],
34
+ execution: {
35
+ lanes: ['local', 'remote', 'sandbox'],
36
+ model: 'optional',
37
+ embedding: 'never',
38
+ network: 'optional',
39
+ sideEffects: 'none',
40
+ provider_spend: 'possible',
41
+ },
42
+ risk: 'read_only',
43
+ capabilities: ['brand.scan', 'repository.snapshot'],
44
+ artifacts: ['brandpack.candidate', 'brand.evidence', 'theme.proposal'],
45
+ preview: { available: true, operation: 'brand.preview' },
46
+ cli: { command: [['brand', 'scan']] },
47
+ docs: { section: 'Brand', examples: ['brand-scan-basic'] },
48
+ status: 'stable',
49
+ async handler(input = {}, ctx = {}) {
50
+ const root = typeof input === 'string'
51
+ ? input
52
+ : (input.root || input.cwd || ctx.cwd || process.cwd());
53
+ const snapshot = input.snapshot
54
+ || await repositorySnapshot({ cwd: root, churnDays: 30 });
55
+ return brandScan({
56
+ cwd: root,
57
+ snapshot,
58
+ maxFiles: input.maxFiles,
59
+ onEvent: input.onEvent,
60
+ });
61
+ },
62
+ });
@@ -0,0 +1,36 @@
1
+ import { defineSamOperation } from '../define.js';
2
+ import { blenderInspect } from '../../lib/cad/blender.js';
3
+
4
+ export const cadBlenderInspectOp = defineSamOperation({
5
+ id: 'cad.blender.inspect',
6
+ version: 1,
7
+ module: 'cad',
8
+ action: 'blender.inspect',
9
+ summary: 'Inspect an existing Blender source (.blend).',
10
+ description: 'Host-tool inspect via Blender binary; no model spend. Requires blender on PATH or blenderBin.',
11
+ execution: {
12
+ lanes: ['local', 'remote', 'sandbox'],
13
+ model: 'never',
14
+ network: 'none',
15
+ sideEffects: 'none',
16
+ },
17
+ risk: 'read_only',
18
+ capabilities: ['cad.blender.inspect'],
19
+ cli: { command: [['cad', 'blender', 'inspect']] },
20
+ docs: { section: 'CAD' },
21
+ status: 'stable',
22
+ async handler(input = {}, ctx = {}) {
23
+ const source = input.source || input.input || input.path;
24
+ if (!source) {
25
+ throw Object.assign(new Error('cad.blender.inspect requires source/input'), {
26
+ code: 'sam_invalid_input',
27
+ });
28
+ }
29
+ return blenderInspect({
30
+ input: source,
31
+ blenderBin: input.blenderBin,
32
+ timeoutSeconds: input.timeoutSeconds,
33
+ cwd: input.cwd || input.root || ctx.cwd || process.cwd(),
34
+ });
35
+ },
36
+ });
@@ -0,0 +1,49 @@
1
+ import { defineSamOperation } from '../define.js';
2
+ import { runCodebaseindexIngest } from '../../commands/codebaseindex.js';
3
+
4
+ export const codebaseindexIngestOp = defineSamOperation({
5
+ id: 'codebaseindex.ingest',
6
+ version: 1,
7
+ module: 'codebaseindex',
8
+ action: 'ingest',
9
+ summary: 'Inventory-first ingest into the knowledge / code-intelligence spine.',
10
+ purpose:
11
+ 'Acquire materials, inventory the environment, confirm scope, resolve embed/storage lanes, dry-run, then index.',
12
+ outcome:
13
+ 'A verified knowledge generation (and optional vectors) with job graph, inventory, and receipt — usable by search/agents without re-learning the product for cloud later.',
14
+ skill: { id: 'agentsam-codebaseindex', help: true },
15
+ accepts: [
16
+ 'directory', 'archive', 'html', 'image', 'glb', 'code', 'document', 'repository',
17
+ ],
18
+ phases: [
19
+ 'material.stage',
20
+ 'inventory.classify',
21
+ 'scope.resolve',
22
+ 'profile.resolve',
23
+ 'lane.resolve',
24
+ 'plan.dry_run',
25
+ 'index.execute',
26
+ 'generation.verify',
27
+ ],
28
+ execution: {
29
+ lanes: ['local', 'remote', 'platform'],
30
+ model: 'optional',
31
+ embedding: 'optional',
32
+ network: 'optional',
33
+ sideEffects: 'local_write',
34
+ provider_spend: 'possible',
35
+ },
36
+ risk: 'write',
37
+ capabilities: ['knowledge.index', 'knowledge.search', 'repository.snapshot'],
38
+ artifacts: [
39
+ 'inventory.v1',
40
+ 'codebaseindex.job.graph.v1',
41
+ 'knowledge.generation',
42
+ ],
43
+ cli: { command: [['codebaseindex'], ['ingest']] },
44
+ docs: { section: 'Codebaseindex', examples: ['codebaseindex-ingest-wizard'] },
45
+ status: 'stable',
46
+ async handler(input = {}, ctx = {}) {
47
+ return runCodebaseindexIngest(input, ctx);
48
+ },
49
+ });
@@ -0,0 +1,59 @@
1
+ import { defineSamOperation } from '../define.js';
2
+ import { evaluate } from '../decision/evaluate.js';
3
+ import { getRegisteredQuestion, listRegisteredQuestions } from '../decision/questions.js';
4
+
5
+ export const decisionEvaluateOp = defineSamOperation({
6
+ id: 'decision.evaluate',
7
+ version: 1,
8
+ module: 'decision',
9
+ action: 'evaluate',
10
+ summary: 'Evaluate choose/score/check questions against a SAM decision state.',
11
+ purpose:
12
+ 'Run a batch of independent typed decision questions against one explicit state.',
13
+ outcome:
14
+ 'Return answers, routing, policy result, and an optional decision receipt (/why-compatible).',
15
+ description:
16
+ 'Systematic Autonomous Machinery decision layer. Prefer deterministic evaluators; semantic evaluators never invent calibrated probabilities.',
17
+ skill: { id: 'agentsam-app-fundamentals', help: true },
18
+ execution: {
19
+ lanes: ['local', 'remote', 'sandbox'],
20
+ model: 'optional',
21
+ embedding: 'never',
22
+ network: 'optional',
23
+ sideEffects: 'none',
24
+ provider_spend: 'possible',
25
+ },
26
+ risk: 'read_only',
27
+ capabilities: ['decision.evaluate', 'planning.goap'],
28
+ artifacts: ['decision.evaluation', 'decision.receipt'],
29
+ cli: { command: [] },
30
+ docs: { section: 'Decision', examples: ['decision-evaluate-terminal'] },
31
+ status: 'stable',
32
+ async handler(input = {}, ctx = {}) {
33
+ const questions = Array.isArray(input.questions)
34
+ ? input.questions.map((q) => {
35
+ if (typeof q === 'string') return getRegisteredQuestion(q, input.overrides?.[q] || {});
36
+ if (q && typeof q === 'object' && typeof q.id === 'string' && !q.type) {
37
+ return getRegisteredQuestion(q.id, q);
38
+ }
39
+ return q;
40
+ })
41
+ : listRegisteredQuestions().slice(0, 0);
42
+
43
+ if (!questions.length) {
44
+ const err = new Error('decision.evaluate requires questions[]');
45
+ err.code = 'invalid_input';
46
+ throw err;
47
+ }
48
+
49
+ return evaluate({
50
+ state: input.state || {},
51
+ questions,
52
+ policy: input.policy || {},
53
+ receipt: input.receipt !== false,
54
+ action: input.action,
55
+ evaluators: input.evaluators,
56
+ signal: ctx.signal,
57
+ });
58
+ },
59
+ });