martin-loop 0.1.5 → 1.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.
- package/CODE_OF_CONDUCT.md +32 -0
- package/LICENSE +21 -21
- package/README.md +307 -398
- package/demo/seeded-workspace/README.md +35 -35
- package/demo/seeded-workspace/TASKS.md +29 -29
- package/demo/seeded-workspace/martin.config.yaml +11 -11
- package/demo/seeded-workspace/package.json +8 -8
- package/demo/seeded-workspace/src/invoice-summary.js +11 -11
- package/demo/seeded-workspace/test/invoice-summary.test.js +20 -20
- package/dist/bin/martin-loop.js +0 -0
- package/dist/vendor/adapters/counter.d.ts +1 -0
- package/dist/vendor/adapters/counter.js +4 -0
- package/dist/vendor/adapters/git-baseline.d.ts +50 -0
- package/dist/vendor/adapters/git-baseline.js +233 -0
- package/dist/vendor/adapters/openrouter-adapter.d.ts +15 -0
- package/dist/vendor/adapters/openrouter-adapter.js +302 -0
- package/dist/vendor/adapters/usage.d.ts +48 -0
- package/dist/vendor/adapters/usage.js +66 -0
- package/dist/vendor/cli/bin/exit.d.ts +12 -0
- package/dist/vendor/cli/bin/exit.js +28 -0
- package/dist/vendor/cli/commands/analyze.d.ts +5 -0
- package/dist/vendor/cli/commands/analyze.js +58 -0
- package/dist/vendor/cli/commands/audit-log-verify.d.ts +34 -0
- package/dist/vendor/cli/commands/audit-log-verify.js +99 -0
- package/dist/vendor/cli/commands/audit.d.ts +8 -0
- package/dist/vendor/cli/commands/audit.js +199 -0
- package/dist/vendor/cli/commands/corpus.d.ts +5 -0
- package/dist/vendor/cli/commands/corpus.js +60 -0
- package/dist/vendor/cli/commands/doctor.d.ts +8 -0
- package/dist/vendor/cli/commands/doctor.js +219 -0
- package/dist/vendor/cli/commands/explain.d.ts +17 -0
- package/dist/vendor/cli/commands/explain.js +176 -0
- package/dist/vendor/cli/commands/export.d.ts +5 -0
- package/dist/vendor/cli/commands/export.js +60 -0
- package/dist/vendor/cli/commands/governance.d.ts +8 -0
- package/dist/vendor/cli/commands/governance.js +95 -0
- package/dist/vendor/cli/commands/improve.d.ts +18 -0
- package/dist/vendor/cli/commands/improve.js +396 -0
- package/dist/vendor/cli/commands/init.d.ts +8 -0
- package/dist/vendor/cli/commands/init.js +281 -0
- package/dist/vendor/cli/commands/migration.d.ts +8 -0
- package/dist/vendor/cli/commands/migration.js +67 -0
- package/dist/vendor/cli/commands/prior.d.ts +23 -0
- package/dist/vendor/cli/commands/prior.js +145 -0
- package/dist/vendor/cli/commands/resume.d.ts +21 -0
- package/dist/vendor/cli/commands/resume.js +73 -0
- package/dist/vendor/cli/commands/verify.d.ts +6 -0
- package/dist/vendor/cli/commands/verify.js +43 -0
- package/dist/vendor/cli/research/public-corpus.d.ts +43 -0
- package/dist/vendor/cli/research/public-corpus.js +151 -0
- package/dist/vendor/cli/ui/error-card.d.ts +38 -0
- package/dist/vendor/cli/ui/error-card.js +103 -0
- package/dist/vendor/cli/ui/mission-brief.d.ts +41 -0
- package/dist/vendor/cli/ui/mission-brief.js +173 -0
- package/dist/vendor/cli/ui/summary-card.d.ts +34 -0
- package/dist/vendor/cli/ui/summary-card.js +102 -0
- package/dist/vendor/contracts/audit.d.ts +46 -0
- package/dist/vendor/contracts/audit.js +360 -0
- package/dist/vendor/contracts/post-phase15.d.ts +240 -0
- package/dist/vendor/contracts/post-phase15.js +166 -0
- package/dist/vendor/core/agent/mandates.d.ts +46 -0
- package/dist/vendor/core/agent/mandates.js +178 -0
- package/dist/vendor/core/agent/receipts.d.ts +38 -0
- package/dist/vendor/core/agent/receipts.js +131 -0
- package/dist/vendor/core/agent/signing.d.ts +17 -0
- package/dist/vendor/core/agent/signing.js +91 -0
- package/dist/vendor/core/attestation/sign.d.ts +25 -0
- package/dist/vendor/core/attestation/sign.js +216 -0
- package/dist/vendor/core/autonomy/autonomous-promotion.d.ts +120 -0
- package/dist/vendor/core/autonomy/autonomous-promotion.js +346 -0
- package/dist/vendor/core/autonomy/envelope-v2.d.ts +29 -0
- package/dist/vendor/core/autonomy/envelope-v2.js +60 -0
- package/dist/vendor/core/autonomy/envelope.d.ts +17 -0
- package/dist/vendor/core/autonomy/envelope.js +27 -0
- package/dist/vendor/core/autonomy/escalation-ledger.d.ts +20 -0
- package/dist/vendor/core/autonomy/escalation-ledger.js +18 -0
- package/dist/vendor/core/autonomy/resume.d.ts +15 -0
- package/dist/vendor/core/autonomy/resume.js +23 -0
- package/dist/vendor/core/circuit/circuit-breaker.d.ts +60 -0
- package/dist/vendor/core/circuit/circuit-breaker.js +143 -0
- package/dist/vendor/core/context-distillation.d.ts +3 -0
- package/dist/vendor/core/context-distillation.js +44 -0
- package/dist/vendor/core/context-flow/compile-context.d.ts +8 -0
- package/dist/vendor/core/context-flow/compile-context.js +111 -0
- package/dist/vendor/core/context-flow/entities.d.ts +2 -0
- package/dist/vendor/core/context-flow/entities.js +44 -0
- package/dist/vendor/core/context-flow/evaluate-policy.d.ts +2 -0
- package/dist/vendor/core/context-flow/evaluate-policy.js +42 -0
- package/dist/vendor/core/context-flow/index.d.ts +11 -0
- package/dist/vendor/core/context-flow/index.js +24 -0
- package/dist/vendor/core/context-flow/labels.d.ts +3 -0
- package/dist/vendor/core/context-flow/labels.js +17 -0
- package/dist/vendor/core/context-flow/normalizer.d.ts +9 -0
- package/dist/vendor/core/context-flow/normalizer.js +69 -0
- package/dist/vendor/core/context-flow/profiles.d.ts +33 -0
- package/dist/vendor/core/context-flow/profiles.js +36 -0
- package/dist/vendor/core/context-flow/redaction.d.ts +1 -0
- package/dist/vendor/core/context-flow/redaction.js +6 -0
- package/dist/vendor/core/context-flow/sensitivity.d.ts +2 -0
- package/dist/vendor/core/context-flow/sensitivity.js +27 -0
- package/dist/vendor/core/context-flow/sync-preview.d.ts +2 -0
- package/dist/vendor/core/context-flow/sync-preview.js +22 -0
- package/dist/vendor/core/context-flow/token-estimator.d.ts +3 -0
- package/dist/vendor/core/context-flow/token-estimator.js +13 -0
- package/dist/vendor/core/context-flow/types.d.ts +91 -0
- package/dist/vendor/core/context-flow/types.js +2 -0
- package/dist/vendor/core/context-utility.d.ts +47 -0
- package/dist/vendor/core/context-utility.js +405 -0
- package/dist/vendor/core/cost/pipeline.d.ts +92 -0
- package/dist/vendor/core/cost/pipeline.js +141 -0
- package/dist/vendor/core/cost/tagged-cost.d.ts +27 -0
- package/dist/vendor/core/cost/tagged-cost.js +55 -0
- package/dist/vendor/core/cost-governor.d.ts +2 -0
- package/dist/vendor/core/cost-governor.js +50 -0
- package/dist/vendor/core/cve/cve-check.d.ts +80 -0
- package/dist/vendor/core/cve/cve-check.js +172 -0
- package/dist/vendor/core/digital-twin/index.d.ts +27 -0
- package/dist/vendor/core/digital-twin/index.js +90 -0
- package/dist/vendor/core/drift/drift-graph.d.ts +47 -0
- package/dist/vendor/core/drift/drift-graph.js +100 -0
- package/dist/vendor/core/drift/objective-lock.d.ts +69 -0
- package/dist/vendor/core/drift/objective-lock.js +88 -0
- package/dist/vendor/core/drift/scope.d.ts +46 -0
- package/dist/vendor/core/drift/scope.js +102 -0
- package/dist/vendor/core/drift/signature-lock.d.ts +48 -0
- package/dist/vendor/core/drift/signature-lock.js +202 -0
- package/dist/vendor/core/drift/stale-proof-gate.d.ts +21 -0
- package/dist/vendor/core/drift/stale-proof-gate.js +19 -0
- package/dist/vendor/core/eval/known-bad-world-runner.d.ts +24 -0
- package/dist/vendor/core/eval/known-bad-world-runner.js +256 -0
- package/dist/vendor/core/evidence/claim-audit.d.ts +18 -0
- package/dist/vendor/core/evidence/claim-audit.js +89 -0
- package/dist/vendor/core/exit-intelligence.d.ts +2 -0
- package/dist/vendor/core/exit-intelligence.js +58 -0
- package/dist/vendor/core/explain/formatter.d.ts +42 -0
- package/dist/vendor/core/explain/formatter.js +171 -0
- package/dist/vendor/core/explain/timeline.d.ts +29 -0
- package/dist/vendor/core/explain/timeline.js +213 -0
- package/dist/vendor/core/failure-taxonomy.d.ts +2 -0
- package/dist/vendor/core/failure-taxonomy.js +76 -0
- package/dist/vendor/core/gateway/index.d.ts +10 -0
- package/dist/vendor/core/gateway/index.js +12 -0
- package/dist/vendor/core/gateway/registry.d.ts +40 -0
- package/dist/vendor/core/gateway/registry.js +97 -0
- package/dist/vendor/core/gateway/transport.d.ts +31 -0
- package/dist/vendor/core/gateway/transport.js +82 -0
- package/dist/vendor/core/gateway/vault.d.ts +19 -0
- package/dist/vendor/core/gateway/vault.js +29 -0
- package/dist/vendor/core/graph/adapters.d.ts +43 -0
- package/dist/vendor/core/graph/adapters.js +91 -0
- package/dist/vendor/core/graph/hotspots.d.ts +22 -0
- package/dist/vendor/core/graph/hotspots.js +30 -0
- package/dist/vendor/core/graph/index.d.ts +1 -0
- package/dist/vendor/core/graph/index.js +2 -0
- package/dist/vendor/core/honey/honey-tokens.d.ts +32 -0
- package/dist/vendor/core/honey/honey-tokens.js +44 -0
- package/dist/vendor/core/index.d.ts +2 -2
- package/dist/vendor/core/index.js +38 -12
- package/dist/vendor/core/learning/bayesian-update.d.ts +31 -0
- package/dist/vendor/core/learning/bayesian-update.js +60 -0
- package/dist/vendor/core/learning/prior-sets.d.ts +42 -0
- package/dist/vendor/core/learning/prior-sets.js +111 -0
- package/dist/vendor/core/learning/promotion-gate.d.ts +17 -0
- package/dist/vendor/core/learning/promotion-gate.js +23 -0
- package/dist/vendor/core/leash/blast-radius.d.ts +42 -0
- package/dist/vendor/core/leash/blast-radius.js +156 -0
- package/dist/vendor/core/leash/policy-leash.d.ts +31 -0
- package/dist/vendor/core/leash/policy-leash.js +117 -0
- package/dist/vendor/core/memo/memo.d.ts +63 -0
- package/dist/vendor/core/memo/memo.js +97 -0
- package/dist/vendor/core/memory/learning-pipeline.d.ts +154 -0
- package/dist/vendor/core/memory/learning-pipeline.js +391 -0
- package/dist/vendor/core/memory/palace.d.ts +84 -0
- package/dist/vendor/core/memory/palace.js +379 -0
- package/dist/vendor/core/merge/ast-merge.d.ts +22 -0
- package/dist/vendor/core/merge/ast-merge.js +350 -0
- package/dist/vendor/core/merge/text-merge.d.ts +12 -0
- package/dist/vendor/core/merge/text-merge.js +182 -0
- package/dist/vendor/core/otel/tracer.d.ts +45 -0
- package/dist/vendor/core/otel/tracer.js +116 -0
- package/dist/vendor/core/parallel/parallel-attempts.d.ts +28 -0
- package/dist/vendor/core/parallel/parallel-attempts.js +41 -0
- package/dist/vendor/core/parallel/scorer.d.ts +24 -0
- package/dist/vendor/core/parallel/scorer.js +65 -0
- package/dist/vendor/core/pattern-detection.d.ts +64 -0
- package/dist/vendor/core/pattern-detection.js +108 -0
- package/dist/vendor/core/persistence/checkpoint.d.ts +44 -0
- package/dist/vendor/core/persistence/checkpoint.js +156 -0
- package/dist/vendor/core/persistence/cleanup.d.ts +22 -0
- package/dist/vendor/core/persistence/cleanup.js +131 -0
- package/dist/vendor/core/persistence/index.d.ts +2 -0
- package/dist/vendor/core/persistence/index.js +1 -0
- package/dist/vendor/core/persistence/runs-reader.d.ts +52 -0
- package/dist/vendor/core/persistence/runs-reader.js +84 -0
- package/dist/vendor/core/persistence/store.d.ts +6 -1
- package/dist/vendor/core/persistence/store.js +5 -0
- package/dist/vendor/core/policy/file-touch-quota.d.ts +60 -0
- package/dist/vendor/core/policy/file-touch-quota.js +105 -0
- package/dist/vendor/core/policy/policy-loader.d.ts +30 -0
- package/dist/vendor/core/policy/policy-loader.js +170 -0
- package/dist/vendor/core/policy/policy-schema.d.ts +55 -0
- package/dist/vendor/core/policy/policy-schema.js +78 -0
- package/dist/vendor/core/probe/probe.d.ts +49 -0
- package/dist/vendor/core/probe/probe.js +115 -0
- package/dist/vendor/core/proof/patch-proof.d.ts +58 -0
- package/dist/vendor/core/proof/patch-proof.js +84 -0
- package/dist/vendor/core/proof/semantic-probe.d.ts +25 -0
- package/dist/vendor/core/proof/semantic-probe.js +82 -0
- package/dist/vendor/core/recovery/failure-mode-runner.d.ts +29 -0
- package/dist/vendor/core/recovery/failure-mode-runner.js +39 -0
- package/dist/vendor/core/red-blue/red-phase.d.ts +64 -0
- package/dist/vendor/core/red-blue/red-phase.js +141 -0
- package/dist/vendor/core/red-blue/risk-tiers.d.ts +22 -0
- package/dist/vendor/core/red-blue/risk-tiers.js +33 -0
- package/dist/vendor/core/replay/replay.d.ts +85 -0
- package/dist/vendor/core/replay/replay.js +109 -0
- package/dist/vendor/core/router/engine.d.ts +54 -0
- package/dist/vendor/core/router/engine.js +131 -0
- package/dist/vendor/core/router/index.d.ts +1 -0
- package/dist/vendor/core/router/index.js +2 -0
- package/dist/vendor/core/router/trust-calibration.d.ts +57 -0
- package/dist/vendor/core/router/trust-calibration.js +127 -0
- package/dist/vendor/core/run-martin.d.ts +2 -0
- package/dist/vendor/core/run-martin.js +287 -0
- package/dist/vendor/core/security/cve-scanner.d.ts +62 -0
- package/dist/vendor/core/security/cve-scanner.js +178 -0
- package/dist/vendor/core/sentinel/efficiency-sentinel.d.ts +29 -0
- package/dist/vendor/core/sentinel/efficiency-sentinel.js +30 -0
- package/dist/vendor/core/sentinel/progress-guard.d.ts +35 -0
- package/dist/vendor/core/sentinel/progress-guard.js +46 -0
- package/dist/vendor/core/siem/siem-emitter.d.ts +49 -0
- package/dist/vendor/core/siem/siem-emitter.js +157 -0
- package/dist/vendor/core/strategy/attempt-brief.d.ts +22 -0
- package/dist/vendor/core/strategy/attempt-brief.js +89 -0
- package/dist/vendor/core/summarize/diff-summary.d.ts +35 -0
- package/dist/vendor/core/summarize/diff-summary.js +204 -0
- package/dist/vendor/core/surface-signals.d.ts +21 -0
- package/dist/vendor/core/surface-signals.js +139 -0
- package/dist/vendor/core/truth/truth-wall.d.ts +51 -0
- package/dist/vendor/core/truth/truth-wall.js +69 -0
- package/dist/vendor/core/truth-spine.d.ts +26 -0
- package/dist/vendor/core/truth-spine.js +62 -0
- package/dist/vendor/core/types.d.ts +115 -0
- package/dist/vendor/core/types.js +2 -0
- package/dist/vendor/core/verification/tiered-verify.d.ts +17 -0
- package/dist/vendor/core/verification/tiered-verify.js +29 -0
- package/dist/vendor/core/verifier-pyramid.d.ts +32 -0
- package/dist/vendor/core/verifier-pyramid.js +111 -0
- package/dist/vendor/core/workflow-artifacts.d.ts +99 -0
- package/dist/vendor/core/workflow-artifacts.js +668 -0
- package/dist/vendor/core/wrap/supervised-run.d.ts +96 -0
- package/dist/vendor/core/wrap/supervised-run.js +178 -0
- package/docs/assets/cli-animated.svg +139 -0
- package/docs/assets/cli-static.svg +34 -0
- package/docs/assets/github-hero-v2.svg +23 -0
- package/docs/assets/martin-raplph.png.jpg +0 -0
- package/docs/assets/martinloop-logo.png +0 -0
- package/docs/assets/nvidia-inception-program-light.png +0 -0
- package/docs/assets/nvidia-inception-program.png +0 -0
- package/docs/assets/phase3c-sidesidebyside-demo.html +228 -0
- package/docs/assets/side-by-side.svg +134 -0
- package/docs/oss/CLAUDE-CODE-WALKTHROUGH.md +142 -142
- package/docs/oss/EXAMPLES.md +134 -134
- package/docs/oss/OSS-BOUNDARY-REPORT.json +1 -1
- package/docs/oss/OSS-BOUNDARY-REPORT.md +1 -1
- package/docs/oss/QUICKSTART.md +170 -165
- package/docs/oss/RALPH-LOOP-SAFETY.md +113 -113
- package/docs/oss/README.md +96 -96
- package/docs/oss/RELEASE-SURFACE-REPORT.json +2 -1
- package/docs/oss/RELEASE-SURFACE-REPORT.md +2 -1
- package/package.json +130 -58
- package/docs/distribution/DIRECTORY-SUBMISSIONS.md +0 -89
- package/docs/distribution/INTEGRATION-OUTREACH.md +0 -61
- package/docs/distribution/UNDER-3-CHALLENGE.md +0 -65
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { appendFile, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { resolveMartinHome } from "../attestation/sign.js";
|
|
5
|
+
import { loadActiveLearningHeuristics, runPromotionPipeline } from "./learning-pipeline.js";
|
|
6
|
+
// ─── Stop words for relevance scoring ────────────────────────────────────────
|
|
7
|
+
const STOP_WORDS = new Set([
|
|
8
|
+
"a",
|
|
9
|
+
"an",
|
|
10
|
+
"and",
|
|
11
|
+
"are",
|
|
12
|
+
"for",
|
|
13
|
+
"from",
|
|
14
|
+
"into",
|
|
15
|
+
"keep",
|
|
16
|
+
"loop",
|
|
17
|
+
"not",
|
|
18
|
+
"the",
|
|
19
|
+
"this",
|
|
20
|
+
"that",
|
|
21
|
+
"with",
|
|
22
|
+
"without"
|
|
23
|
+
]);
|
|
24
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
25
|
+
export function resolveMemoryRoot(env = process.env) {
|
|
26
|
+
return env["MARTIN_MEMORY_DIR"]?.trim() || join(resolveMartinHome(), "memory");
|
|
27
|
+
}
|
|
28
|
+
export function createFileLoopMemoryStore(options = {}) {
|
|
29
|
+
const memoryRoot = options.memoryRoot ?? resolveMemoryRoot();
|
|
30
|
+
return {
|
|
31
|
+
async recall(input) {
|
|
32
|
+
const wingKey = buildWingKey(input.workspaceId, input.projectId);
|
|
33
|
+
const wingPath = join(memoryRoot, slugifyKey(wingKey));
|
|
34
|
+
const roomNames = await safeReaddir(wingPath);
|
|
35
|
+
const activeHeuristics = await loadActiveLearningHeuristics(memoryRoot);
|
|
36
|
+
if (roomNames.length === 0) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const queryTokens = buildQueryTokens(input.objective, input.focus, input.previousAttempts);
|
|
40
|
+
const lastAttempt = input.previousAttempts.at(-1);
|
|
41
|
+
const scoredEntries = [];
|
|
42
|
+
for (const roomName of roomNames) {
|
|
43
|
+
if (roomName === "wing.json") {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const drawers = await readDrawersFile(join(wingPath, roomName, "drawers.jsonl"));
|
|
47
|
+
for (const drawer of drawers) {
|
|
48
|
+
const { score, reason } = scoreDrawer(drawer, queryTokens, lastAttempt, activeHeuristics.recallScoring);
|
|
49
|
+
if (score <= 0) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
scoredEntries.push({
|
|
53
|
+
drawerId: drawer.drawerId,
|
|
54
|
+
roomKey: drawer.roomKey,
|
|
55
|
+
lesson: drawer.lesson,
|
|
56
|
+
content: drawer.content,
|
|
57
|
+
sourceRunId: drawer.sourceRunId,
|
|
58
|
+
...(drawer.sourceAttemptIndex !== undefined
|
|
59
|
+
? { sourceAttemptIndex: drawer.sourceAttemptIndex }
|
|
60
|
+
: {}),
|
|
61
|
+
score,
|
|
62
|
+
reason
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const entries = scoredEntries
|
|
67
|
+
.sort((left, right) => right.score - left.score)
|
|
68
|
+
.slice(0, Math.max(1, input.limit ?? 3));
|
|
69
|
+
if (entries.length === 0) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
if (input.currentRunId && input.currentAttemptIndex !== undefined) {
|
|
73
|
+
await persistRecallAudit({
|
|
74
|
+
memoryRoot,
|
|
75
|
+
wingKey,
|
|
76
|
+
runId: input.currentRunId,
|
|
77
|
+
attemptIndex: input.currentAttemptIndex,
|
|
78
|
+
entries
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
wingKey,
|
|
83
|
+
recalledAt: new Date().toISOString(),
|
|
84
|
+
entries
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
async recordLoop(input) {
|
|
88
|
+
const wingKey = buildWingKey(input.loop.workspaceId, input.loop.projectId);
|
|
89
|
+
const wingPath = join(memoryRoot, slugifyKey(wingKey));
|
|
90
|
+
const drawers = buildMemoryDrawers(input);
|
|
91
|
+
const grouped = new Map();
|
|
92
|
+
for (const drawer of drawers) {
|
|
93
|
+
const bucket = grouped.get(drawer.roomKey) ?? [];
|
|
94
|
+
bucket.push(drawer);
|
|
95
|
+
grouped.set(drawer.roomKey, bucket);
|
|
96
|
+
}
|
|
97
|
+
await mkdir(wingPath, { recursive: true });
|
|
98
|
+
await writeJsonFile(join(wingPath, "wing.json"), {
|
|
99
|
+
wingKey,
|
|
100
|
+
workspaceId: input.loop.workspaceId,
|
|
101
|
+
projectId: input.loop.projectId,
|
|
102
|
+
roomCount: grouped.size,
|
|
103
|
+
updatedAt: input.loop.updatedAt
|
|
104
|
+
});
|
|
105
|
+
for (const [roomKey, roomDrawers] of grouped.entries()) {
|
|
106
|
+
const roomPath = join(wingPath, slugifyKey(roomKey));
|
|
107
|
+
const previousDrawers = await readDrawersFile(join(roomPath, "drawers.jsonl"));
|
|
108
|
+
await mkdir(roomPath, { recursive: true });
|
|
109
|
+
await writeJsonFile(join(roomPath, "room.json"), {
|
|
110
|
+
wingKey,
|
|
111
|
+
roomKey,
|
|
112
|
+
roomTitle: roomDrawers[0]?.roomTitle ?? roomKey,
|
|
113
|
+
roomType: roomDrawers[0]?.outcome === "failure" ? "failure" : "outcome",
|
|
114
|
+
drawerCount: previousDrawers.length + roomDrawers.length,
|
|
115
|
+
lastRunId: input.loop.loopId,
|
|
116
|
+
updatedAt: input.loop.updatedAt
|
|
117
|
+
});
|
|
118
|
+
const payload = roomDrawers.map((drawer) => JSON.stringify(drawer)).join("\n");
|
|
119
|
+
await appendFile(join(roomPath, "drawers.jsonl"), `${payload}\n`, "utf8");
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
roomCount: grouped.size,
|
|
123
|
+
drawerCount: drawers.length
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
async recordPriorLearning(input) {
|
|
127
|
+
// Phase 30 — Guarded Promotion Pipeline
|
|
128
|
+
// Runs the full shadow → holdout → approval gate pipeline before any
|
|
129
|
+
// heuristic insight is promoted to active status. Fail-open: any error
|
|
130
|
+
// keeps existing heuristics active and appends to audit log only.
|
|
131
|
+
const auditPath = join(memoryRoot, "prior-learning-audit.jsonl");
|
|
132
|
+
try {
|
|
133
|
+
const candidateId = `cand_${createHash("sha256")
|
|
134
|
+
.update(JSON.stringify({ ...input, ts: Date.now() }))
|
|
135
|
+
.digest("hex")
|
|
136
|
+
.slice(0, 16)}`;
|
|
137
|
+
const existingScores = Array.isArray(input["existingScores"])
|
|
138
|
+
? input["existingScores"]
|
|
139
|
+
: [];
|
|
140
|
+
const candidateScores = Array.isArray(input["candidateScores"])
|
|
141
|
+
? input["candidateScores"]
|
|
142
|
+
: [];
|
|
143
|
+
const holdoutExistingScores = Array.isArray(input["holdoutExistingScores"])
|
|
144
|
+
? input["holdoutExistingScores"]
|
|
145
|
+
: [];
|
|
146
|
+
const holdoutCandidateScores = Array.isArray(input["holdoutCandidateScores"])
|
|
147
|
+
? input["holdoutCandidateScores"]
|
|
148
|
+
: [];
|
|
149
|
+
const candidate = {
|
|
150
|
+
candidateId,
|
|
151
|
+
sourceRunId: typeof input["sourceRunId"] === "string" ? input["sourceRunId"] : "unknown",
|
|
152
|
+
heuristicFamily: typeof input["heuristicFamily"] === "string" ? input["heuristicFamily"] : "recall_scoring",
|
|
153
|
+
description: typeof input["description"] === "string" ? input["description"] : "Prior learning candidate",
|
|
154
|
+
payload: input,
|
|
155
|
+
status: "pending_shadow",
|
|
156
|
+
createdAt: new Date().toISOString()
|
|
157
|
+
};
|
|
158
|
+
const result = await runPromotionPipeline({
|
|
159
|
+
candidate,
|
|
160
|
+
existingScores,
|
|
161
|
+
candidateScores,
|
|
162
|
+
holdoutExistingScores,
|
|
163
|
+
holdoutCandidateScores,
|
|
164
|
+
pipelineRoot: memoryRoot
|
|
165
|
+
});
|
|
166
|
+
const auditEntry = JSON.stringify({
|
|
167
|
+
candidateId,
|
|
168
|
+
promoted: result.promoted,
|
|
169
|
+
reason: result.reason,
|
|
170
|
+
timestamp: new Date().toISOString()
|
|
171
|
+
});
|
|
172
|
+
await appendFile(auditPath, `${auditEntry}\n`, "utf8");
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Fail-open: append raw input to audit log, never block the caller
|
|
176
|
+
const fallbackEntry = JSON.stringify({ ...input, timestamp: new Date().toISOString() });
|
|
177
|
+
await appendFile(auditPath, `${fallbackEntry}\n`, "utf8");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function buildMemoryDrawers(input) {
|
|
183
|
+
const wingKey = buildWingKey(input.loop.workspaceId, input.loop.projectId);
|
|
184
|
+
const createdAt = input.loop.updatedAt;
|
|
185
|
+
const drawers = input.loop.attempts.map((attempt) => {
|
|
186
|
+
const failureClass = attempt.failureClass;
|
|
187
|
+
const roomKey = failureClass ? `failure/${failureClass}` : "outcome/completion";
|
|
188
|
+
const roomTitle = failureClass
|
|
189
|
+
? `Failure · ${failureClass}`
|
|
190
|
+
: "Outcome · completion";
|
|
191
|
+
const lesson = failureClass
|
|
192
|
+
? `A similar loop hit ${failureClass}${attempt.intervention ? ` and required ${attempt.intervention}` : ""}. Reuse that narrower recovery before widening scope or changing model.`
|
|
193
|
+
: `A similar loop completed without widening scope. Reuse the same narrow, verifier-first shape before trying a broader patch.`;
|
|
194
|
+
const content = [
|
|
195
|
+
input.loop.task.title,
|
|
196
|
+
input.loop.task.objective,
|
|
197
|
+
attempt.summary,
|
|
198
|
+
attempt.verifierSummary
|
|
199
|
+
]
|
|
200
|
+
.filter((value) => Boolean(value?.trim()))
|
|
201
|
+
.join(" ");
|
|
202
|
+
return {
|
|
203
|
+
drawerId: buildDrawerId(input.loop.loopId, roomKey, attempt.index, createdAt),
|
|
204
|
+
wingKey,
|
|
205
|
+
roomKey,
|
|
206
|
+
roomTitle,
|
|
207
|
+
workspaceId: input.loop.workspaceId,
|
|
208
|
+
projectId: input.loop.projectId,
|
|
209
|
+
sourceRunId: input.loop.loopId,
|
|
210
|
+
sourceAttemptIndex: attempt.index,
|
|
211
|
+
outcome: failureClass ? "failure" : "completion",
|
|
212
|
+
...(failureClass ? { failureClass } : {}),
|
|
213
|
+
...(attempt.intervention ? { intervention: attempt.intervention } : {}),
|
|
214
|
+
tags: compact([
|
|
215
|
+
failureClass,
|
|
216
|
+
attempt.intervention,
|
|
217
|
+
...extractPathTags(input.loop.task.allowedPaths)
|
|
218
|
+
]),
|
|
219
|
+
tokens: buildDrawerTokens(content, failureClass, attempt.intervention),
|
|
220
|
+
lesson,
|
|
221
|
+
content,
|
|
222
|
+
createdAt
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
const runRoomKey = input.status === "completed" ? "outcome/completed" : "outcome/exited";
|
|
226
|
+
const runLesson = input.status === "completed"
|
|
227
|
+
? `A prior loop finished inside the declared contract. Prefer the same bounded route before widening files, network, or dependency scope.`
|
|
228
|
+
: `A prior loop exited in ${input.lifecycleState}. Preserve the guardrail and avoid forcing a fake completion.`;
|
|
229
|
+
const runContent = [
|
|
230
|
+
input.loop.task.title,
|
|
231
|
+
input.loop.task.objective,
|
|
232
|
+
input.reason
|
|
233
|
+
]
|
|
234
|
+
.filter((value) => Boolean(value?.trim()))
|
|
235
|
+
.join(" ");
|
|
236
|
+
drawers.push({
|
|
237
|
+
drawerId: buildDrawerId(input.loop.loopId, runRoomKey, 0, createdAt),
|
|
238
|
+
wingKey,
|
|
239
|
+
roomKey: runRoomKey,
|
|
240
|
+
roomTitle: input.status === "completed" ? "Outcome · completed" : "Outcome · exited",
|
|
241
|
+
workspaceId: input.loop.workspaceId,
|
|
242
|
+
projectId: input.loop.projectId,
|
|
243
|
+
sourceRunId: input.loop.loopId,
|
|
244
|
+
outcome: input.status === "completed" ? "completion" : "exit",
|
|
245
|
+
tags: compact([
|
|
246
|
+
input.status,
|
|
247
|
+
input.lifecycleState,
|
|
248
|
+
...extractPathTags(input.loop.task.allowedPaths)
|
|
249
|
+
]),
|
|
250
|
+
tokens: buildDrawerTokens(runContent, undefined, undefined),
|
|
251
|
+
lesson: runLesson,
|
|
252
|
+
content: runContent,
|
|
253
|
+
createdAt
|
|
254
|
+
});
|
|
255
|
+
return drawers;
|
|
256
|
+
}
|
|
257
|
+
function scoreDrawer(drawer, queryTokens, lastAttempt, heuristics) {
|
|
258
|
+
const reasons = [];
|
|
259
|
+
let score = 0;
|
|
260
|
+
if (lastAttempt?.failureClass && drawer.failureClass === lastAttempt.failureClass) {
|
|
261
|
+
score += heuristics.failureClassWeight;
|
|
262
|
+
reasons.push("matched failure class");
|
|
263
|
+
}
|
|
264
|
+
if (lastAttempt?.intervention && drawer.intervention === lastAttempt.intervention) {
|
|
265
|
+
score += heuristics.interventionWeight;
|
|
266
|
+
reasons.push("matched intervention");
|
|
267
|
+
}
|
|
268
|
+
const overlap = countIntersection(queryTokens, drawer.tokens);
|
|
269
|
+
if (overlap > 0) {
|
|
270
|
+
score += overlap * heuristics.tokenOverlapWeight;
|
|
271
|
+
reasons.push("matched objective tokens");
|
|
272
|
+
}
|
|
273
|
+
if (drawer.outcome === "completion") {
|
|
274
|
+
score += heuristics.completionWeight;
|
|
275
|
+
reasons.push("completion memory");
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
score,
|
|
279
|
+
reason: reasons.join(" and ")
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function buildQueryTokens(objective, focus, attempts) {
|
|
283
|
+
const lastAttempt = attempts.at(-1);
|
|
284
|
+
return uniqueTokens([
|
|
285
|
+
...tokenize(objective),
|
|
286
|
+
...tokenize(focus),
|
|
287
|
+
...tokenize(lastAttempt?.summary ?? ""),
|
|
288
|
+
...(lastAttempt?.failureClass ? [lastAttempt.failureClass] : []),
|
|
289
|
+
...(lastAttempt?.intervention ? [lastAttempt.intervention] : [])
|
|
290
|
+
]);
|
|
291
|
+
}
|
|
292
|
+
function buildDrawerTokens(content, failureClass, intervention) {
|
|
293
|
+
return uniqueTokens([
|
|
294
|
+
...tokenize(content),
|
|
295
|
+
...(failureClass ? [failureClass] : []),
|
|
296
|
+
...(intervention ? [intervention] : [])
|
|
297
|
+
]);
|
|
298
|
+
}
|
|
299
|
+
function tokenize(value) {
|
|
300
|
+
return (value.toLowerCase().match(/[a-z0-9_/-]{3,}/g) ?? []).filter((token) => !STOP_WORDS.has(token));
|
|
301
|
+
}
|
|
302
|
+
function uniqueTokens(values) {
|
|
303
|
+
return [...new Set(values.filter((value) => value.trim().length > 0))];
|
|
304
|
+
}
|
|
305
|
+
function countIntersection(left, right) {
|
|
306
|
+
const rightSet = new Set(right);
|
|
307
|
+
return left.filter((token) => rightSet.has(token)).length;
|
|
308
|
+
}
|
|
309
|
+
function extractPathTags(paths) {
|
|
310
|
+
return compact((paths ?? [])
|
|
311
|
+
.map((path) => path.split(/[\\/]/u)[0])
|
|
312
|
+
.filter((segment) => Boolean(segment && segment !== "**" && segment.trim().length > 0)));
|
|
313
|
+
}
|
|
314
|
+
function buildWingKey(workspaceId, projectId) {
|
|
315
|
+
return `${workspaceId}::${projectId}`;
|
|
316
|
+
}
|
|
317
|
+
function buildDrawerId(runId, roomKey, attemptIndex, createdAt) {
|
|
318
|
+
return createHash("sha256")
|
|
319
|
+
.update(`${runId}:${roomKey}:${String(attemptIndex)}:${createdAt}`)
|
|
320
|
+
.digest("hex")
|
|
321
|
+
.slice(0, 16);
|
|
322
|
+
}
|
|
323
|
+
function slugifyKey(value) {
|
|
324
|
+
return value
|
|
325
|
+
.replace(/::/g, "--")
|
|
326
|
+
.replace(/[^a-zA-Z0-9]+/g, "-")
|
|
327
|
+
.replace(/^-+|-+$/g, "")
|
|
328
|
+
.toLowerCase();
|
|
329
|
+
}
|
|
330
|
+
async function readDrawersFile(filePath) {
|
|
331
|
+
try {
|
|
332
|
+
const raw = await readFile(filePath, "utf8");
|
|
333
|
+
return raw
|
|
334
|
+
.split(/\r?\n/u)
|
|
335
|
+
.map((line) => line.trim())
|
|
336
|
+
.filter(Boolean)
|
|
337
|
+
.map((line) => JSON.parse(line));
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
return [];
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async function safeReaddir(directory) {
|
|
344
|
+
try {
|
|
345
|
+
return await readdir(directory);
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
return [];
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
async function persistRecallAudit(input) {
|
|
352
|
+
const wingPath = join(input.memoryRoot, slugifyKey(input.wingKey));
|
|
353
|
+
await mkdir(wingPath, { recursive: true });
|
|
354
|
+
const recalledAt = new Date().toISOString();
|
|
355
|
+
const payload = input.entries
|
|
356
|
+
.map((entry) => JSON.stringify({
|
|
357
|
+
recallId: createHash("sha256")
|
|
358
|
+
.update(`${input.runId}:${String(input.attemptIndex)}:${entry.drawerId}:${recalledAt}`)
|
|
359
|
+
.digest("hex")
|
|
360
|
+
.slice(0, 16),
|
|
361
|
+
wingKey: input.wingKey,
|
|
362
|
+
roomKey: entry.roomKey,
|
|
363
|
+
drawerId: entry.drawerId,
|
|
364
|
+
runId: input.runId,
|
|
365
|
+
attemptIndex: input.attemptIndex,
|
|
366
|
+
recallScore: entry.score,
|
|
367
|
+
recallReason: entry.reason,
|
|
368
|
+
recalledAt
|
|
369
|
+
}))
|
|
370
|
+
.join("\n");
|
|
371
|
+
await appendFile(join(wingPath, "recalls.jsonl"), `${payload}\n`, "utf8");
|
|
372
|
+
}
|
|
373
|
+
async function writeJsonFile(path, value) {
|
|
374
|
+
await writeFile(path, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
375
|
+
}
|
|
376
|
+
function compact(values) {
|
|
377
|
+
return values.filter((value) => Boolean(value?.trim()));
|
|
378
|
+
}
|
|
379
|
+
//# sourceMappingURL=palace.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type MergeType = "ast" | "text" | "trivial";
|
|
2
|
+
export type ConflictType = "same_function_body" | "delete_vs_modify" | "symbol_conflict";
|
|
3
|
+
export interface MergeResult {
|
|
4
|
+
conflict: boolean;
|
|
5
|
+
conflictType?: ConflictType;
|
|
6
|
+
conflictReport?: string;
|
|
7
|
+
mergedDiff?: string;
|
|
8
|
+
mergeType: MergeType;
|
|
9
|
+
tsMorphError?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface MergeArtifact {
|
|
12
|
+
runId: string;
|
|
13
|
+
patchA: string;
|
|
14
|
+
patchB: string;
|
|
15
|
+
result: MergeResult;
|
|
16
|
+
producedAt: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function astMerge(baseSource: string, patchA: string, patchB: string, options?: {
|
|
19
|
+
filePath?: string;
|
|
20
|
+
runId?: string;
|
|
21
|
+
}): MergeResult;
|
|
22
|
+
export declare function buildMergeArtifact(runId: string, patchA: string, patchB: string, result: MergeResult): MergeArtifact;
|