@smartmemory/stratum 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/cli/guard.js +91 -0
  2. package/dist/cli/guard.js.map +1 -0
  3. package/dist/cli/mcp_install.js +302 -0
  4. package/dist/cli/mcp_install.js.map +1 -0
  5. package/dist/cli/query_gate.js +316 -0
  6. package/dist/cli/query_gate.js.map +1 -0
  7. package/dist/cli/stratum.js +291 -0
  8. package/dist/cli/stratum.js.map +1 -0
  9. package/dist/connectors/background.js +531 -0
  10. package/dist/connectors/background.js.map +1 -0
  11. package/dist/connectors/base.js +12 -0
  12. package/dist/connectors/base.js.map +1 -0
  13. package/dist/connectors/claude-bg-worker.js +99 -0
  14. package/dist/connectors/claude-bg-worker.js.map +1 -0
  15. package/dist/connectors/claude.js +170 -0
  16. package/dist/connectors/claude.js.map +1 -0
  17. package/dist/connectors/codex.js +319 -0
  18. package/dist/connectors/codex.js.map +1 -0
  19. package/dist/connectors/index.js +7 -0
  20. package/dist/connectors/index.js.map +1 -0
  21. package/dist/connectors/proc_identity.js +90 -0
  22. package/dist/connectors/proc_identity.js.map +1 -0
  23. package/dist/connectors/runner.js +63 -0
  24. package/dist/connectors/runner.js.map +1 -0
  25. package/dist/contracts/events.json +65 -0
  26. package/dist/contracts/mcp-surface.json +215 -0
  27. package/dist/engine/checkpoint.js +50 -0
  28. package/dist/engine/checkpoint.js.map +1 -0
  29. package/dist/engine/engine.js +2356 -0
  30. package/dist/engine/engine.js.map +1 -0
  31. package/dist/engine/ledger.js +36 -0
  32. package/dist/engine/ledger.js.map +1 -0
  33. package/dist/engine/state.js +42 -0
  34. package/dist/engine/state.js.map +1 -0
  35. package/dist/eval/expr.js +679 -0
  36. package/dist/eval/expr.js.map +1 -0
  37. package/dist/eval/files.js +130 -0
  38. package/dist/eval/files.js.map +1 -0
  39. package/dist/guard/canonical.js +116 -0
  40. package/dist/guard/canonical.js.map +1 -0
  41. package/dist/guard/errors.js +80 -0
  42. package/dist/guard/errors.js.map +1 -0
  43. package/dist/guard/evidence.js +475 -0
  44. package/dist/guard/evidence.js.map +1 -0
  45. package/dist/guard/fingerprint.js +13 -0
  46. package/dist/guard/fingerprint.js.map +1 -0
  47. package/dist/guard/lock.js +360 -0
  48. package/dist/guard/lock.js.map +1 -0
  49. package/dist/guard/store.js +396 -0
  50. package/dist/guard/store.js.map +1 -0
  51. package/dist/guard/transition.js +477 -0
  52. package/dist/guard/transition.js.map +1 -0
  53. package/dist/ir/refs.js +69 -0
  54. package/dist/ir/refs.js.map +1 -0
  55. package/dist/ir/schema.js +123 -0
  56. package/dist/ir/schema.js.map +1 -0
  57. package/dist/ir/validate.js +595 -0
  58. package/dist/ir/validate.js.map +1 -0
  59. package/dist/judge/codex_judged.js +85 -0
  60. package/dist/judge/codex_judged.js.map +1 -0
  61. package/dist/judge/fixture_judged.js +62 -0
  62. package/dist/judge/fixture_judged.js.map +1 -0
  63. package/dist/judge/judged.js +89 -0
  64. package/dist/judge/judged.js.map +1 -0
  65. package/dist/judge/pricing.js +22 -0
  66. package/dist/judge/pricing.js.map +1 -0
  67. package/dist/mcp/contracts.js +162 -0
  68. package/dist/mcp/contracts.js.map +1 -0
  69. package/dist/mcp/main.js +7 -0
  70. package/dist/mcp/main.js.map +1 -0
  71. package/dist/mcp/server.js +370 -0
  72. package/dist/mcp/server.js.map +1 -0
  73. package/dist/migrate/check.js +164 -0
  74. package/dist/migrate/check.js.map +1 -0
  75. package/dist/parallel/certificate.js +37 -0
  76. package/dist/parallel/certificate.js.map +1 -0
  77. package/dist/parallel/evaluate.js +73 -0
  78. package/dist/parallel/evaluate.js.map +1 -0
  79. package/dist/speckit/compiler.js +162 -0
  80. package/dist/speckit/compiler.js.map +1 -0
  81. package/package.json +47 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificate.js","sourceRoot":"","sources":["../../src/parallel/certificate.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAsB,EAAE,MAA+B;IACzF,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACxE,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC;IAEzC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,UAAU,CAAC,IAAI,CAAC,gCAAgC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,iBAAiB,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QAC7C,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACjD,IAAI,CAAC,UAAU;YAAE,OAAO,UAAU,CAAC;QACnC,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;QACnE,IAAI,eAAe,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC;YAC9E,UAAU,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAG,MAAiB;IAC/C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IAClE,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { validateCertificate } from "./certificate.js";
2
+ /** Evaluate a non-pipeline parallel_dispatch result without mutating its input. */
3
+ export function evaluateParallel(input) {
4
+ const [mergeStatusStr, conflictBounces] = normalizeMergeStatus(input.mergeStatus);
5
+ const bouncedTasks = [...input.gateBounces, ...conflictBounces];
6
+ const effectiveCert = input.certTemplate && input.agentIsClaude ? input.certTemplate : null;
7
+ const perTaskCertStrs = [];
8
+ const tasks = input.tasks.map((task) => {
9
+ if (task.status !== "complete" || effectiveCert === null)
10
+ return { ...task };
11
+ const violations = validateCertificate(effectiveCert, task.result ?? {});
12
+ if (violations.length === 0)
13
+ return { ...task };
14
+ perTaskCertStrs.push(`task '${task.task_id}' cert: ${violations.join("; ")}`);
15
+ return {
16
+ ...task,
17
+ status: "failed",
18
+ error: `cert validation: ${violations.join("; ")}`,
19
+ cert_violations: violations,
20
+ };
21
+ });
22
+ const completed = tasks.filter((task) => task.status === "complete");
23
+ // Non-pipeline skipped tasks remain failures so clients cannot bypass require:all.
24
+ const failed = tasks.filter((task) => task.status !== "complete");
25
+ const requireSatisfied = isRequireSatisfied(input.require, completed, failed);
26
+ const mergeOk = mergeStatusStr !== "conflict";
27
+ for (const bounce of bouncedTasks) {
28
+ if (bounce.reason === "gate_failed") {
29
+ perTaskCertStrs.push(`task '${bounce.taskId}' failed pre-merge gate \`${bounce.command}\` `
30
+ + `(exit ${pythonValue(bounce.exitCode)}) — diff NOT merged`);
31
+ }
32
+ else if (bounce.reason === "merge_conflict") {
33
+ const files = bounce.files.join(", ") || "(unknown files)";
34
+ perTaskCertStrs.push(`task '${bounce.taskId}' merge conflict on ${files}`);
35
+ }
36
+ }
37
+ const aggregate = {
38
+ tasks,
39
+ merge_status: mergeStatusStr,
40
+ completed,
41
+ failed,
42
+ outcome: requireSatisfied && mergeOk ? "complete" : "failed",
43
+ };
44
+ const evaluation = {
45
+ aggregate,
46
+ per_task_cert_strs: perTaskCertStrs,
47
+ bounced_tasks: bouncedTasks,
48
+ require: input.require,
49
+ completed,
50
+ failed,
51
+ require_satisfied: requireSatisfied,
52
+ merge_ok: mergeOk,
53
+ };
54
+ return { canAdvance: requireSatisfied && mergeOk, tasks, evaluation };
55
+ }
56
+ function normalizeMergeStatus(mergeStatus) {
57
+ if (typeof mergeStatus === "string")
58
+ return [mergeStatus, []];
59
+ return [mergeStatus.status ?? "clean", mergeStatus.bounced_tasks ?? []];
60
+ }
61
+ function isRequireSatisfied(require, completed, failed) {
62
+ if (require === "all")
63
+ return failed.length === 0;
64
+ if (require === "any")
65
+ return completed.length > 0;
66
+ if (typeof require === "number" && Number.isInteger(require))
67
+ return completed.length >= require;
68
+ return failed.length === 0;
69
+ }
70
+ function pythonValue(value) {
71
+ return value ?? "None";
72
+ }
73
+ //# sourceMappingURL=evaluate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../src/parallel/evaluate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,162 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { basename, join, parse as parsePath } from "node:path";
3
+ import { stringify } from "yaml";
4
+ import { validateSpec } from "../ir/validate.js";
5
+ export class SpeckitCompileError extends Error {
6
+ kind;
7
+ constructor(kind, message) {
8
+ super(message);
9
+ this.kind = kind;
10
+ this.name = "SpeckitCompileError";
11
+ }
12
+ }
13
+ const FILE_EXISTS_RE = /^file\s+(\S+)\s+exists?$/i;
14
+ const FILE_CONTAINS_RE = /^file\s+(\S+)\s+contains?\s+(?:"([^"]+)"|'([^']+)'|(\S+))$/i;
15
+ const TESTS_PASS_RE = /\btests?\b.*\bpass/i;
16
+ const LINT_RE = /(no lint errors?|lint (passes?|clean))/i;
17
+ export function criterionToEnsure(text) {
18
+ const criterion = text.trim();
19
+ const exists = FILE_EXISTS_RE.exec(criterion);
20
+ if (exists?.[1])
21
+ return { file_exists: exists[1] };
22
+ const contains = FILE_CONTAINS_RE.exec(criterion);
23
+ if (contains?.[1]) {
24
+ const substring = (contains[2] ?? contains[3] ?? contains[4]).replaceAll("\"", "\\\"");
25
+ return { file_contains: { path: contains[1], text: substring } };
26
+ }
27
+ if (TESTS_PASS_RE.test(criterion))
28
+ return { expr: "result.tests_pass == true" };
29
+ if (LINT_RE.test(criterion))
30
+ return { expr: "result.lint_clean == true" };
31
+ return null;
32
+ }
33
+ export function stepIdFromStem(stem) {
34
+ let slug = stem.toLowerCase().replace(/[^a-z0-9]/g, "_").replace(/^_+|_+$/g, "");
35
+ if (slug && !/^[a-z]/.test(slug))
36
+ slug = `t${slug}`;
37
+ return slug || "task";
38
+ }
39
+ export async function parseTaskFile(path) {
40
+ const lines = (await readFile(path, "utf8")).split(/\r?\n/);
41
+ let titleRaw = "";
42
+ let titleLineIndex = 0;
43
+ for (const [index, line] of lines.entries()) {
44
+ if (line.trimStart().startsWith("#")) {
45
+ titleRaw = line.trim().replace(/^#+\s*(?:Task:\s*)?/, "");
46
+ titleLineIndex = index;
47
+ break;
48
+ }
49
+ }
50
+ const isParallel = /\[P\]/i.test(titleRaw);
51
+ const title = titleRaw.replace(/\s*\[P\]\s*/gi, " ").trim();
52
+ const criteriaStart = lines.findIndex((line) => /^#+\s*Acceptance Criteria/i.test(line));
53
+ const description = lines.slice(titleLineIndex + 1, criteriaStart < 0 ? lines.length : criteriaStart).join("\n").trim();
54
+ const rawCriteria = [];
55
+ if (criteriaStart >= 0) {
56
+ for (const line of lines.slice(criteriaStart + 1)) {
57
+ const match = /^\s*-\s*\[[ xX]\]\s*(.+)/.exec(line);
58
+ if (match?.[1])
59
+ rawCriteria.push(match[1].trim());
60
+ }
61
+ }
62
+ const ensures = [];
63
+ const judgment = [];
64
+ let needsTestsPass = false;
65
+ let needsLintClean = false;
66
+ for (const criterion of rawCriteria) {
67
+ const ensure = criterionToEnsure(criterion);
68
+ if (ensure === null) {
69
+ judgment.push(criterion);
70
+ continue;
71
+ }
72
+ ensures.push(ensure);
73
+ if ("expr" in ensure && ensure.expr.includes("tests_pass"))
74
+ needsTestsPass = true;
75
+ if ("expr" in ensure && ensure.expr.includes("lint_clean"))
76
+ needsLintClean = true;
77
+ }
78
+ return {
79
+ filename: basename(path), stepId: stepIdFromStem(parsePath(path).name), title, description, isParallel,
80
+ ensures, judgment, needsTestsPass, needsLintClean,
81
+ };
82
+ }
83
+ export function buildDependencyGraph(tasks) {
84
+ const dependencies = {};
85
+ let lastSequential;
86
+ let currentParallelGroup = [];
87
+ for (const task of tasks) {
88
+ if (task.isParallel) {
89
+ dependencies[task.stepId] = lastSequential ? [lastSequential] : [];
90
+ currentParallelGroup.push(task.stepId);
91
+ continue;
92
+ }
93
+ const after = currentParallelGroup.length > 0 ? [...currentParallelGroup] : lastSequential ? [lastSequential] : [];
94
+ currentParallelGroup = [];
95
+ dependencies[task.stepId] = after;
96
+ lastSequential = task.stepId;
97
+ }
98
+ return dependencies;
99
+ }
100
+ export function buildSpec(tasks, flowName = "tasks") {
101
+ if (tasks.length === 0)
102
+ throw new SpeckitCompileError("no_tasks", "No task files (*.md) supplied");
103
+ // "entry" is the reserved string sentinel that names the entry flow; a computed
104
+ // { entry: name, [name]: flow } would overwrite it with the flow object.
105
+ if (flowName === "entry")
106
+ throw new SpeckitCompileError("compile_error", "flow_name 'entry' is reserved (it names the entry-flow sentinel); choose another name");
107
+ const dependencies = buildDependencyGraph(tasks);
108
+ const steps = tasks.map((task) => {
109
+ const intent = [task.title, ...(task.description ? [task.description] : []), ...(task.judgment.length ? [`Also verify: ${task.judgment.join("; ")}`] : [])].join("\n");
110
+ const after = dependencies[task.stepId] ?? [];
111
+ return {
112
+ id: task.stepId,
113
+ do: intent,
114
+ out: "TaskResult",
115
+ ensure: [...task.ensures, { expr: "result.done == true" }],
116
+ attempts: 3,
117
+ ...(after.length ? { after } : {}),
118
+ };
119
+ });
120
+ const lastTask = tasks.at(-1);
121
+ const flow = {
122
+ input: { project_context: "string" },
123
+ output: { from: `\${${lastTask.stepId}.output}`, contract: "TaskResult" },
124
+ steps,
125
+ };
126
+ return {
127
+ version: 1,
128
+ contracts: { TaskResult: { done: "boolean", tests_pass: "boolean?", lint_clean: "boolean?" } },
129
+ flows: { entry: flowName, [flowName]: flow },
130
+ };
131
+ }
132
+ export async function compileSpeckit(tasksDir, flowName = "tasks") {
133
+ const taskFiles = (await readdir(tasksDir)).filter((name) => name.endsWith(".md")).sort();
134
+ if (taskFiles.length === 0)
135
+ throw new SpeckitCompileError("no_tasks", `No task files (*.md) found in ${tasksDir}`);
136
+ const tasks = await Promise.all(taskFiles.map((filename) => parseTaskFile(join(tasksDir, filename))));
137
+ const seen = new Map();
138
+ for (const task of tasks) {
139
+ const first = seen.get(task.stepId);
140
+ if (first) {
141
+ throw new SpeckitCompileError("step_id_collision", `Step ID collision: '${task.stepId}' from '${task.filename}' conflicts with '${first}'. Rename one of the files to produce a distinct step ID.`);
142
+ }
143
+ seen.set(task.stepId, task.filename);
144
+ }
145
+ const spec = buildSpec(tasks, flowName);
146
+ // The tool's contract is "return YAML you pass straight to stratum_plan", so never
147
+ // return `ok` with un-plannable IR. The most common cause is `${...}` in task text:
148
+ // the TS engine interprets it as a reference (there is no literal escape), so
149
+ // ordinary shell/template snippets fail REF_INVALID. Surface that at compile time.
150
+ const validation = validateSpec(spec);
151
+ if (!validation.ok) {
152
+ const first = validation.errors[0];
153
+ const detail = first ? `${first.code} at ${first.path}: ${first.message}` : "unknown validation error";
154
+ throw new SpeckitCompileError("compile_error", `generated spec failed validation (${detail}). Task text containing '\${...}' template syntax is not supported by the TS engine's reference resolver — remove or reword it.`);
155
+ }
156
+ return {
157
+ yaml: stringify(spec),
158
+ flowName,
159
+ steps: tasks.map((task) => ({ id: task.stepId, title: task.title, parallel: task.isParallel, ensures: task.ensures, judgment: task.judgment })),
160
+ };
161
+ }
162
+ //# sourceMappingURL=compiler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compiler.js","sourceRoot":"","sources":["../../src/speckit/compiler.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@smartmemory/stratum",
3
+ "version": "0.3.0",
4
+ "description": "Stratum engine — typed, resumable, postcondition-enforced workflows for AI agents (TypeScript port)",
5
+ "type": "module",
6
+ "bin": {
7
+ "stratum": "./dist/cli/stratum.js",
8
+ "stratum-mcp": "./dist/mcp/main.js"
9
+ },
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "engines": {
17
+ "node": ">=22.15"
18
+ },
19
+ "scripts": {
20
+ "build": "node scripts/prepare-dist.mjs --clean && tsc -p tsconfig.build.json && node scripts/prepare-dist.mjs",
21
+ "prepack": "npm run build",
22
+ "test": "vitest run",
23
+ "typecheck": "tsc --noEmit"
24
+ },
25
+ "dependencies": {
26
+ "@ai-sdk/anthropic": "^4.0.11",
27
+ "@ai-sdk/openai": "^4.0.11",
28
+ "@anthropic-ai/claude-agent-sdk": "0.3.206",
29
+ "@modelcontextprotocol/sdk": "^1.29.0",
30
+ "@openai/codex-sdk": "0.144.3",
31
+ "ai": "^7.0.19",
32
+ "js-tiktoken": "^1.0.21",
33
+ "yaml": "^2.9.0",
34
+ "zod": "^3.25.0"
35
+ },
36
+ "overrides": {
37
+ "@anthropic-ai/sdk": "0.110.0",
38
+ "@anthropic-ai/claude-agent-sdk": {
39
+ "zod": "$zod"
40
+ }
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.15.0",
44
+ "typescript": "^5.8.0",
45
+ "vitest": "^3.2.0"
46
+ }
47
+ }