pi-crew 0.9.48 → 0.9.50
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/AGENTS.md +18 -0
- package/CHANGELOG.md +314 -0
- package/dist/build-meta.json +70 -42
- package/dist/index.mjs +505 -430
- package/dist/index.mjs.map +4 -4
- package/docs/decisions/2026-07-24-oidc-trusted-publishing.md +112 -0
- package/package.json +2 -3
- package/skills/.gitkeep +0 -0
- package/skills/distill-persona/BUILD-NOTES.md +55 -0
- package/skills/distill-persona/SKILL.md +550 -0
- package/skills/distill-persona/UPGRADE-LOG-RESEARCH-SKILLS.md +100 -0
- package/skills/distill-persona/references/coverage-manifest.md +65 -0
- package/skills/distill-persona/references/cross-skill-differentiation.md +12 -0
- package/skills/distill-persona/references/description-discipline.md +6 -0
- package/skills/distill-persona/references/diagnostic-path.md +25 -0
- package/skills/distill-persona/references/distillation-field-synthesis-pass2.md +59 -0
- package/skills/distill-persona/references/distillation-field-synthesis.md +108 -0
- package/skills/distill-persona/references/fidelity-rubric.md +19 -0
- package/skills/distill-persona/references/field-models.md +20 -0
- package/skills/distill-persona/references/handoff.md +42 -0
- package/skills/distill-persona/references/optional-body-sections.md +9 -0
- package/skills/distill-persona/references/registry-routing.md +11 -0
- package/skills/distill-persona/references/research/lesson-memory-shortcut.md +33 -0
- package/skills/distill-persona/references/research/r1-a-examples.md +23 -0
- package/skills/distill-persona/references/research/r1-b-scripts.md +26 -0
- package/skills/distill-persona/references/research/r1-c-human-readme.md +31 -0
- package/skills/distill-persona/references/research/r1-d-tests.md +28 -0
- package/skills/distill-persona/references/research/r1-verification.md +36 -0
- package/skills/distill-persona/references/research/r2-low-yield.md +26 -0
- package/skills/distill-persona/references/self-upgrade-directive.md +20 -0
- package/skills/distill-persona/references/taste-principles.md +8 -0
- package/skills/distill-persona/references/topic-variant.md +13 -0
- package/skills/distill-persona/references/update-mode.md +7 -0
- package/skills/distill-persona/scripts/fidelity_eval.py +244 -0
- package/skills/distill-persona/scripts/validate-run.mjs +297 -0
- package/skills/distill-persona/scripts/validate-skill-structure.mjs +177 -0
- package/skills/distill-software/BUILD-NOTES.md +56 -0
- package/skills/distill-software/SKILL.md +363 -0
- package/skills/distill-software/references/handoff.md +47 -0
- package/skills/distill-software/scripts/code_dna.py +290 -0
- package/skills/research/DISTILLATION-PROCESS-CHECKLIST.md +120 -0
- package/skills/research/EXCAVATION-CHECKLIST.md +142 -0
- package/skills/research/FIDELITY.md +180 -0
- package/skills/research/SKILL.md +432 -0
- package/skills/research/references/anti-patterns.md +184 -0
- package/skills/research/references/fidelity.md +241 -0
- package/skills/research/references/handoff.md +48 -0
- package/skills/research/references/research-protocol.md +162 -0
- package/skills/research/references/source-inventory.md +135 -0
- package/skills/research/references/verified-models.md +163 -0
- package/skills/research/scripts/__pycache__/safe_io.cpython-312.pyc +0 -0
- package/skills/research/scripts/code_dna.py +233 -0
- package/skills/research/scripts/emit_run_summary.py +142 -0
- package/skills/research/scripts/safe_io.py +314 -0
- package/skills/research/scripts/source_evaluator.py +234 -0
- package/skills/research/scripts/validate-skill-structure.mjs +177 -0
- package/skills/research/scripts/verify_citations.py +225 -0
- package/skills/security-priority.json +28 -0
- package/src/config/config.ts +1 -0
- package/src/config/role-tools.ts +6 -3
- package/src/config/types.ts +8 -0
- package/src/extension/crew-cleanup.ts +18 -1
- package/src/extension/crew-vibes/index.ts +11 -2
- package/src/extension/register.ts +1 -1
- package/src/extension/registration/command-registration.ts +1 -0
- package/src/extension/registration/commands.ts +7 -3
- package/src/extension/registration/lifecycle-handlers.ts +1 -3
- package/src/extension/registration/ui.ts +4 -0
- package/src/extension/registration/viewers.ts +3 -0
- package/src/extension/team-tool/run.ts +7 -6
- package/src/runtime/background-runner.ts +11 -16
- package/src/runtime/chain-runner.ts +3 -2
- package/src/runtime/heartbeat-watcher.ts +28 -1
- package/src/runtime/pipeline-runner.ts +8 -7
- package/src/runtime/task-runner.ts +165 -119
- package/src/schema/config-schema.ts +1 -0
- package/src/ui/live-run-sidebar.ts +2 -0
- package/src/ui/mascot.ts +11 -9
- package/src/ui/render-coalescer.ts +9 -0
- package/src/ui/run-snapshot-cache.ts +10 -11
- package/src/ui/terminal-status.ts +5 -0
- package/src/ui/widget/index.ts +3 -5
- package/src/ui/widget/widget-types.ts +0 -1
- package/src/utils/gh-protocol.ts +9 -8
- package/workflows/distill.workflow.md +198 -0
- package/assets/runner-spritesheet.png +0 -0
package/src/ui/mascot.ts
CHANGED
|
@@ -226,7 +226,7 @@ export class AnimatedMascot {
|
|
|
226
226
|
private tickTypewriter(): boolean {
|
|
227
227
|
const state = this.effectState;
|
|
228
228
|
if (state.pos === undefined) return true;
|
|
229
|
-
for (let i = 0; i <
|
|
229
|
+
for (let i = 0; i < 18; i++) {
|
|
230
230
|
const row = Math.floor(state.pos / ARMIN_WIDTH);
|
|
231
231
|
const x = state.pos % ARMIN_WIDTH;
|
|
232
232
|
if (row >= ARMIN_DISPLAY_HEIGHT) return true;
|
|
@@ -239,9 +239,11 @@ export class AnimatedMascot {
|
|
|
239
239
|
private tickScanline(): boolean {
|
|
240
240
|
const state = this.effectState;
|
|
241
241
|
if (state.row === undefined) return true;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
242
|
+
for (let step = 0; step < 3; step++) {
|
|
243
|
+
if (state.row >= ARMIN_DISPLAY_HEIGHT) return true;
|
|
244
|
+
for (let x = 0; x < ARMIN_WIDTH; x++) this.currentArminGrid[state.row][x] = this.finalArminGrid[state.row][x];
|
|
245
|
+
state.row++;
|
|
246
|
+
}
|
|
245
247
|
return false;
|
|
246
248
|
}
|
|
247
249
|
|
|
@@ -264,7 +266,7 @@ export class AnimatedMascot {
|
|
|
264
266
|
break;
|
|
265
267
|
}
|
|
266
268
|
}
|
|
267
|
-
drop.y
|
|
269
|
+
drop.y += 3;
|
|
268
270
|
if (drop.y >= 0 && drop.y < ARMIN_DISPLAY_HEIGHT) {
|
|
269
271
|
if (targetRow >= 0 && drop.y >= targetRow) {
|
|
270
272
|
drop.settled = ARMIN_DISPLAY_HEIGHT - targetRow;
|
|
@@ -280,7 +282,7 @@ export class AnimatedMascot {
|
|
|
280
282
|
private tickFade(): boolean {
|
|
281
283
|
const state = this.effectState;
|
|
282
284
|
if (!state.positions || state.idx === undefined) return true;
|
|
283
|
-
for (let i = 0; i <
|
|
285
|
+
for (let i = 0; i < 54; i++) {
|
|
284
286
|
if (state.idx >= state.positions.length) return true;
|
|
285
287
|
const [row, x] = state.positions[state.idx];
|
|
286
288
|
this.currentArminGrid[row][x] = this.finalArminGrid[row][x];
|
|
@@ -299,7 +301,7 @@ export class AnimatedMascot {
|
|
|
299
301
|
for (let row = Math.max(0, top); row <= Math.min(ARMIN_DISPLAY_HEIGHT - 1, bottom); row++) {
|
|
300
302
|
for (let x = 0; x < ARMIN_WIDTH; x++) this.currentArminGrid[row][x] = this.finalArminGrid[row][x];
|
|
301
303
|
}
|
|
302
|
-
state.expansion
|
|
304
|
+
state.expansion += 3;
|
|
303
305
|
return state.expansion > ARMIN_DISPLAY_HEIGHT;
|
|
304
306
|
}
|
|
305
307
|
|
|
@@ -321,7 +323,7 @@ export class AnimatedMascot {
|
|
|
321
323
|
}
|
|
322
324
|
}
|
|
323
325
|
}
|
|
324
|
-
state.phase
|
|
326
|
+
state.phase += 3;
|
|
325
327
|
return false;
|
|
326
328
|
}
|
|
327
329
|
// Restore final grid in-place
|
|
@@ -336,7 +338,7 @@ export class AnimatedMascot {
|
|
|
336
338
|
private tickDissolve(): boolean {
|
|
337
339
|
const state = this.effectState;
|
|
338
340
|
if (!state.positions || state.idx === undefined) return true;
|
|
339
|
-
for (let i = 0; i <
|
|
341
|
+
for (let i = 0; i < 66; i++) {
|
|
340
342
|
if (state.idx >= state.positions.length) return true;
|
|
341
343
|
const [row, x] = state.positions[state.idx];
|
|
342
344
|
this.currentArminGrid[row][x] = this.finalArminGrid[row][x];
|
|
@@ -73,6 +73,15 @@ export class RenderCoalescer {
|
|
|
73
73
|
this.#timerId = null;
|
|
74
74
|
}
|
|
75
75
|
this.#pending = false;
|
|
76
|
+
const dropped = this.#dropped;
|
|
77
|
+
this.#dropped = 0;
|
|
78
|
+
if (dropped > 0) {
|
|
79
|
+
try {
|
|
80
|
+
this.#onDrop(dropped);
|
|
81
|
+
} catch {
|
|
82
|
+
/* drop callback errors are non-fatal */
|
|
83
|
+
}
|
|
84
|
+
}
|
|
76
85
|
this.#callback();
|
|
77
86
|
}
|
|
78
87
|
|
|
@@ -1005,17 +1005,16 @@ export function createRunSnapshotCache(cwd: string, options: RunSnapshotCacheOpt
|
|
|
1005
1005
|
const scheduleRefresh = (runId: string): void => {
|
|
1006
1006
|
const existing = pendingRefreshes.get(runId);
|
|
1007
1007
|
if (existing) clearTimeout(existing);
|
|
1008
|
-
|
|
1009
|
-
runId
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
);
|
|
1008
|
+
const timer = setTimeout(() => {
|
|
1009
|
+
pendingRefreshes.delete(runId);
|
|
1010
|
+
try {
|
|
1011
|
+
localRefreshIfStale(runId);
|
|
1012
|
+
} catch {
|
|
1013
|
+
/* best-effort; widget falls back gracefully */
|
|
1014
|
+
}
|
|
1015
|
+
}, INVAL_COALESCE_MS);
|
|
1016
|
+
timer.unref();
|
|
1017
|
+
pendingRefreshes.set(runId, timer);
|
|
1019
1018
|
};
|
|
1020
1019
|
const unsubState = runEventBus.onChannel("run:state", (event) => {
|
|
1021
1020
|
if (entries.has(event.runId)) scheduleRefresh(event.runId);
|
|
@@ -213,6 +213,9 @@ export function createTerminalStatusController(ctx: TerminalStatusUi): TerminalS
|
|
|
213
213
|
setTerminalTitle(ctx, buildIdleTitle());
|
|
214
214
|
scheduleIdleReassert(Math.min(delay * 2, IDLE_REASSERT_MAX_MS));
|
|
215
215
|
}, delay);
|
|
216
|
+
// Unref so this recursive backoff timer never keeps the event loop alive
|
|
217
|
+
// (critical on SIGTERM where dispose() is not reached → process hang).
|
|
218
|
+
state.idleTimer.unref?.();
|
|
216
219
|
};
|
|
217
220
|
|
|
218
221
|
return {
|
|
@@ -240,6 +243,8 @@ export function createTerminalStatusController(ctx: TerminalStatusUi): TerminalS
|
|
|
240
243
|
ghosttyClear();
|
|
241
244
|
}
|
|
242
245
|
}, COMPLETE_FLASH_MS);
|
|
246
|
+
// Unref so the one-shot flash clear never blocks process exit.
|
|
247
|
+
state.flashTimer.unref?.();
|
|
243
248
|
},
|
|
244
249
|
onIdle(): void {
|
|
245
250
|
if (state.destroyed) return;
|
package/src/ui/widget/index.ts
CHANGED
|
@@ -154,7 +154,7 @@ class CrewWidgetComponent implements WidgetComponent {
|
|
|
154
154
|
[...listLiveAgents()].some((h) => h.status === "running");
|
|
155
155
|
const animation = hasRunning ? `:spin=${spinnerBucket()}` : "";
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
const sig =
|
|
158
158
|
runs
|
|
159
159
|
.map(
|
|
160
160
|
(entry) =>
|
|
@@ -175,8 +175,8 @@ class CrewWidgetComponent implements WidgetComponent {
|
|
|
175
175
|
})
|
|
176
176
|
.join(","),
|
|
177
177
|
)
|
|
178
|
-
.join("|") + `|live:${liveSig}${animation}
|
|
179
|
-
|
|
178
|
+
.join("|") + `|live:${liveSig}${animation}`;
|
|
179
|
+
return sig;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
private colorize(lines: string[], width: number): string[] {
|
|
@@ -342,8 +342,6 @@ export function stopCrewWidget(
|
|
|
342
342
|
state: CrewWidgetState,
|
|
343
343
|
config?: CrewUiConfig,
|
|
344
344
|
): void {
|
|
345
|
-
if (state.interval) clearInterval(state.interval);
|
|
346
|
-
state.interval = undefined;
|
|
347
345
|
if (ctx?.hasUI) {
|
|
348
346
|
const placement = config?.widgetPlacement ?? DEFAULT_UI.widgetPlacement;
|
|
349
347
|
ctx.ui.setStatus(STATUS_KEY, undefined);
|
package/src/utils/gh-protocol.ts
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* Repo resolution: git remote get-url origin from cwd.
|
|
23
23
|
*/
|
|
24
24
|
import { execFileSync } from "node:child_process";
|
|
25
|
+
import { errorMessage } from "./guards.ts";
|
|
25
26
|
|
|
26
27
|
/** Resolve the default repo from `git remote get-url origin` in cwd. */
|
|
27
28
|
export function resolveDefaultRepo(cwd: string): string {
|
|
@@ -44,7 +45,7 @@ export function resolveDefaultRepo(cwd: string): string {
|
|
|
44
45
|
|
|
45
46
|
throw new Error(`Could not parse git remote URL: ${remoteUrl}`);
|
|
46
47
|
} catch (err) {
|
|
47
|
-
const msg =
|
|
48
|
+
const msg = errorMessage(err);
|
|
48
49
|
throw new Error(`Failed to resolve default repo from git: ${msg}`);
|
|
49
50
|
}
|
|
50
51
|
}
|
|
@@ -314,7 +315,7 @@ function runGh(cwd: string, args: string[]): string {
|
|
|
314
315
|
stdio: ["pipe", "pipe", "pipe"],
|
|
315
316
|
});
|
|
316
317
|
} catch (err) {
|
|
317
|
-
const msg =
|
|
318
|
+
const msg = errorMessage(err);
|
|
318
319
|
throw new Error(`gh command failed: ${msg}`);
|
|
319
320
|
}
|
|
320
321
|
}
|
|
@@ -375,7 +376,7 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
|
|
|
375
376
|
try {
|
|
376
377
|
items = ghJson<GitHubListItem[]>(cwd, args);
|
|
377
378
|
} catch (err) {
|
|
378
|
-
const msg =
|
|
379
|
+
const msg = errorMessage(err);
|
|
379
380
|
throw new Error(`${scheme}:// listing failed: ${msg}`);
|
|
380
381
|
}
|
|
381
382
|
|
|
@@ -395,7 +396,7 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
|
|
|
395
396
|
try {
|
|
396
397
|
repo = resolveDefaultRepo(cwd);
|
|
397
398
|
} catch (err) {
|
|
398
|
-
const msg =
|
|
399
|
+
const msg = errorMessage(err);
|
|
399
400
|
throw new Error(
|
|
400
401
|
`${scheme}://${(parsed as ParsedSingle).number} could not resolve a default repo from cwd '${cwd}': ${msg}\nUse ${scheme}://<owner>/<repo>/${(parsed as ParsedSingle).number} instead.`,
|
|
401
402
|
);
|
|
@@ -417,7 +418,7 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
|
|
|
417
418
|
notes: [`Full diff for ${scheme}://${repo}/${parsed.number}`],
|
|
418
419
|
};
|
|
419
420
|
} catch (err) {
|
|
420
|
-
const msg =
|
|
421
|
+
const msg = errorMessage(err);
|
|
421
422
|
throw new Error(`pr://${parsed.number}/diff failed: ${msg}`);
|
|
422
423
|
}
|
|
423
424
|
}
|
|
@@ -456,7 +457,7 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
|
|
|
456
457
|
notes: [`File listing for pr://${repo}/${parsed.number}`],
|
|
457
458
|
};
|
|
458
459
|
} catch (err) {
|
|
459
|
-
const msg =
|
|
460
|
+
const msg = errorMessage(err);
|
|
460
461
|
throw new Error(`pr://${parsed.number}/diff failed: ${msg}`);
|
|
461
462
|
}
|
|
462
463
|
}
|
|
@@ -503,7 +504,7 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
|
|
|
503
504
|
notes: [`Diff for file ${parsed.index}/${fileLines.length}: ${fileName} in pr://${repo}/${parsed.number}`],
|
|
504
505
|
};
|
|
505
506
|
} catch (err) {
|
|
506
|
-
const msg =
|
|
507
|
+
const msg = errorMessage(err);
|
|
507
508
|
throw new Error(`pr://${parsed.number}/diff/${parsed.index} failed: ${msg}`);
|
|
508
509
|
}
|
|
509
510
|
}
|
|
@@ -539,7 +540,7 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
|
|
|
539
540
|
notes: [`${scheme}://${repo}/${single.number} via gh`],
|
|
540
541
|
};
|
|
541
542
|
} catch (err) {
|
|
542
|
-
const msg =
|
|
543
|
+
const msg = errorMessage(err);
|
|
543
544
|
throw new Error(`${scheme}://${repo}/${single.number} failed: ${msg}`);
|
|
544
545
|
}
|
|
545
546
|
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: distill
|
|
3
|
+
description: Adapter for distill-persona/distill-software — orchestrates the full distillation pipeline as one command. Parallel research → merge → triple-verify → verify-prune(V1-V5) → build → fidelity. **Run with team='implementation'** (needs explorer/analyst/planner/critic/executor/verifier roles; the default team lacks analyst+critic). Pass the target in {goal} (e.g. "distill Karpathy persona" / "distill oh-my-pi codebase conventions" / "distill the field of perf-debugging").
|
|
4
|
+
topology: complex-dag
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!--
|
|
8
|
+
This workflow is the pi-crew ADAPTER for the distill-* skills. It bakes the
|
|
9
|
+
methodology (distill-persona / distill-software) into enforced orchestration:
|
|
10
|
+
parallel research, an INDEPENDENT fresh-context verifier (the F2' independence
|
|
11
|
+
fix), and the V1-V5 extraction gate. Every step loads the relevant distill
|
|
12
|
+
skill for methodology; the workflow enforces structure + independence.
|
|
13
|
+
|
|
14
|
+
Flavor is chosen in {goal}: "persona"/"person" → distill-persona (6 streams);
|
|
15
|
+
"codebase"/"software"/"engineer" → distill-software (6+extra streams + code-DNA);
|
|
16
|
+
"field"/"topic" → distill-persona topic variant. Detect from {goal}; if unclear,
|
|
17
|
+
default to person.
|
|
18
|
+
-->
|
|
19
|
+
|
|
20
|
+
## phase0-route
|
|
21
|
+
role: planner
|
|
22
|
+
output: distill-plan.md
|
|
23
|
+
|
|
24
|
+
Read the distill skill matching {goal}'s flavor (distill-persona for person/field, distill-software for codebase/engineer). Determine: flavor, target, `language`+`distilled_against` (software) or research-date (person), cost tier, and the output skill dir. Create the skill dir + `references/research/`. Write a one-paragraph run plan (flavor, target, staleness anchors, tier, coverage manifest approach) to distill-plan.md. Do NOT research yet — just route + scaffold.
|
|
25
|
+
|
|
26
|
+
## research-1
|
|
27
|
+
role: explorer
|
|
28
|
+
parallelGroup: research
|
|
29
|
+
dependsOn: phase0-route
|
|
30
|
+
output: research/01-writings.md
|
|
31
|
+
|
|
32
|
+
Stream 1 — **writings/docs**: for person → books/essays/papers/newsletters; for software → design docs/ADRs/RFCs/READMEs/commit messages. Follow the distill skill's stream-1 spec. Write findings (with sources + credibility) to `<skill-dir>/references/research/01-writings.md`. Research not persisted = not done.
|
|
33
|
+
|
|
34
|
+
**W5 fix — WRITE ACCESS CLARIFICATION**: You CAN and SHOULD write your findings to `<output-dir>/references/research/0N-<stream>.md` (the run artifacts dir, NOT the target project). The READ-ONLY restriction applies to the TARGET codebase (don't edit the project being learned from). If the output dir doesn't exist, `mkdir -p` it first. Do NOT emit your full output as TEXT in your result message — write to the file directly. The previous run's Stream 2 + Stream 4 deferred file writes and emitted TEXT, forcing a downstream worker to re-save — avoid that.
|
|
35
|
+
|
|
36
|
+
## research-2
|
|
37
|
+
role: explorer
|
|
38
|
+
parallelGroup: research
|
|
39
|
+
dependsOn: phase0-route
|
|
40
|
+
output: research/02-conversations.md
|
|
41
|
+
|
|
42
|
+
Stream 2 — **conversations/discourse**: person → podcasts/AMAs/interviews (stance-change moments, refusals); software → code-review comments/PR threads/incident retros. Write to `references/research/02-conversations.md`.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
**W5 fix — WRITE ACCESS CLARIFICATION**: You CAN and SHOULD write your findings to `<output-dir>/references/research/0N-<stream>.md` (the run artifacts dir, NOT the target project). The READ-ONLY restriction applies to the TARGET codebase (don't edit the project being learned from). If the output dir doesn't exist, `mkdir -p` it first. Do NOT emit your full output as TEXT in your result message — write to the file directly. The previous run's Stream 2 + Stream 4 deferred file writes and emitted TEXT, forcing a downstream worker to re-save — avoid that.
|
|
47
|
+
## research-3
|
|
48
|
+
role: explorer
|
|
49
|
+
parallelGroup: research
|
|
50
|
+
dependsOn: phase0-route
|
|
51
|
+
output: research/03-expression-dna.md
|
|
52
|
+
|
|
53
|
+
Stream 3 — **expression/DNA**: person → prose expression-DNA (sentence length, analogy density, certainty spectrum, 口癖); software → CODE Expression-DNA (run `code_dna.py` if software flavor; naming/function-length/comment/error-handling/type-strictness). Write to `references/research/03-expression-dna.md`.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
**W5 fix — WRITE ACCESS CLARIFICATION**: You CAN and SHOULD write your findings to `<output-dir>/references/research/0N-<stream>.md` (the run artifacts dir, NOT the target project). The READ-ONLY restriction applies to the TARGET codebase (don't edit the project being learned from). If the output dir doesn't exist, `mkdir -p` it first. Do NOT emit your full output as TEXT in your result message — write to the file directly. The previous run's Stream 2 + Stream 4 deferred file writes and emitted TEXT, forcing a downstream worker to re-save — avoid that.
|
|
58
|
+
## research-4
|
|
59
|
+
role: explorer
|
|
60
|
+
parallelGroup: research
|
|
61
|
+
dependsOn: phase0-route
|
|
62
|
+
output: research/04-external-views.md
|
|
63
|
+
|
|
64
|
+
Stream 4 — **critics/failures**: person → biography/criticism/peer-contrast; software → postmortems/bug reports/dep CVEs/arch-review. Write to `references/research/04-external-views.md`.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
**W5 fix — WRITE ACCESS CLARIFICATION**: You CAN and SHOULD write your findings to `<output-dir>/references/research/0N-<stream>.md` (the run artifacts dir, NOT the target project). The READ-ONLY restriction applies to the TARGET codebase (don't edit the project being learned from). If the output dir doesn't exist, `mkdir -p` it first. Do NOT emit your full output as TEXT in your result message — write to the file directly. The previous run's Stream 2 + Stream 4 deferred file writes and emitted TEXT, forcing a downstream worker to re-save — avoid that.
|
|
69
|
+
## research-5
|
|
70
|
+
role: explorer
|
|
71
|
+
parallelGroup: research
|
|
72
|
+
dependsOn: phase0-route
|
|
73
|
+
output: research/05-decisions.md
|
|
74
|
+
|
|
75
|
+
Stream 5 — **decisions** (where mental models live): person → major life/career decisions + say-vs-do gaps; software → ADRs/tradeoff records/"why X over Y" in commits+PRs (mine with `git log --grep`). Write to `references/research/05-decisions.md`.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
**W5 fix — WRITE ACCESS CLARIFICATION**: You CAN and SHOULD write your findings to `<output-dir>/references/research/0N-<stream>.md` (the run artifacts dir, NOT the target project). The READ-ONLY restriction applies to the TARGET codebase (don't edit the project being learned from). If the output dir doesn't exist, `mkdir -p` it first. Do NOT emit your full output as TEXT in your result message — write to the file directly. The previous run's Stream 2 + Stream 4 deferred file writes and emitted TEXT, forcing a downstream worker to re-save — avoid that.
|
|
80
|
+
## research-6
|
|
81
|
+
role: explorer
|
|
82
|
+
parallelGroup: research
|
|
83
|
+
dependsOn: phase0-route
|
|
84
|
+
output: research/06-timeline.md
|
|
85
|
+
|
|
86
|
+
Stream 6 — **timeline**: person → chronology + last 12 months (anti-staleness); software → `git log` IS the timeline (architecture evolution, what's actively changing). Write to `references/research/06-timeline.md`. For software flavor, ALSO sweep the extra streams (tests-as-invariants, CI/lint, dep manifests, release-pipeline, risk-posture, concurrency, platform-hardening) — fold each into the matching research file or add `07-extra.md`.
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
**W5 fix — WRITE ACCESS CLARIFICATION**: You CAN and SHOULD write your findings to `<output-dir>/references/research/0N-<stream>.md` (the run artifacts dir, NOT the target project). The READ-ONLY restriction applies to the TARGET codebase (don't edit the project being learned from). If the output dir doesn't exist, `mkdir -p` it first. Do NOT emit your full output as TEXT in your result message — write to the file directly. The previous run's Stream 2 + Stream 4 deferred file writes and emitted TEXT, forcing a downstream worker to re-save — avoid that.
|
|
91
|
+
## merge
|
|
92
|
+
role: analyst
|
|
93
|
+
dependsOn: research-1, research-2, research-3, research-4, research-5, research-6
|
|
94
|
+
output: research-coverage.md
|
|
95
|
+
|
|
96
|
+
Read all 6 (or 7) research files. Produce the Phase 1.5 coverage table: streams × source-count × key-findings × contradictions × gaps. **Surface contradictions explicitly — do NOT average them into false consensus** (contradiction-as-signal). Flag any stream with thin coverage. Write to `references/research-coverage.md`.
|
|
97
|
+
|
|
98
|
+
## synthesize
|
|
99
|
+
role: planner
|
|
100
|
+
dependsOn: merge
|
|
101
|
+
output: models.md
|
|
102
|
+
|
|
103
|
+
Read the research files + coverage. List all candidate claims (usually 15-30). Apply **triple-verification** to each (cross-domain/module recurrence + generative + exclusive): all-3 → mental model (3-7); 1-2 → decision heuristic (5-10); 0 → discard. The exclusivity test is the anti-bloat weapon (kills "use version control" generic advice). Extract expression-DNA, values+anti-patterns, ≥2 preserved inner tensions, intellectual lineage, ≥3 honest boundaries + staleness date. Write the model set to `references/models.md`.
|
|
104
|
+
|
|
105
|
+
**W4 fix — target-equivalent check**: Before proposing any model that implies "create new file/module/helper" in the target, you MUST grep the target codebase for an existing equivalent (e.g. `rg -l "errorMessage|toErrorMessage" <target>/src/` for an error-message helper claim). The oh-my-pi→pi-crew run's H11 said "create `src/runtime/error-message.ts`" but the helper already existed at `src/utils/guards.ts:96` — would have shipped a duplicate. Any "create" claim without a grep-confirmed absence in target is **OVERSTATED** — re-frame as "adopt existing X at target:file:line" or remove.
|
|
106
|
+
|
|
107
|
+
## verify-prune
|
|
108
|
+
role: critic
|
|
109
|
+
dependsOn: synthesize
|
|
110
|
+
|
|
111
|
+
**Fresh-context extraction verification (V1-V5)** — do NOT trust the synthesis at face value. Apply to every candidate model: V1 signal (method/principle, not persona-content/quirk — flag quirk-vs-principle ⚠️); V2 non-redundant (>70% overlap → merge/drop); V3 effective (changes a real decision?); V4 optimal (simplest form); **V5 factual-accuracy** — every quoted constant/function-name/path/regex/threshold is grep-verified against the actual source (codebase) or the research files (person); cite evidence; reject over-absolute claims. Output the PRUNED model set + reject reasons (audit trail) to `references/verified-models.md`. Over-extraction is worse than under-extraction — default to PRUNE.
|
|
112
|
+
|
|
113
|
+
## three-filter
|
|
114
|
+
role: critic
|
|
115
|
+
dependsOn: verify-prune
|
|
116
|
+
output: three-filter.md
|
|
117
|
+
|
|
118
|
+
**Phase 2.5 (new — SELF-UPGRADE DIRECTIVE).** Apply the 3-chiều filter to every KEEP candidate from `verified-models.md`, using `target-analysis.md` as ground truth. For each candidate, walk the 3 dimensions:
|
|
119
|
+
1. **RELEVANCE** — relevant to target's domain/scale/context? NO → SKIP.
|
|
120
|
+
2. **PRESENCE** — target already has something similar? NO → NECESSITY (does target need it? NO → SKIP, YES → ADOPT). YES → QUALITY COMPARISON: source BETTER → IMPROVE, EQUAL/WORSE → SKIP, COMPLEMENTARY → MERGE.
|
|
121
|
+
3. **For each SELECTED** → note adaptation needed for target context (license boundary, toolchain differences, existing patterns to preserve).
|
|
122
|
+
|
|
123
|
+
Output: per-candidate verdict (SKIP / ADOPT / IMPROVE / MERGE) with target-evidence citations. Write to `references/three-filter.md`. **This is the gate that prevents applying patterns the target already has better.**
|
|
124
|
+
|
|
125
|
+
## effectiveness-gate
|
|
126
|
+
role: critic
|
|
127
|
+
dependsOn: three-filter
|
|
128
|
+
output: effectiveness-gate.md
|
|
129
|
+
|
|
130
|
+
**Phase 2.6 (new — MANDATORY pre-apply gate).** For every SELECTED candidate from `three-filter.md`, run the EFFECTIVENESS VERIFICATION — SELECTED ≠ TO-APPLY. Each SELECTED must prove it's effective FOR THIS TARGET:
|
|
131
|
+
a. **CONCRETE DELTA** — exactly what changes in the target? (1-line: "AGENTS.md +rule X" / "lint +rule Y" / "src/runtime/new-file.ts +function Z")
|
|
132
|
+
b. **EFFECTIVENESS PROOF** (≥1 of): GENERATIVE (changes a real decision/answer/behavior? name the case), PROBLEM-EXISTS (target has a problem this solves? grep/test/convention-gap evidence), DELTA-TEST (apply in isolation → measure improvement on 1 target case)
|
|
133
|
+
c. **CONFLICT CHECK** — conflicts with target's existing practice? resolve or downgrade
|
|
134
|
+
d. **VERDICT**: ✅ EFFECTIVENESS-VERIFIED → TO-APPLY, or ❌ REJECTED → log reason (rejection goes to APPLY-LOG)
|
|
135
|
+
|
|
136
|
+
Output: per-candidate verdict with concrete delta + proof + conflict check. Write to `references/effectiveness-gate.md`. **Only TO-APPLY items enter Phase 3.** This is the analog of V1-V4 (which verify MODEL effective at extract) applied to APPLY (which verifies apply effective at integrate) — same rigor, different stage.
|
|
137
|
+
|
|
138
|
+
## plan-application
|
|
139
|
+
role: planner
|
|
140
|
+
dependsOn: effectiveness-gate
|
|
141
|
+
output: apply-plan.md
|
|
142
|
+
|
|
143
|
+
**Phase 3 (new).** For each TO-APPLY item from `effectiveness-gate.md`, produce a concrete apply plan:
|
|
144
|
+
- **HOW to apply**: AGENTS.md edit, lint rule add, src/ pattern adopt, CONTRIBUTING.md update, scripts/ operational script, or skill in target's skills/ dir
|
|
145
|
+
- **Exact file:line target** in the target project
|
|
146
|
+
- **Tier priority**: Tier 1 (high V3, low V4 cost) → Tier 2 (high V3, medium V4 cost) → Tier 3 (high V3, high V4 cost — pilot first)
|
|
147
|
+
- **Verification gate per item**: `npm run test:critical` + `npm run typecheck` + `npm run build:bundle` must pass after each apply; bundle MD5 must match or be updated; if tests fail → rollback
|
|
148
|
+
|
|
149
|
+
Write to `references/apply-plan.md`. This is the input for the executor in Phase 4.
|
|
150
|
+
|
|
151
|
+
## apply
|
|
152
|
+
role: executor
|
|
153
|
+
dependsOn: plan-application
|
|
154
|
+
output: applied-changes.md
|
|
155
|
+
|
|
156
|
+
**Phase 4 (new — THE KEY DELIVERABLE).** Read `apply-plan.md`. For each TO-APPLY item, in tier order (Tier 1 first), apply the concrete delta to the target project. **The apply MUST happen here, not be deferred to a "downstream worker"** (this was W1's root cause in the oh-my-pi→pi-crew run — the build phase deferred apply and hung).
|
|
157
|
+
|
|
158
|
+
Per-item protocol:
|
|
159
|
+
1. Edit the target file(s) as specified in apply-plan.md
|
|
160
|
+
2. Run verification gate: `npm run test:critical` (or equivalent) + `npm run typecheck` + `npm run build:bundle`
|
|
161
|
+
3. Capture before/after diff + bundle MD5 (before/after)
|
|
162
|
+
4. If any gate fails → rollback the change (git checkout the file), log REJECTED in APPLY-LOG, continue with next item
|
|
163
|
+
5. If passes → log APPLIED in APPLY-LOG with file:line
|
|
164
|
+
|
|
165
|
+
**Anti-loop guard (W2 fix)**: this task has a hard tool-call budget of 50 tool calls and a wall-clock timeout of 15 minutes. If you hit either, STOP and write a partial APPLY-LOG with what was completed + what's remaining. Do NOT re-verify completed items.
|
|
166
|
+
|
|
167
|
+
Write per-item results to `references/applied-changes.md` AND append to `APPLY-LOG.md` in the target project (or the run's APPLY-LOG location).
|
|
168
|
+
|
|
169
|
+
## verify-target-improved
|
|
170
|
+
role: verifier
|
|
171
|
+
dependsOn: apply
|
|
172
|
+
verify: true
|
|
173
|
+
|
|
174
|
+
**Phase 5 (new — Darwin ratchet).** The output of a distillation is NOT "has skill" — it's "target improved." Read `applied-changes.md` + the target project's git diff. For each APPLIED item, re-verify:
|
|
175
|
+
- Does the change actually improve the target? (concrete, measurable — e.g. "new helper reduces 18 sites to 1 import"; not vibes)
|
|
176
|
+
- Do the tests still pass? (`npm run test:critical`)
|
|
177
|
+
- Did the bundle MD5 change as expected? (intentional change OK; unexpected change → flag)
|
|
178
|
+
- Is the change consistent with target's existing style/conventions? (no foreign code injected)
|
|
179
|
+
|
|
180
|
+
Output: per-item verdict (IMPROVED / NEUTRAL / REGRESSED) + recommendation (KEEP / ROLLBACK). If any REGRESSED → flag for rollback. Write to `references/target-improvement.md`.
|
|
181
|
+
|
|
182
|
+
**Ship-gate**: ≥3 items APPLIED + verified IMPROVED → PASS. Otherwise → FAIL with the gap.
|
|
183
|
+
|
|
184
|
+
## build
|
|
185
|
+
role: executor
|
|
186
|
+
dependsOn: verify-prune
|
|
187
|
+
output: SKILL.md
|
|
188
|
+
|
|
189
|
+
Read `verified-models.md`. Render the output `<target>-perspective` (person) or `<target>-conventions` (codebase) SKILL.md from the distill skill's template. MUST include: staleness anchors (language+distilled_against for software), the Agentic Protocol (research-before-answer, Step-2 dims DERIVED from the models, F2' third-category rule), the verified models (each with evidence+limitation), expression/code-DNA, ≥3 honest boundaries, sources. For software flavor: wire operational scripts INTO the Agentic Protocol (F13), run `code_dna.py`. Write the SKILL.md into the skill dir.
|
|
190
|
+
|
|
191
|
+
**Anti-loop guard (W2 fix)**: After writing SKILL.md (and FIDELITY.md if fidelity is your job), output `DONE` and stop immediately. Do NOT re-verify, re-read, or re-grep completed files. Hard limits: ≤30 tool calls total, ≤10 min wall-clock. The oh-my-pi→pi-crew run had 11_build loop 14+ times in a verification loop (re-read SKILL.md, re-check claims, re-grep source) and never converged. If you hit either limit, stop and write whatever you've completed.
|
|
192
|
+
|
|
193
|
+
## fidelity
|
|
194
|
+
role: verifier
|
|
195
|
+
dependsOn: build
|
|
196
|
+
verify: true
|
|
197
|
+
|
|
198
|
+
**Independent fresh-context fidelity check** (the F2' fix — this verifier has NOT seen the synthesis/build reasoning; it reads only the built SKILL.md + ground truth). For person: pose 3 known-stance + 1 NOVEL framework-answerable edge question; score stance-consistency + style + edge-honesty (must flag inference, not fabricate). For codebase: pose a novel "how would this codebase handle X new scenario" question; verify the skill's models give complete consistent guidance + that every factual claim still grep-matches source (V5 re-check). Gate: edge-honesty/accuracy failure = NO-SHIP (return FAIL with the specific failure + which model/claim broke). On PASS, confirm the skill is installable + self-contained. Write the fidelity report to `references/fidelity.md`.
|
|
Binary file
|