@lumoai/cli 1.41.0 → 1.43.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/assets/skill/SKILL.md +47 -41
- package/assets/skill/references/criteria.md +97 -252
- package/assets/skill/references/doc-editing.md +146 -0
- package/assets/skill/references/docs.md +49 -278
- package/assets/skill/references/memory.md +29 -0
- package/assets/skill/references/onboarding.md +4 -4
- package/assets/skill/references/sessions.md +84 -97
- package/assets/skill/references/task-context.md +65 -149
- package/assets/skill/references/task-deps.md +113 -0
- package/assets/skill/references/tasks.md +2 -133
- package/assets/skill/references/verify.md +130 -201
- package/assets/skill/references/worktree.md +21 -36
- package/dist/cli/src/commands/memory-fold.js +76 -0
- package/dist/cli/src/commands/task-lineage.js +18 -4
- package/dist/cli/src/commands/task-status.js +74 -0
- package/dist/cli/src/index.js +6 -0
- package/package.json +1 -1
|
@@ -102,10 +102,14 @@ function formatLineageMarkdown(data) {
|
|
|
102
102
|
lines.push(`**Status**: ${data.task.status}`);
|
|
103
103
|
lines.push('');
|
|
104
104
|
if (data.groups.length === 0) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
// LUM-559: an empty report is fail-closed — it means no session ever bound
|
|
106
|
+
// to this task, so neither its cost nor its causal trail could be measured.
|
|
107
|
+
// Say "not measured" explicitly; never let the blank read as "zero cost".
|
|
108
|
+
lines.push('_Cost not measured — no session was ever bound to this task, so its ' +
|
|
109
|
+
'cost and causal trail could not be recorded. This is "not measured", ' +
|
|
110
|
+
'not "zero cost". Cost and lineage are captured once a session binds ' +
|
|
111
|
+
'(`lumo session attach <id>`) and consumes the context; bind before ' +
|
|
112
|
+
'working so future runs are recorded._');
|
|
109
113
|
lines.push('');
|
|
110
114
|
return lines.join('\n');
|
|
111
115
|
}
|
|
@@ -146,6 +150,16 @@ function formatLineageMarkdown(data) {
|
|
|
146
150
|
}
|
|
147
151
|
const summary = outcomeSummary(fragmentOutcomeCounts(g.fragments));
|
|
148
152
|
lines.push(`**Fragments** (${g.fragments.length}${summary ? `: ${summary}` : ''}):`);
|
|
153
|
+
// LUM-559: an edgeless cost group is a session that spent tokens but
|
|
154
|
+
// recorded no fragments (it bound after session-start). Its empty trail is
|
|
155
|
+
// "not captured", NOT "the session used nothing" — say so, and skip the
|
|
156
|
+
// per-fragment usage legend that has nothing to annotate.
|
|
157
|
+
if (g.fragments.length === 0) {
|
|
158
|
+
lines.push('_Causal fragments not captured — this session bound after start, so ' +
|
|
159
|
+
'its cost is recorded but its fragment trail is not._');
|
|
160
|
+
lines.push('');
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
149
163
|
lines.push('_✓ used · · abstained · ✗ unused (manual)_');
|
|
150
164
|
for (const f of g.fragments) {
|
|
151
165
|
const tag = f.disclosure === 'INDEX'
|
|
@@ -134,6 +134,7 @@ function formatTaskStatus(data, extras = {}) {
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
|
+
pushStruggleTrail(lines, data);
|
|
137
138
|
lines.push('');
|
|
138
139
|
if (data.nextActions.length === 0) {
|
|
139
140
|
lines.push(data.currentRound > 0
|
|
@@ -165,6 +166,79 @@ function formatTaskStatus(data, extras = {}) {
|
|
|
165
166
|
pushOpenCrossings(lines, extras);
|
|
166
167
|
return lines.join('\n') + '\n';
|
|
167
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Append the honest "Struggle / rework / outstanding" section (LUM-561) — the
|
|
171
|
+
* anti-mum-and-deaf block (kills a silent "Nothing outstanding"). It is ALWAYS
|
|
172
|
+
* rendered when the contract exists, even on a clean 0-unmet task: a passing
|
|
173
|
+
* task that bounced, was sent back, or left a follow-up behind still shows its
|
|
174
|
+
* scars. When the trail is genuinely empty the block states the *basis* for
|
|
175
|
+
* that ("none — N rounds run, 0 FAIL …"), or, when nothing has been verified,
|
|
176
|
+
* that absence cannot be confirmed — never a bare clean slate. Skipped only
|
|
177
|
+
* when the server didn't emit the field (older server).
|
|
178
|
+
*/
|
|
179
|
+
function pushStruggleTrail(lines, data) {
|
|
180
|
+
const trail = data.struggleTrail;
|
|
181
|
+
if (!trail)
|
|
182
|
+
return; // older server: can't fabricate, so don't claim "none".
|
|
183
|
+
lines.push('');
|
|
184
|
+
lines.push('Struggle / rework / outstanding:');
|
|
185
|
+
// A single PR is the happy path; >1 PR is the iteration signal. Reopens (a
|
|
186
|
+
// bounce after IN_REVIEW/DONE) always count. These two catch the rework that
|
|
187
|
+
// lives in PR cycles / status flips rather than in FAIL verdicts (LUM-561
|
|
188
|
+
// follow-up — without them a 10-PR task like LUM-557 reads as one hiccup).
|
|
189
|
+
const prIterated = trail.pullRequests.length > 1;
|
|
190
|
+
const empty = trail.reworkRounds.length === 0 &&
|
|
191
|
+
trail.sendBacks.length === 0 &&
|
|
192
|
+
trail.followUps.length === 0 &&
|
|
193
|
+
trail.reopens.length === 0 &&
|
|
194
|
+
!prIterated;
|
|
195
|
+
if (empty) {
|
|
196
|
+
if (data.currentRound === 0) {
|
|
197
|
+
// Honest fail-open: nothing was verified, so we cannot claim there were
|
|
198
|
+
// no difficulties — say so rather than render an implicitly-clean slate.
|
|
199
|
+
lines.push(' No verification has run yet — cannot confirm there were no difficulties. Run `lumo verify`.');
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
const rounds = `${data.currentRound} verification round${data.currentRound === 1 ? '' : 's'}`;
|
|
203
|
+
lines.push(` None recorded — ${rounds} run, 0 FAIL, no send-backs, no reopens, no leftover follow-ups.`);
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (trail.reworkRounds.length > 0) {
|
|
208
|
+
const parts = trail.reworkRounds.map(r => `round ${r.round} (${r.failed} FAIL)`);
|
|
209
|
+
lines.push(` Rework rounds: ${parts.join(', ')}`);
|
|
210
|
+
}
|
|
211
|
+
if (trail.sendBacks.length > 0) {
|
|
212
|
+
lines.push(' Send-backs:');
|
|
213
|
+
for (const s of trail.sendBacks) {
|
|
214
|
+
const lifecycle = s.status === 'resolved'
|
|
215
|
+
? `resolved (sent back r${s.failedAtRound}${s.resolvedAtRound != null ? ` → r${s.resolvedAtRound}` : ''})`
|
|
216
|
+
: `open (sent back r${s.failedAtRound})`;
|
|
217
|
+
lines.push(` • ${(0, sanitize_1.sanitizeField)(s.statement)} — ${lifecycle}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (trail.followUps.length > 0) {
|
|
221
|
+
lines.push(' Follow-ups left behind:');
|
|
222
|
+
for (const f of trail.followUps) {
|
|
223
|
+
lines.push(` • ${(0, sanitize_1.sanitizeField)(f.statement)} — flagged r${f.round}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// PR iteration — the dominant rework signal when the verify loop only ran
|
|
227
|
+
// once but the work churned across many PRs (LUM-557). Only when >1 PR.
|
|
228
|
+
if (prIterated) {
|
|
229
|
+
const PR_CAP = 12;
|
|
230
|
+
const nums = trail.pullRequests.map(p => `#${p.number}`);
|
|
231
|
+
const shown = nums.slice(0, PR_CAP).join(', ');
|
|
232
|
+
const overflow = nums.length > PR_CAP ? `, +${nums.length - PR_CAP} more` : '';
|
|
233
|
+
lines.push(` PR iterations: ${trail.pullRequests.length} PRs (${shown}${overflow})`);
|
|
234
|
+
}
|
|
235
|
+
if (trail.reopens.length > 0) {
|
|
236
|
+
lines.push(` Reopened ${trail.reopens.length}× (bounced back after review/done):`);
|
|
237
|
+
for (const r of trail.reopens) {
|
|
238
|
+
lines.push(` • ${r.from} → ${r.to}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
168
242
|
/**
|
|
169
243
|
* Append the OPEN boundary-crossings safety block (LUM-448) — a count, one line
|
|
170
244
|
* per crossing with its severity + category + clipped detail, and a pointer to
|
package/dist/cli/src/index.js
CHANGED
|
@@ -70,6 +70,7 @@ const memory_rm_1 = require("./commands/memory-rm");
|
|
|
70
70
|
const memory_show_1 = require("./commands/memory-show");
|
|
71
71
|
const memory_sync_1 = require("./commands/memory-sync");
|
|
72
72
|
const memory_push_1 = require("./commands/memory-push");
|
|
73
|
+
const memory_fold_1 = require("./commands/memory-fold");
|
|
73
74
|
const task_artifact_add_1 = require("./commands/task-artifact-add");
|
|
74
75
|
const task_criteria_set_1 = require("./commands/task-criteria-set");
|
|
75
76
|
const task_criteria_list_1 = require("./commands/task-criteria-list");
|
|
@@ -533,6 +534,11 @@ memoryCmd
|
|
|
533
534
|
.option('--dir <path>', 'Memory dir (default: ~/.claude/projects/<cwd>/memory)')
|
|
534
535
|
.option('--dry-run', 'List what would be pushed without sending')
|
|
535
536
|
.action(wrap((opts) => (0, memory_push_1.memoryPush)(opts)));
|
|
537
|
+
memoryCmd
|
|
538
|
+
.command('fold [project-ref]')
|
|
539
|
+
.description('Preview the autonomous topic-fold pass (folding itself runs daily, automatically). Requires --dry-run.')
|
|
540
|
+
.option('--dry-run', 'preview proposed subsystem cards + which fine cards they fold; writes nothing')
|
|
541
|
+
.action(wrap((ref, opts) => (0, memory_fold_1.memoryFold)(ref, opts)));
|
|
536
542
|
const milestoneCmd = program
|
|
537
543
|
.command('milestone')
|
|
538
544
|
.description('Inspect milestones from the terminal');
|