cclaw-cli 0.8.0 → 0.10.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/dist/content/examples.d.ts +16 -0
- package/dist/content/examples.js +364 -55
- package/dist/content/harness-tool-refs.d.ts +20 -0
- package/dist/content/harness-tool-refs.js +240 -0
- package/dist/content/hooks.js +48 -2
- package/dist/content/meta-skill.js +72 -4
- package/dist/content/skills.d.ts +5 -0
- package/dist/content/skills.js +118 -46
- package/dist/content/stage-schema.d.ts +9 -3
- package/dist/content/stage-schema.js +72 -22
- package/dist/content/subagents.js +21 -0
- package/dist/content/templates.js +13 -3
- package/dist/doctor.js +82 -0
- package/dist/harness-adapters.js +11 -3
- package/dist/install.js +25 -1
- package/dist/policy.js +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,19 @@
|
|
|
1
1
|
import type { FlowStage } from "../types.js";
|
|
2
2
|
export declare function stageGoodBadExamples(stage: FlowStage): string;
|
|
3
|
+
export declare const STAGE_EXAMPLES_REFERENCE_DIR = "references/stages";
|
|
4
|
+
export declare function stageExamplesReferencePath(stage: FlowStage): string;
|
|
5
|
+
/**
|
|
6
|
+
* Returns the full example artifact body as a standalone reference markdown
|
|
7
|
+
* file. Materialized under .cclaw/references/stages/<stage>-examples.md so
|
|
8
|
+
* the always-rendered skill body can link instead of inlining.
|
|
9
|
+
*/
|
|
10
|
+
export declare function stageExamplesReferenceMarkdown(stage: FlowStage): string | null;
|
|
11
|
+
/**
|
|
12
|
+
* Returns the short inline pointer rendered directly inside the stage skill.
|
|
13
|
+
* Replaces the previous always-inline ~50-100 line fenced block and
|
|
14
|
+
* delivers true progressive disclosure: the full example lives in a
|
|
15
|
+
* reference file loaded on demand.
|
|
16
|
+
*/
|
|
3
17
|
export declare function stageExamples(stage: FlowStage): string;
|
|
18
|
+
export type ExampleDomain = "web" | "cli" | "library" | "data-pipeline";
|
|
19
|
+
export declare function stageDomainExamples(stage: FlowStage): string;
|
package/dist/content/examples.js
CHANGED
|
@@ -433,68 +433,205 @@ Execution rule: complete and verify each wave before starting the next wave.
|
|
|
433
433
|
- PR URL: https://github.com/example/repo/pull/42`,
|
|
434
434
|
};
|
|
435
435
|
const GOOD_BAD_EXAMPLES = {
|
|
436
|
-
brainstorm:
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
436
|
+
brainstorm: [
|
|
437
|
+
{
|
|
438
|
+
label: "Problem / success statement",
|
|
439
|
+
good: "Problem: release checks are fragile and inconsistent between CI and local runs; invalid metadata sometimes reaches npm publish. Success: invalid release preconditions are caught before publish with explicit operator feedback, in both CI and local workflows. Constraints: no new runtime dependencies.",
|
|
440
|
+
bad: "Problem: releases are broken. Success: make them better. Constraints: be careful.",
|
|
441
|
+
lesson: "\"Make it better\" is not a success criterion — an agent cannot know when it is done. State the observable condition that proves success."
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
label: "Alternative direction (one of 2–3)",
|
|
445
|
+
good: "Option B: Pre-publish verifier script invoked from \`release.yml\` and a \`pnpm release:check\` target. Pros: one enforcement surface; fails fast locally. Cons: adds a script to maintain; must stay in sync with \`package.json\`. Rejected alternative: relying on npm lifecycle hooks only — they run too late to block publish.",
|
|
446
|
+
bad: "We could also use a script, or hooks, or something in CI. We'll pick whichever is easier later.",
|
|
447
|
+
lesson: "Alternatives are only useful if they are concrete and comparable. Name each one, call out pros/cons, and say what was rejected — otherwise \"later\" becomes \"never\" and the choice is made by accident."
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
label: "Clarifying question",
|
|
451
|
+
good: "Before I lock direction: should a failed release:check block the CI job (hard failure) or only warn and continue? The former is safer but costs a revert cycle when the check itself is wrong; the latter preserves velocity but can let bad metadata through. Recommend A (block). Pick: A) Block B) Warn-only C) Block in CI, warn locally.",
|
|
452
|
+
bad: "Do you want it to fail or warn? Let me know.",
|
|
453
|
+
lesson: "A good question gives the user context, a recommendation, and lettered options they can answer with one keystroke. \"Let me know\" shifts the framing cost back to the user."
|
|
454
|
+
}
|
|
455
|
+
],
|
|
456
|
+
scope: [
|
|
457
|
+
{
|
|
458
|
+
label: "In / out / deferred boundaries",
|
|
459
|
+
good: "In scope: in-app notification feed, SSE delivery path, read/unread state, retry on transient failures. Out of scope: email/SMS/push providers, per-user preferences. Deferred: WebSocket channel, rich media, full-text search.",
|
|
460
|
+
bad: "In scope: notifications. Out of scope: stuff we are not doing. Deferred: v2.",
|
|
461
|
+
lesson: "Vague boundaries get relitigated in every subsequent stage. Enumerate concrete capabilities on each side — \"stuff we are not doing\" is not a decision."
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
label: "Scope change trace",
|
|
465
|
+
good: "Scope delta at 2026-04-15: user asked to add per-user mute preferences. Decision: moved from Out-of-scope → In-scope; acknowledged cost (≈1 day, +1 schema migration); risk: touches settings surface. Recorded in \`03-design.md#scope-trace\`. Requires re-running scope review before design lock.",
|
|
466
|
+
bad: "Added mute preferences to scope.",
|
|
467
|
+
lesson: "Scope changes silently are how projects drift. Every in↔out move needs a timestamp, a cost estimate, and a link to the next review it invalidates."
|
|
468
|
+
}
|
|
469
|
+
],
|
|
470
|
+
design: [
|
|
471
|
+
{
|
|
472
|
+
label: "Failure mode row",
|
|
473
|
+
good: "Failure: SSE connection drop. Trigger: network interruption. Detection: client heartbeat timeout (30s). Mitigation: auto-reconnect with exponential backoff + REST snapshot fallback. User impact: ≤10s delay, no data loss.",
|
|
474
|
+
bad: "Failure: network errors. Mitigation: retry and log. User impact: users may see issues sometimes.",
|
|
475
|
+
lesson: "A failure row without a detection signal and a bounded user impact is aspirational, not a design. Name the trigger, the detector, and the recovery behavior."
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
label: "Rejected design alternative",
|
|
479
|
+
good: "Considered WebSocket instead of SSE. Rejected because: (1) our proxy layer strips upgrade headers; (2) one-way push fits the \"notification feed\" semantics; (3) SSE plays nicer with HTTP/2 fan-out. Trade-off accepted: no client→server channel; we will fall back to REST for the tiny set of acks.",
|
|
480
|
+
bad: "We chose SSE. WebSocket could also work.",
|
|
481
|
+
lesson: "A design without a rejected alternative reads like a requirement, not a decision. The rejection is the part that survives review — it tells future readers what trade-off was taken."
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
label: "Diagram caption",
|
|
485
|
+
good: "Figure 1 — Notification pipeline (sequence diagram): producer → outbox(durable) → relay → SSE stream → client. Label on relay shows \"at-least-once; dedupe by event_id\"; label on client shows \"merge by dedupe_key before render\".",
|
|
486
|
+
bad: "Figure 1: notification flow.",
|
|
487
|
+
lesson: "An unlabeled diagram is decoration. Every arrow needs a delivery guarantee, every box needs an action verb — otherwise the diagram contradicts the prose without anyone noticing."
|
|
488
|
+
}
|
|
489
|
+
],
|
|
490
|
+
spec: [
|
|
491
|
+
{
|
|
492
|
+
label: "Observable acceptance criterion",
|
|
493
|
+
good: "AC-1: Given a signed-in user with an active session, when the server publishes a new notification event for that user, the client feed shows the new item within 5 seconds without a full page reload.",
|
|
494
|
+
bad: "AC-1: Users should see their notifications quickly and reliably, with a good user experience.",
|
|
495
|
+
lesson: "Spec criteria must be observable, measurable, and falsifiable. \"Quickly\" is a feeling; \"within 5 seconds without a full page reload\" is a test."
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
label: "Negative / error-path criterion",
|
|
499
|
+
good: "AC-4: Given the SSE connection drops mid-session, when the client detects no heartbeat for 30 seconds, the UI shows a \"Reconnecting…\" badge and automatically re-subscribes; missed events delivered since the last ACKed id are replayed exactly once.",
|
|
500
|
+
bad: "AC-4: Handle errors gracefully.",
|
|
501
|
+
lesson: "Error-path criteria are where most bugs hide. Write them with the same \"given/when/then\" rigor as happy-path — otherwise QA ends up inventing them at release time."
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
label: "Non-functional budget",
|
|
505
|
+
good: "NFR-2: p95 end-to-end publish-to-visible latency ≤5s under 1k concurrent subscribers on a 2-vCPU pod; CPU headroom ≥30% at steady state. Measurement: \`k6 run tests/load/notifications.js\`, report median + p95 + p99.",
|
|
506
|
+
bad: "NFR-2: Performance should be good.",
|
|
507
|
+
lesson: "Non-functional goals without numbers + a measurement command are aspirational. Pin the percentile, the load shape, and the script that produces the evidence."
|
|
508
|
+
}
|
|
509
|
+
],
|
|
510
|
+
plan: [
|
|
511
|
+
{
|
|
512
|
+
label: "Single task row",
|
|
513
|
+
good: "T-2: Implement publisher + outbox write path. Acceptance: AC-1. Verification: \`pnpm vitest run tests/integration/publisher.test.ts\`. Depends on: T-1. Effort: M (≈4 min).",
|
|
514
|
+
bad: "T-2: Build the backend. Verify: manual testing. Effort: a few days.",
|
|
515
|
+
lesson: "A task without a single acceptance criterion and a reproducible verification command is a wish. If you cannot say how you will know it is done, you cannot ship it."
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
label: "Dependency graph entry",
|
|
519
|
+
good: "T-5 (consume SSE client) depends on T-3 (stream endpoint) and T-4 (auth cookie forwarding). Parallelizable with T-6 (read-state persistence). Blocks T-8 (end-to-end happy-path e2e).",
|
|
520
|
+
bad: "T-5 depends on other tasks.",
|
|
521
|
+
lesson: "The value of a dependency graph is mechanical scheduling. \"Depends on other tasks\" is a shrug — list the IDs so the execution order is unambiguous."
|
|
522
|
+
}
|
|
523
|
+
],
|
|
524
|
+
tdd: [
|
|
525
|
+
{
|
|
526
|
+
label: "RED → GREEN → REFACTOR slice",
|
|
527
|
+
good: "RED: \`pnpm vitest run tests/unit/dedupe-feed.test.ts\` → \`publishToOutbox is not a function\`. GREEN (after minimal impl): same command, 47/47 pass, full suite. REFACTOR: extracted \`mergeLatestByDedupeKey\`; suite still 47/47.",
|
|
528
|
+
bad: "Wrote the publisher code. Tests pass now. Will add unit tests later when I have time.",
|
|
529
|
+
lesson: "Code written before a failing test is guessing validated after the fact. The RED failure IS the specification — without it, the GREEN pass proves nothing about the intended behavior."
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
label: "Bug-fix reproduction test",
|
|
533
|
+
good: "Bug B-17: dedup fails when two events arrive in the same ms. Prove-It RED: added \`tests/unit/dedupe-feed.test.ts > dedupes when timestamps collide\`; run → \`expected 1 item, received 2\`. Fix applied; same test passes; full suite still 47/47.",
|
|
534
|
+
bad: "Fixed the duplicate rendering issue.",
|
|
535
|
+
lesson: "A bug without a reproducing test is a bug that comes back. Ship the RED test as part of the fix — it is the contract that prevents regression."
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
label: "Refactor-only slice (state-based)",
|
|
539
|
+
good: "Refactor: moved heartbeat logic into \`useHeartbeat()\` hook. No behavior change intended. Evidence: no new tests; existing state-based tests \`feed-state.test.ts\` (42 assertions) still pass; coverage unchanged at 94%.",
|
|
540
|
+
bad: "Refactored the component. Added some interaction mocks to check the new hook is called.",
|
|
541
|
+
lesson: "A refactor should assert on state, not on call shape. If you had to rewrite your mocks, it was not a refactor — it was a redesign dressed as one."
|
|
542
|
+
}
|
|
543
|
+
],
|
|
544
|
+
review: [
|
|
545
|
+
{
|
|
546
|
+
label: "Critical finding",
|
|
547
|
+
good: "R-1 Critical: snapshot endpoint returns newest N rows but does not guarantee consistency with stream cursor — users can miss items between snapshot and subscribe. Evidence: integration test \`notification-consistency.test.ts:22-58\`. Status: open.",
|
|
548
|
+
bad: "Looks good overall. A few small things could be polished, maybe refactor the merge logic. LGTM.",
|
|
549
|
+
lesson: "\"LGTM\" is not a review — it is a signature on whatever the author shipped. Every finding needs a severity, a falsifiable description, evidence, and a status."
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
label: "Security review row",
|
|
553
|
+
good: "R-4 High (sec): SSE endpoint accepts any user_id in the query string; a logged-in attacker can subscribe to another user's stream. Evidence: \`curl\` repro in \`docs/notes/sec-r4.md\`. Fix: require auth cookie, filter events by session.user.id server-side. Status: fix in T-11; verified in \`notifications-auth.test.ts\`.",
|
|
554
|
+
bad: "Might want to double-check auth on the SSE endpoint.",
|
|
555
|
+
lesson: "Security findings without a reproduction step and a tied fix-task are suggestions, not reviews. Attach the curl (or equivalent), the fix task ID, and the verification test."
|
|
556
|
+
}
|
|
557
|
+
],
|
|
558
|
+
ship: [
|
|
559
|
+
{
|
|
560
|
+
label: "Rollback contract",
|
|
561
|
+
good: "Rollback trigger: error rate on \`/notifications/stream\` >5% for 5 minutes, or p95 publish-to-visible lag >10s. Steps: \`git revert <merge-sha> && git push origin main\` then redeploy; run \`2026_04_12_notifications_cursor_down.sql\` before traffic. Verification: error rate returns to baseline within 10 minutes.",
|
|
562
|
+
bad: "Rollback plan: revert the commit if anything goes wrong.",
|
|
563
|
+
lesson: "\"Revert if anything goes wrong\" leaves the on-call engineer to invent the plan at 2 a.m. The rollback trigger is an operational contract: state the signal, the command, and the verification."
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
label: "Preflight check",
|
|
567
|
+
good: "Preflight: \`pnpm release:check\` ✅ (package metadata ok, changeset captured), \`pnpm test\` ✅ 195/195, \`pnpm build\` ✅, CI green on feat/notifications @ \`abc1234\`, rollback plan captured, migration reviewed. Finalization mode: Merge via squash.",
|
|
568
|
+
bad: "All good, shipping it.",
|
|
569
|
+
lesson: "A preflight is a checklist that names each gate and the command that proved it. \"All good\" is a vibe — it cannot be audited after the fact when the deploy misbehaves."
|
|
570
|
+
}
|
|
571
|
+
]
|
|
476
572
|
};
|
|
477
573
|
export function stageGoodBadExamples(stage) {
|
|
478
|
-
const
|
|
479
|
-
if (!
|
|
574
|
+
const samples = GOOD_BAD_EXAMPLES[stage];
|
|
575
|
+
if (!samples || samples.length === 0)
|
|
480
576
|
return "";
|
|
481
|
-
|
|
577
|
+
const blocks = [
|
|
482
578
|
"## Good vs Bad (at-a-glance)",
|
|
483
579
|
"",
|
|
484
|
-
"Contrasting samples to calibrate the quality bar for this stage. Read before writing the artifact — mirror the **Good** shape, avoid the **Bad** shape.",
|
|
485
|
-
""
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
580
|
+
"Contrasting samples to calibrate the quality bar for this stage. Read before writing the artifact — mirror the **Good** shape, avoid the **Bad** shape. Each block targets a different axis of the stage so you can spot-check more than one dimension of your draft.",
|
|
581
|
+
""
|
|
582
|
+
];
|
|
583
|
+
samples.forEach((sample, index) => {
|
|
584
|
+
blocks.push(`### ${index + 1}. ${sample.label}`);
|
|
585
|
+
blocks.push("");
|
|
586
|
+
blocks.push("**Good**");
|
|
587
|
+
blocks.push("");
|
|
588
|
+
blocks.push("> " + sample.good);
|
|
589
|
+
blocks.push("");
|
|
590
|
+
blocks.push("**Bad**");
|
|
591
|
+
blocks.push("");
|
|
592
|
+
blocks.push("> " + sample.bad);
|
|
593
|
+
blocks.push("");
|
|
594
|
+
blocks.push("**Why it matters:** " + sample.lesson);
|
|
595
|
+
blocks.push("");
|
|
596
|
+
});
|
|
597
|
+
return blocks.join("\n");
|
|
598
|
+
}
|
|
599
|
+
export const STAGE_EXAMPLES_REFERENCE_DIR = "references/stages";
|
|
600
|
+
export function stageExamplesReferencePath(stage) {
|
|
601
|
+
return `.cclaw/${STAGE_EXAMPLES_REFERENCE_DIR}/${stage}-examples.md`;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Returns the full example artifact body as a standalone reference markdown
|
|
605
|
+
* file. Materialized under .cclaw/references/stages/<stage>-examples.md so
|
|
606
|
+
* the always-rendered skill body can link instead of inlining.
|
|
607
|
+
*/
|
|
608
|
+
export function stageExamplesReferenceMarkdown(stage) {
|
|
609
|
+
const examples = STAGE_EXAMPLES[stage];
|
|
610
|
+
if (!examples)
|
|
611
|
+
return null;
|
|
612
|
+
return [
|
|
613
|
+
`---`,
|
|
614
|
+
`stage: ${stage}`,
|
|
615
|
+
`name: ${stage}-stage-examples`,
|
|
616
|
+
`description: "Full sample artifact for the ${stage} stage. Loaded only when an agent explicitly needs a complete example; the stage skill links here rather than inlining."`,
|
|
617
|
+
`---`,
|
|
489
618
|
"",
|
|
490
|
-
|
|
619
|
+
`# ${stage} stage — full artifact sample`,
|
|
491
620
|
"",
|
|
492
|
-
|
|
621
|
+
`This file is linked from \`.cclaw/skills/<${stage}-stage>/SKILL.md\` under **Examples → See also**. The sample uses H2 headings that mirror the artifact a cclaw session must produce, so the markdown is wrapped in a fence to avoid collapsing into the outline.`,
|
|
493
622
|
"",
|
|
494
|
-
"
|
|
623
|
+
"```markdown",
|
|
624
|
+
examples,
|
|
625
|
+
"```",
|
|
495
626
|
""
|
|
496
627
|
].join("\n");
|
|
497
628
|
}
|
|
629
|
+
/**
|
|
630
|
+
* Returns the short inline pointer rendered directly inside the stage skill.
|
|
631
|
+
* Replaces the previous always-inline ~50-100 line fenced block and
|
|
632
|
+
* delivers true progressive disclosure: the full example lives in a
|
|
633
|
+
* reference file loaded on demand.
|
|
634
|
+
*/
|
|
498
635
|
export function stageExamples(stage) {
|
|
499
636
|
const examples = STAGE_EXAMPLES[stage];
|
|
500
637
|
if (!examples)
|
|
@@ -502,11 +639,183 @@ export function stageExamples(stage) {
|
|
|
502
639
|
return [
|
|
503
640
|
"## Examples",
|
|
504
641
|
"",
|
|
505
|
-
|
|
642
|
+
`Full artifact sample for this stage lives at \`${stageExamplesReferencePath(stage)}\`. Open it when you need a complete reference; do NOT paste the example into the artifact verbatim — it is a shape guide, not a template.`,
|
|
506
643
|
"",
|
|
507
|
-
"
|
|
508
|
-
|
|
509
|
-
"```",
|
|
644
|
+
"Summary of what the reference covers:",
|
|
645
|
+
...exampleSummaryBullets(stage),
|
|
510
646
|
""
|
|
511
647
|
].join("\n");
|
|
512
648
|
}
|
|
649
|
+
function exampleSummaryBullets(stage) {
|
|
650
|
+
const headings = STAGE_EXAMPLE_SECTION_HEADINGS[stage] ?? [];
|
|
651
|
+
if (headings.length === 0)
|
|
652
|
+
return ["- Full artifact structure."];
|
|
653
|
+
return headings.map((heading) => `- ${heading}`);
|
|
654
|
+
}
|
|
655
|
+
// Kept in sync with STAGE_EXAMPLES above so the inline summary matches the
|
|
656
|
+
// reference file without duplicating the heavy text. Update whenever the
|
|
657
|
+
// sample in STAGE_EXAMPLES gains or loses a top-level section.
|
|
658
|
+
const STAGE_EXAMPLE_SECTION_HEADINGS = {
|
|
659
|
+
brainstorm: [
|
|
660
|
+
"Problem framing (problem, success, constraints)",
|
|
661
|
+
"Candidate approaches with trade-offs",
|
|
662
|
+
"Recommended direction + open questions",
|
|
663
|
+
"Clarification log and decision record"
|
|
664
|
+
],
|
|
665
|
+
scope: [
|
|
666
|
+
"In-scope / out-of-scope / deferred lists with concrete capabilities",
|
|
667
|
+
"Requirements table with stable R# IDs",
|
|
668
|
+
"Boundary stress-tests and non-negotiables",
|
|
669
|
+
"Decision record for premise challenges"
|
|
670
|
+
],
|
|
671
|
+
design: [
|
|
672
|
+
"Blast-radius file list",
|
|
673
|
+
"Mandatory architecture diagram (Mermaid)",
|
|
674
|
+
"Failure-mode table with detection + mitigation",
|
|
675
|
+
"Test strategy + performance budget",
|
|
676
|
+
"Completion dashboard + unresolved decisions"
|
|
677
|
+
],
|
|
678
|
+
spec: [
|
|
679
|
+
"Acceptance-criteria table (observable, measurable, falsifiable)",
|
|
680
|
+
"Requirement-ref column tying each AC back to an R# from scope",
|
|
681
|
+
"Verification-approach column",
|
|
682
|
+
"Approval block"
|
|
683
|
+
],
|
|
684
|
+
plan: [
|
|
685
|
+
"Dependency graph + dependency waves",
|
|
686
|
+
"Task list with effort + minutes estimate per task",
|
|
687
|
+
"Acceptance mapping (every AC → task IDs)",
|
|
688
|
+
"No-Placeholder scan row + WAIT_FOR_CONFIRM marker"
|
|
689
|
+
],
|
|
690
|
+
tdd: [
|
|
691
|
+
"RED evidence per slice (failing test output)",
|
|
692
|
+
"Acceptance mapping per slice",
|
|
693
|
+
"GREEN evidence (full-suite pass)",
|
|
694
|
+
"REFACTOR notes with behavior-preservation confirmation",
|
|
695
|
+
"Test-pyramid shape + prove-it reproduction when applicable"
|
|
696
|
+
],
|
|
697
|
+
review: [
|
|
698
|
+
"Spec-compliance findings (Layer 1)",
|
|
699
|
+
"Code-quality findings (Layer 2)",
|
|
700
|
+
"Severity, evidence, and status per finding",
|
|
701
|
+
"Go / no-go verdict"
|
|
702
|
+
],
|
|
703
|
+
ship: [
|
|
704
|
+
"Release checklist (version, changelog, tag, artifacts)",
|
|
705
|
+
"Rollback plan with trigger, steps, verification",
|
|
706
|
+
"Runbook (how to verify the release post-deploy)",
|
|
707
|
+
"Sign-off block"
|
|
708
|
+
]
|
|
709
|
+
};
|
|
710
|
+
const DOMAIN_LABELS = {
|
|
711
|
+
web: "Web app (full-stack)",
|
|
712
|
+
cli: "CLI tool",
|
|
713
|
+
library: "Library / SDK",
|
|
714
|
+
"data-pipeline": "Data pipeline / ETL"
|
|
715
|
+
};
|
|
716
|
+
const STAGE_DOMAIN_SAMPLES = {
|
|
717
|
+
spec: [
|
|
718
|
+
{
|
|
719
|
+
domain: "web",
|
|
720
|
+
label: "AC",
|
|
721
|
+
body: "AC-W1: Given a signed-in admin viewing `/dashboard/orders`, when an order's status changes server-side, the row updates within 2s without a full navigation (assert via `pnpm playwright test orders-live.spec.ts`)."
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
domain: "cli",
|
|
725
|
+
label: "AC",
|
|
726
|
+
body: "AC-C1: Given `cclaw init --claude` run in an empty directory, exit code is `0`, `.cclaw/config.yaml` is created with `harnesses: [claude]`, and stderr contains no warnings (asserted by `tests/integration/init-sync-doctor.test.ts`)."
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
domain: "library",
|
|
730
|
+
label: "AC",
|
|
731
|
+
body: "AC-L1: `validateHookDocument(obj)` returns `{ ok: true }` for every fixture under `tests/fixtures/valid-hooks/` and `{ ok: false, errors: [...] }` with at least one message for every fixture under `tests/fixtures/invalid-hooks/`."
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
domain: "data-pipeline",
|
|
735
|
+
label: "AC",
|
|
736
|
+
body: "AC-D1: For any `orders.csv` input, the pipeline emits exactly one row per `(order_id, event_ts)` pair to `warehouse.fact_orders`; running the job twice on the same input is idempotent (row count unchanged, verified by `dbt test --select fact_orders`)."
|
|
737
|
+
}
|
|
738
|
+
],
|
|
739
|
+
plan: [
|
|
740
|
+
{
|
|
741
|
+
domain: "web",
|
|
742
|
+
label: "Task",
|
|
743
|
+
body: "T-W-3 `[~4m]`: Wire SSE endpoint `/api/orders/stream` into `useOrderFeed` hook. AC-W1. Verify: `pnpm playwright test orders-live.spec.ts`. Depends on: T-W-2."
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
domain: "cli",
|
|
747
|
+
label: "Task",
|
|
748
|
+
body: "T-C-2 `[~3m]`: Add `--dry-run` flag to `cclaw archive` that prints the would-be-archived run IDs to stdout and exits 0. AC-C3. Verify: `node dist/cli.js archive --dry-run` + `tests/unit/cli-parse.test.ts`."
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
domain: "library",
|
|
752
|
+
label: "Task",
|
|
753
|
+
body: "T-L-1 `[~5m]`: Expose `validateHookDocument` from the package root and re-export its types. AC-L1. Verify: `pnpm build && node -e \"console.log(require('./dist').validateHookDocument)\"`."
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
domain: "data-pipeline",
|
|
757
|
+
label: "Task",
|
|
758
|
+
body: "T-D-2 `[~5m]`: Add dedup step keyed on `(order_id, event_ts)` between `raw.orders` and `fact_orders`. AC-D1. Verify: `dbt run --select fact_orders+ && dbt test --select fact_orders`."
|
|
759
|
+
}
|
|
760
|
+
],
|
|
761
|
+
tdd: [
|
|
762
|
+
{
|
|
763
|
+
domain: "web",
|
|
764
|
+
label: "RED→GREEN→REFACTOR",
|
|
765
|
+
body: "RED: `pnpm playwright test orders-live.spec.ts` → timeout waiting for row update. GREEN: wired SSE event → row rerenders via `useOrderFeed`. REFACTOR: extracted `applyOrderEvent(row, event)` pure helper; 87/87 tests still pass."
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
domain: "cli",
|
|
769
|
+
label: "RED→GREEN→REFACTOR",
|
|
770
|
+
body: "RED: `tests/unit/cli-parse.test.ts` expects `--dry-run` flag → `unknown option` error. GREEN: added to the Zod parser; 19/19 pass. REFACTOR: hoisted the dry-run formatter into `src/cli/format.ts` shared with `status`."
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
domain: "library",
|
|
774
|
+
label: "RED→GREEN→REFACTOR",
|
|
775
|
+
body: "RED: `tests/unit/hook-schema.test.ts` imports `validateHookDocument` from package root → `export not found`. GREEN: added re-export + types. REFACTOR: renamed internal `__validate` to `validateHookDocument` so the export name matches the source."
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
domain: "data-pipeline",
|
|
779
|
+
label: "RED→GREEN→REFACTOR",
|
|
780
|
+
body: "RED: `dbt test --select fact_orders` → `unique test on (order_id, event_ts)` fails on re-run. GREEN: added `row_number()` dedup in the staging model. REFACTOR: extracted the dedup CTE into `int_orders_deduped` for reuse by `fact_returns`."
|
|
781
|
+
}
|
|
782
|
+
],
|
|
783
|
+
ship: [
|
|
784
|
+
{
|
|
785
|
+
domain: "web",
|
|
786
|
+
label: "Rollback",
|
|
787
|
+
body: "Trigger: error rate on `/api/orders/stream` > 2% for 5 minutes, or p95 latency > 1.5s for 10 minutes. Steps: `vercel rollback <deployment>`; run `2026_04_14_revert_orders_stream.sql` before traffic returns. Verify: error rate returns to baseline within 10 minutes on the `orders-live` dashboard."
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
domain: "cli",
|
|
791
|
+
label: "Rollback",
|
|
792
|
+
body: "Trigger: `cclaw init --claude` exits non-zero on a fresh tmp dir, OR `cclaw doctor` regresses (FAIL count increases) on the smoke matrix. Steps: `npm unpublish cclaw-cli@<version>` (within the 72h window) or `npm deprecate cclaw-cli@<version> '<reason>'`; publish the previous patch. Verify: `npx cclaw-cli@latest --version` prints the previous version."
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
domain: "library",
|
|
796
|
+
label: "Rollback",
|
|
797
|
+
body: "Trigger: any consumer reports `validateHookDocument` no longer exported, OR the CI `dual-package-check` job fails. Steps: `npm deprecate cclaw-cli@<version> 'broken package export — use <prev>'`; publish the previous minor with a patch bump; emit changelog `## Rollback` entry. Verify: a smoke consumer project `pnpm add cclaw-cli@latest` imports cleanly."
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
domain: "data-pipeline",
|
|
801
|
+
label: "Rollback",
|
|
802
|
+
body: "Trigger: `dbt test --select fact_orders` fails on production run, OR downstream dashboard MAU count drops >10% week-over-week. Steps: disable the new model via `dbt_project.yml` + `dbt run --select state:modified` with the previous git SHA; rerun backfill `dagster asset materialize fact_orders --partition <yesterday>`. Verify: `fact_orders` row count within ±1% of the previous week's baseline."
|
|
803
|
+
}
|
|
804
|
+
]
|
|
805
|
+
};
|
|
806
|
+
export function stageDomainExamples(stage) {
|
|
807
|
+
const samples = STAGE_DOMAIN_SAMPLES[stage];
|
|
808
|
+
if (!samples || samples.length === 0)
|
|
809
|
+
return "";
|
|
810
|
+
const lines = [
|
|
811
|
+
"## Living Examples by Domain",
|
|
812
|
+
"",
|
|
813
|
+
"Use the row matching your project shape to calibrate voice, specificity, and command choice. The rows are deliberately terse — copy the **shape**, not the text.",
|
|
814
|
+
""
|
|
815
|
+
];
|
|
816
|
+
for (const sample of samples) {
|
|
817
|
+
lines.push(`**${DOMAIN_LABELS[sample.domain]} — ${sample.label}:** ${sample.body}`);
|
|
818
|
+
lines.push("");
|
|
819
|
+
}
|
|
820
|
+
return lines.join("\n");
|
|
821
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-harness tool-mapping reference files.
|
|
3
|
+
*
|
|
4
|
+
* Addresses A.1#4: the four supported harnesses (claude, cursor, opencode, codex)
|
|
5
|
+
* expose different primitive names for the same capabilities (ask-user,
|
|
6
|
+
* delegate/Task, web fetch, file edit, code execution, ...). cclaw's stage skills
|
|
7
|
+
* need to pick the right name at runtime without bloating every stage with per-harness
|
|
8
|
+
* if/else ladders.
|
|
9
|
+
*
|
|
10
|
+
* Each file below is short (one table per capability), authoritative, and materialised
|
|
11
|
+
* at `.cclaw/references/harness-tools/<harness>.md`. Stage skills and the meta-skill
|
|
12
|
+
* cite the folder instead of duplicating the mappings inline.
|
|
13
|
+
*
|
|
14
|
+
* When a new harness is added (or an existing one renames a tool), update the
|
|
15
|
+
* corresponding entry here — do NOT scatter tool names across skill text.
|
|
16
|
+
*/
|
|
17
|
+
import type { HarnessId } from "../types.js";
|
|
18
|
+
export declare const HARNESS_TOOL_REFS_DIR = "references/harness-tools";
|
|
19
|
+
export declare function harnessToolRefMarkdown(harness: HarnessId): string;
|
|
20
|
+
export declare const HARNESS_TOOL_REFS_INDEX_MD = "---\nname: Harness tool maps\ndescription: \"Index file. One reference per supported harness \u2014 cite the per-harness file instead of hardcoding tool names in stage skills.\"\n---\n\n# Harness Tool Maps\n\ncclaw supports four harnesses; each exposes different primitive names for the same capabilities. Stage skills and utility skills cite the file matching the currently active harness and fall back to plain-text equivalents for capabilities that the harness lacks.\n\n| Harness | File | Notes |\n|---|---|---|\n| Claude Code | `.cclaw/references/harness-tools/claude.md` | Richest tool surface (AskUserQuestion, Task, WebFetch, WebSearch, MCP, \u2026). |\n| Cursor | `.cclaw/references/harness-tools/cursor.md` | Near-parity with Claude; uses `AskQuestion` instead of `AskUserQuestion`. |\n| OpenCode | `.cclaw/references/harness-tools/opencode.md` | No native ask-user / dispatch; more plain-text fallbacks. |\n| Codex | `.cclaw/references/harness-tools/codex.md` | No native ask-user / dispatch; shell + file I/O only by default. |\n\nWhen a new harness is added or an existing one renames a tool, update the corresponding file (and this index) \u2014 do NOT scatter tool names across skill text.\n";
|