agent-bober 0.17.1 → 0.18.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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +15 -0
- package/README.md +158 -5
- package/dist/chat/answerer.d.ts +17 -0
- package/dist/chat/answerer.d.ts.map +1 -0
- package/dist/chat/answerer.js +52 -0
- package/dist/chat/answerer.js.map +1 -0
- package/dist/chat/approval-cursor.d.ts +25 -0
- package/dist/chat/approval-cursor.d.ts.map +1 -0
- package/dist/chat/approval-cursor.js +61 -0
- package/dist/chat/approval-cursor.js.map +1 -0
- package/dist/chat/approval-reader.d.ts +11 -0
- package/dist/chat/approval-reader.d.ts.map +1 -0
- package/dist/chat/approval-reader.js +20 -0
- package/dist/chat/approval-reader.js.map +1 -0
- package/dist/chat/careful-sidecar.d.ts +15 -0
- package/dist/chat/careful-sidecar.d.ts.map +1 -0
- package/dist/chat/careful-sidecar.js +39 -0
- package/dist/chat/careful-sidecar.js.map +1 -0
- package/dist/chat/chat-session.d.ts +129 -0
- package/dist/chat/chat-session.d.ts.map +1 -0
- package/dist/chat/chat-session.js +470 -0
- package/dist/chat/chat-session.js.map +1 -0
- package/dist/chat/completion-tailer.d.ts +27 -0
- package/dist/chat/completion-tailer.d.ts.map +1 -0
- package/dist/chat/completion-tailer.js +187 -0
- package/dist/chat/completion-tailer.js.map +1 -0
- package/dist/chat/conversation-store.d.ts +22 -0
- package/dist/chat/conversation-store.d.ts.map +1 -0
- package/dist/chat/conversation-store.js +66 -0
- package/dist/chat/conversation-store.js.map +1 -0
- package/dist/chat/cursor-store.d.ts +23 -0
- package/dist/chat/cursor-store.d.ts.map +1 -0
- package/dist/chat/cursor-store.js +42 -0
- package/dist/chat/cursor-store.js.map +1 -0
- package/dist/chat/pid-sidecar.d.ts +22 -0
- package/dist/chat/pid-sidecar.d.ts.map +1 -0
- package/dist/chat/pid-sidecar.js +42 -0
- package/dist/chat/pid-sidecar.js.map +1 -0
- package/dist/chat/roster-reader.d.ts +16 -0
- package/dist/chat/roster-reader.d.ts.map +1 -0
- package/dist/chat/roster-reader.js +39 -0
- package/dist/chat/roster-reader.js.map +1 -0
- package/dist/chat/run-spawner.d.ts +71 -0
- package/dist/chat/run-spawner.d.ts.map +1 -0
- package/dist/chat/run-spawner.js +121 -0
- package/dist/chat/run-spawner.js.map +1 -0
- package/dist/chat/slash-commands.d.ts +36 -0
- package/dist/chat/slash-commands.d.ts.map +1 -0
- package/dist/chat/slash-commands.js +133 -0
- package/dist/chat/slash-commands.js.map +1 -0
- package/dist/chat/steer-cleanup.d.ts +12 -0
- package/dist/chat/steer-cleanup.d.ts.map +1 -0
- package/dist/chat/steer-cleanup.js +60 -0
- package/dist/chat/steer-cleanup.js.map +1 -0
- package/dist/chat/turn-classifier.d.ts +43 -0
- package/dist/chat/turn-classifier.d.ts.map +1 -0
- package/dist/chat/turn-classifier.js +150 -0
- package/dist/chat/turn-classifier.js.map +1 -0
- package/dist/cli/commands/blackboard.d.ts +33 -0
- package/dist/cli/commands/blackboard.d.ts.map +1 -0
- package/dist/cli/commands/blackboard.js +114 -0
- package/dist/cli/commands/blackboard.js.map +1 -0
- package/dist/cli/commands/chat.d.ts +13 -0
- package/dist/cli/commands/chat.d.ts.map +1 -0
- package/dist/cli/commands/chat.js +43 -0
- package/dist/cli/commands/chat.js.map +1 -0
- package/dist/cli/commands/evolve.d.ts +18 -0
- package/dist/cli/commands/evolve.d.ts.map +1 -0
- package/dist/cli/commands/evolve.js +72 -0
- package/dist/cli/commands/evolve.js.map +1 -0
- package/dist/cli/commands/facts.d.ts +15 -0
- package/dist/cli/commands/facts.d.ts.map +1 -0
- package/dist/cli/commands/facts.js +213 -0
- package/dist/cli/commands/facts.js.map +1 -0
- package/dist/cli/commands/medical.d.ts +24 -0
- package/dist/cli/commands/medical.d.ts.map +1 -0
- package/dist/cli/commands/medical.js +132 -0
- package/dist/cli/commands/medical.js.map +1 -0
- package/dist/cli/commands/memory.d.ts +2 -1
- package/dist/cli/commands/memory.d.ts.map +1 -1
- package/dist/cli/commands/memory.js +94 -7
- package/dist/cli/commands/memory.js.map +1 -1
- package/dist/cli/commands/plan.d.ts.map +1 -1
- package/dist/cli/commands/plan.js +29 -3
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/replay.d.ts +17 -0
- package/dist/cli/commands/replay.d.ts.map +1 -0
- package/dist/cli/commands/replay.js +261 -0
- package/dist/cli/commands/replay.js.map +1 -0
- package/dist/cli/commands/run.d.ts +9 -0
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +27 -1
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/sprint.d.ts.map +1 -1
- package/dist/cli/commands/sprint.js +17 -3
- package/dist/cli/commands/sprint.js.map +1 -1
- package/dist/cli/index.js +12 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +8 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/role-providers.d.ts +1 -1
- package/dist/config/role-providers.d.ts.map +1 -1
- package/dist/config/role-providers.js +6 -1
- package/dist/config/role-providers.js.map +1 -1
- package/dist/config/schema.d.ts +467 -222
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +25 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/contracts/eval-result.d.ts +84 -84
- package/dist/contracts/spec.d.ts +28 -28
- package/dist/contracts/sprint-contract.d.ts +4 -4
- package/dist/fleet/critic-deep.d.ts +53 -0
- package/dist/fleet/critic-deep.d.ts.map +1 -0
- package/dist/fleet/critic-deep.js +199 -0
- package/dist/fleet/critic-deep.js.map +1 -0
- package/dist/fleet/decomposer-deep-constants.d.ts +4 -0
- package/dist/fleet/decomposer-deep-constants.d.ts.map +1 -0
- package/dist/fleet/decomposer-deep-constants.js +14 -0
- package/dist/fleet/decomposer-deep-constants.js.map +1 -0
- package/dist/fleet/decomposer-deep-types.d.ts +8 -0
- package/dist/fleet/decomposer-deep-types.d.ts.map +1 -0
- package/dist/fleet/decomposer-deep-types.js +9 -0
- package/dist/fleet/decomposer-deep-types.js.map +1 -0
- package/dist/fleet/decomposer-deep.d.ts +51 -0
- package/dist/fleet/decomposer-deep.d.ts.map +1 -0
- package/dist/fleet/decomposer-deep.js +261 -0
- package/dist/fleet/decomposer-deep.js.map +1 -0
- package/dist/fleet/decomposer.d.ts +22 -0
- package/dist/fleet/decomposer.d.ts.map +1 -0
- package/dist/fleet/decomposer.js +144 -0
- package/dist/fleet/decomposer.js.map +1 -0
- package/dist/fleet/index.d.ts +93 -0
- package/dist/fleet/index.d.ts.map +1 -1
- package/dist/fleet/index.js +230 -2
- package/dist/fleet/index.js.map +1 -1
- package/dist/fleet/manifest-write.d.ts +30 -0
- package/dist/fleet/manifest-write.d.ts.map +1 -0
- package/dist/fleet/manifest-write.js +90 -0
- package/dist/fleet/manifest-write.js.map +1 -0
- package/dist/fleet/manifest.d.ts +6 -6
- package/dist/fleet/shared-blackboard.d.ts +51 -0
- package/dist/fleet/shared-blackboard.d.ts.map +1 -0
- package/dist/fleet/shared-blackboard.js +79 -0
- package/dist/fleet/shared-blackboard.js.map +1 -0
- package/dist/fleet/synthesis.d.ts +16 -0
- package/dist/fleet/synthesis.d.ts.map +1 -0
- package/dist/fleet/synthesis.js +22 -0
- package/dist/fleet/synthesis.js.map +1 -0
- package/dist/fleet/tier-policy.d.ts +18 -0
- package/dist/fleet/tier-policy.d.ts.map +1 -0
- package/dist/fleet/tier-policy.js +53 -0
- package/dist/fleet/tier-policy.js.map +1 -0
- package/dist/fleet/tool-role-guard.d.ts +24 -0
- package/dist/fleet/tool-role-guard.d.ts.map +1 -0
- package/dist/fleet/tool-role-guard.js +55 -0
- package/dist/fleet/tool-role-guard.js.map +1 -0
- package/dist/incident/resolution-verify.d.ts +4 -4
- package/dist/incident/types.d.ts +8 -8
- package/dist/mcp/run-manager.d.ts +9 -1
- package/dist/mcp/run-manager.d.ts.map +1 -1
- package/dist/mcp/run-manager.js.map +1 -1
- package/dist/medical/adapters/apple-health.d.ts +32 -0
- package/dist/medical/adapters/apple-health.d.ts.map +1 -0
- package/dist/medical/adapters/apple-health.js +100 -0
- package/dist/medical/adapters/apple-health.js.map +1 -0
- package/dist/medical/audit.d.ts +31 -0
- package/dist/medical/audit.d.ts.map +1 -0
- package/dist/medical/audit.js +56 -0
- package/dist/medical/audit.js.map +1 -0
- package/dist/medical/consent.d.ts +37 -0
- package/dist/medical/consent.d.ts.map +1 -0
- package/dist/medical/consent.js +73 -0
- package/dist/medical/consent.js.map +1 -0
- package/dist/medical/disclaimer.d.ts +11 -0
- package/dist/medical/disclaimer.d.ts.map +1 -0
- package/dist/medical/disclaimer.js +21 -0
- package/dist/medical/disclaimer.js.map +1 -0
- package/dist/medical/egress.d.ts +30 -0
- package/dist/medical/egress.d.ts.map +1 -0
- package/dist/medical/egress.js +50 -0
- package/dist/medical/egress.js.map +1 -0
- package/dist/medical/engine.d.ts +73 -0
- package/dist/medical/engine.d.ts.map +1 -0
- package/dist/medical/engine.js +333 -0
- package/dist/medical/engine.js.map +1 -0
- package/dist/medical/guardrails.d.ts +47 -0
- package/dist/medical/guardrails.d.ts.map +1 -0
- package/dist/medical/guardrails.js +92 -0
- package/dist/medical/guardrails.js.map +1 -0
- package/dist/medical/health-store.d.ts +80 -0
- package/dist/medical/health-store.d.ts.map +1 -0
- package/dist/medical/health-store.js +204 -0
- package/dist/medical/health-store.js.map +1 -0
- package/dist/medical/inference.d.ts +22 -0
- package/dist/medical/inference.d.ts.map +1 -0
- package/dist/medical/inference.js +39 -0
- package/dist/medical/inference.js.map +1 -0
- package/dist/medical/ingestion.d.ts +33 -0
- package/dist/medical/ingestion.d.ts.map +1 -0
- package/dist/medical/ingestion.js +52 -0
- package/dist/medical/ingestion.js.map +1 -0
- package/dist/medical/numerics.d.ts +66 -0
- package/dist/medical/numerics.d.ts.map +1 -0
- package/dist/medical/numerics.js +216 -0
- package/dist/medical/numerics.js.map +1 -0
- package/dist/medical/red-flag.d.ts +42 -0
- package/dist/medical/red-flag.d.ts.map +1 -0
- package/dist/medical/red-flag.js +161 -0
- package/dist/medical/red-flag.js.map +1 -0
- package/dist/medical/refusal.d.ts +46 -0
- package/dist/medical/refusal.d.ts.map +1 -0
- package/dist/medical/refusal.js +131 -0
- package/dist/medical/refusal.js.map +1 -0
- package/dist/medical/retrieval/grounding-critic.d.ts +34 -0
- package/dist/medical/retrieval/grounding-critic.d.ts.map +1 -0
- package/dist/medical/retrieval/grounding-critic.js +153 -0
- package/dist/medical/retrieval/grounding-critic.js.map +1 -0
- package/dist/medical/retrieval/literature.d.ts +78 -0
- package/dist/medical/retrieval/literature.d.ts.map +1 -0
- package/dist/medical/retrieval/literature.js +292 -0
- package/dist/medical/retrieval/literature.js.map +1 -0
- package/dist/medical/retrieval/medline-source.d.ts +72 -0
- package/dist/medical/retrieval/medline-source.d.ts.map +1 -0
- package/dist/medical/retrieval/medline-source.js +120 -0
- package/dist/medical/retrieval/medline-source.js.map +1 -0
- package/dist/medical/team.d.ts +15 -0
- package/dist/medical/team.d.ts.map +1 -0
- package/dist/medical/team.js +44 -0
- package/dist/medical/team.js.map +1 -0
- package/dist/medical/types.d.ts +175 -0
- package/dist/medical/types.d.ts.map +1 -0
- package/dist/medical/types.js +8 -0
- package/dist/medical/types.js.map +1 -0
- package/dist/medical/whoop/whoop-client.d.ts +114 -0
- package/dist/medical/whoop/whoop-client.d.ts.map +1 -0
- package/dist/medical/whoop/whoop-client.js +226 -0
- package/dist/medical/whoop/whoop-client.js.map +1 -0
- package/dist/medical/whoop/whoop-sync.d.ts +25 -0
- package/dist/medical/whoop/whoop-sync.d.ts.map +1 -0
- package/dist/medical/whoop/whoop-sync.js +97 -0
- package/dist/medical/whoop/whoop-sync.js.map +1 -0
- package/dist/medical/whoop/whoop-token.d.ts +44 -0
- package/dist/medical/whoop/whoop-token.d.ts.map +1 -0
- package/dist/medical/whoop/whoop-token.js +66 -0
- package/dist/medical/whoop/whoop-token.js.map +1 -0
- package/dist/orchestrator/context-handoff.d.ts +60 -60
- package/dist/orchestrator/contract-materialization.d.ts +33 -0
- package/dist/orchestrator/contract-materialization.d.ts.map +1 -0
- package/dist/orchestrator/contract-materialization.js +113 -0
- package/dist/orchestrator/contract-materialization.js.map +1 -0
- package/dist/orchestrator/memory/distill.d.ts +4 -1
- package/dist/orchestrator/memory/distill.d.ts.map +1 -1
- package/dist/orchestrator/memory/distill.js +41 -1
- package/dist/orchestrator/memory/distill.js.map +1 -1
- package/dist/orchestrator/memory/fact-detector.d.ts +61 -0
- package/dist/orchestrator/memory/fact-detector.d.ts.map +1 -0
- package/dist/orchestrator/memory/fact-detector.js +153 -0
- package/dist/orchestrator/memory/fact-detector.js.map +1 -0
- package/dist/orchestrator/memory/fact-judge.d.ts +19 -0
- package/dist/orchestrator/memory/fact-judge.d.ts.map +1 -0
- package/dist/orchestrator/memory/fact-judge.js +121 -0
- package/dist/orchestrator/memory/fact-judge.js.map +1 -0
- package/dist/orchestrator/memory/fact-retrieve.d.ts +52 -0
- package/dist/orchestrator/memory/fact-retrieve.d.ts.map +1 -0
- package/dist/orchestrator/memory/fact-retrieve.js +117 -0
- package/dist/orchestrator/memory/fact-retrieve.js.map +1 -0
- package/dist/orchestrator/memory/hygiene.d.ts +66 -0
- package/dist/orchestrator/memory/hygiene.d.ts.map +1 -0
- package/dist/orchestrator/memory/hygiene.js +153 -0
- package/dist/orchestrator/memory/hygiene.js.map +1 -0
- package/dist/orchestrator/memory/reconcile.d.ts +47 -0
- package/dist/orchestrator/memory/reconcile.d.ts.map +1 -0
- package/dist/orchestrator/memory/reconcile.js +116 -0
- package/dist/orchestrator/memory/reconcile.js.map +1 -0
- package/dist/orchestrator/memory/retrieve.d.ts +5 -3
- package/dist/orchestrator/memory/retrieve.d.ts.map +1 -1
- package/dist/orchestrator/memory/retrieve.js +9 -6
- package/dist/orchestrator/memory/retrieve.js.map +1 -1
- package/dist/orchestrator/pipeline.d.ts +19 -3
- package/dist/orchestrator/pipeline.d.ts.map +1 -1
- package/dist/orchestrator/pipeline.js +63 -52
- package/dist/orchestrator/pipeline.js.map +1 -1
- package/dist/orchestrator/planner-agent.d.ts.map +1 -1
- package/dist/orchestrator/planner-agent.js +16 -1
- package/dist/orchestrator/planner-agent.js.map +1 -1
- package/dist/orchestrator/selfimprove/eval-guards.d.ts +51 -0
- package/dist/orchestrator/selfimprove/eval-guards.d.ts.map +1 -0
- package/dist/orchestrator/selfimprove/eval-guards.js +120 -0
- package/dist/orchestrator/selfimprove/eval-guards.js.map +1 -0
- package/dist/orchestrator/selfimprove/gepa.d.ts +74 -0
- package/dist/orchestrator/selfimprove/gepa.d.ts.map +1 -0
- package/dist/orchestrator/selfimprove/gepa.js +227 -0
- package/dist/orchestrator/selfimprove/gepa.js.map +1 -0
- package/dist/orchestrator/selfimprove/replay-harness.d.ts +65 -0
- package/dist/orchestrator/selfimprove/replay-harness.d.ts.map +1 -0
- package/dist/orchestrator/selfimprove/replay-harness.js +134 -0
- package/dist/orchestrator/selfimprove/replay-harness.js.map +1 -0
- package/dist/orchestrator/selfimprove/replay-store.d.ts +45 -0
- package/dist/orchestrator/selfimprove/replay-store.d.ts.map +1 -0
- package/dist/orchestrator/selfimprove/replay-store.js +119 -0
- package/dist/orchestrator/selfimprove/replay-store.js.map +1 -0
- package/dist/orchestrator/selfimprove/replay-types.d.ts +32 -0
- package/dist/orchestrator/selfimprove/replay-types.d.ts.map +1 -0
- package/dist/orchestrator/selfimprove/replay-types.js +15 -0
- package/dist/orchestrator/selfimprove/replay-types.js.map +1 -0
- package/dist/orchestrator/workflow/engine.d.ts +3 -1
- package/dist/orchestrator/workflow/engine.d.ts.map +1 -1
- package/dist/orchestrator/workflow/selector.d.ts +18 -0
- package/dist/orchestrator/workflow/selector.d.ts.map +1 -1
- package/dist/orchestrator/workflow/selector.js +41 -0
- package/dist/orchestrator/workflow/selector.js.map +1 -1
- package/dist/orchestrator/workflow/ts-engine.d.ts +3 -1
- package/dist/orchestrator/workflow/ts-engine.d.ts.map +1 -1
- package/dist/orchestrator/workflow/ts-engine.js +2 -2
- package/dist/orchestrator/workflow/ts-engine.js.map +1 -1
- package/dist/orchestrator/workflow/workflow-engine.d.ts +3 -1
- package/dist/orchestrator/workflow/workflow-engine.d.ts.map +1 -1
- package/dist/orchestrator/workflow/workflow-engine.js +3 -3
- package/dist/orchestrator/workflow/workflow-engine.js.map +1 -1
- package/dist/state/facts.d.ts +110 -0
- package/dist/state/facts.d.ts.map +1 -0
- package/dist/state/facts.js +208 -0
- package/dist/state/facts.js.map +1 -0
- package/dist/state/guidance.d.ts +37 -0
- package/dist/state/guidance.d.ts.map +1 -0
- package/dist/state/guidance.js +144 -0
- package/dist/state/guidance.js.map +1 -0
- package/dist/state/history.d.ts +2 -2
- package/dist/state/index.d.ts +1 -1
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +1 -1
- package/dist/state/index.js.map +1 -1
- package/dist/state/memory.d.ts +43 -11
- package/dist/state/memory.d.ts.map +1 -1
- package/dist/state/memory.js +93 -15
- package/dist/state/memory.js.map +1 -1
- package/dist/state/pause.d.ts +47 -0
- package/dist/state/pause.d.ts.map +1 -0
- package/dist/state/pause.js +146 -0
- package/dist/state/pause.js.map +1 -0
- package/dist/state/sprint-state.d.ts +8 -0
- package/dist/state/sprint-state.d.ts.map +1 -1
- package/dist/state/sprint-state.js +32 -1
- package/dist/state/sprint-state.js.map +1 -1
- package/dist/teams/registry.d.ts +16 -0
- package/dist/teams/registry.d.ts.map +1 -0
- package/dist/teams/registry.js +53 -0
- package/dist/teams/registry.js.map +1 -0
- package/dist/teams/types.d.ts +25 -0
- package/dist/teams/types.d.ts.map +1 -0
- package/dist/teams/types.js +2 -0
- package/dist/teams/types.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import Database from "better-sqlite3";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { ensureDir } from "./helpers.js";
|
|
6
|
+
import { memoryDir } from "./memory.js";
|
|
7
|
+
// ── Re-exports from reconcile layer ──────────────────────────────────────
|
|
8
|
+
// writeFact lives in reconcile.ts (to avoid a runtime import cycle) but is
|
|
9
|
+
// re-exported here so consumers can import it from the facts module.
|
|
10
|
+
export { writeFact } from "../orchestrator/memory/reconcile.js";
|
|
11
|
+
// ── Schema ────────────────────────────────────────────────────────────
|
|
12
|
+
/**
|
|
13
|
+
* Zod schema for a fact input — mirrors LessonEntrySchema in memory.ts.
|
|
14
|
+
* All timestamps are ISO 8601 strings; the store never reads the clock.
|
|
15
|
+
*/
|
|
16
|
+
export const FactSchema = z.object({
|
|
17
|
+
scope: z.string(),
|
|
18
|
+
subject: z.string().min(1),
|
|
19
|
+
predicate: z.string().min(1),
|
|
20
|
+
value: z.string().min(1),
|
|
21
|
+
confidence: z.number().min(0).max(1).default(1),
|
|
22
|
+
sourceRunId: z.string().nullable().default(null),
|
|
23
|
+
tValid: z.string().datetime(),
|
|
24
|
+
tCreated: z.string().datetime(),
|
|
25
|
+
});
|
|
26
|
+
// ── Deterministic id ──────────────────────────────────────────────────
|
|
27
|
+
/**
|
|
28
|
+
* Derive a deterministic 16-char hex fact id from the fact signature.
|
|
29
|
+
* Mirrors lessonIdFromSignature in src/orchestrator/memory/distill.ts:88-99.
|
|
30
|
+
* Identical inputs always produce the same id — no wall-clock dependency.
|
|
31
|
+
*/
|
|
32
|
+
export function factId(scope, subject, predicate, value, tCreated) {
|
|
33
|
+
return createHash("sha256")
|
|
34
|
+
.update(`${scope}|${subject}|${predicate}|${value}|${tCreated}`)
|
|
35
|
+
.digest("hex")
|
|
36
|
+
.slice(0, 16);
|
|
37
|
+
}
|
|
38
|
+
// ── Path helpers ──────────────────────────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the absolute path to facts.db for the given project root and namespace.
|
|
41
|
+
* Uses the same memoryDir mapping rule as memory.ts (no duplication).
|
|
42
|
+
*/
|
|
43
|
+
export function factsDbPath(projectRoot, namespace) {
|
|
44
|
+
return join(memoryDir(projectRoot, namespace), "facts.db");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Ensure the directory that will hold the DB file exists.
|
|
48
|
+
* Must be called by the CLI handler before constructing a file-backed FactStore.
|
|
49
|
+
* Not needed for ':memory:' paths.
|
|
50
|
+
*/
|
|
51
|
+
export async function ensureFactsDir(projectRoot, namespace) {
|
|
52
|
+
await ensureDir(memoryDir(projectRoot, namespace));
|
|
53
|
+
}
|
|
54
|
+
function rowToRecord(row) {
|
|
55
|
+
return {
|
|
56
|
+
id: row.id,
|
|
57
|
+
scope: row.scope,
|
|
58
|
+
subject: row.subject,
|
|
59
|
+
predicate: row.predicate,
|
|
60
|
+
value: row.value,
|
|
61
|
+
confidence: row.confidence,
|
|
62
|
+
sourceRunId: row.source_run_id,
|
|
63
|
+
tValid: row.t_valid,
|
|
64
|
+
tInvalid: row.t_invalid,
|
|
65
|
+
tCreated: row.t_created,
|
|
66
|
+
tInvalidated: row.t_invalidated,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// ── FactStore ─────────────────────────────────────────────────────────
|
|
70
|
+
/**
|
|
71
|
+
* Bi-temporal SQLite-backed fact store.
|
|
72
|
+
*
|
|
73
|
+
* PURE: Never calls Date.now() or new Date() — every timestamp is a parameter.
|
|
74
|
+
* Hidden behind this interface so the driver (better-sqlite3) is swappable.
|
|
75
|
+
*
|
|
76
|
+
* bober: in-memory or file-backed via better-sqlite3 (synchronous); swap for
|
|
77
|
+
* node:sqlite when engines.node is raised to >=22.5.
|
|
78
|
+
*/
|
|
79
|
+
export class FactStore {
|
|
80
|
+
db;
|
|
81
|
+
constructor(dbPath) {
|
|
82
|
+
this.db = new Database(dbPath);
|
|
83
|
+
this.db.exec(`
|
|
84
|
+
CREATE TABLE IF NOT EXISTS semantic_facts (
|
|
85
|
+
id TEXT PRIMARY KEY,
|
|
86
|
+
scope TEXT NOT NULL,
|
|
87
|
+
subject TEXT NOT NULL,
|
|
88
|
+
predicate TEXT NOT NULL,
|
|
89
|
+
value TEXT NOT NULL,
|
|
90
|
+
confidence REAL NOT NULL,
|
|
91
|
+
source_run_id TEXT,
|
|
92
|
+
t_valid TEXT NOT NULL,
|
|
93
|
+
t_invalid TEXT,
|
|
94
|
+
t_created TEXT NOT NULL,
|
|
95
|
+
t_invalidated TEXT
|
|
96
|
+
);
|
|
97
|
+
CREATE INDEX IF NOT EXISTS idx_facts_sp ON semantic_facts(scope, subject, predicate);
|
|
98
|
+
CREATE INDEX IF NOT EXISTS idx_facts_active ON semantic_facts(scope, t_invalidated);
|
|
99
|
+
`);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Insert a new fact. Validates input with FactSchema and derives the
|
|
103
|
+
* deterministic id. Returns the persisted FactRecord.
|
|
104
|
+
*/
|
|
105
|
+
insertFact(input) {
|
|
106
|
+
const result = FactSchema.safeParse(input);
|
|
107
|
+
if (!result.success) {
|
|
108
|
+
const issues = result.error.issues
|
|
109
|
+
.map((i) => ` - ${i.path.join(".")}: ${i.message}`)
|
|
110
|
+
.join("\n");
|
|
111
|
+
throw new Error(`Invalid fact input:\n${issues}`);
|
|
112
|
+
}
|
|
113
|
+
const data = result.data;
|
|
114
|
+
const id = factId(data.scope, data.subject, data.predicate, data.value, data.tCreated);
|
|
115
|
+
this.db
|
|
116
|
+
.prepare(`INSERT OR REPLACE INTO semantic_facts
|
|
117
|
+
(id, scope, subject, predicate, value, confidence, source_run_id, t_valid, t_invalid, t_created, t_invalidated)
|
|
118
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, NULL)`)
|
|
119
|
+
.run(id, data.scope, data.subject, data.predicate, data.value, data.confidence, data.sourceRunId, data.tValid, data.tCreated);
|
|
120
|
+
return {
|
|
121
|
+
id,
|
|
122
|
+
scope: data.scope,
|
|
123
|
+
subject: data.subject,
|
|
124
|
+
predicate: data.predicate,
|
|
125
|
+
value: data.value,
|
|
126
|
+
confidence: data.confidence,
|
|
127
|
+
sourceRunId: data.sourceRunId,
|
|
128
|
+
tValid: data.tValid,
|
|
129
|
+
tInvalid: null,
|
|
130
|
+
tCreated: data.tCreated,
|
|
131
|
+
tInvalidated: null,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Return all active (non-invalidated) facts matching the given scope.
|
|
136
|
+
* Optionally filtered by subject and/or predicate.
|
|
137
|
+
* Active = t_invalidated IS NULL.
|
|
138
|
+
*/
|
|
139
|
+
getActiveFacts(scope, subject, predicate) {
|
|
140
|
+
if (subject !== undefined && predicate !== undefined) {
|
|
141
|
+
const rows = this.db
|
|
142
|
+
.prepare(`SELECT * FROM semantic_facts
|
|
143
|
+
WHERE scope = ? AND subject = ? AND predicate = ? AND t_invalidated IS NULL`)
|
|
144
|
+
.all(scope, subject, predicate);
|
|
145
|
+
return rows.map(rowToRecord);
|
|
146
|
+
}
|
|
147
|
+
if (subject !== undefined) {
|
|
148
|
+
const rows = this.db
|
|
149
|
+
.prepare(`SELECT * FROM semantic_facts
|
|
150
|
+
WHERE scope = ? AND subject = ? AND t_invalidated IS NULL`)
|
|
151
|
+
.all(scope, subject);
|
|
152
|
+
return rows.map(rowToRecord);
|
|
153
|
+
}
|
|
154
|
+
if (predicate !== undefined) {
|
|
155
|
+
const rows = this.db
|
|
156
|
+
.prepare(`SELECT * FROM semantic_facts
|
|
157
|
+
WHERE scope = ? AND predicate = ? AND t_invalidated IS NULL`)
|
|
158
|
+
.all(scope, predicate);
|
|
159
|
+
return rows.map(rowToRecord);
|
|
160
|
+
}
|
|
161
|
+
const rows = this.db
|
|
162
|
+
.prepare(`SELECT * FROM semantic_facts
|
|
163
|
+
WHERE scope = ? AND t_invalidated IS NULL`)
|
|
164
|
+
.all(scope);
|
|
165
|
+
return rows.map(rowToRecord);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Return a single fact by its id regardless of invalidation status.
|
|
169
|
+
* Returns null if not found.
|
|
170
|
+
*/
|
|
171
|
+
getFact(id) {
|
|
172
|
+
const row = this.db
|
|
173
|
+
.prepare(`SELECT * FROM semantic_facts WHERE id = ?`)
|
|
174
|
+
.get(id);
|
|
175
|
+
return row ? rowToRecord(row) : null;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Soft-delete a fact by setting t_invalidated.
|
|
179
|
+
* Returns true if the fact was invalidated, false if it was already invalidated or not found.
|
|
180
|
+
* Never deletes rows.
|
|
181
|
+
*/
|
|
182
|
+
invalidateFact(id, tInvalidated) {
|
|
183
|
+
const info = this.db
|
|
184
|
+
.prepare(`UPDATE semantic_facts
|
|
185
|
+
SET t_invalidated = ?
|
|
186
|
+
WHERE id = ? AND t_invalidated IS NULL`)
|
|
187
|
+
.run(tInvalidated, id);
|
|
188
|
+
return info.changes > 0;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Supersede a fact: set BOTH t_invalidated (record-time) AND t_invalid (world-time end).
|
|
192
|
+
* Used by reconcile on UPDATE to carry both bi-temporal closure fields.
|
|
193
|
+
* Returns true if the row was updated; false if not found or already invalidated.
|
|
194
|
+
*/
|
|
195
|
+
supersedeFact(id, tInvalidated, tInvalid) {
|
|
196
|
+
const info = this.db
|
|
197
|
+
.prepare(`UPDATE semantic_facts
|
|
198
|
+
SET t_invalidated = ?, t_invalid = ?
|
|
199
|
+
WHERE id = ? AND t_invalidated IS NULL`)
|
|
200
|
+
.run(tInvalidated, tInvalid, id);
|
|
201
|
+
return info.changes > 0;
|
|
202
|
+
}
|
|
203
|
+
/** Close the underlying database connection. */
|
|
204
|
+
close() {
|
|
205
|
+
this.db.close();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facts.js","sourceRoot":"","sources":["../../src/state/facts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate that a runId is a safe path segment.
|
|
3
|
+
* Rejects empty strings, strings containing path separators (/ or \),
|
|
4
|
+
* strings containing '..', and absolute paths.
|
|
5
|
+
* This is a security guard: a malicious runId must never escape .bober/runs.
|
|
6
|
+
*/
|
|
7
|
+
export declare function safeSegment(runId: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Check whether the run directory exists for the given runId.
|
|
10
|
+
* Returns false if not found — never throws.
|
|
11
|
+
* Mirrors approval-state.ts:pendingExists.
|
|
12
|
+
*/
|
|
13
|
+
export declare function hasRunDir(projectRoot: string, runId: string): Promise<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* Append a guidance entry to .bober/runs/<runId>/guidance.jsonl.
|
|
16
|
+
*
|
|
17
|
+
* Security: validates runId is a safe path segment BEFORE building any path.
|
|
18
|
+
* Throws with a clear message if runId is unsafe (caller should surface to user).
|
|
19
|
+
*
|
|
20
|
+
* Existence: the run directory must already exist (guard with hasRunDir if
|
|
21
|
+
* you want an unknown-run check; appendGuidance itself creates the dir for
|
|
22
|
+
* robustness, but callers in chat-session.ts should guard first for UX).
|
|
23
|
+
*/
|
|
24
|
+
export declare function appendGuidance(projectRoot: string, runId: string, text: string): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Drain pending (unconsumed) guidance entries for a runId.
|
|
27
|
+
*
|
|
28
|
+
* Reads all lines, collects the text of entries where consumed !== true,
|
|
29
|
+
* then atomically rewrites the file with ALL entries marked consumed:true
|
|
30
|
+
* (temp-file + rename, mirrors run-state.ts:41-52).
|
|
31
|
+
*
|
|
32
|
+
* Returns the drained texts in order.
|
|
33
|
+
* Missing file → returns [] (never throws — safe to call on every pipeline sprint).
|
|
34
|
+
* Second drain → returns [] (all entries already marked consumed).
|
|
35
|
+
*/
|
|
36
|
+
export declare function drainGuidance(projectRoot: string, runId: string): Promise<string[]>;
|
|
37
|
+
//# sourceMappingURL=guidance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guidance.d.ts","sourceRoot":"","sources":["../../src/state/guidance.ts"],"names":[],"mappings":"AAyCA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CASlD;AAID;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOpF;AAID;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAcf;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CA+CnB"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// ── guidance.ts ───────────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Disk-persistence helpers for the runId-keyed guidance channel.
|
|
4
|
+
//
|
|
5
|
+
// Layout: .bober/runs/<runId>/guidance.jsonl
|
|
6
|
+
// One JSON object per line: { ts: string, text: string, consumed: boolean }
|
|
7
|
+
//
|
|
8
|
+
// Every drain rewrite is atomic via temp-file + rename
|
|
9
|
+
// (mirrors src/state/run-state.ts:41-52 atomic write pattern).
|
|
10
|
+
import { readFile, writeFile, appendFile, rename, access } from "node:fs/promises";
|
|
11
|
+
import { constants } from "node:fs";
|
|
12
|
+
import { randomBytes } from "node:crypto";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { ensureDir } from "./helpers.js";
|
|
15
|
+
// ── Path helpers ──────────────────────────────────────────────────────
|
|
16
|
+
function runsRoot(projectRoot) {
|
|
17
|
+
return join(projectRoot, ".bober", "runs");
|
|
18
|
+
}
|
|
19
|
+
function runDir(projectRoot, runId) {
|
|
20
|
+
return join(runsRoot(projectRoot), runId);
|
|
21
|
+
}
|
|
22
|
+
function guidancePath(projectRoot, runId) {
|
|
23
|
+
return join(runDir(projectRoot, runId), "guidance.jsonl");
|
|
24
|
+
}
|
|
25
|
+
// ── Path-traversal guard ──────────────────────────────────────────────
|
|
26
|
+
/**
|
|
27
|
+
* Validate that a runId is a safe path segment.
|
|
28
|
+
* Rejects empty strings, strings containing path separators (/ or \),
|
|
29
|
+
* strings containing '..', and absolute paths.
|
|
30
|
+
* This is a security guard: a malicious runId must never escape .bober/runs.
|
|
31
|
+
*/
|
|
32
|
+
export function safeSegment(runId) {
|
|
33
|
+
if (!runId)
|
|
34
|
+
return false;
|
|
35
|
+
if (runId.includes("/"))
|
|
36
|
+
return false;
|
|
37
|
+
if (runId.includes("\\"))
|
|
38
|
+
return false;
|
|
39
|
+
if (runId.includes(".."))
|
|
40
|
+
return false;
|
|
41
|
+
if (runId.startsWith("."))
|
|
42
|
+
return false;
|
|
43
|
+
// Reject if it looks like an absolute path (Unix or Windows)
|
|
44
|
+
if (runId.startsWith("/") || /^[A-Za-z]:[/\\]/.test(runId))
|
|
45
|
+
return false;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
// ── Existence guard ───────────────────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* Check whether the run directory exists for the given runId.
|
|
51
|
+
* Returns false if not found — never throws.
|
|
52
|
+
* Mirrors approval-state.ts:pendingExists.
|
|
53
|
+
*/
|
|
54
|
+
export async function hasRunDir(projectRoot, runId) {
|
|
55
|
+
try {
|
|
56
|
+
await access(runDir(projectRoot, runId), constants.R_OK);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// ── Append ────────────────────────────────────────────────────────────
|
|
64
|
+
/**
|
|
65
|
+
* Append a guidance entry to .bober/runs/<runId>/guidance.jsonl.
|
|
66
|
+
*
|
|
67
|
+
* Security: validates runId is a safe path segment BEFORE building any path.
|
|
68
|
+
* Throws with a clear message if runId is unsafe (caller should surface to user).
|
|
69
|
+
*
|
|
70
|
+
* Existence: the run directory must already exist (guard with hasRunDir if
|
|
71
|
+
* you want an unknown-run check; appendGuidance itself creates the dir for
|
|
72
|
+
* robustness, but callers in chat-session.ts should guard first for UX).
|
|
73
|
+
*/
|
|
74
|
+
export async function appendGuidance(projectRoot, runId, text) {
|
|
75
|
+
if (!safeSegment(runId)) {
|
|
76
|
+
throw new Error(`Invalid runId "${runId}": must be a safe path segment (no path separators, no '..').`);
|
|
77
|
+
}
|
|
78
|
+
await ensureDir(runDir(projectRoot, runId));
|
|
79
|
+
const entry = {
|
|
80
|
+
ts: new Date().toISOString(),
|
|
81
|
+
text,
|
|
82
|
+
consumed: false,
|
|
83
|
+
};
|
|
84
|
+
// appendFile is safe for JSONL: each call writes exactly one complete line.
|
|
85
|
+
await appendFile(guidancePath(projectRoot, runId), JSON.stringify(entry) + "\n", "utf-8");
|
|
86
|
+
}
|
|
87
|
+
// ── Drain ─────────────────────────────────────────────────────────────
|
|
88
|
+
/**
|
|
89
|
+
* Drain pending (unconsumed) guidance entries for a runId.
|
|
90
|
+
*
|
|
91
|
+
* Reads all lines, collects the text of entries where consumed !== true,
|
|
92
|
+
* then atomically rewrites the file with ALL entries marked consumed:true
|
|
93
|
+
* (temp-file + rename, mirrors run-state.ts:41-52).
|
|
94
|
+
*
|
|
95
|
+
* Returns the drained texts in order.
|
|
96
|
+
* Missing file → returns [] (never throws — safe to call on every pipeline sprint).
|
|
97
|
+
* Second drain → returns [] (all entries already marked consumed).
|
|
98
|
+
*/
|
|
99
|
+
export async function drainGuidance(projectRoot, runId) {
|
|
100
|
+
const filePath = guidancePath(projectRoot, runId);
|
|
101
|
+
let raw;
|
|
102
|
+
try {
|
|
103
|
+
raw = await readFile(filePath, "utf-8");
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// File does not exist or is unreadable — return empty (no-op)
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
const lines = raw.split("\n").filter((l) => l.trim() !== "");
|
|
110
|
+
if (lines.length === 0)
|
|
111
|
+
return [];
|
|
112
|
+
const entries = [];
|
|
113
|
+
const drained = [];
|
|
114
|
+
for (const line of lines) {
|
|
115
|
+
try {
|
|
116
|
+
const entry = JSON.parse(line);
|
|
117
|
+
if (entry.consumed !== true) {
|
|
118
|
+
drained.push(entry.text);
|
|
119
|
+
}
|
|
120
|
+
entries.push({ ...entry, consumed: true });
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Skip malformed lines — do not lose other entries
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (drained.length === 0) {
|
|
127
|
+
// Nothing unconsumed — still rewrite atomically to normalize the file
|
|
128
|
+
// (all entries stay consumed:true from previous drain)
|
|
129
|
+
const allConsumed = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
130
|
+
const rnd = randomBytes(4).toString("hex");
|
|
131
|
+
const tmp = `${filePath}.${process.pid}.${Date.now()}.${rnd}.tmp`;
|
|
132
|
+
await writeFile(tmp, allConsumed, { encoding: "utf-8", mode: 0o600 });
|
|
133
|
+
await rename(tmp, filePath);
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
// Atomically rewrite all entries as consumed
|
|
137
|
+
const rewritten = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
138
|
+
const rnd = randomBytes(4).toString("hex");
|
|
139
|
+
const tmp = `${filePath}.${process.pid}.${Date.now()}.${rnd}.tmp`;
|
|
140
|
+
await writeFile(tmp, rewritten, { encoding: "utf-8", mode: 0o600 });
|
|
141
|
+
await rename(tmp, filePath);
|
|
142
|
+
return drained;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=guidance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guidance.js","sourceRoot":"","sources":["../../src/state/guidance.ts"],"names":[],"mappings":"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"}
|
package/dist/state/history.d.ts
CHANGED
|
@@ -13,13 +13,13 @@ export declare const HistoryEntrySchema: z.ZodObject<{
|
|
|
13
13
|
details: Record<string, unknown>;
|
|
14
14
|
timestamp: string;
|
|
15
15
|
event: string;
|
|
16
|
-
phase: "
|
|
16
|
+
phase: "complete" | "failed" | "init" | "planning" | "curating" | "generating" | "evaluating" | "rework";
|
|
17
17
|
sprintId?: string | undefined;
|
|
18
18
|
}, {
|
|
19
19
|
details: Record<string, unknown>;
|
|
20
20
|
timestamp: string;
|
|
21
21
|
event: string;
|
|
22
|
-
phase: "
|
|
22
|
+
phase: "complete" | "failed" | "init" | "planning" | "curating" | "generating" | "evaluating" | "rework";
|
|
23
23
|
sprintId?: string | undefined;
|
|
24
24
|
}>;
|
|
25
25
|
export type HistoryEntry = z.infer<typeof HistoryEntrySchema>;
|
package/dist/state/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { saveContract, loadContract, listContracts, updateContract, } from "./sprint-state.js";
|
|
1
|
+
export { saveContract, loadContract, listContracts, updateContract, clearContractsForSpec, } from "./sprint-state.js";
|
|
2
2
|
export { saveSpec, loadSpec, loadLatestSpec, listSpecs, } from "./plan-state.js";
|
|
3
3
|
export { PhaseSchema, HistoryEntrySchema, type Phase, type HistoryEntry, appendHistory, loadHistory, loadRecentHistory, updateProgress, } from "./history.js";
|
|
4
4
|
export { saveResearch, readResearch, listResearch, } from "./research-state.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAEL,WAAW,EACX,kBAAkB,EAElB,KAAK,KAAK,EACV,KAAK,YAAY,EAEjB,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,GACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,QAAQ,EACR,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAKxB;;;GAGG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvE"}
|
package/dist/state/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { ensureDir } from "./helpers.js";
|
|
3
|
-
export { saveContract, loadContract, listContracts, updateContract, } from "./sprint-state.js";
|
|
3
|
+
export { saveContract, loadContract, listContracts, updateContract, clearContractsForSpec, } from "./sprint-state.js";
|
|
4
4
|
export { saveSpec, loadSpec, loadLatestSpec, listSpecs, } from "./plan-state.js";
|
|
5
5
|
export {
|
|
6
6
|
// Zod schemas
|
package/dist/state/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAC;AAEzB,OAAO;AACL,cAAc;AACd,WAAW,EACX,kBAAkB;AAIlB,YAAY;AACZ,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,GACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,QAAQ,EACR,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,aAAa,GAKd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAExB,MAAM,SAAS,GAAG,QAAQ,CAAC;AAC3B,MAAM,OAAO,GAAG,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAU,CAAC;AAE1J;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAmB;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC/C,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;IAE3B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;IACxC,CAAC;AACH,CAAC"}
|
package/dist/state/memory.d.ts
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the memory directory path for the given namespace.
|
|
4
|
+
*
|
|
5
|
+
* Mapping rule (centralized here — do NOT duplicate in callers):
|
|
6
|
+
* namespace undefined | "" | "programming" → .bober/memory/ (current path, no subdir)
|
|
7
|
+
* any other value → .bober/memory/<ns>/
|
|
8
|
+
*
|
|
9
|
+
* The programming sentinel ("") comes from Sprint 1's built-in team (registry.ts:66).
|
|
10
|
+
* Values are constrained to ^[a-z0-9_-]+$ by the Sprint 1 schema regex, so no
|
|
11
|
+
* path-traversal sanitization is needed here (schema already guards config inputs).
|
|
12
|
+
*/
|
|
13
|
+
export declare function memoryDir(projectRoot: string, namespace?: string): string;
|
|
14
|
+
export declare function lessonPath(projectRoot: string, lessonId: string, namespace?: string): string;
|
|
15
|
+
export declare function indexPath(projectRoot: string, namespace?: string): string;
|
|
16
|
+
export declare function quarantinePath(projectRoot: string, namespace?: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Move lessonId lines from INDEX.md to QUARANTINE.md (line-level rewrite).
|
|
19
|
+
*
|
|
20
|
+
* - Reads INDEX.md and partitions non-blank lines: those whose second token
|
|
21
|
+
* (the lessonId) is in `quarantinedIds` are moved; the rest stay.
|
|
22
|
+
* - Rewrites INDEX.md with the kept lines.
|
|
23
|
+
* - Appends the moved lines to QUARANTINE.md (creating it if absent) with a
|
|
24
|
+
* deterministic provenance block: `<!-- quarantined: <reason> @ <now> -->`.
|
|
25
|
+
* - NEVER touches per-lesson <lessonId>.md files.
|
|
26
|
+
*
|
|
27
|
+
* @param projectRoot - Absolute project root containing .bober/
|
|
28
|
+
* @param quarantinedIds - Set of lessonIds to move out of INDEX.md
|
|
29
|
+
* @param reason - Human-readable reason (e.g. "decay" | "conflict")
|
|
30
|
+
* @param now - ISO 8601 wall-clock, injected by the CLI handler
|
|
31
|
+
* @param namespace - Optional memory namespace
|
|
32
|
+
*/
|
|
33
|
+
export declare function rewriteIndexForQuarantine(projectRoot: string, quarantinedIds: Set<string>, reason: string, now: string, namespace?: string): Promise<void>;
|
|
2
34
|
export declare const LessonEntrySchema: z.ZodObject<{
|
|
3
35
|
lessonId: z.ZodString;
|
|
4
36
|
createdAt: z.ZodString;
|
|
@@ -9,21 +41,21 @@ export declare const LessonEntrySchema: z.ZodObject<{
|
|
|
9
41
|
severity: z.ZodEnum<["info", "warn", "high"]>;
|
|
10
42
|
sourceEntryRefs: z.ZodArray<z.ZodString, "many">;
|
|
11
43
|
}, "strip", z.ZodTypeAny, {
|
|
12
|
-
severity: "info" | "high" | "warn";
|
|
13
|
-
summary: string;
|
|
14
|
-
category: string;
|
|
15
|
-
createdAt: string;
|
|
16
44
|
lessonId: string;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
category: string;
|
|
17
47
|
tags: string[];
|
|
48
|
+
summary: string;
|
|
18
49
|
occurrences: number;
|
|
50
|
+
severity: "info" | "warn" | "high";
|
|
19
51
|
sourceEntryRefs: string[];
|
|
20
52
|
}, {
|
|
21
|
-
severity: "info" | "high" | "warn";
|
|
22
|
-
summary: string;
|
|
23
|
-
category: string;
|
|
24
|
-
createdAt: string;
|
|
25
53
|
lessonId: string;
|
|
54
|
+
createdAt: string;
|
|
55
|
+
category: string;
|
|
56
|
+
summary: string;
|
|
26
57
|
occurrences: number;
|
|
58
|
+
severity: "info" | "warn" | "high";
|
|
27
59
|
sourceEntryRefs: string[];
|
|
28
60
|
tags?: string[] | undefined;
|
|
29
61
|
}>;
|
|
@@ -42,7 +74,7 @@ export interface LessonIndexRecord {
|
|
|
42
74
|
* Upserts exactly one INDEX.md line for this lessonId (replace if exists, else append).
|
|
43
75
|
* Throws if the lesson fails schema validation (sourceEntryRefs must be non-empty).
|
|
44
76
|
*/
|
|
45
|
-
export declare function appendLesson(projectRoot: string, lesson: LessonEntry): Promise<void>;
|
|
77
|
+
export declare function appendLesson(projectRoot: string, lesson: LessonEntry, namespace?: string): Promise<void>;
|
|
46
78
|
/**
|
|
47
79
|
* Load at most `limit` lesson index records from INDEX.md.
|
|
48
80
|
* Never opens individual lesson files — parses only INDEX.md.
|
|
@@ -50,11 +82,11 @@ export declare function appendLesson(projectRoot: string, lesson: LessonEntry):
|
|
|
50
82
|
*/
|
|
51
83
|
export declare function loadLessonIndex(projectRoot: string, { limit }: {
|
|
52
84
|
limit: number;
|
|
53
|
-
}): Promise<LessonIndexRecord[]>;
|
|
85
|
+
}, namespace?: string): Promise<LessonIndexRecord[]>;
|
|
54
86
|
/**
|
|
55
87
|
* Load a single lesson by ID from its <lessonId>.md file.
|
|
56
88
|
* Parses front-matter and validates against LessonEntrySchema.
|
|
57
89
|
* Throws a descriptive error if the file does not exist or fails validation.
|
|
58
90
|
*/
|
|
59
|
-
export declare function loadLesson(projectRoot: string, lessonId: string): Promise<LessonEntry>;
|
|
91
|
+
export declare function loadLesson(projectRoot: string, lessonId: string, namespace?: string): Promise<LessonEntry>;
|
|
60
92
|
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/state/memory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/state/memory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAKzE;AAID,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5F;AAED,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9E;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,EAC3B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAoDf;AAID,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AA6ID;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAkCf;AAID;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAC5B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAoB9B;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,CAAC,CAkCtB"}
|