oh-my-claudecode 0.2.1 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -2
- package/commands/cthulhu.md +9 -0
- package/commands/necronomicon-bind.md +106 -0
- package/dist/cli/bind-cron.d.ts +86 -0
- package/dist/cli/bind-cron.d.ts.map +1 -0
- package/dist/cli/bind-cron.js +161 -0
- package/dist/cli/bind-cron.js.map +1 -0
- package/dist/cli/bind.d.ts +78 -0
- package/dist/cli/bind.d.ts.map +1 -0
- package/dist/cli/bind.js +417 -0
- package/dist/cli/bind.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +43 -7
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.js +61 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/install.d.ts.map +1 -1
- package/dist/cli/install.js +106 -16
- package/dist/cli/install.js.map +1 -1
- package/dist/cli/project-scan.d.ts +94 -0
- package/dist/cli/project-scan.d.ts.map +1 -0
- package/dist/cli/project-scan.js +387 -0
- package/dist/cli/project-scan.js.map +1 -0
- package/dist/cli/sisyphus-migrate.d.ts +50 -0
- package/dist/cli/sisyphus-migrate.d.ts.map +1 -0
- package/dist/cli/sisyphus-migrate.js +226 -0
- package/dist/cli/sisyphus-migrate.js.map +1 -0
- package/dist/cli/tui.d.ts +94 -0
- package/dist/cli/tui.d.ts.map +1 -0
- package/dist/cli/tui.js +180 -0
- package/dist/cli/tui.js.map +1 -0
- package/dist/features/yith-archive/functions/backfill.d.ts +70 -0
- package/dist/features/yith-archive/functions/backfill.d.ts.map +1 -0
- package/dist/features/yith-archive/functions/backfill.js +572 -0
- package/dist/features/yith-archive/functions/backfill.js.map +1 -0
- package/dist/features/yith-archive/functions/compress-batch.d.ts +4 -0
- package/dist/features/yith-archive/functions/compress-batch.d.ts.map +1 -0
- package/dist/features/yith-archive/functions/compress-batch.js +290 -0
- package/dist/features/yith-archive/functions/compress-batch.js.map +1 -0
- package/dist/features/yith-archive/functions/compress.d.ts +2 -1
- package/dist/features/yith-archive/functions/compress.d.ts.map +1 -1
- package/dist/features/yith-archive/functions/compress.js +1 -1
- package/dist/features/yith-archive/functions/compress.js.map +1 -1
- package/dist/features/yith-archive/functions/opencode-import.d.ts +67 -0
- package/dist/features/yith-archive/functions/opencode-import.d.ts.map +1 -0
- package/dist/features/yith-archive/functions/opencode-import.js +272 -0
- package/dist/features/yith-archive/functions/opencode-import.js.map +1 -0
- package/dist/features/yith-archive/index.d.ts.map +1 -1
- package/dist/features/yith-archive/index.js +27 -2
- package/dist/features/yith-archive/index.js.map +1 -1
- package/dist/features/yith-archive/providers/embedding/local.d.ts +22 -0
- package/dist/features/yith-archive/providers/embedding/local.d.ts.map +1 -1
- package/dist/features/yith-archive/providers/embedding/local.js +56 -2
- package/dist/features/yith-archive/providers/embedding/local.js.map +1 -1
- package/dist/features/yith-archive/state/bind-state.d.ts +84 -0
- package/dist/features/yith-archive/state/bind-state.d.ts.map +1 -0
- package/dist/features/yith-archive/state/bind-state.js +120 -0
- package/dist/features/yith-archive/state/bind-state.js.map +1 -0
- package/dist/features/yith-archive/state/schema.d.ts +22 -0
- package/dist/features/yith-archive/state/schema.d.ts.map +1 -1
- package/dist/features/yith-archive/state/schema.js +22 -0
- package/dist/features/yith-archive/state/schema.js.map +1 -1
- package/dist/hooks/cthulhu-auto.d.ts +1 -1
- package/dist/hooks/cthulhu-auto.d.ts.map +1 -1
- package/dist/hooks/cthulhu-auto.js +75 -0
- package/dist/hooks/cthulhu-auto.js.map +1 -1
- package/dist/hooks/cthulhu-preflight.d.ts +45 -0
- package/dist/hooks/cthulhu-preflight.d.ts.map +1 -0
- package/dist/hooks/cthulhu-preflight.js +91 -0
- package/dist/hooks/cthulhu-preflight.js.map +1 -0
- package/dist/hooks/memory-override.d.ts +1 -1
- package/dist/hooks/memory-override.d.ts.map +1 -1
- package/dist/hooks/memory-override.js +13 -5
- package/dist/hooks/memory-override.js.map +1 -1
- package/dist/mcp/yith-catalog.d.ts.map +1 -1
- package/dist/mcp/yith-catalog.js +6 -0
- package/dist/mcp/yith-catalog.js.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ These aren't three plugins you pick and choose. They're one integrated system th
|
|
|
61
61
|
| **Work-packet protocol** | LLM-requiring memory ops (consolidate, summarize, reflect, etc.) run in sessions with no API key — each function has a state-machine variant that emits prompts for the parent agent to execute with its own subscription auth. |
|
|
62
62
|
| **Block Summarizer** | In-session delegation summarization with on-disk block archive |
|
|
63
63
|
| **8 lifecycle hooks** | Auto-activation, memory redirect, todo enforcement, completion loops, code-quality checks, rule injection, write guards |
|
|
64
|
-
| **
|
|
64
|
+
| **10 slash commands** | Direct-invoke any mode or flow from the Claude Code chat bar |
|
|
65
65
|
| **Intent gate** | Every user message is classified and routed before Cthulhu acts |
|
|
66
66
|
| **Work plan system** | Multi-step planning flow with interview → scope → plan → review before execution |
|
|
67
67
|
| **3-level config** | Defaults → user (`~/.claude/oh-my-claudecode.jsonc`) → project (`.claude/...`) with Zod validation and partial parsing |
|
|
@@ -140,10 +140,57 @@ Named for the Great Race of Yith from *The Shadow Out of Time* — mind-transfer
|
|
|
140
140
|
- **Exposed as an MCP server** — during `install`, Yith Archive is registered with Claude Code as a stdio MCP server named `yith-archive`. Sessions get 7 tools: `yith_remember`, `yith_search`, `yith_recall`, `yith_context`, `yith_observe`, `yith_commit_work`, and `yith_trigger` (escape hatch for ~90 advanced memory functions, with a curated top-20 catalog embedded in the tool description).
|
|
141
141
|
- **Rich memory primitives** — `remember`, `search`, `recall`, `context`, `observe`, plus dozens more under the hood: consolidation pipelines, temporal graph retrieval, lesson crystallization, pattern extraction, eviction and retention policies, file-scoped memory index, sliding window compression, query expansion, working memory, session timeline, export/import.
|
|
142
142
|
- **Automatic capture** — notable events during a session can be observed into the archive; a background consolidation pass merges similar memories into distilled lessons.
|
|
143
|
-
- **Zero external runtime** — file-backed JSON storage
|
|
143
|
+
- **Zero external runtime** — file-backed JSON storage at `~/.oh-my-claudecode/yith/necronomicon.json` (legacy installs are auto-migrated from `store.json` on boot). Atomic writes via tmpfile + rename so a crash mid-write can't corrupt the tome. No database, no background server, no subprocess, no network, no ports to manage. The MCP server itself is registered user-level in `~/.claude.json`.
|
|
144
144
|
- **Crash-safe work-packet flows** — pending continuations for LLM-requiring operations persist to the same store and survive server restarts; resuming with the same continuation token picks up where the flow left off.
|
|
145
145
|
- **Replaces Claude Code's built-in auto-memory** via the `memory-override` SessionStart hook, which tells the session not to write to the built-in memory files. Disable the override with `disabled_hooks: ["memory-override"]` if you prefer to keep the built-in system active.
|
|
146
146
|
|
|
147
|
+
### The binding ritual (`oh-my-claudecode bind`)
|
|
148
|
+
|
|
149
|
+
Fresh installs start with an empty `necronomicon.json`. To populate it
|
|
150
|
+
with history, run one command in your terminal:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
oh-my-claudecode bind
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This kicks off a six-phase ritual with a real ANSI TUI (progress bars,
|
|
157
|
+
section headers, per-phase status):
|
|
158
|
+
|
|
159
|
+
1. **Embedding sigil** — downloads the local nomic embedding model
|
|
160
|
+
(~137 MB) with a live byte-counter progress bar.
|
|
161
|
+
2. **Claude Code transcripts** — scans every subdirectory under
|
|
162
|
+
`~/.claude/projects/` (every project you've ever opened a session
|
|
163
|
+
in), parses the `.jsonl` transcripts, and writes one raw
|
|
164
|
+
observation per user prompt / assistant text / tool call.
|
|
165
|
+
3. **Opencode grimoire** — if you're migrating from oh-my-opencode, the
|
|
166
|
+
ritual auto-detects `~/.local/share/opencode/opencode.db` and
|
|
167
|
+
imports every project / session / message / part it finds.
|
|
168
|
+
4. **Sisyphus migration** — walks your home looking for legacy
|
|
169
|
+
`.sisyphus/` directories (the oh-my-opencode equivalent of
|
|
170
|
+
`.elder-gods/`) and copies plans, handoffs, and evidence into the
|
|
171
|
+
new layout without touching the source.
|
|
172
|
+
5. **Project code scan** — for each project the CLI has seen, walks
|
|
173
|
+
the code tree (gitignore-aware) and seeds preliminary memories:
|
|
174
|
+
language stats, package metadata, README sections, directory tree.
|
|
175
|
+
6. **Sealing** — reports how many raw observations are queued for
|
|
176
|
+
compression and points you at the next step.
|
|
177
|
+
|
|
178
|
+
The ritual is **resumable**: if any phase errors or you interrupt it,
|
|
179
|
+
re-running `oh-my-claudecode bind` picks up from the failed phase via
|
|
180
|
+
the `KV.bindState` cursor — no manual intervention required.
|
|
181
|
+
|
|
182
|
+
Phase 2 (LLM-dependent compression of raw observations into
|
|
183
|
+
searchable memories) runs **inside a Claude Code session** via the
|
|
184
|
+
work-packet loop. Either:
|
|
185
|
+
|
|
186
|
+
- Open Claude Code and run `/necronomicon-bind` — uses your
|
|
187
|
+
subscription auth via the MCP work-packet protocol.
|
|
188
|
+
- Or install a cron entry that spawns `claude -p` on an interval:
|
|
189
|
+
```bash
|
|
190
|
+
oh-my-claudecode bind --install-cron --interval 1h
|
|
191
|
+
```
|
|
192
|
+
The cron tick drives compression unattended. No API key needed.
|
|
193
|
+
|
|
147
194
|
### Work-packet protocol — LLM ops without an API key
|
|
148
195
|
|
|
149
196
|
13 of Yith's memory operations need an LLM to do their work (`crystallize`, `consolidate`, `consolidate-pipeline`, `compress`, `summarize`, `flow-compress`, `graph-extract`, `temporal-graph-extract`, `expand-query`, `skill-extract`, `reflect`, `enrich-window`, `enrich-session`). If Yith has its own `ANTHROPIC_API_KEY` in `~/.oh-my-claudecode/yith/.env`, these run directly in-process.
|
|
@@ -233,6 +280,7 @@ After installation these are available in Claude Code sessions:
|
|
|
233
280
|
| Command | Description |
|
|
234
281
|
|---------|-------------|
|
|
235
282
|
| `/cthulhu` | Activate Cthulhu orchestrator mode (also creates `.elder-gods/` on first use) |
|
|
283
|
+
| `/necronomicon-bind` | Necronomicon binding ritual — shells out to `oh-my-claudecode bind` (real TUI, all-projects ingestion, opencode import, sisyphus migration, preliminary code scan) then drains pending compression via the work-packet loop using this session's LLM |
|
|
236
284
|
| `/shoggoth` | Fast parallel codebase search |
|
|
237
285
|
| `/yog-sothoth` | Consult the architecture/debug advisor |
|
|
238
286
|
| `/elder-loop` | Start the self-referential completion loop |
|
package/commands/cthulhu.md
CHANGED
|
@@ -7,6 +7,15 @@ Activate Cthulhu orchestrator mode.
|
|
|
7
7
|
|
|
8
8
|
**First**: ensure `.elder-gods/` exists at the project root. If it does not, create it now (empty is fine — `mkdir .elder-gods`). This marker makes every future Claude Code session in this project auto-activate Cthulhu via the `cthulhu-auto` SessionStart hook, so the user will not need to run `/cthulhu` again here. If the directory already exists, proceed silently.
|
|
9
9
|
|
|
10
|
+
**Second — Necronomicon preflight**: before accepting the user's request, verify that the Yith Archive memory system is bound on this machine. Run ONE lightweight check:
|
|
11
|
+
|
|
12
|
+
- Try calling `yith_context({ project: "." })` (the Yith MCP tool).
|
|
13
|
+
- If the tool **is not available at all** (no `yith_context` in your tool list), or if the call errors with "MCP server not connected" / similar, the Necronomicon has not been bound yet.
|
|
14
|
+
- In that case, tell the user exactly: "I notice the Necronomicon hasn't been bound on this machine yet. Run `/bind-necronomicon` first — it's a one-time setup ritual that verifies the MCP server, warms up the embedding model, and optionally backfills past sessions. After that, every Cthulhu session will have persistent memory across projects. Run `/bind-necronomicon` now, or proceed without memory for this session?" Wait for the user's decision before doing anything else.
|
|
15
|
+
- If the tool call succeeds (even with empty context), proceed silently — the Necronomicon is ready.
|
|
16
|
+
|
|
17
|
+
Do this preflight exactly once per session, not before every user message.
|
|
18
|
+
|
|
10
19
|
You are now operating as Cthulhu, the Great Dreamer — primary orchestrator of the oh-my-claudecode system.
|
|
11
20
|
|
|
12
21
|
Your operating principles:
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bind-necronomicon
|
|
3
|
+
description: First-run setup ritual for Yith Archive. Verifies the MCP server is reachable, warms up the embedding model, and offers to backfill past Claude Code sessions into the Necronomicon. Safe to run multiple times — it detects what's already done.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are performing the binding ritual for the **Necronomicon** — the on-disk grimoire that the Great Race of Yith maintains for this machine. The Necronomicon is the physical JSON file at `~/.oh-my-claudecode/yith/necronomicon.json`; Yith Archive is the archival practice that writes to and reads from it. Both names refer to the same system, viewed through different lenses.
|
|
7
|
+
|
|
8
|
+
Run the ritual in phases. For each phase, print a header line, run the check, and report the outcome with a status glyph (`✓`, `⚠`, `✗`, or `…`) and a short explanation. Do NOT proceed to the next phase until the current one is resolved.
|
|
9
|
+
|
|
10
|
+
## Phase I — The Tome Exists
|
|
11
|
+
|
|
12
|
+
Check whether the Necronomicon has been bound on this machine.
|
|
13
|
+
|
|
14
|
+
1. Use the `yith_context` MCP tool with a placeholder project like `{ project: "." }`. This is a lightweight call that exercises the MCP server without writing anything.
|
|
15
|
+
2. If the tool returns successfully (even with empty context), the server is reachable → `✓ Necronomicon is bound and the Great Race answers.`
|
|
16
|
+
3. If the MCP tool is not available at all (the `yith_trigger`/`yith_context` tools don't appear in your tool list), the MCP server is not registered. Tell the user to run `oh-my-claudecode install` in their terminal, then start a NEW Claude Code session and re-run `/bind-necronomicon`. Stop here.
|
|
17
|
+
4. If the tool is available but errors out, report the error verbatim and stop.
|
|
18
|
+
|
|
19
|
+
## Phase II — The Embedding Sigil
|
|
20
|
+
|
|
21
|
+
If this is a fresh install, the local nomic embedding model (~137 MB) has not been downloaded yet. The first memory write or search triggers the download. We'll warm it up explicitly now so the first real use is fast.
|
|
22
|
+
|
|
23
|
+
1. Call `yith_remember` with a harmless sentinel memory:
|
|
24
|
+
```
|
|
25
|
+
yith_remember({
|
|
26
|
+
content: "Necronomicon binding sentinel — written during /bind-necronomicon ritual",
|
|
27
|
+
type: "reference",
|
|
28
|
+
concepts: ["bind-necronomicon", "sentinel"]
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
2. The response may take 30-90 seconds on first call because the nomic model downloads in the background. While you wait, print a progress indicator to the user:
|
|
32
|
+
```
|
|
33
|
+
▓▓▓▓▓▓▓▓▓░░░░░░░░ warming up the embedding sigil...
|
|
34
|
+
```
|
|
35
|
+
(Only one frame — you cannot actually animate in a Claude Code session. The single bar communicates "work is happening, this is the expected delay.")
|
|
36
|
+
3. If the call succeeds → `✓ The embedding sigil pulses. Model is cached under ~/.cache/huggingface/.`
|
|
37
|
+
4. If the call fails with a network error, tell the user the nomic download needs internet and offer to skip this phase (BM25-only mode still works). Continue.
|
|
38
|
+
5. If the call fails with a parse or validation error, report it and stop.
|
|
39
|
+
|
|
40
|
+
## Phase III — Searching the Tome
|
|
41
|
+
|
|
42
|
+
Verify hybrid search actually returns the sentinel memory we just wrote.
|
|
43
|
+
|
|
44
|
+
1. Call `yith_search({ query: "Necronomicon binding sentinel", limit: 5 })`.
|
|
45
|
+
2. If the result contains at least one hit referencing the sentinel → `✓ Hybrid search is operational (BM25 + vector index in sync).`
|
|
46
|
+
3. If zero hits but the sentinel is definitely in KV (you can verify with `yith_trigger({ name: "mem::diagnose", args: {} })`), the index is out of sync. Call `yith_trigger({ name: "mem::rebuild-index", args: {} })` if such a function exists, or tell the user to restart their Claude Code session (the MCP server rebuilds the index on boot). Continue.
|
|
47
|
+
|
|
48
|
+
## Phase IV — Past Sessions (Optional)
|
|
49
|
+
|
|
50
|
+
The user may have Claude Code transcripts from past sessions on this machine, in `~/.claude/projects/<sanitized-cwd>/*.jsonl`. Offer to backfill them into the Necronomicon so the archive has history from before it existed.
|
|
51
|
+
|
|
52
|
+
1. Ask the user: "Would you like to backfill past Claude Code sessions into the Necronomicon? This reads your historical `~/.claude/projects/` transcripts and converts user prompts + assistant responses + tool calls into observations that get compressed and made searchable. (yes / skip / specific-project-path)"
|
|
53
|
+
2. If the user says `skip`, note it and move on.
|
|
54
|
+
3. If they say `yes` or provide a path, run:
|
|
55
|
+
```
|
|
56
|
+
yith_trigger({
|
|
57
|
+
name: "mem::backfill-sessions",
|
|
58
|
+
args: {
|
|
59
|
+
projectCwd: <path or "." for cwd>,
|
|
60
|
+
dryRun: false,
|
|
61
|
+
maxObservations: 500
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
4. The backfill runs through the work-packet loop. Each compression round will return a `needs_llm_work` envelope with one or more packets. For each round:
|
|
66
|
+
- Run the packets' prompts through your own reasoning (inline — the systemPrompt + userPrompt describe a compression task, you act as the LLM for Yith).
|
|
67
|
+
- Commit the completions via `yith_commit_work({ continuation, packetResults: [...] })`.
|
|
68
|
+
- Loop until the response is terminal.
|
|
69
|
+
5. Between rounds, render a progress bar using monospace ASCII:
|
|
70
|
+
```
|
|
71
|
+
[▓▓▓▓▓▓░░░░░░░░░░░░] 34% — 171/500 observations compressed
|
|
72
|
+
```
|
|
73
|
+
Update the numbers in each round's status message. Users can't get an animated bar, but a re-printed bar in each tool call shows forward motion.
|
|
74
|
+
6. Report the final counts from the backfill terminal result.
|
|
75
|
+
|
|
76
|
+
## Phase V — Sealing the Ritual
|
|
77
|
+
|
|
78
|
+
1. Print a summary of what was done:
|
|
79
|
+
```
|
|
80
|
+
═════════════════════════════════════════════════════
|
|
81
|
+
The Necronomicon is bound.
|
|
82
|
+
═════════════════════════════════════════════════════
|
|
83
|
+
Tome: ~/.oh-my-claudecode/yith/necronomicon.json
|
|
84
|
+
MCP server: yith-archive (reachable)
|
|
85
|
+
Embedding model: local:nomic-embed-text-v1.5 (768 dims)
|
|
86
|
+
Memories: <count from yith_trigger mem::diagnose>
|
|
87
|
+
Observations: <count from yith_trigger mem::diagnose>
|
|
88
|
+
Backfill: <yes/skipped + counts>
|
|
89
|
+
═════════════════════════════════════════════════════
|
|
90
|
+
The Great Race of Yith now remembers this machine.
|
|
91
|
+
Every new Claude Code session will have access to
|
|
92
|
+
the Necronomicon through yith_search, yith_remember,
|
|
93
|
+
yith_context, and the other MCP tools.
|
|
94
|
+
```
|
|
95
|
+
2. If any phase reported a warning, restate the warnings at the end so the user doesn't miss them.
|
|
96
|
+
|
|
97
|
+
## Re-entry
|
|
98
|
+
|
|
99
|
+
This command is idempotent. Running it twice in a row:
|
|
100
|
+
- Phase I passes immediately (MCP reachable)
|
|
101
|
+
- Phase II is a no-op if the embedding model is already cached (the call returns fast)
|
|
102
|
+
- Phase III passes immediately
|
|
103
|
+
- Phase IV offers to backfill again (the user can skip if they already did it)
|
|
104
|
+
- Phase V prints the final summary
|
|
105
|
+
|
|
106
|
+
Run it any time you want to verify the Necronomicon is still bound.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron installer + `claude -p` spawn-command assembly for unattended
|
|
3
|
+
* Necronomicon bind / compression.
|
|
4
|
+
*
|
|
5
|
+
* Everything here is a pure function over strings — no process
|
|
6
|
+
* spawning, no crontab mutation, no fs writes. The CLI entry point
|
|
7
|
+
* orchestrates the actual `crontab -l` / `crontab -` dance; this
|
|
8
|
+
* module only handles the string-level logic so tests can verify
|
|
9
|
+
* every edge case without side effects.
|
|
10
|
+
*
|
|
11
|
+
* The cron entry calls `oh-my-claudecode bind --resume`, which:
|
|
12
|
+
* 1. Runs any pending Phase 1 work (filesystem ingestion — no LLM).
|
|
13
|
+
* 2. For Phase 2 (compression), if an ANTHROPIC_API_KEY is
|
|
14
|
+
* configured, routes directly through the in-process LLM
|
|
15
|
+
* provider. Otherwise spawns `claude -p` with the command
|
|
16
|
+
* produced by `buildClaudePSpawnCommand` below, so Claude Code's
|
|
17
|
+
* own subscription auth drives the work-packet loop.
|
|
18
|
+
*/
|
|
19
|
+
/** Suffix appended to every bind-installed crontab entry so the
|
|
20
|
+
* installer can find + replace its own line without clobbering
|
|
21
|
+
* unrelated entries. */
|
|
22
|
+
export declare const BIND_CRON_MARKER = "# oh-my-claudecode bind";
|
|
23
|
+
/**
|
|
24
|
+
* Convert a short interval spec like `"1h"`, `"30m"`, `"1d"` into a
|
|
25
|
+
* cron schedule string. Accepts:
|
|
26
|
+
*
|
|
27
|
+
* `Nm` — every N minutes (N > 0)
|
|
28
|
+
* `Nh` — every N hours (N > 0)
|
|
29
|
+
* `Nd` — every N days (currently supports 1d; multi-day uses
|
|
30
|
+
* "at midnight every day" since cron doesn't natively
|
|
31
|
+
* express "every 2 days" without a workaround)
|
|
32
|
+
* `N` — bare number, interpreted as minutes
|
|
33
|
+
*
|
|
34
|
+
* Throws on malformed input or zero/negative intervals so the CLI
|
|
35
|
+
* can surface a clear error.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseIntervalSpec(spec: string): string;
|
|
38
|
+
export interface ClaudePSpawnOptions {
|
|
39
|
+
/** Observations per compress-batch-step call. Default 100. */
|
|
40
|
+
limit?: number;
|
|
41
|
+
/** Dollar cap on the claude -p invocation. Default 2.00. */
|
|
42
|
+
maxBudgetUsd?: number;
|
|
43
|
+
/** Model alias. Default "sonnet" — fast and cheap for compression. */
|
|
44
|
+
model?: string;
|
|
45
|
+
/** Where to write the claude -p log. Default /dev/null. */
|
|
46
|
+
logPath?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Assemble the shell command that a cron tick runs to drive Phase 2
|
|
50
|
+
* compression via `claude -p`. The command is a single string suitable
|
|
51
|
+
* for a crontab line or a shell -c invocation.
|
|
52
|
+
*
|
|
53
|
+
* Security contract: --allowedTools restricts the spawn to the yith
|
|
54
|
+
* MCP tools only, so a runaway prompt can't shell out / edit files /
|
|
55
|
+
* read arbitrary code. --max-budget-usd caps the total API spend per
|
|
56
|
+
* tick. --permission-mode auto skips interactive prompts.
|
|
57
|
+
*
|
|
58
|
+
* The embedded prompt tells the spawned Claude to call
|
|
59
|
+
* mem::compress-batch-step in a loop via the work-packet protocol,
|
|
60
|
+
* terminating when the response is {status: "success"} or after 20
|
|
61
|
+
* rounds (safety cap).
|
|
62
|
+
*/
|
|
63
|
+
export declare function buildClaudePSpawnCommand(opts?: ClaudePSpawnOptions): string;
|
|
64
|
+
export interface CrontabLineOptions {
|
|
65
|
+
/** 5-field cron schedule string, e.g. `0 * * * *`. */
|
|
66
|
+
schedule: string;
|
|
67
|
+
/** Command to run on each tick. */
|
|
68
|
+
command: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Build a full crontab line including the installer marker. The marker
|
|
72
|
+
* is a trailing comment so the line looks like a normal cron entry to
|
|
73
|
+
* operators who inspect their crontab.
|
|
74
|
+
*/
|
|
75
|
+
export declare function buildCrontabLine(opts: CrontabLineOptions): string;
|
|
76
|
+
/**
|
|
77
|
+
* Merge `newLine` into an existing crontab file body, replacing any
|
|
78
|
+
* previous bind entry (identified by BIND_CRON_MARKER) in place. If
|
|
79
|
+
* no previous entry exists, appends. Preserves all other lines
|
|
80
|
+
* unchanged — including comments, whitespace, and unrelated jobs.
|
|
81
|
+
*
|
|
82
|
+
* Returns the updated crontab body as a string. Callers pipe this
|
|
83
|
+
* to `crontab -` to commit.
|
|
84
|
+
*/
|
|
85
|
+
export declare function installCrontabEntry(existing: string, newLine: string): string;
|
|
86
|
+
//# sourceMappingURL=bind-cron.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind-cron.d.ts","sourceRoot":"","sources":["../../src/cli/bind-cron.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;yBAEyB;AACzB,eAAO,MAAM,gBAAgB,4BAA4B,CAAA;AAMzD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiCtD;AAMD,MAAM,WAAW,mBAAmB;IAClC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,GAAE,mBAAwB,GAC7B,MAAM,CA0BR;AAYD,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAA;IAChB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAEjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,MAAM,CA8BR"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron installer + `claude -p` spawn-command assembly for unattended
|
|
3
|
+
* Necronomicon bind / compression.
|
|
4
|
+
*
|
|
5
|
+
* Everything here is a pure function over strings — no process
|
|
6
|
+
* spawning, no crontab mutation, no fs writes. The CLI entry point
|
|
7
|
+
* orchestrates the actual `crontab -l` / `crontab -` dance; this
|
|
8
|
+
* module only handles the string-level logic so tests can verify
|
|
9
|
+
* every edge case without side effects.
|
|
10
|
+
*
|
|
11
|
+
* The cron entry calls `oh-my-claudecode bind --resume`, which:
|
|
12
|
+
* 1. Runs any pending Phase 1 work (filesystem ingestion — no LLM).
|
|
13
|
+
* 2. For Phase 2 (compression), if an ANTHROPIC_API_KEY is
|
|
14
|
+
* configured, routes directly through the in-process LLM
|
|
15
|
+
* provider. Otherwise spawns `claude -p` with the command
|
|
16
|
+
* produced by `buildClaudePSpawnCommand` below, so Claude Code's
|
|
17
|
+
* own subscription auth drives the work-packet loop.
|
|
18
|
+
*/
|
|
19
|
+
/** Suffix appended to every bind-installed crontab entry so the
|
|
20
|
+
* installer can find + replace its own line without clobbering
|
|
21
|
+
* unrelated entries. */
|
|
22
|
+
export const BIND_CRON_MARKER = "# oh-my-claudecode bind";
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Interval spec parser
|
|
25
|
+
// ============================================================================
|
|
26
|
+
/**
|
|
27
|
+
* Convert a short interval spec like `"1h"`, `"30m"`, `"1d"` into a
|
|
28
|
+
* cron schedule string. Accepts:
|
|
29
|
+
*
|
|
30
|
+
* `Nm` — every N minutes (N > 0)
|
|
31
|
+
* `Nh` — every N hours (N > 0)
|
|
32
|
+
* `Nd` — every N days (currently supports 1d; multi-day uses
|
|
33
|
+
* "at midnight every day" since cron doesn't natively
|
|
34
|
+
* express "every 2 days" without a workaround)
|
|
35
|
+
* `N` — bare number, interpreted as minutes
|
|
36
|
+
*
|
|
37
|
+
* Throws on malformed input or zero/negative intervals so the CLI
|
|
38
|
+
* can surface a clear error.
|
|
39
|
+
*/
|
|
40
|
+
export function parseIntervalSpec(spec) {
|
|
41
|
+
if (!spec)
|
|
42
|
+
throw new Error("parseIntervalSpec: empty interval");
|
|
43
|
+
const m = spec.match(/^(\d+)([mhd])?$/);
|
|
44
|
+
if (!m) {
|
|
45
|
+
throw new Error(`parseIntervalSpec: invalid interval "${spec}" — use Nm / Nh / Nd`);
|
|
46
|
+
}
|
|
47
|
+
const n = parseInt(m[1], 10);
|
|
48
|
+
const unit = m[2] ?? "m";
|
|
49
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
50
|
+
throw new Error(`parseIntervalSpec: interval must be > 0 (got ${n})`);
|
|
51
|
+
}
|
|
52
|
+
if (unit === "m") {
|
|
53
|
+
// Every N minutes. If N divides 60 evenly, use step syntax.
|
|
54
|
+
if (n >= 60 && n % 60 === 0) {
|
|
55
|
+
const hours = n / 60;
|
|
56
|
+
return hours === 1 ? "0 * * * *" : `0 */${hours} * * *`;
|
|
57
|
+
}
|
|
58
|
+
return `*/${n} * * * *`;
|
|
59
|
+
}
|
|
60
|
+
if (unit === "h") {
|
|
61
|
+
return n === 1 ? "0 * * * *" : `0 */${n} * * *`;
|
|
62
|
+
}
|
|
63
|
+
// Days: run at midnight every N days. Cron doesn't natively support
|
|
64
|
+
// "every 2 days" so we emit the 1d form only.
|
|
65
|
+
if (n === 1)
|
|
66
|
+
return "0 0 * * *";
|
|
67
|
+
// Fall back to "every N-th day of month" — not perfect but better
|
|
68
|
+
// than refusing the input.
|
|
69
|
+
return `0 0 */${n} * *`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Assemble the shell command that a cron tick runs to drive Phase 2
|
|
73
|
+
* compression via `claude -p`. The command is a single string suitable
|
|
74
|
+
* for a crontab line or a shell -c invocation.
|
|
75
|
+
*
|
|
76
|
+
* Security contract: --allowedTools restricts the spawn to the yith
|
|
77
|
+
* MCP tools only, so a runaway prompt can't shell out / edit files /
|
|
78
|
+
* read arbitrary code. --max-budget-usd caps the total API spend per
|
|
79
|
+
* tick. --permission-mode auto skips interactive prompts.
|
|
80
|
+
*
|
|
81
|
+
* The embedded prompt tells the spawned Claude to call
|
|
82
|
+
* mem::compress-batch-step in a loop via the work-packet protocol,
|
|
83
|
+
* terminating when the response is {status: "success"} or after 20
|
|
84
|
+
* rounds (safety cap).
|
|
85
|
+
*/
|
|
86
|
+
export function buildClaudePSpawnCommand(opts = {}) {
|
|
87
|
+
const limit = opts.limit ?? 100;
|
|
88
|
+
const maxBudgetUsd = opts.maxBudgetUsd ?? 2.0;
|
|
89
|
+
const model = opts.model ?? "sonnet";
|
|
90
|
+
const logPath = opts.logPath ?? "/dev/null";
|
|
91
|
+
const prompt = `Call yith_trigger with name "mem::compress-batch-step" and args {"limit": ${limit}}. ` +
|
|
92
|
+
`If the response has status "needs_llm_work", execute each packet's prompts ` +
|
|
93
|
+
`(read the systemPrompt + userPrompt, produce the compression XML the system ` +
|
|
94
|
+
`prompt asks for), then call yith_commit_work with the continuation token and ` +
|
|
95
|
+
`an array of {id, completion} results. Repeat this loop until the response is ` +
|
|
96
|
+
`{status: "success"} or you've processed 20 batches total. Output a single-line ` +
|
|
97
|
+
`JSON summary {"compressed": N, "failed": N, "errors": []} and exit.`;
|
|
98
|
+
return [
|
|
99
|
+
`claude`,
|
|
100
|
+
`--print`,
|
|
101
|
+
`--permission-mode auto`,
|
|
102
|
+
`--max-budget-usd ${maxBudgetUsd}`,
|
|
103
|
+
`--model ${model}`,
|
|
104
|
+
`--allowedTools "mcp__yith-archive__yith_trigger,mcp__yith-archive__yith_commit_work"`,
|
|
105
|
+
`--output-format json`,
|
|
106
|
+
`${shellEscapeSingle(prompt)}`,
|
|
107
|
+
`>> ${logPath} 2>&1`,
|
|
108
|
+
].join(" ");
|
|
109
|
+
}
|
|
110
|
+
function shellEscapeSingle(s) {
|
|
111
|
+
// Wrap in single quotes and escape any literal single quote the
|
|
112
|
+
// shell-safe way: '...''...'...
|
|
113
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Build a full crontab line including the installer marker. The marker
|
|
117
|
+
* is a trailing comment so the line looks like a normal cron entry to
|
|
118
|
+
* operators who inspect their crontab.
|
|
119
|
+
*/
|
|
120
|
+
export function buildCrontabLine(opts) {
|
|
121
|
+
return `${opts.schedule} ${opts.command} ${BIND_CRON_MARKER}`;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Merge `newLine` into an existing crontab file body, replacing any
|
|
125
|
+
* previous bind entry (identified by BIND_CRON_MARKER) in place. If
|
|
126
|
+
* no previous entry exists, appends. Preserves all other lines
|
|
127
|
+
* unchanged — including comments, whitespace, and unrelated jobs.
|
|
128
|
+
*
|
|
129
|
+
* Returns the updated crontab body as a string. Callers pipe this
|
|
130
|
+
* to `crontab -` to commit.
|
|
131
|
+
*/
|
|
132
|
+
export function installCrontabEntry(existing, newLine) {
|
|
133
|
+
const lines = existing.split("\n");
|
|
134
|
+
const out = [];
|
|
135
|
+
let replaced = false;
|
|
136
|
+
for (const line of lines) {
|
|
137
|
+
if (line.includes(BIND_CRON_MARKER)) {
|
|
138
|
+
if (!replaced) {
|
|
139
|
+
out.push(newLine);
|
|
140
|
+
replaced = true;
|
|
141
|
+
}
|
|
142
|
+
// Drop duplicate bind entries.
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
out.push(line);
|
|
146
|
+
}
|
|
147
|
+
if (!replaced) {
|
|
148
|
+
// Make sure we don't leave a trailing empty line + the new entry
|
|
149
|
+
// mashed together. Trim trailing blank lines before appending.
|
|
150
|
+
while (out.length > 0 && out[out.length - 1] === "") {
|
|
151
|
+
out.pop();
|
|
152
|
+
}
|
|
153
|
+
out.push(newLine);
|
|
154
|
+
}
|
|
155
|
+
// Ensure trailing newline — crontabs want it.
|
|
156
|
+
let body = out.join("\n");
|
|
157
|
+
if (!body.endsWith("\n"))
|
|
158
|
+
body += "\n";
|
|
159
|
+
return body;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=bind-cron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind-cron.js","sourceRoot":"","sources":["../../src/cli/bind-cron.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;yBAEyB;AACzB,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAA;AAEzD,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IAC/D,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACvC,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CACb,wCAAwC,IAAI,sBAAsB,CACnE,CAAA;IACH,CAAC;IACD,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAC5B,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;IACxB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,GAAG,CAAC,CAAA;IACvE,CAAC;IAED,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QACjB,4DAA4D;QAC5D,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,CAAA;YACpB,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAA;QACzD,CAAC;QACD,OAAO,KAAK,CAAC,UAAU,CAAA;IACzB,CAAC;IAED,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAA;IACjD,CAAC;IAED,oEAAoE;IACpE,8CAA8C;IAC9C,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAA;IAC/B,kEAAkE;IAClE,2BAA2B;IAC3B,OAAO,SAAS,CAAC,MAAM,CAAA;AACzB,CAAC;AAiBD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAA4B,EAAE;IAE9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,GAAG,CAAA;IAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,GAAG,CAAA;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAA;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,WAAW,CAAA;IAE3C,MAAM,MAAM,GACV,6EAA6E,KAAK,KAAK;QACvF,6EAA6E;QAC7E,8EAA8E;QAC9E,+EAA+E;QAC/E,+EAA+E;QAC/E,iFAAiF;QACjF,qEAAqE,CAAA;IAEvE,OAAO;QACL,QAAQ;QACR,SAAS;QACT,wBAAwB;QACxB,oBAAoB,YAAY,EAAE;QAClC,WAAW,KAAK,EAAE;QAClB,sFAAsF;QACtF,sBAAsB;QACtB,GAAG,iBAAiB,CAAC,MAAM,CAAC,EAAE;QAC9B,MAAM,OAAO,OAAO;KACrB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACb,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAS;IAClC,gEAAgE;IAChE,gCAAgC;IAChC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAA;AACxC,CAAC;AAaD;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAwB;IACvD,OAAO,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,IAAI,gBAAgB,EAAE,CAAA;AAC/D,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,OAAe;IAEf,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAClC,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,IAAI,QAAQ,GAAG,KAAK,CAAA;IAEpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBACjB,QAAQ,GAAG,IAAI,CAAA;YACjB,CAAC;YACD,+BAA+B;YAC/B,SAAQ;QACV,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAChB,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,iEAAiE;QACjE,+DAA+D;QAC/D,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;YACpD,GAAG,CAAC,GAAG,EAAE,CAAA;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnB,CAAC;IAED,8CAA8C;IAC9C,IAAI,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,IAAI,IAAI,IAAI,CAAA;IACtC,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oh-my-claudecode bind — the CLI subcommand that drives the
|
|
3
|
+
* Necronomicon binding ritual.
|
|
4
|
+
*
|
|
5
|
+
* Architecture: a state-machine runner (`runBind`) reads `KV.bindState`,
|
|
6
|
+
* walks through each phase in `BIND_PHASE_ORDER`, invokes the matching
|
|
7
|
+
* `PhaseRunner`, and persists progress after every transition. Phases
|
|
8
|
+
* are injectable — tests pass fakes; production passes the real
|
|
9
|
+
* runners defined in `defaultPhaseRunners()`.
|
|
10
|
+
*
|
|
11
|
+
* Failure semantics: if any phase throws, `runBind` records the error
|
|
12
|
+
* into bindState, halts (does NOT run subsequent phases), and returns.
|
|
13
|
+
* The CLI entry point surfaces the error via the TUI and exits with
|
|
14
|
+
* a non-zero code. A re-run picks up from the failed phase and retries
|
|
15
|
+
* it — the state machine treats `failed` the same as `pending`.
|
|
16
|
+
*
|
|
17
|
+
* Cron-friendly: the same entry point is called from `bind --resume`
|
|
18
|
+
* which prints to stdout and exits, so a crontab can invoke it on
|
|
19
|
+
* an interval without an interactive session.
|
|
20
|
+
*/
|
|
21
|
+
import type { YithArchiveHandle } from "../features/yith-archive/index.js";
|
|
22
|
+
import { type BindPhase, type BindState } from "../features/yith-archive/state/bind-state.js";
|
|
23
|
+
import { TuiWriter } from "./tui.js";
|
|
24
|
+
export interface BindContext {
|
|
25
|
+
archive: YithArchiveHandle;
|
|
26
|
+
tui: TuiWriter;
|
|
27
|
+
}
|
|
28
|
+
export interface PhaseRunner {
|
|
29
|
+
name: BindPhase;
|
|
30
|
+
/**
|
|
31
|
+
* Execute the phase's work. Return a details object to merge into
|
|
32
|
+
* the phase's `details` field (e.g., per-project counts, cursor
|
|
33
|
+
* positions). Throw on failure — the runner catches and records
|
|
34
|
+
* the error into bindState for you.
|
|
35
|
+
*/
|
|
36
|
+
run(ctx: BindContext): Promise<{
|
|
37
|
+
details?: Record<string, unknown>;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
export interface RunBindOptions {
|
|
41
|
+
archive: YithArchiveHandle;
|
|
42
|
+
tui: TuiWriter;
|
|
43
|
+
/**
|
|
44
|
+
* Phase implementations. Defaults to `defaultPhaseRunners()` when
|
|
45
|
+
* omitted. Tests pass fakes to drive the state machine without
|
|
46
|
+
* hitting the real embedding / backfill / opencode paths.
|
|
47
|
+
*/
|
|
48
|
+
phases?: PhaseRunner[];
|
|
49
|
+
/**
|
|
50
|
+
* When set, runs only the listed phases (even if they're already
|
|
51
|
+
* completed). Used by `bind --force <phase>` to re-run a specific
|
|
52
|
+
* phase without touching the others. Default: respect bindState.
|
|
53
|
+
*/
|
|
54
|
+
force?: BindPhase[];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* State-machine driver. Reads bindState, runs pending phases in order,
|
|
58
|
+
* persists progress after each, halts on first failure.
|
|
59
|
+
*
|
|
60
|
+
* Returns the final BindState so callers (the CLI entry point) can
|
|
61
|
+
* summarize what happened and exit with the right code.
|
|
62
|
+
*/
|
|
63
|
+
export declare function runBind(opts: RunBindOptions): Promise<BindState>;
|
|
64
|
+
/**
|
|
65
|
+
* Production phase runners. Tests inject fakes; the CLI entry point
|
|
66
|
+
* uses these defaults.
|
|
67
|
+
*
|
|
68
|
+
* Each runner is a thin wrapper that calls the underlying feature
|
|
69
|
+
* (provider warmup, backfill function, opencode importer, etc.) and
|
|
70
|
+
* reports progress via the context's TUI writer.
|
|
71
|
+
*
|
|
72
|
+
* Phases B, C, and D (opencode_import, sisyphus_migrate,
|
|
73
|
+
* preliminary_seed) currently register placeholders that log a
|
|
74
|
+
* "pending implementation" status and complete without work. They
|
|
75
|
+
* get real implementations in their respective phase files.
|
|
76
|
+
*/
|
|
77
|
+
export declare function defaultPhaseRunners(): PhaseRunner[];
|
|
78
|
+
//# sourceMappingURL=bind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../../src/cli/bind.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAA;AAO1E,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,8CAA8C,CAAA;AACrD,OAAO,EACL,SAAS,EAMV,MAAM,UAAU,CAAA;AAMjB,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,iBAAiB,CAAA;IAC1B,GAAG,EAAE,SAAS,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAA;IACf;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAA;CACtE;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,iBAAiB,CAAA;IAC1B,GAAG,EAAE,SAAS,CAAA;IACd;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,EAAE,CAAA;IACtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,EAAE,CAAA;CACpB;AAwBD;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC,CAqHtE;AA4DD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,IAAI,WAAW,EAAE,CA+TnD"}
|