@lore-ai/cli 0.1.7 → 0.1.9
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 +149 -78
- package/dist/bin/lore.js +56 -11
- package/dist/bin/lore.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -2,7 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
**Automated project knowledge that writes itself.**
|
|
4
4
|
|
|
5
|
-
Lore is a CLI that
|
|
5
|
+
Lore is a CLI that scans your development activity -- git history, AI coding conversations (Cursor, Claude Code) -- and distills them into living, always-current project documentation. It works globally across all your repos from a single `~/.lore/` installation.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
### AI Agent CLI (required -- pick one)
|
|
10
|
+
|
|
11
|
+
Lore is an orchestrator. All intelligence -- scanning, classifying, distilling, and generating documentation -- is delegated to an AI agent CLI. **Without one of these installed and authenticated, Lore cannot do anything.**
|
|
12
|
+
|
|
13
|
+
| Agent | Command | Install |
|
|
14
|
+
|-------|---------|---------|
|
|
15
|
+
| **Claude Code CLI** | `claude` | [docs.anthropic.com/en/docs/claude-code](https://docs.anthropic.com/en/docs/claude-code/overview) |
|
|
16
|
+
| **Cursor Agent CLI** | `cursor` | Built into [Cursor IDE](https://cursor.com) |
|
|
17
|
+
|
|
18
|
+
By default, `lore sync` tries Claude Code first, then falls back to Cursor Agent. You can lock to one:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
lore sync --cli claude # use only Claude Code
|
|
22
|
+
lore sync --cli cursor # use only Cursor Agent
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or set it globally in `~/.lore/config.json` under `llm.cli` (`"auto"` | `"claude"` | `"cursor"`).
|
|
26
|
+
|
|
27
|
+
### Other Dependencies
|
|
28
|
+
|
|
29
|
+
- **Node.js 18+** -- runtime ([nodejs.org](https://nodejs.org))
|
|
30
|
+
- **Git** -- for scanning commit history
|
|
31
|
+
- **GitHub CLI** (`gh`) -- for PR metadata scanning and `lore pr` ([cli.github.com](https://cli.github.com/))
|
|
6
32
|
|
|
7
33
|
## Installation
|
|
8
34
|
|
|
@@ -18,106 +44,125 @@ npx @lore-ai/cli
|
|
|
18
44
|
|
|
19
45
|
### Editor Extension
|
|
20
46
|
|
|
21
|
-
Search **"Lore"** in the
|
|
47
|
+
Search **"Lore"** in the Cursor extension marketplace, or install manually from a [GitHub Release](https://github.com/matan1542/lore/releases):
|
|
22
48
|
|
|
23
49
|
```bash
|
|
24
|
-
# VS Code
|
|
25
|
-
code --install-extension lore-cursor-extension-<version>.vsix
|
|
26
|
-
|
|
27
|
-
# Cursor
|
|
28
50
|
cursor --install-extension lore-cursor-extension-<version>.vsix
|
|
29
51
|
```
|
|
30
52
|
|
|
31
|
-
###
|
|
53
|
+
### From Source (contributors)
|
|
32
54
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
55
|
+
```bash
|
|
56
|
+
git clone https://github.com/matan1542/lore.git
|
|
57
|
+
cd lore
|
|
58
|
+
npm install
|
|
59
|
+
npm run build
|
|
60
|
+
npm link
|
|
61
|
+
```
|
|
37
62
|
|
|
38
63
|
## Quick Start
|
|
39
64
|
|
|
40
65
|
```bash
|
|
41
|
-
# Initialize Lore
|
|
66
|
+
# 1. Initialize Lore globally
|
|
42
67
|
lore init
|
|
43
68
|
|
|
44
|
-
#
|
|
69
|
+
# 2. Select which repos to scan
|
|
70
|
+
lore repos
|
|
71
|
+
|
|
72
|
+
# 3. Run your first scan
|
|
45
73
|
lore sync
|
|
46
74
|
|
|
47
|
-
# Check what was captured
|
|
75
|
+
# 4. Check what was captured
|
|
48
76
|
lore status
|
|
49
77
|
|
|
50
|
-
#
|
|
51
|
-
lore
|
|
78
|
+
# 5. Launch the web dashboard
|
|
79
|
+
lore ui
|
|
52
80
|
|
|
53
|
-
#
|
|
54
|
-
lore
|
|
81
|
+
# 6. Generate a SKILL.md for a specific repo
|
|
82
|
+
lore skills -r my-project
|
|
55
83
|
|
|
56
|
-
#
|
|
57
|
-
lore
|
|
84
|
+
# 7. Generate a PR description
|
|
85
|
+
lore pr
|
|
58
86
|
```
|
|
59
87
|
|
|
60
88
|
## How It Works
|
|
61
89
|
|
|
62
90
|
```
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
v
|
|
66
|
-
Git commits + AI conversations accumulate
|
|
91
|
+
AI conversations accumulate (Cursor sessions, Claude Code transcripts)
|
|
92
|
+
Git commits accumulate (commits, diffs, PRs)
|
|
67
93
|
|
|
|
68
94
|
v
|
|
69
95
|
[ lore sync ] <-- manual or cron trigger
|
|
70
96
|
|
|
|
71
|
-
+--->
|
|
72
|
-
|
|
73
|
-
+---> Scans Claude Code sessions (JSONL transcripts)
|
|
74
|
-
+---> Scans Cursor conversations (workspace storage)
|
|
75
|
-
+---> Reads current documentation state
|
|
76
|
-
|
|
|
77
|
-
v
|
|
78
|
-
[ Alignment Engine ]
|
|
79
|
-
|
|
|
80
|
-
+---> Matches commits to conversations (by file overlap, branch, timing)
|
|
81
|
-
+---> Produces: matched pairs, unmatched commits, unmatched conversations
|
|
97
|
+
+---> Phase 1: Summarize
|
|
98
|
+
| Reads all AI conversations, produces concise summaries
|
|
82
99
|
|
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
+---> Phase 2: Classify
|
|
101
|
+
| Matches conversations to repos (file overlap, branch, timing)
|
|
85
102
|
|
|
|
86
|
-
+--->
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
+---> Finds stale documentation
|
|
103
|
+
+---> Phase 3: Distill
|
|
104
|
+
| Extracts what changed and WHY, architectural decisions,
|
|
105
|
+
| emerging patterns, stale documentation
|
|
90
106
|
|
|
|
91
|
-
|
|
92
|
-
|
|
107
|
+
+---> Phase 4: Verdict
|
|
108
|
+
| Checks relevance, decides what to update
|
|
93
109
|
|
|
|
94
|
-
+--->
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
+---> Queues items for human review
|
|
110
|
+
+---> Phase 5: Skill Generate
|
|
111
|
+
Writes/updates SKILL.md files per repo
|
|
112
|
+
(.cursor/skills/{repo}-guide/SKILL.md)
|
|
98
113
|
```
|
|
99
114
|
|
|
100
115
|
## Commands
|
|
101
116
|
|
|
102
117
|
| Command | Description |
|
|
103
118
|
|---------|-------------|
|
|
104
|
-
| `lore init` | Set up Lore
|
|
105
|
-
| `lore sync` | Run a one-off scan
|
|
119
|
+
| `lore init` | Set up Lore globally (`~/.lore/`). Auto-detects available sources and CLI agents. |
|
|
120
|
+
| `lore sync` | Run a one-off scan of all AI conversations. |
|
|
106
121
|
| `lore watch` | Start periodic scanning on a cron schedule. |
|
|
107
|
-
| `lore status` | Show
|
|
108
|
-
| `lore recall <topic>` | Query accumulated knowledge about a topic. |
|
|
109
|
-
| `lore review` |
|
|
122
|
+
| `lore status` | Show what has been captured and what is pending. |
|
|
123
|
+
| `lore recall <topic>` | Query accumulated knowledge about a topic (progressive disclosure). |
|
|
124
|
+
| `lore review` | Show proposed documentation updates awaiting approval. |
|
|
110
125
|
| `lore config [get\|set] <key> [value]` | View or edit configuration. |
|
|
126
|
+
| `lore repos [select\|list\|add\|remove]` | Manage which repos Lore processes. |
|
|
127
|
+
| `lore ui [-p port]` | Launch the web dashboard (default: port 3333). |
|
|
128
|
+
| `lore summarize` | Summarize all AI conversations and cluster by repo. |
|
|
129
|
+
| `lore skills [-r repo]` | Generate per-repo SKILL.md guides from conversations and git history. |
|
|
130
|
+
| `lore debug [sources\|scan\|conversations]` | Run pipeline diagnostics to troubleshoot scan issues. |
|
|
131
|
+
| `lore pr [-t tier]` | Generate a PR description from git history and cached conversation summaries. |
|
|
132
|
+
|
|
133
|
+
## Web Dashboard
|
|
134
|
+
|
|
135
|
+
Launch the built-in dashboard to explore everything Lore has captured:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
lore ui # starts at http://localhost:3333
|
|
139
|
+
lore ui -p 4000 # custom port
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Requires `lore init` and at least one `lore sync` to have data to display.
|
|
143
|
+
|
|
144
|
+
**Available pages:**
|
|
145
|
+
|
|
146
|
+
| Page | What it shows |
|
|
147
|
+
|------|---------------|
|
|
148
|
+
| Overview | Summary of all scanned repos, recent activity |
|
|
149
|
+
| Conversations | All AI conversations with summaries and metadata |
|
|
150
|
+
| Skills | Generated SKILL.md files per repo |
|
|
151
|
+
| Scans | Scan history and timeline |
|
|
152
|
+
| Repo Scans | Per-repo scan details |
|
|
153
|
+
| Analytics | Charts and metrics across scans |
|
|
154
|
+
| Vetting | Skill quality vetting pipeline |
|
|
155
|
+
| Review | Pending documentation updates |
|
|
156
|
+
| Phase Review | Drill into individual pipeline phases |
|
|
157
|
+
| Tool Usage | AI tool call analytics |
|
|
111
158
|
|
|
112
159
|
## Configuration
|
|
113
160
|
|
|
114
|
-
After `lore init`, configuration lives in
|
|
161
|
+
After `lore init`, configuration lives in `~/.lore/config.json`:
|
|
115
162
|
|
|
116
163
|
```json
|
|
117
164
|
{
|
|
118
165
|
"sources": {
|
|
119
|
-
"git": { "enabled": true },
|
|
120
|
-
"github": { "enabled": true, "repo": "owner/repo" },
|
|
121
166
|
"cursor": { "enabled": true },
|
|
122
167
|
"claudeCode": { "enabled": true }
|
|
123
168
|
},
|
|
@@ -126,53 +171,79 @@ After `lore init`, configuration lives in `.lore/config.json`:
|
|
|
126
171
|
"adr": "docs/decisions/",
|
|
127
172
|
"architecture": "docs/architecture.md"
|
|
128
173
|
},
|
|
174
|
+
"repos": {
|
|
175
|
+
"mode": "auto",
|
|
176
|
+
"include": [],
|
|
177
|
+
"exclude": [],
|
|
178
|
+
"auto": {
|
|
179
|
+
"maxRepos": 15,
|
|
180
|
+
"activityWindowDays": 14
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"llm": {
|
|
184
|
+
"cli": "auto"
|
|
185
|
+
},
|
|
129
186
|
"schedule": "0 */4 * * *",
|
|
130
187
|
"reviewMode": "propose"
|
|
131
188
|
}
|
|
132
189
|
```
|
|
133
190
|
|
|
134
|
-
###
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
191
|
+
### Key Settings
|
|
192
|
+
|
|
193
|
+
| Key | Default | Description |
|
|
194
|
+
|-----|---------|-------------|
|
|
195
|
+
| `sources.cursor.enabled` | `true` | Scan Cursor AI conversations |
|
|
196
|
+
| `sources.claudeCode.enabled` | `true` | Scan Claude Code transcripts |
|
|
197
|
+
| `repos.mode` | `"auto"` | `auto` (top N by activity), `whitelist` (only `include` list), or `all` |
|
|
198
|
+
| `repos.include` | `[]` | Always process these repos (names, org/repo, or path substrings) |
|
|
199
|
+
| `repos.exclude` | `[]` | Never process these repos |
|
|
200
|
+
| `repos.auto.maxRepos` | `15` | Max repos to process in auto mode |
|
|
201
|
+
| `repos.auto.activityWindowDays` | `14` | Only consider repos with recent activity |
|
|
202
|
+
| `llm.cli` | `"auto"` | AI agent: `auto` (Claude first, then Cursor), `claude`, or `cursor` |
|
|
203
|
+
| `schedule` | `"0 */4 * * *"` | Cron schedule for `lore watch` |
|
|
204
|
+
| `reviewMode` | `"propose"` | `propose` (queue for review) or `auto` (apply directly) |
|
|
138
205
|
|
|
139
206
|
## Data Sources
|
|
140
207
|
|
|
141
|
-
###
|
|
142
|
-
Scans commits, diffs, and changed files since the last sync.
|
|
143
|
-
|
|
144
|
-
### GitHub PRs
|
|
145
|
-
Uses `gh` CLI to fetch merged PRs, review comments, and discussions.
|
|
208
|
+
### AI Conversations
|
|
146
209
|
|
|
147
|
-
|
|
148
|
-
Reads JSONL transcripts from `~/.claude/projects/`. Extracts conversation turns, tool usage, and files modified.
|
|
210
|
+
**Cursor** -- Reads conversation metadata from Cursor's workspace SQLite storage.
|
|
149
211
|
|
|
150
|
-
|
|
151
|
-
Reads conversation metadata from Cursor's workspace SQLite storage.
|
|
212
|
+
**Claude Code** -- Reads JSONL transcripts from `~/.claude/projects/`. Extracts conversation turns, tool usage, and files modified.
|
|
152
213
|
|
|
153
|
-
|
|
214
|
+
### Git History
|
|
154
215
|
|
|
155
|
-
|
|
216
|
+
Scans commits, diffs, and changed files since the last sync.
|
|
156
217
|
|
|
157
|
-
|
|
158
|
-
2. **Branch + time window**: same branch, commit within session timeframe
|
|
159
|
-
3. **Commit message match**: session contains a git commit command with matching message
|
|
218
|
+
### GitHub PRs
|
|
160
219
|
|
|
161
|
-
|
|
220
|
+
Uses `gh` CLI to fetch merged PRs, review comments, and discussions.
|
|
162
221
|
|
|
163
222
|
## Architecture
|
|
164
223
|
|
|
165
224
|
Built with:
|
|
225
|
+
|
|
226
|
+
**CLI & Pipeline:**
|
|
166
227
|
- **TypeScript** with strict mode
|
|
167
228
|
- **Commander** for CLI framework
|
|
168
|
-
- **Clack** for
|
|
229
|
+
- **Clack** for interactive prompts
|
|
169
230
|
- **Zod** for runtime validation
|
|
170
231
|
- **Simple-git** for git operations
|
|
171
232
|
- **Execa** for subprocess management
|
|
172
|
-
- **
|
|
173
|
-
- **
|
|
233
|
+
- **better-sqlite3** / **sql.js** for local state
|
|
234
|
+
- **js-tiktoken** for token counting
|
|
235
|
+
|
|
236
|
+
**Web Dashboard:**
|
|
237
|
+
- **Hono** for API server
|
|
238
|
+
- **React 19** with **React Router 7**
|
|
239
|
+
- **TanStack Query** for data fetching
|
|
240
|
+
- **Recharts** for analytics charts
|
|
241
|
+
- **Vite** for build tooling
|
|
242
|
+
- **Tailwind CSS** for styling
|
|
243
|
+
|
|
244
|
+
**AI Integration:**
|
|
245
|
+
- **Claude Code CLI** or **Cursor Agent CLI** for all AI-powered phases
|
|
174
246
|
|
|
175
247
|
## License
|
|
176
248
|
|
|
177
249
|
MIT
|
|
178
|
-
# lore
|
package/dist/bin/lore.js
CHANGED
|
@@ -505,6 +505,44 @@ function isRateLimited(output) {
|
|
|
505
505
|
const lower = output.toLowerCase();
|
|
506
506
|
return lower.includes("you've hit your limit") || lower.includes("hit your limit") || lower.includes("rate limit") || lower.includes("rate_limit") || lower.includes("too many requests") || lower.includes("quota exceeded") || lower.includes("overloaded") || lower.includes("usage limit reached");
|
|
507
507
|
}
|
|
508
|
+
function safeExeca(cmd, args, options) {
|
|
509
|
+
const { signal, ...execaOpts } = options;
|
|
510
|
+
const child = execa(cmd, args, {
|
|
511
|
+
...execaOpts,
|
|
512
|
+
// Disable execa's cleanup handler that registers signal-exit listeners
|
|
513
|
+
// on the parent process. We manage the lifecycle manually.
|
|
514
|
+
cleanup: false
|
|
515
|
+
});
|
|
516
|
+
if (signal) {
|
|
517
|
+
let forceKillTimer = null;
|
|
518
|
+
const onAbort = () => {
|
|
519
|
+
try {
|
|
520
|
+
child.kill("SIGTERM");
|
|
521
|
+
} catch {
|
|
522
|
+
}
|
|
523
|
+
forceKillTimer = setTimeout(() => {
|
|
524
|
+
try {
|
|
525
|
+
child.kill("SIGKILL");
|
|
526
|
+
} catch {
|
|
527
|
+
}
|
|
528
|
+
}, FORCE_KILL_TIMEOUT_MS);
|
|
529
|
+
};
|
|
530
|
+
if (signal.aborted) {
|
|
531
|
+
onAbort();
|
|
532
|
+
} else {
|
|
533
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
534
|
+
}
|
|
535
|
+
const cleanup = () => {
|
|
536
|
+
signal.removeEventListener("abort", onAbort);
|
|
537
|
+
if (forceKillTimer) {
|
|
538
|
+
clearTimeout(forceKillTimer);
|
|
539
|
+
forceKillTimer = null;
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
child.then(cleanup, cleanup);
|
|
543
|
+
}
|
|
544
|
+
return child;
|
|
545
|
+
}
|
|
508
546
|
async function invokeCliOnce(target, opts) {
|
|
509
547
|
const { cmd, name } = target;
|
|
510
548
|
const vendor = getVendorConfig(name);
|
|
@@ -543,11 +581,11 @@ ${input}`;
|
|
|
543
581
|
}
|
|
544
582
|
args = filtered;
|
|
545
583
|
}
|
|
546
|
-
const child =
|
|
584
|
+
const child = safeExeca(cmd, args, {
|
|
547
585
|
input,
|
|
548
586
|
cwd: opts.cwd,
|
|
549
587
|
timeout: opts.timeout,
|
|
550
|
-
|
|
588
|
+
signal: opts.signal,
|
|
551
589
|
...opts.env && { env: { ...process.env, ...opts.env } }
|
|
552
590
|
});
|
|
553
591
|
let rawOutput = "";
|
|
@@ -713,7 +751,7 @@ async function invokeWithFallbackAndTag(opts, label, phase, runId) {
|
|
|
713
751
|
}
|
|
714
752
|
return result;
|
|
715
753
|
}
|
|
716
|
-
var LORE_MARKER_PREFIX, LORE_PROCESS_MARKER, CLI_VENDOR_CONFIG, CLI_CHAIN, BACKOFF_DELAYS, JITTER_FRACTION, MODEL_TIER_MAP, rateLimitStats, cliPreference, resolvedCli;
|
|
754
|
+
var LORE_MARKER_PREFIX, LORE_PROCESS_MARKER, CLI_VENDOR_CONFIG, CLI_CHAIN, BACKOFF_DELAYS, JITTER_FRACTION, MODEL_TIER_MAP, rateLimitStats, cliPreference, resolvedCli, FORCE_KILL_TIMEOUT_MS;
|
|
717
755
|
var init_cli = __esm({
|
|
718
756
|
"src/utils/cli.ts"() {
|
|
719
757
|
"use strict";
|
|
@@ -777,6 +815,7 @@ var init_cli = __esm({
|
|
|
777
815
|
};
|
|
778
816
|
cliPreference = "auto";
|
|
779
817
|
resolvedCli = null;
|
|
818
|
+
FORCE_KILL_TIMEOUT_MS = 5e3;
|
|
780
819
|
}
|
|
781
820
|
});
|
|
782
821
|
|
|
@@ -7700,14 +7739,14 @@ ${userPrompt}`;
|
|
|
7700
7739
|
// auto-approve MCPs in headless mode (needed for Octocode)
|
|
7701
7740
|
]
|
|
7702
7741
|
];
|
|
7703
|
-
const child =
|
|
7742
|
+
const child = safeExeca(
|
|
7704
7743
|
cli.cmd,
|
|
7705
7744
|
baseArgs,
|
|
7706
7745
|
{
|
|
7707
7746
|
cwd,
|
|
7708
7747
|
input: researchInput,
|
|
7709
7748
|
timeout: SKILL_TIMEOUT_MS,
|
|
7710
|
-
|
|
7749
|
+
signal: options.signal
|
|
7711
7750
|
}
|
|
7712
7751
|
);
|
|
7713
7752
|
const result = isClaude ? await streamAndCollect(child, `research:${repoName}`, options) : await collectPlainOutput(child);
|
|
@@ -7807,14 +7846,14 @@ ${userPrompt}`;
|
|
|
7807
7846
|
];
|
|
7808
7847
|
const startTime = Date.now();
|
|
7809
7848
|
let lastActivityTime = Date.now();
|
|
7810
|
-
const child =
|
|
7849
|
+
const child = safeExeca(
|
|
7811
7850
|
cli.cmd,
|
|
7812
7851
|
baseArgs,
|
|
7813
7852
|
{
|
|
7814
7853
|
input: genInput,
|
|
7815
7854
|
timeout: WRITING_HARD_CEILING_MS,
|
|
7816
7855
|
// absolute safety net only
|
|
7817
|
-
|
|
7856
|
+
signal: options.signal,
|
|
7818
7857
|
env: { ...process.env, ...WRITING_ENV_OVERRIDES }
|
|
7819
7858
|
}
|
|
7820
7859
|
);
|
|
@@ -7835,7 +7874,10 @@ ${userPrompt}`;
|
|
|
7835
7874
|
if (stallMs > WRITING_STALL_TIMEOUT_MS) {
|
|
7836
7875
|
const stallSec = Math.round(stallMs / 1e3);
|
|
7837
7876
|
options.onOutput?.(`[skill-gen] [gen:${repoName}] No progress for ${stallSec}s \u2014 aborting stalled agent (${elapsed}s total)`);
|
|
7838
|
-
|
|
7877
|
+
try {
|
|
7878
|
+
child.kill();
|
|
7879
|
+
} catch {
|
|
7880
|
+
}
|
|
7839
7881
|
return;
|
|
7840
7882
|
}
|
|
7841
7883
|
options.onOutput?.(`[skill-gen] [gen:${repoName}] Writing...${progressStr} (${elapsed}s elapsed)`);
|
|
@@ -7974,14 +8016,14 @@ ${userPrompt}`;
|
|
|
7974
8016
|
];
|
|
7975
8017
|
const startTime = Date.now();
|
|
7976
8018
|
let lastActivityTime = Date.now();
|
|
7977
|
-
const child =
|
|
8019
|
+
const child = safeExeca(
|
|
7978
8020
|
cli.cmd,
|
|
7979
8021
|
baseArgs,
|
|
7980
8022
|
{
|
|
7981
8023
|
input: genInput,
|
|
7982
8024
|
timeout: WRITING_HARD_CEILING_MS,
|
|
7983
8025
|
// absolute safety net only
|
|
7984
|
-
|
|
8026
|
+
signal: options.signal,
|
|
7985
8027
|
env: { ...process.env, ...WRITING_ENV_OVERRIDES }
|
|
7986
8028
|
}
|
|
7987
8029
|
);
|
|
@@ -8002,7 +8044,10 @@ ${userPrompt}`;
|
|
|
8002
8044
|
if (stallMs > WRITING_STALL_TIMEOUT_MS) {
|
|
8003
8045
|
const stallSec = Math.round(stallMs / 1e3);
|
|
8004
8046
|
options.onOutput?.(`[skill-gen] [delta:${repoName}] No progress for ${stallSec}s \u2014 aborting stalled agent (${elapsed}s total)`);
|
|
8005
|
-
|
|
8047
|
+
try {
|
|
8048
|
+
child.kill();
|
|
8049
|
+
} catch {
|
|
8050
|
+
}
|
|
8006
8051
|
return;
|
|
8007
8052
|
}
|
|
8008
8053
|
options.onOutput?.(`[skill-gen] [delta:${repoName}] Writing...${progressStr} (${elapsed}s elapsed)`);
|