cclaw-cli 0.5.4 → 0.5.5

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/doctor.js CHANGED
@@ -426,10 +426,7 @@ export async function doctorChecks(projectRoot, options = {}) {
426
426
  "stop-checkpoint.sh",
427
427
  "prompt-guard.sh",
428
428
  "workflow-guard.sh",
429
- "context-monitor.sh",
430
- "observe.sh",
431
- "summarize-observations.sh",
432
- "summarize-observations.mjs"
429
+ "context-monitor.sh"
433
430
  ]) {
434
431
  const scriptPath = path.join(projectRoot, RUNTIME_ROOT, "hooks", script);
435
432
  const scriptExists = await exists(scriptPath);
@@ -524,15 +521,12 @@ export async function doctorChecks(projectRoot, options = {}) {
524
521
  const wiringOk = sessionCommands.some((cmd) => cmd.includes("session-start.sh")) &&
525
522
  preCommands.some((cmd) => cmd.includes("prompt-guard.sh")) &&
526
523
  preCommands.some((cmd) => cmd.includes("workflow-guard.sh")) &&
527
- preCommands.some((cmd) => cmd.includes("observe.sh pre")) &&
528
- postCommands.some((cmd) => cmd.includes("observe.sh post")) &&
529
524
  postCommands.some((cmd) => cmd.includes("context-monitor.sh")) &&
530
- stopCommands.some((cmd) => cmd.includes("summarize-observations.sh")) &&
531
525
  stopCommands.some((cmd) => cmd.includes("stop-checkpoint.sh"));
532
526
  checks.push({
533
527
  name: "hook:wiring:claude",
534
528
  ok: wiringOk,
535
- details: `${file} must wire session-start/prompt-guard/workflow-guard/observe/context-monitor/summarize/stop-checkpoint`
529
+ details: `${file} must wire session-start/prompt-guard/workflow-guard/context-monitor/stop-checkpoint`
536
530
  });
537
531
  }
538
532
  if (configuredHarnesses.includes("cursor")) {
@@ -560,15 +554,12 @@ export async function doctorChecks(projectRoot, options = {}) {
560
554
  const wiringOk = sessionCommands.some((cmd) => cmd.includes("session-start.sh")) &&
561
555
  preCommands.some((cmd) => cmd.includes("prompt-guard.sh")) &&
562
556
  preCommands.some((cmd) => cmd.includes("workflow-guard.sh")) &&
563
- preCommands.some((cmd) => cmd.includes("observe.sh pre")) &&
564
- postCommands.some((cmd) => cmd.includes("observe.sh post")) &&
565
557
  postCommands.some((cmd) => cmd.includes("context-monitor.sh")) &&
566
- stopCommands.some((cmd) => cmd.includes("summarize-observations.sh")) &&
567
558
  stopCommands.some((cmd) => cmd.includes("stop-checkpoint.sh"));
568
559
  checks.push({
569
560
  name: "hook:wiring:cursor",
570
561
  ok: wiringOk,
571
- details: `${file} must wire session-start/prompt-guard/workflow-guard/observe/context-monitor/summarize/stop-checkpoint`
562
+ details: `${file} must wire session-start/prompt-guard/workflow-guard/context-monitor/stop-checkpoint`
572
563
  });
573
564
  const cursorRulePath = path.join(projectRoot, ".cursor/rules/cclaw-workflow.mdc");
574
565
  let cursorRuleOk = false;
@@ -603,15 +594,12 @@ export async function doctorChecks(projectRoot, options = {}) {
603
594
  const wiringOk = sessionCommands.some((cmd) => cmd.includes("session-start.sh")) &&
604
595
  preCommands.some((cmd) => cmd.includes("prompt-guard.sh")) &&
605
596
  preCommands.some((cmd) => cmd.includes("workflow-guard.sh")) &&
606
- preCommands.some((cmd) => cmd.includes("observe.sh pre")) &&
607
- postCommands.some((cmd) => cmd.includes("observe.sh post")) &&
608
597
  postCommands.some((cmd) => cmd.includes("context-monitor.sh")) &&
609
- stopCommands.some((cmd) => cmd.includes("summarize-observations.sh")) &&
610
598
  stopCommands.some((cmd) => cmd.includes("stop-checkpoint.sh"));
611
599
  checks.push({
612
600
  name: "hook:wiring:codex",
613
601
  ok: wiringOk,
614
- details: `${file} must wire session-start/prompt-guard/workflow-guard/observe/context-monitor/summarize/stop-checkpoint`
602
+ details: `${file} must wire session-start/prompt-guard/workflow-guard/context-monitor/stop-checkpoint`
615
603
  });
616
604
  }
617
605
  if (configuredHarnesses.includes("opencode")) {
@@ -627,7 +615,6 @@ export async function doctorChecks(projectRoot, options = {}) {
627
615
  content.includes("workflow-guard.sh") &&
628
616
  content.includes("context-monitor.sh") &&
629
617
  content.includes('"session.idle"') &&
630
- content.includes('"session.updated"') &&
631
618
  content.includes('"session.resumed"') &&
632
619
  content.includes('"session.cleared"') &&
633
620
  content.includes('"experimental.chat.system.transform"');
@@ -635,7 +622,7 @@ export async function doctorChecks(projectRoot, options = {}) {
635
622
  checks.push({
636
623
  name: "lifecycle:opencode:rehydration_events",
637
624
  ok,
638
- details: `${file} must include event lifecycle handler, tool.execute.before/after with prompt/workflow/context hooks, session.idle summarization, and transform rehydration`
625
+ details: `${file} must include event lifecycle handler, tool.execute.before/after with prompt/workflow/context hooks, session.idle checkpoint, and transform rehydration`
639
626
  });
640
627
  const runtimeShape = await opencodePluginRuntimeShapeCheck(projectRoot);
641
628
  checks.push({
@@ -679,11 +666,11 @@ export async function doctorChecks(projectRoot, options = {}) {
679
666
  ok: true,
680
667
  details: hasPython ? "python3 available" : "warning: python3 not found, jq/node paths must stay healthy"
681
668
  });
682
- // Learnings store exists
669
+ // Knowledge store exists
683
670
  checks.push({
684
- name: "learnings:store_exists",
685
- ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "learnings.jsonl")),
686
- details: `${RUNTIME_ROOT}/learnings.jsonl must exist (can be empty)`
671
+ name: "knowledge:store_exists",
672
+ ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "knowledge.md")),
673
+ details: `${RUNTIME_ROOT}/knowledge.md must exist`
687
674
  });
688
675
  checks.push({
689
676
  name: "state:checkpoint_exists",
@@ -751,38 +738,20 @@ export async function doctorChecks(projectRoot, options = {}) {
751
738
  });
752
739
  }
753
740
  const activeRunId = typeof flowState.activeRunId === "string" ? flowState.activeRunId.trim() : "";
754
- const runActivationDeferred = activeRunId === "run-pending";
755
741
  checks.push({
756
742
  name: "flow_state:active_run_id",
757
743
  ok: activeRunId.length > 0,
758
- details: `${RUNTIME_ROOT}/state/flow-state.json must include activeRunId (run-pending is allowed before first active run is materialized)`
744
+ details: `${RUNTIME_ROOT}/state/flow-state.json must include activeRunId`
759
745
  });
760
746
  checks.push({
761
- name: "run:active_artifacts",
762
- ok: runActivationDeferred
763
- ? true
764
- : await exists(path.join(projectRoot, RUNTIME_ROOT, "runs", activeRunId, "artifacts")),
765
- details: runActivationDeferred
766
- ? "active run artifacts are deferred until first feature run activation"
767
- : `${RUNTIME_ROOT}/runs/${activeRunId}/artifacts must exist`
747
+ name: "artifacts:active_root",
748
+ ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "artifacts")),
749
+ details: `${RUNTIME_ROOT}/artifacts must exist as the active artifact root`
768
750
  });
769
751
  checks.push({
770
- name: "run:active_metadata",
771
- ok: runActivationDeferred
772
- ? true
773
- : await exists(path.join(projectRoot, RUNTIME_ROOT, "runs", activeRunId, "run.json")),
774
- details: runActivationDeferred
775
- ? "active run metadata is deferred until first feature run activation"
776
- : `${RUNTIME_ROOT}/runs/${activeRunId}/run.json must exist`
777
- });
778
- checks.push({
779
- name: "run:active_handoff",
780
- ok: runActivationDeferred
781
- ? true
782
- : await exists(path.join(projectRoot, RUNTIME_ROOT, "runs", activeRunId, "handoff.md")),
783
- details: runActivationDeferred
784
- ? "active run handoff is deferred until first feature run activation"
785
- : `${RUNTIME_ROOT}/runs/${activeRunId}/handoff.md must exist`
752
+ name: "runs:archive_root",
753
+ ok: await exists(path.join(projectRoot, RUNTIME_ROOT, "runs")),
754
+ details: `${RUNTIME_ROOT}/runs must exist for archived feature snapshots`
786
755
  });
787
756
  const delegation = await checkMandatoryDelegations(projectRoot, flowState.currentStage);
788
757
  checks.push({
@@ -1,7 +1,7 @@
1
1
  import { COMMAND_FILE_ORDER } from "./constants.js";
2
2
  import { buildTransitionRules, orderedStageSchemas, stageGateIds } from "./content/stage-schema.js";
3
3
  export const TRANSITION_RULES = buildTransitionRules();
4
- export function createInitialFlowState(activeRunId = "run-pending") {
4
+ export function createInitialFlowState(activeRunId = "active") {
5
5
  const stageGateCatalog = {};
6
6
  for (const schema of orderedStageSchemas()) {
7
7
  stageGateCatalog[schema.stage] = {
@@ -37,7 +37,7 @@ Before responding to a coding request:
37
37
  |---|---|
38
38
  | \`/cc\` | **Entry point.** No args = resume current stage. With prompt = start brainstorm with idea. |
39
39
  | \`/cc-next\` | **Progression.** Advances to the next stage when current is complete. |
40
- | \`/cc-learn\` | **Cross-cutting.** Capture or review project learnings. |
40
+ | \`/cc-learn\` | **Cross-cutting.** Capture or review project knowledge. |
41
41
 
42
42
  **Stage order:** brainstorm > scope > design > spec > plan > tdd > review > ship.
43
43
  \`/cc-next\` loads the right stage skill automatically. Gates must pass before handoff.
package/dist/install.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import fs from "node:fs/promises";
3
- import os from "node:os";
4
3
  import path from "node:path";
5
4
  import { promisify } from "node:util";
6
5
  import { COMMAND_FILE_ORDER, REQUIRED_DIRS, RUNTIME_ROOT, UTILITY_COMMANDS } from "./constants.js";
@@ -13,7 +12,7 @@ import { startCommandContract, startCommandSkillMarkdown } from "./content/start
13
12
  import { subagentDrivenDevSkill, parallelAgentsSkill } from "./content/subagents.js";
14
13
  import { sessionHooksSkillMarkdown } from "./content/session-hooks.js";
15
14
  import { sessionStartScript, stopCheckpointScript, opencodePluginJs, claudeHooksJson, cursorHooksJson, codexHooksJson } from "./content/hooks.js";
16
- import { contextMonitorScript, observeScript, promptGuardScript, workflowGuardScript, summarizeObservationsRuntimeModule, summarizeObservationsScript } from "./content/observe.js";
15
+ import { contextMonitorScript, promptGuardScript, workflowGuardScript } from "./content/observe.js";
17
16
  import { META_SKILL_NAME, usingCclawSkillMarkdown } from "./content/meta-skill.js";
18
17
  import { ARTIFACT_TEMPLATES, CURSOR_WORKFLOW_RULE_MDC, RULEBOOK_MARKDOWN, buildRulesJson } from "./content/templates.js";
19
18
  import { stageSkillFolder, stageSkillMarkdown } from "./content/skills.js";
@@ -32,22 +31,6 @@ const execFileAsync = promisify(execFile);
32
31
  function runtimePath(projectRoot, ...segments) {
33
32
  return path.join(projectRoot, RUNTIME_ROOT, ...segments);
34
33
  }
35
- function resolveGlobalLearningsPath(projectRoot, config) {
36
- if (config.globalLearnings !== true) {
37
- return null;
38
- }
39
- const raw = config.globalLearningsPath?.trim() ?? "";
40
- if (raw.length === 0) {
41
- return path.join(os.homedir(), ".cclaw-global-learnings.jsonl");
42
- }
43
- if (raw.startsWith("~/")) {
44
- return path.join(os.homedir(), raw.slice(2));
45
- }
46
- if (path.isAbsolute(raw)) {
47
- return raw;
48
- }
49
- return path.join(projectRoot, raw);
50
- }
51
34
  async function resolveGitHooksDir(projectRoot) {
52
35
  try {
53
36
  const { stdout } = await execFileAsync("git", ["rev-parse", "--git-path", "hooks"], {
@@ -497,23 +480,14 @@ async function writeHooks(projectRoot, config) {
497
480
  const harnesses = config.harnesses;
498
481
  const hooksDir = runtimePath(projectRoot, "hooks");
499
482
  await ensureDir(hooksDir);
500
- await writeFileSafe(path.join(hooksDir, "session-start.sh"), sessionStartScript({
501
- globalLearningsEnabled: config.globalLearnings === true,
502
- globalLearningsPath: config.globalLearningsPath
503
- }));
483
+ await writeFileSafe(path.join(hooksDir, "session-start.sh"), sessionStartScript());
504
484
  await writeFileSafe(path.join(hooksDir, "stop-checkpoint.sh"), stopCheckpointScript());
505
485
  await writeFileSafe(path.join(hooksDir, "prompt-guard.sh"), promptGuardScript({
506
486
  strictMode: config.promptGuardMode === "strict"
507
487
  }));
508
488
  await writeFileSafe(path.join(hooksDir, "workflow-guard.sh"), workflowGuardScript());
509
489
  await writeFileSafe(path.join(hooksDir, "context-monitor.sh"), contextMonitorScript());
510
- await writeFileSafe(path.join(hooksDir, "observe.sh"), observeScript());
511
- await writeFileSafe(path.join(hooksDir, "summarize-observations.sh"), summarizeObservationsScript());
512
- await writeFileSafe(path.join(hooksDir, "summarize-observations.mjs"), summarizeObservationsRuntimeModule());
513
- const opencodePluginSource = opencodePluginJs({
514
- globalLearningsEnabled: config.globalLearnings === true,
515
- globalLearningsPath: config.globalLearningsPath
516
- });
490
+ const opencodePluginSource = opencodePluginJs();
517
491
  await writeFileSafe(path.join(hooksDir, "opencode-plugin.mjs"), opencodePluginSource);
518
492
  try {
519
493
  for (const script of [
@@ -522,9 +496,6 @@ async function writeHooks(projectRoot, config) {
522
496
  "prompt-guard.sh",
523
497
  "workflow-guard.sh",
524
498
  "context-monitor.sh",
525
- "observe.sh",
526
- "summarize-observations.sh",
527
- "summarize-observations.mjs",
528
499
  "opencode-plugin.mjs"
529
500
  ]) {
530
501
  await fs.chmod(path.join(hooksDir, script), 0o755);
@@ -565,20 +536,10 @@ async function writeHooks(projectRoot, config) {
565
536
  // OpenCode registration is auto-managed via opencode.json/opencode.jsonc.
566
537
  }
567
538
  }
568
- async function ensureLearningsStore(projectRoot) {
569
- const storePath = runtimePath(projectRoot, "learnings.jsonl");
539
+ async function ensureKnowledgeStore(projectRoot) {
540
+ const storePath = runtimePath(projectRoot, "knowledge.md");
570
541
  if (!(await exists(storePath))) {
571
- await writeFileSafe(storePath, "");
572
- }
573
- }
574
- async function ensureGlobalLearningsStore(projectRoot, config) {
575
- const globalPath = resolveGlobalLearningsPath(projectRoot, config);
576
- if (!globalPath) {
577
- return;
578
- }
579
- await ensureDir(path.dirname(globalPath));
580
- if (!(await exists(globalPath))) {
581
- await writeFileSafe(globalPath, "");
542
+ await writeFileSafe(storePath, "# Project Knowledge\n\n");
582
543
  }
583
544
  }
584
545
  async function ensureSessionStateFiles(projectRoot) {
@@ -723,6 +684,20 @@ async function cleanLegacyArtifacts(projectRoot) {
723
684
  // best-effort cleanup
724
685
  }
725
686
  }
687
+ for (const legacyRuntimeFile of [
688
+ runtimePath(projectRoot, "learnings.jsonl"),
689
+ runtimePath(projectRoot, "observations.jsonl"),
690
+ runtimePath(projectRoot, "hooks", "observe.sh"),
691
+ runtimePath(projectRoot, "hooks", "summarize-observations.sh"),
692
+ runtimePath(projectRoot, "hooks", "summarize-observations.mjs")
693
+ ]) {
694
+ try {
695
+ await fs.rm(legacyRuntimeFile, { force: true });
696
+ }
697
+ catch {
698
+ // best-effort cleanup
699
+ }
700
+ }
726
701
  }
727
702
  async function cleanStaleFiles(projectRoot) {
728
703
  const expectedShimFiles = new Set([
@@ -769,8 +744,7 @@ async function materializeRuntime(projectRoot, config, forceStateReset) {
769
744
  await ensureRunSystem(projectRoot, { createIfMissing: false });
770
745
  await ensureSessionStateFiles(projectRoot);
771
746
  await writeAdapterManifest(projectRoot, harnesses);
772
- await ensureLearningsStore(projectRoot);
773
- await ensureGlobalLearningsStore(projectRoot, config);
747
+ await ensureKnowledgeStore(projectRoot);
774
748
  await writeHooks(projectRoot, config);
775
749
  await syncDisabledHarnessArtifacts(projectRoot, harnesses);
776
750
  await syncManagedGitHooks(projectRoot, config);
@@ -854,7 +828,7 @@ function stripManagedHookCommands(value) {
854
828
  }
855
829
  function isManagedRuntimeHookCommand(command) {
856
830
  const normalized = command.trim().replace(/\s+/gu, " ");
857
- return /(^|\s)(?:bash\s+)?(?:\.\/)?\.cclaw\/hooks\/(?:session-start|stop-checkpoint|prompt-guard|workflow-guard|context-monitor|observe|summarize-observations)\.sh(?:\s|$)/u.test(normalized);
831
+ return /(^|\s)(?:bash\s+)?(?:\.\/)?\.cclaw\/hooks\/(?:session-start|stop-checkpoint|prompt-guard|workflow-guard|context-monitor)\.sh(?:\s|$)/u.test(normalized);
858
832
  }
859
833
  async function removeManagedHookEntries(hookFilePath) {
860
834
  if (!(await exists(hookFilePath)))
package/dist/policy.js CHANGED
@@ -85,9 +85,8 @@ export async function policyChecks(projectRoot, options = {}) {
85
85
  // --- utility skill checks ---
86
86
  const runtimeFile = (relativePath) => `${RUNTIME_ROOT}/${relativePath}`;
87
87
  const utilitySkillChecks = [
88
- { file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Learning Entry Schema", name: "utility_skill:learnings:schema" },
88
+ { file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Entry format (append-only)", name: "utility_skill:learnings:entry_format" },
89
89
  { file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Subcommands", name: "utility_skill:learnings:subcommands" },
90
- { file: runtimeFile("skills/learnings/SKILL.md"), needle: "## Confidence Decay", name: "utility_skill:learnings:decay" },
91
90
  { file: runtimeFile("skills/learnings/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:learnings:hard_gate" },
92
91
  { file: runtimeFile("commands/learn.md"), needle: "## Subcommands", name: "utility_command:learn:subcommands" },
93
92
  { file: runtimeFile("skills/subagent-dev/SKILL.md"), needle: "## HARD-GATE", name: "utility_skill:sdd:hard_gate" },
@@ -152,8 +151,6 @@ export async function policyChecks(projectRoot, options = {}) {
152
151
  { file: runtimeFile("hooks/workflow-guard.sh"), needle: "stage_invocation_without_recent_flow_read", name: "hooks:workflow_guard:flow_read_reason" },
153
152
  { file: runtimeFile("hooks/workflow-guard.sh"), needle: "stage_jump_", name: "hooks:workflow_guard:stage_jump_reason" },
154
153
  { file: runtimeFile("hooks/context-monitor.sh"), needle: "remaining is", name: "hooks:context:threshold_warning" },
155
- { file: runtimeFile("hooks/observe.sh"), needle: "stage-activity.jsonl", name: "hooks:observe:activity_write" },
156
- { file: runtimeFile("hooks/summarize-observations.mjs"), needle: "frequent-errors-", name: "hooks:summarize:runtime_module" },
157
154
  { file: runtimeFile("hooks/opencode-plugin.mjs"), needle: "activeRunId", name: "hooks:opencode:active_run" }
158
155
  ];
159
156
  if (activeHarnesses.has("opencode")) {
package/dist/runs.d.ts CHANGED
@@ -3,20 +3,20 @@ export interface CclawRunMeta {
3
3
  id: string;
4
4
  title: string;
5
5
  createdAt: string;
6
- archivedAt?: string;
7
- stateSnapshot?: Omit<FlowState, "activeRunId">;
6
+ }
7
+ export interface ArchiveRunResult {
8
+ archiveId: string;
9
+ archivePath: string;
10
+ archivedAt: string;
11
+ featureName: string;
12
+ resetState: FlowState;
8
13
  }
9
14
  interface EnsureRunSystemOptions {
10
15
  createIfMissing?: boolean;
11
16
  }
12
17
  export declare function readFlowState(projectRoot: string): Promise<FlowState>;
13
18
  export declare function writeFlowState(projectRoot: string, state: FlowState): Promise<void>;
19
+ export declare function ensureRunSystem(projectRoot: string, _options?: EnsureRunSystemOptions): Promise<FlowState>;
14
20
  export declare function listRuns(projectRoot: string): Promise<CclawRunMeta[]>;
15
- export declare function ensureRunSystem(projectRoot: string, options?: EnsureRunSystemOptions): Promise<FlowState>;
16
- export declare function startNewFeatureRun(projectRoot: string, title?: string): Promise<CclawRunMeta>;
17
- export declare function resumeRun(projectRoot: string, runId: string): Promise<CclawRunMeta>;
18
- export declare function archiveRun(projectRoot: string, runId?: string): Promise<{
19
- archived: CclawRunMeta;
20
- active: CclawRunMeta;
21
- }>;
21
+ export declare function archiveRun(projectRoot: string, featureName?: string): Promise<ArchiveRunResult>;
22
22
  export {};