agent-bober 0.17.0 → 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/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +25 -0
- package/README.md +169 -6
- 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/init.d.ts +9 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +1 -1
- package/dist/cli/commands/init.js.map +1 -1
- 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/commands/update.d.ts +18 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +81 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/index.js +15 -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,187 @@
|
|
|
1
|
+
// ── completion-tailer.ts ─────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Tails .bober/history.jsonl from a persisted byte cursor and returns new
|
|
4
|
+
// pipeline-complete events. Rotation-safe: detects shrink (stat.size < cursor)
|
|
5
|
+
// and resets the cursor to 0 before re-scanning. Dedupes by runId across polls
|
|
6
|
+
// and across session restarts via CursorStore.
|
|
7
|
+
//
|
|
8
|
+
// When the pipeline-complete line itself omits runId (pipeline.ts:925-934),
|
|
9
|
+
// the tailer falls back to scanning .bober/runs/<id>.completed.json markers.
|
|
10
|
+
import { readFile, stat, readdir } from "node:fs/promises";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { Buffer } from "node:buffer";
|
|
13
|
+
import { HistoryEntrySchema } from "../state/history.js";
|
|
14
|
+
import { historyActivePath } from "../state/history-rotation.js";
|
|
15
|
+
import { fileExists } from "../utils/fs.js";
|
|
16
|
+
import { CursorStore } from "./cursor-store.js";
|
|
17
|
+
// ── Helpers ────────────────────────────────────────────────────────────
|
|
18
|
+
/**
|
|
19
|
+
* Extract runId from a parsed JSONL record (mirrors event-stream.ts:47-58).
|
|
20
|
+
* Returns undefined when the record does not carry a runId — callers must
|
|
21
|
+
* fall back to the .completed.json marker.
|
|
22
|
+
*/
|
|
23
|
+
function extractRunId(rec) {
|
|
24
|
+
if (typeof rec !== "object" || rec === null)
|
|
25
|
+
return undefined;
|
|
26
|
+
const r = rec;
|
|
27
|
+
if (typeof r.runId === "string")
|
|
28
|
+
return r.runId;
|
|
29
|
+
if (typeof r.details === "object" && r.details !== null) {
|
|
30
|
+
const d = r.details;
|
|
31
|
+
if (typeof d.runId === "string")
|
|
32
|
+
return d.runId;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Scan .bober/runs/ for any .completed.json markers that are NOT already in
|
|
38
|
+
* seenRunIds. Returns the first unmatched runId found, or undefined.
|
|
39
|
+
* Used as a fallback when the pipeline-complete history line omits runId.
|
|
40
|
+
*/
|
|
41
|
+
async function findUnseenMarkerRunId(projectRoot, seenRunIds, timestamp) {
|
|
42
|
+
const runsDir = join(projectRoot, ".bober", "runs");
|
|
43
|
+
let entries;
|
|
44
|
+
try {
|
|
45
|
+
entries = await readdir(runsDir);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
if (!entry.endsWith(".completed.json"))
|
|
52
|
+
continue;
|
|
53
|
+
const runId = entry.slice(0, -".completed.json".length);
|
|
54
|
+
if (seenRunIds.has(runId))
|
|
55
|
+
continue;
|
|
56
|
+
// Verify the file actually exists and contains a matching runId
|
|
57
|
+
const markerPath = join(runsDir, entry);
|
|
58
|
+
if (!(await fileExists(markerPath)))
|
|
59
|
+
continue;
|
|
60
|
+
try {
|
|
61
|
+
const raw = await readFile(markerPath, "utf-8");
|
|
62
|
+
const parsed = JSON.parse(raw);
|
|
63
|
+
const markerRunId = typeof parsed.runId === "string" ? parsed.runId : runId;
|
|
64
|
+
// Cross-correlate by proximity: use if not yet seen.
|
|
65
|
+
// bober: uses first-unseen marker; for multi-run sessions this may
|
|
66
|
+
// mis-assign. Upgrade path: embed runId in the pipeline-complete line.
|
|
67
|
+
void timestamp; // parameter kept for future timestamp-based correlation
|
|
68
|
+
return markerRunId;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Malformed marker — skip
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
// ── CompletionTailer ───────────────────────────────────────────────────
|
|
77
|
+
export class CompletionTailer {
|
|
78
|
+
projectRoot;
|
|
79
|
+
store;
|
|
80
|
+
constructor(projectRoot, sessionId) {
|
|
81
|
+
this.projectRoot = projectRoot;
|
|
82
|
+
this.store = new CursorStore(projectRoot, sessionId);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Poll .bober/history.jsonl for new pipeline-complete events since the last
|
|
86
|
+
* persisted byte cursor. Returns only newly-seen completions.
|
|
87
|
+
*
|
|
88
|
+
* Algorithm:
|
|
89
|
+
* 1. stat the file; ENOENT → return [].
|
|
90
|
+
* 2. If stat.size < cursor (rotation/shrink) → readFrom = 0.
|
|
91
|
+
* 3. Read bytes [readFrom, EOF) via Buffer slice.
|
|
92
|
+
* 4. Parse complete lines only (skip partial trailing line).
|
|
93
|
+
* 5. Filter for event === "pipeline-complete"; extract runId via marker.
|
|
94
|
+
* 6. Dedupe against seenRunIds; persist updated cursor + seenRunIds.
|
|
95
|
+
*/
|
|
96
|
+
async poll() {
|
|
97
|
+
const cursor = await this.store.read();
|
|
98
|
+
const seenSet = new Set(cursor.seenRunIds);
|
|
99
|
+
const histPath = historyActivePath(this.projectRoot);
|
|
100
|
+
// Step 1: stat — ENOENT → graceful empty
|
|
101
|
+
let fileSize;
|
|
102
|
+
try {
|
|
103
|
+
const s = await stat(histPath);
|
|
104
|
+
fileSize = s.size;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// File missing — return empty, do NOT alter the stored cursor
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
// Step 2: Rotation/shrink detection
|
|
111
|
+
const readFrom = fileSize < cursor.byteCursor ? 0 : cursor.byteCursor;
|
|
112
|
+
// Step 3: Read bytes [readFrom, EOF)
|
|
113
|
+
let buf;
|
|
114
|
+
try {
|
|
115
|
+
const full = await readFile(histPath);
|
|
116
|
+
buf = full.subarray(readFrom);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
// Step 4: Keep only complete lines (up to last \n)
|
|
122
|
+
// Find the last newline byte position
|
|
123
|
+
let lastNewline = -1;
|
|
124
|
+
for (let i = buf.length - 1; i >= 0; i--) {
|
|
125
|
+
if (buf[i] === 0x0a) {
|
|
126
|
+
// '\n'
|
|
127
|
+
lastNewline = i;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// If there are no complete lines at all, persist potentially-reset cursor
|
|
132
|
+
// but return empty. Advance cursor only over complete lines.
|
|
133
|
+
const consumedBuf = lastNewline >= 0 ? buf.subarray(0, lastNewline + 1) : Buffer.alloc(0);
|
|
134
|
+
const newByteCursor = readFrom + consumedBuf.length;
|
|
135
|
+
const events = [];
|
|
136
|
+
if (consumedBuf.length > 0) {
|
|
137
|
+
const text = consumedBuf.toString("utf-8");
|
|
138
|
+
const lines = text.split("\n").filter((l) => l.trim().length > 0);
|
|
139
|
+
for (const line of lines) {
|
|
140
|
+
let parsed;
|
|
141
|
+
try {
|
|
142
|
+
parsed = JSON.parse(line);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
continue; // Skip malformed JSON
|
|
146
|
+
}
|
|
147
|
+
const result = HistoryEntrySchema.safeParse(parsed);
|
|
148
|
+
if (!result.success)
|
|
149
|
+
continue;
|
|
150
|
+
const entry = result.data;
|
|
151
|
+
if (entry.event !== "pipeline-complete")
|
|
152
|
+
continue;
|
|
153
|
+
const phase = entry.phase;
|
|
154
|
+
const details = entry.details;
|
|
155
|
+
const completed = typeof details.completed === "number" ? details.completed : 0;
|
|
156
|
+
const failed = typeof details.failed === "number" ? details.failed : 0;
|
|
157
|
+
const durationMs = typeof details.durationMs === "number" ? details.durationMs : 0;
|
|
158
|
+
// Resolve runId: line-level first, then .completed.json marker fallback
|
|
159
|
+
let runId = extractRunId(parsed);
|
|
160
|
+
if (!runId) {
|
|
161
|
+
runId = await findUnseenMarkerRunId(this.projectRoot, seenSet, entry.timestamp);
|
|
162
|
+
}
|
|
163
|
+
// Build synthetic dedupe key for completions with no resolvable runId
|
|
164
|
+
const dedupeKey = runId ?? `${entry.timestamp}:${durationMs}`;
|
|
165
|
+
if (seenSet.has(dedupeKey))
|
|
166
|
+
continue;
|
|
167
|
+
seenSet.add(dedupeKey);
|
|
168
|
+
events.push({
|
|
169
|
+
runId,
|
|
170
|
+
phase,
|
|
171
|
+
completed,
|
|
172
|
+
failed,
|
|
173
|
+
durationMs,
|
|
174
|
+
timestamp: entry.timestamp,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Step 6: Persist updated cursor + seenRunIds
|
|
179
|
+
await this.store.write({
|
|
180
|
+
byteCursor: newByteCursor,
|
|
181
|
+
lastSize: fileSize,
|
|
182
|
+
seenRunIds: Array.from(seenSet),
|
|
183
|
+
});
|
|
184
|
+
return events;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=completion-tailer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion-tailer.js","sourceRoot":"","sources":["../../src/chat/completion-tailer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface TurnRecord {
|
|
2
|
+
role: "user" | "assistant";
|
|
3
|
+
content: string;
|
|
4
|
+
ts: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class ConversationStore {
|
|
7
|
+
private readonly projectRoot;
|
|
8
|
+
private readonly sessionId;
|
|
9
|
+
constructor(projectRoot: string, sessionId: string);
|
|
10
|
+
/**
|
|
11
|
+
* Append a turn record to the session JSONL file.
|
|
12
|
+
* Creates the .bober/chat/ directory if it does not yet exist.
|
|
13
|
+
*/
|
|
14
|
+
append(record: TurnRecord): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Load the most recent `limit` turns from the session JSONL.
|
|
17
|
+
* Returns records newest-last (chronological order).
|
|
18
|
+
* Skips any malformed (non-parseable) lines silently.
|
|
19
|
+
*/
|
|
20
|
+
loadRecent(limit: number): Promise<TurnRecord[]>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=conversation-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-store.d.ts","sourceRoot":"","sources":["../../src/chat/conversation-store.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAcD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKlD;;;OAGG;IACG,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/C;;;;OAIG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAyBvD"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// ── conversation-store.ts ──────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Append-only JSONL persistence for chat conversations.
|
|
4
|
+
// Layout: .bober/chat/<sessionId>.jsonl
|
|
5
|
+
// Each line is a JSON-encoded TurnRecord.
|
|
6
|
+
import { appendFile, readFile } from "node:fs/promises";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { ensureDir } from "../utils/fs.js";
|
|
9
|
+
// ── Path helpers ──────────────────────────────────────────────────────
|
|
10
|
+
function chatDir(projectRoot) {
|
|
11
|
+
return join(projectRoot, ".bober", "chat");
|
|
12
|
+
}
|
|
13
|
+
function sessionPath(projectRoot, sessionId) {
|
|
14
|
+
return join(chatDir(projectRoot), `${sessionId}.jsonl`);
|
|
15
|
+
}
|
|
16
|
+
// ── ConversationStore ─────────────────────────────────────────────────
|
|
17
|
+
export class ConversationStore {
|
|
18
|
+
projectRoot;
|
|
19
|
+
sessionId;
|
|
20
|
+
constructor(projectRoot, sessionId) {
|
|
21
|
+
this.projectRoot = projectRoot;
|
|
22
|
+
this.sessionId = sessionId;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Append a turn record to the session JSONL file.
|
|
26
|
+
* Creates the .bober/chat/ directory if it does not yet exist.
|
|
27
|
+
*/
|
|
28
|
+
async append(record) {
|
|
29
|
+
const dir = chatDir(this.projectRoot);
|
|
30
|
+
await ensureDir(dir);
|
|
31
|
+
const path = sessionPath(this.projectRoot, this.sessionId);
|
|
32
|
+
await appendFile(path, JSON.stringify(record) + "\n", "utf-8");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Load the most recent `limit` turns from the session JSONL.
|
|
36
|
+
* Returns records newest-last (chronological order).
|
|
37
|
+
* Skips any malformed (non-parseable) lines silently.
|
|
38
|
+
*/
|
|
39
|
+
async loadRecent(limit) {
|
|
40
|
+
const path = sessionPath(this.projectRoot, this.sessionId);
|
|
41
|
+
let raw;
|
|
42
|
+
try {
|
|
43
|
+
raw = await readFile(path, "utf-8");
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// File does not exist yet — no prior conversation
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const records = [];
|
|
50
|
+
for (const line of raw.split("\n")) {
|
|
51
|
+
const trimmed = line.trim();
|
|
52
|
+
if (trimmed.length === 0)
|
|
53
|
+
continue;
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(trimmed);
|
|
56
|
+
records.push(parsed);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Skip malformed lines
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Return up to `limit` newest-last (chronological order = array tail)
|
|
63
|
+
return records.slice(-limit);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=conversation-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-store.js","sourceRoot":"","sources":["../../src/chat/conversation-store.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,wDAAwD;AACxD,wCAAwC;AACxC,0CAA0C;AAE1C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAU3C,yEAAyE;AAEzE,SAAS,OAAO,CAAC,WAAmB;IAClC,OAAO,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,WAAW,CAAC,WAAmB,EAAE,SAAiB;IACzD,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,GAAG,SAAS,QAAQ,CAAC,CAAC;AAC1D,CAAC;AAED,yEAAyE;AAEzE,MAAM,OAAO,iBAAiB;IACX,WAAW,CAAS;IACpB,SAAS,CAAS;IAEnC,YAAY,WAAmB,EAAE,SAAiB;QAChD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,MAAkB;QAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QACrB,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3D,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAU,CAAC,KAAa;QAC5B,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3D,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;YAClD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,OAAO,GAAiB,EAAE,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACnC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAe,CAAC;gBACjD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;QACH,CAAC;QAED,sEAAsE;QACtE,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface CursorFile {
|
|
2
|
+
byteCursor: number;
|
|
3
|
+
lastSize: number;
|
|
4
|
+
/** Serialised as an array; hydrate into a Set on read. */
|
|
5
|
+
seenRunIds: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare class CursorStore {
|
|
8
|
+
private readonly projectRoot;
|
|
9
|
+
private readonly sessionId;
|
|
10
|
+
constructor(projectRoot: string, sessionId: string);
|
|
11
|
+
private path;
|
|
12
|
+
/**
|
|
13
|
+
* Read the stored cursor. Returns the zero-state default on any error
|
|
14
|
+
* (missing file, malformed JSON) — never throws.
|
|
15
|
+
*/
|
|
16
|
+
read(): Promise<CursorFile>;
|
|
17
|
+
/**
|
|
18
|
+
* Persist an updated cursor file to disk.
|
|
19
|
+
* Creates .bober/chat/ if it does not exist.
|
|
20
|
+
*/
|
|
21
|
+
write(cursor: CursorFile): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=cursor-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-store.d.ts","sourceRoot":"","sources":["../../src/chat/cursor-store.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAMD,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM;IAGpC,OAAO,CAAC,IAAI;IASZ;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IAQjC;;;OAGG;IACG,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ/C"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// ── cursor-store.ts ──────────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Persists the byte cursor + seen-run-ids set for a CompletionTailer session
|
|
4
|
+
// at .bober/chat/<sessionId>.cursor.json. Survives REPL restarts.
|
|
5
|
+
// Modeled on pid-sidecar.ts (sc-3-6).
|
|
6
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { ensureDir } from "../utils/fs.js";
|
|
9
|
+
const EMPTY = { byteCursor: 0, lastSize: 0, seenRunIds: [] };
|
|
10
|
+
// ── CursorStore ────────────────────────────────────────────────────────
|
|
11
|
+
export class CursorStore {
|
|
12
|
+
projectRoot;
|
|
13
|
+
sessionId;
|
|
14
|
+
constructor(projectRoot, sessionId) {
|
|
15
|
+
this.projectRoot = projectRoot;
|
|
16
|
+
this.sessionId = sessionId;
|
|
17
|
+
}
|
|
18
|
+
path() {
|
|
19
|
+
return join(this.projectRoot, ".bober", "chat", `${this.sessionId}.cursor.json`);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read the stored cursor. Returns the zero-state default on any error
|
|
23
|
+
* (missing file, malformed JSON) — never throws.
|
|
24
|
+
*/
|
|
25
|
+
async read() {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(await readFile(this.path(), "utf-8"));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return { ...EMPTY };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Persist an updated cursor file to disk.
|
|
35
|
+
* Creates .bober/chat/ if it does not exist.
|
|
36
|
+
*/
|
|
37
|
+
async write(cursor) {
|
|
38
|
+
await ensureDir(join(this.projectRoot, ".bober", "chat"));
|
|
39
|
+
await writeFile(this.path(), JSON.stringify(cursor, null, 2) + "\n", { encoding: "utf-8", mode: 0o600 });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=cursor-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-store.js","sourceRoot":"","sources":["../../src/chat/cursor-store.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,6EAA6E;AAC7E,kEAAkE;AAClE,sCAAsC;AAEtC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAW3C,MAAM,KAAK,GAAe,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;AAEzE,0EAA0E;AAE1E,MAAM,OAAO,WAAW;IAEH;IACA;IAFnB,YACmB,WAAmB,EACnB,SAAiB;QADjB,gBAAW,GAAX,WAAW,CAAQ;QACnB,cAAS,GAAT,SAAS,CAAQ;IACjC,CAAC;IAEI,IAAI;QACV,OAAO,IAAI,CACT,IAAI,CAAC,WAAW,EAChB,QAAQ,EACR,MAAM,EACN,GAAG,IAAI,CAAC,SAAS,cAAc,CAChC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAe,CAAC;QACxE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK,CAAC,MAAkB;QAC5B,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1D,MAAM,SAAS,CACb,IAAI,CAAC,IAAI,EAAE,EACX,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EACtC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CACnC,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface PidEntry {
|
|
2
|
+
pid?: number;
|
|
3
|
+
task: string;
|
|
4
|
+
spawnedAt: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class PidSidecar {
|
|
7
|
+
private readonly projectRoot;
|
|
8
|
+
private readonly sessionId;
|
|
9
|
+
constructor(projectRoot: string, sessionId: string);
|
|
10
|
+
private path;
|
|
11
|
+
/**
|
|
12
|
+
* Read all pid entries for this session from disk.
|
|
13
|
+
* Returns an empty map if the file is missing or malformed — never throws.
|
|
14
|
+
*/
|
|
15
|
+
readAll(): Promise<Record<string, PidEntry>>;
|
|
16
|
+
/**
|
|
17
|
+
* Record a runId->PidEntry mapping persistently.
|
|
18
|
+
* Reads existing entries, merges, and atomically rewrites the sidecar file.
|
|
19
|
+
*/
|
|
20
|
+
record(runId: string, entry: PidEntry): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=pid-sidecar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pid-sidecar.d.ts","sourceRoot":"","sources":["../../src/chat/pid-sidecar.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,qBAAa,UAAU;IAEnB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM;IAGpC,OAAO,CAAC,IAAI;IASZ;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAUlD;;;OAGG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAU5D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// ── pid-sidecar.ts ─────────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Persists runId -> {pid, task, spawnedAt} for a chat session at
|
|
4
|
+
// .bober/chat/<sessionId>.pids.json. Survives across instances (sc-2-7).
|
|
5
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { ensureDir } from "../utils/fs.js";
|
|
8
|
+
// ── PidSidecar ────────────────────────────────────────────────────────
|
|
9
|
+
export class PidSidecar {
|
|
10
|
+
projectRoot;
|
|
11
|
+
sessionId;
|
|
12
|
+
constructor(projectRoot, sessionId) {
|
|
13
|
+
this.projectRoot = projectRoot;
|
|
14
|
+
this.sessionId = sessionId;
|
|
15
|
+
}
|
|
16
|
+
path() {
|
|
17
|
+
return join(this.projectRoot, ".bober", "chat", `${this.sessionId}.pids.json`);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read all pid entries for this session from disk.
|
|
21
|
+
* Returns an empty map if the file is missing or malformed — never throws.
|
|
22
|
+
*/
|
|
23
|
+
async readAll() {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(await readFile(this.path(), "utf-8"));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Record a runId->PidEntry mapping persistently.
|
|
33
|
+
* Reads existing entries, merges, and atomically rewrites the sidecar file.
|
|
34
|
+
*/
|
|
35
|
+
async record(runId, entry) {
|
|
36
|
+
await ensureDir(join(this.projectRoot, ".bober", "chat"));
|
|
37
|
+
const all = await this.readAll();
|
|
38
|
+
all[runId] = entry;
|
|
39
|
+
await writeFile(this.path(), JSON.stringify(all, null, 2) + "\n", { encoding: "utf-8", mode: 0o600 });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=pid-sidecar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pid-sidecar.js","sourceRoot":"","sources":["../../src/chat/pid-sidecar.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,iEAAiE;AACjE,yEAAyE;AAEzE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAU3C,yEAAyE;AAEzE,MAAM,OAAO,UAAU;IAEF;IACA;IAFnB,YACmB,WAAmB,EACnB,SAAiB;QADjB,gBAAW,GAAX,WAAW,CAAQ;QACnB,cAAS,GAAT,SAAS,CAAQ;IACjC,CAAC;IAEI,IAAI;QACV,OAAO,IAAI,CACT,IAAI,CAAC,WAAW,EAChB,QAAQ,EACR,MAAM,EACN,GAAG,IAAI,CAAC,SAAS,YAAY,CAC9B,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CACf,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,CACT,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,KAAe;QACzC,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QACnB,MAAM,SAAS,CACb,IAAI,CAAC,IAAI,EAAE,EACX,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EACnC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CACnC,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RunState } from "../mcp/run-manager.js";
|
|
2
|
+
export declare class RosterReader {
|
|
3
|
+
private readonly projectRoot;
|
|
4
|
+
constructor(projectRoot: string);
|
|
5
|
+
/**
|
|
6
|
+
* Read all run states from disk. Delegated entirely to readRunStatesFromDisk
|
|
7
|
+
* which is purely read-only and never mutates disk state.
|
|
8
|
+
*/
|
|
9
|
+
read(): Promise<RunState[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Produce a compact human-readable summary of the given run states.
|
|
12
|
+
* Used for /runs slash-command output and as LLM prompt context.
|
|
13
|
+
*/
|
|
14
|
+
summarize(states: RunState[]): string;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=roster-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roster-reader.d.ts","sourceRoot":"","sources":["../../src/chat/roster-reader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAItD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,WAAW,EAAE,MAAM;IAI/B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAIjC;;;OAGG;IACH,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM;CAoBtC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// ── roster-reader.ts ──────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Read-only wrapper over readRunStatesFromDisk for chat context.
|
|
4
|
+
// Uses readRunStatesFromDisk (read-only) — never the reconciling load method.
|
|
5
|
+
import { readRunStatesFromDisk } from "../state/run-state.js";
|
|
6
|
+
// ── RosterReader ──────────────────────────────────────────────────────
|
|
7
|
+
export class RosterReader {
|
|
8
|
+
projectRoot;
|
|
9
|
+
constructor(projectRoot) {
|
|
10
|
+
this.projectRoot = projectRoot;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Read all run states from disk. Delegated entirely to readRunStatesFromDisk
|
|
14
|
+
* which is purely read-only and never mutates disk state.
|
|
15
|
+
*/
|
|
16
|
+
async read() {
|
|
17
|
+
return readRunStatesFromDisk(this.projectRoot);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Produce a compact human-readable summary of the given run states.
|
|
21
|
+
* Used for /runs slash-command output and as LLM prompt context.
|
|
22
|
+
*/
|
|
23
|
+
summarize(states) {
|
|
24
|
+
if (states.length === 0) {
|
|
25
|
+
return "No runs found.";
|
|
26
|
+
}
|
|
27
|
+
const lines = [`Runs (${states.length} total):`];
|
|
28
|
+
for (const s of states) {
|
|
29
|
+
const completed = s.completedAt ? ` completed=${s.completedAt}` : "";
|
|
30
|
+
const spec = s.specId ? ` spec=${s.specId}` : "";
|
|
31
|
+
const pending = s.status === "input-required" && s.pendingCheckpointId
|
|
32
|
+
? ` waiting=${s.pendingCheckpointId}`
|
|
33
|
+
: "";
|
|
34
|
+
lines.push(` [${s.status.toUpperCase()}] ${s.runId} task="${s.task}"${spec} started=${s.startedAt}${completed}${pending}`);
|
|
35
|
+
}
|
|
36
|
+
return lines.join("\n");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=roster-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roster-reader.js","sourceRoot":"","sources":["../../src/chat/roster-reader.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,iEAAiE;AACjE,8EAA8E;AAE9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,yEAAyE;AAEzE,MAAM,OAAO,YAAY;IACN,WAAW,CAAS;IAErC,YAAY,WAAmB;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI;QACR,OAAO,qBAAqB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACjD,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,MAAkB;QAC1B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,gBAAgB,CAAC;QAC1B,CAAC;QAED,MAAM,KAAK,GAAa,CAAC,SAAS,MAAM,CAAC,MAAM,UAAU,CAAC,CAAC;QAC3D,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,SAAS,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,MAAM,OAAO,GACX,CAAC,CAAC,MAAM,KAAK,gBAAgB,IAAI,CAAC,CAAC,mBAAmB;gBACpD,CAAC,CAAC,YAAY,CAAC,CAAC,mBAAmB,EAAE;gBACrC,CAAC,CAAC,EAAE,CAAC;YACT,KAAK,CAAC,IAAI,CACR,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,IAAI,IAAI,IAAI,aAAa,CAAC,CAAC,SAAS,GAAG,SAAS,GAAG,OAAO,EAAE,CAClH,CAAC;QACJ,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export interface StopResult {
|
|
2
|
+
stopped: boolean;
|
|
3
|
+
runId: string;
|
|
4
|
+
killedPid?: number;
|
|
5
|
+
fallbackFlagOnly?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface SpawnAck {
|
|
8
|
+
runId: string;
|
|
9
|
+
task: string;
|
|
10
|
+
pid?: number;
|
|
11
|
+
cwd: string;
|
|
12
|
+
spawnError?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Injected spawn fn — default wraps execa. Tests pass a fake that records
|
|
16
|
+
* args + returns a fake child without launching a real process.
|
|
17
|
+
*/
|
|
18
|
+
export type SpawnFn = (file: string, args: string[], options: {
|
|
19
|
+
cwd: string;
|
|
20
|
+
detached: boolean;
|
|
21
|
+
stdio: "ignore";
|
|
22
|
+
}) => {
|
|
23
|
+
pid?: number;
|
|
24
|
+
unref: () => void;
|
|
25
|
+
};
|
|
26
|
+
/** Injected kill function. Defaults to process.kill. Tests pass a fake. */
|
|
27
|
+
export type KillFn = (pid: number, signal?: string | number) => void;
|
|
28
|
+
export interface RunSpawnerOptions {
|
|
29
|
+
projectRoot: string;
|
|
30
|
+
sessionId: string;
|
|
31
|
+
/** Injected spawn function. Defaults to a thin execa wrapper. */
|
|
32
|
+
spawn?: SpawnFn;
|
|
33
|
+
/** Injected CLI entry path. Defaults to resolveCliEntry(). */
|
|
34
|
+
cliEntry?: string;
|
|
35
|
+
/** Injected Node.js binary path. Defaults to process.execPath. */
|
|
36
|
+
nodeBin?: string;
|
|
37
|
+
/** Injected clock returning ISO string. Defaults to () => new Date().toISOString(). */
|
|
38
|
+
now?: () => string;
|
|
39
|
+
/** Injected kill function. Defaults to process.kill. Tests pass a fake. */
|
|
40
|
+
kill?: KillFn;
|
|
41
|
+
}
|
|
42
|
+
export declare class RunSpawner {
|
|
43
|
+
private readonly projectRoot;
|
|
44
|
+
private readonly sessionId;
|
|
45
|
+
private readonly spawnFn;
|
|
46
|
+
private readonly killFn;
|
|
47
|
+
private readonly cliEntry;
|
|
48
|
+
private readonly nodeBin;
|
|
49
|
+
private readonly now;
|
|
50
|
+
private readonly sidecar;
|
|
51
|
+
constructor(opts: RunSpawnerOptions);
|
|
52
|
+
/**
|
|
53
|
+
* Write the roster state.json, launch a detached child, record the pid,
|
|
54
|
+
* and return an immediate SpawnAck without waiting for the child to finish.
|
|
55
|
+
*
|
|
56
|
+
* @param opts.careful - When true, appends --approve-gates with the curated
|
|
57
|
+
* gate list to the child args. Default false (autopilot — byte-for-byte
|
|
58
|
+
* identical to Phase 1 behavior).
|
|
59
|
+
*/
|
|
60
|
+
spawn(task: string, runId: string, opts?: {
|
|
61
|
+
careful?: boolean;
|
|
62
|
+
}): Promise<SpawnAck>;
|
|
63
|
+
/**
|
|
64
|
+
* Stop a running run by its runId.
|
|
65
|
+
* Resolves the PID from the session sidecar and sends SIGTERM.
|
|
66
|
+
* If no sidecar entry is found, flips state to 'aborted' on disk only.
|
|
67
|
+
* Tolerates ESRCH (already-dead pid) — treat as already stopped.
|
|
68
|
+
*/
|
|
69
|
+
stop(runId: string, reason: string): Promise<StopResult>;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=run-spawner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-spawner.d.ts","sourceRoot":"","sources":["../../src/chat/run-spawner.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,CACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,KACzD;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC;AAEzC,2EAA2E;AAC3E,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;gBAEzB,IAAI,EAAE,iBAAiB;IAkBnC;;;;;;;OAOG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IA6C7F;;;;;OAKG;IACG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CAqC/D"}
|