planflow-ai 1.3.5 → 1.4.3

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.
Files changed (123) hide show
  1. package/.claude/commands/brainstorm.md +6 -14
  2. package/.claude/commands/create-contract.md +6 -38
  3. package/.claude/commands/create-plan.md +18 -38
  4. package/.claude/commands/discovery-plan.md +19 -49
  5. package/.claude/commands/execute-plan.md +116 -77
  6. package/.claude/commands/flow.md +27 -2
  7. package/.claude/commands/heartbeat.md +12 -14
  8. package/.claude/commands/learn.md +20 -80
  9. package/.claude/commands/note.md +6 -23
  10. package/.claude/commands/resume-work.md +261 -0
  11. package/.claude/commands/review-code.md +19 -51
  12. package/.claude/commands/review-pr.md +21 -57
  13. package/.claude/commands/setup.md +8 -56
  14. package/.claude/commands/write-tests.md +7 -41
  15. package/.claude/resources/core/atomic-commits.md +380 -0
  16. package/.claude/resources/core/autopilot-mode.md +3 -2
  17. package/.claude/resources/core/compaction-guide.md +15 -1
  18. package/.claude/resources/core/heartbeat.md +129 -1
  19. package/.claude/resources/core/per-task-verification.md +362 -0
  20. package/.claude/resources/core/phase-isolation.md +237 -4
  21. package/.claude/resources/core/session-scratchpad.md +1 -0
  22. package/.claude/resources/core/shared-context.md +110 -0
  23. package/.claude/resources/core/wave-execution.md +407 -0
  24. package/.claude/resources/patterns/plans-patterns.md +56 -0
  25. package/.claude/resources/patterns/plans-templates.md +152 -0
  26. package/.claude/resources/skills/create-plan-skill.md +71 -5
  27. package/.claude/resources/skills/execute-plan-skill.md +420 -14
  28. package/.claude/resources/skills/resume-work-skill.md +159 -0
  29. package/README.md +154 -96
  30. package/dist/cli/commands/brain.d.ts +20 -0
  31. package/dist/cli/commands/brain.d.ts.map +1 -0
  32. package/dist/cli/commands/brain.js +127 -0
  33. package/dist/cli/commands/brain.js.map +1 -0
  34. package/dist/cli/commands/init.d.ts.map +1 -1
  35. package/dist/cli/commands/init.js +10 -1
  36. package/dist/cli/commands/init.js.map +1 -1
  37. package/dist/cli/commands/state-query.d.ts +13 -0
  38. package/dist/cli/commands/state-query.d.ts.map +1 -0
  39. package/dist/cli/commands/state-query.js +32 -0
  40. package/dist/cli/commands/state-query.js.map +1 -0
  41. package/dist/cli/commands/state.d.ts +12 -0
  42. package/dist/cli/commands/state.d.ts.map +1 -0
  43. package/dist/cli/commands/state.js +47 -0
  44. package/dist/cli/commands/state.js.map +1 -0
  45. package/dist/cli/daemon/desktop-notifier.d.ts +16 -0
  46. package/dist/cli/daemon/desktop-notifier.d.ts.map +1 -0
  47. package/dist/cli/daemon/desktop-notifier.js +53 -0
  48. package/dist/cli/daemon/desktop-notifier.js.map +1 -0
  49. package/dist/cli/daemon/event-writer.d.ts +22 -0
  50. package/dist/cli/daemon/event-writer.d.ts.map +1 -0
  51. package/dist/cli/daemon/event-writer.js +76 -0
  52. package/dist/cli/daemon/event-writer.js.map +1 -0
  53. package/dist/cli/daemon/heartbeat-daemon.js +81 -1
  54. package/dist/cli/daemon/heartbeat-daemon.js.map +1 -1
  55. package/dist/cli/daemon/log-writer.d.ts +17 -0
  56. package/dist/cli/daemon/log-writer.d.ts.map +1 -0
  57. package/dist/cli/daemon/log-writer.js +62 -0
  58. package/dist/cli/daemon/log-writer.js.map +1 -0
  59. package/dist/cli/daemon/notification-router.d.ts +17 -0
  60. package/dist/cli/daemon/notification-router.d.ts.map +1 -0
  61. package/dist/cli/daemon/notification-router.js +35 -0
  62. package/dist/cli/daemon/notification-router.js.map +1 -0
  63. package/dist/cli/daemon/prompt-manager.d.ts +27 -0
  64. package/dist/cli/daemon/prompt-manager.d.ts.map +1 -0
  65. package/dist/cli/daemon/prompt-manager.js +107 -0
  66. package/dist/cli/daemon/prompt-manager.js.map +1 -0
  67. package/dist/cli/daemon/shared-context.d.ts +38 -0
  68. package/dist/cli/daemon/shared-context.d.ts.map +1 -0
  69. package/dist/cli/daemon/shared-context.js +129 -0
  70. package/dist/cli/daemon/shared-context.js.map +1 -0
  71. package/dist/cli/handlers/claude.d.ts.map +1 -1
  72. package/dist/cli/handlers/claude.js +18 -0
  73. package/dist/cli/handlers/claude.js.map +1 -1
  74. package/dist/cli/handlers/shared.js +1 -1
  75. package/dist/cli/handlers/shared.js.map +1 -1
  76. package/dist/cli/index.js +30 -0
  77. package/dist/cli/index.js.map +1 -1
  78. package/dist/cli/state/brain-query.d.ts +48 -0
  79. package/dist/cli/state/brain-query.d.ts.map +1 -0
  80. package/dist/cli/state/brain-query.js +113 -0
  81. package/dist/cli/state/brain-query.js.map +1 -0
  82. package/dist/cli/state/flowconfig-parser.d.ts +16 -0
  83. package/dist/cli/state/flowconfig-parser.d.ts.map +1 -0
  84. package/dist/cli/state/flowconfig-parser.js +166 -0
  85. package/dist/cli/state/flowconfig-parser.js.map +1 -0
  86. package/dist/cli/state/heartbeat-state.d.ts +16 -0
  87. package/dist/cli/state/heartbeat-state.d.ts.map +1 -0
  88. package/dist/cli/state/heartbeat-state.js +97 -0
  89. package/dist/cli/state/heartbeat-state.js.map +1 -0
  90. package/dist/cli/state/model-router.d.ts +8 -0
  91. package/dist/cli/state/model-router.d.ts.map +1 -0
  92. package/dist/cli/state/model-router.js +36 -0
  93. package/dist/cli/state/model-router.js.map +1 -0
  94. package/dist/cli/state/plan-parser.d.ts +16 -0
  95. package/dist/cli/state/plan-parser.d.ts.map +1 -0
  96. package/dist/cli/state/plan-parser.js +124 -0
  97. package/dist/cli/state/plan-parser.js.map +1 -0
  98. package/dist/cli/state/session-state.d.ts +21 -0
  99. package/dist/cli/state/session-state.d.ts.map +1 -0
  100. package/dist/cli/state/session-state.js +36 -0
  101. package/dist/cli/state/session-state.js.map +1 -0
  102. package/dist/cli/state/state-md-parser.d.ts +18 -0
  103. package/dist/cli/state/state-md-parser.d.ts.map +1 -0
  104. package/dist/cli/state/state-md-parser.js +222 -0
  105. package/dist/cli/state/state-md-parser.js.map +1 -0
  106. package/dist/cli/state/types.d.ts +137 -0
  107. package/dist/cli/state/types.d.ts.map +1 -0
  108. package/dist/cli/state/types.js +8 -0
  109. package/dist/cli/state/types.js.map +1 -0
  110. package/dist/cli/state/wave-calculator.d.ts +18 -0
  111. package/dist/cli/state/wave-calculator.d.ts.map +1 -0
  112. package/dist/cli/state/wave-calculator.js +134 -0
  113. package/dist/cli/state/wave-calculator.js.map +1 -0
  114. package/dist/cli/types.d.ts +15 -0
  115. package/dist/cli/types.d.ts.map +1 -1
  116. package/package.json +7 -2
  117. package/templates/shared/CLAUDE.md.template +4 -0
  118. package/.claude/resources/core/_index.md +0 -304
  119. package/.claude/resources/languages/_index.md +0 -76
  120. package/.claude/resources/patterns/_index.md +0 -200
  121. package/.claude/resources/skills/_index.md +0 -285
  122. package/.claude/resources/tools/_index.md +0 -110
  123. package/.claude/resources/tools/reference-expansion-tool.md +0 -326
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Flowconfig Parser
3
+ *
4
+ * Parses `flow/.flowconfig` YAML into a structured FlowConfig object.
5
+ * Uses regex-based line parsing consistent with the heartbeat daemon pattern.
6
+ * Provides legacy fallbacks for `.autopilot` and `.gitcontrol` files.
7
+ */
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ const DEFAULT_CONFIG = {
11
+ autopilot: false,
12
+ commit: false,
13
+ push: false,
14
+ pr: false,
15
+ branch: '',
16
+ wave_execution: true,
17
+ phase_isolation: true,
18
+ model_routing: false,
19
+ max_verify_retries: 2,
20
+ };
21
+ const MIN_VERIFY_RETRIES = 1;
22
+ const MAX_VERIFY_RETRIES = 5;
23
+ /**
24
+ * Extract a boolean value from flowconfig content by key name.
25
+ * Returns undefined if the key is not found.
26
+ */
27
+ function extractBoolean(content, key) {
28
+ const match = content.match(new RegExp(`^${key}:\\s*(true|false)`, 'm'));
29
+ if (!match)
30
+ return undefined;
31
+ return match[1] === 'true';
32
+ }
33
+ /**
34
+ * Extract a string value from flowconfig content by key name.
35
+ * Returns undefined if the key is not found.
36
+ */
37
+ function extractString(content, key) {
38
+ const match = content.match(new RegExp(`^${key}:\\s*(.+)`, 'm'));
39
+ if (!match)
40
+ return undefined;
41
+ return match[1].trim();
42
+ }
43
+ /**
44
+ * Extract a numeric value from flowconfig content by key name.
45
+ * Returns undefined if the key is not found.
46
+ */
47
+ function extractNumber(content, key) {
48
+ const match = content.match(new RegExp(`^${key}:\\s*(\\d+)`, 'm'));
49
+ if (!match)
50
+ return undefined;
51
+ return parseInt(match[1], 10);
52
+ }
53
+ /**
54
+ * Read legacy `.autopilot` file to determine autopilot setting.
55
+ * File existence means autopilot is enabled.
56
+ */
57
+ function readLegacyAutopilot(flowDir) {
58
+ return existsSync(join(flowDir, '.autopilot'));
59
+ }
60
+ /**
61
+ * Read legacy `.gitcontrol` file for commit/push/branch settings.
62
+ * Returns partial config values found in the file.
63
+ */
64
+ function readLegacyGitControl(flowDir) {
65
+ const gitControlPath = join(flowDir, '.gitcontrol');
66
+ if (!existsSync(gitControlPath))
67
+ return {};
68
+ try {
69
+ const content = readFileSync(gitControlPath, 'utf-8');
70
+ return {
71
+ commit: extractBoolean(content, 'commit'),
72
+ push: extractBoolean(content, 'push'),
73
+ branch: extractString(content, 'branch'),
74
+ };
75
+ }
76
+ catch {
77
+ return {};
78
+ }
79
+ }
80
+ /**
81
+ * Parse `flow/.flowconfig` into a structured FlowConfig object.
82
+ *
83
+ * Applies defaults for missing keys and falls back to legacy files
84
+ * (`.autopilot`, `.gitcontrol`) when keys are absent from `.flowconfig`.
85
+ */
86
+ export function parseFlowConfig(flowDir) {
87
+ const configPath = join(flowDir, '.flowconfig');
88
+ const config = { ...DEFAULT_CONFIG };
89
+ if (!existsSync(configPath)) {
90
+ // No .flowconfig — use legacy fallbacks + defaults
91
+ config.autopilot = readLegacyAutopilot(flowDir);
92
+ const legacy = readLegacyGitControl(flowDir);
93
+ if (legacy.commit !== undefined)
94
+ config.commit = legacy.commit;
95
+ if (legacy.push !== undefined)
96
+ config.push = legacy.push;
97
+ if (legacy.branch !== undefined)
98
+ config.branch = legacy.branch;
99
+ return config;
100
+ }
101
+ let content;
102
+ try {
103
+ content = readFileSync(configPath, 'utf-8');
104
+ }
105
+ catch {
106
+ return config;
107
+ }
108
+ // Parse boolean keys
109
+ const autopilot = extractBoolean(content, 'autopilot');
110
+ if (autopilot !== undefined) {
111
+ config.autopilot = autopilot;
112
+ }
113
+ else {
114
+ // Legacy fallback: check .autopilot file
115
+ config.autopilot = readLegacyAutopilot(flowDir);
116
+ }
117
+ const commit = extractBoolean(content, 'commit');
118
+ const push = extractBoolean(content, 'push');
119
+ const pr = extractBoolean(content, 'pr');
120
+ const branch = extractString(content, 'branch');
121
+ if (commit !== undefined) {
122
+ config.commit = commit;
123
+ }
124
+ if (push !== undefined) {
125
+ config.push = push;
126
+ }
127
+ if (pr !== undefined) {
128
+ config.pr = pr;
129
+ }
130
+ if (branch !== undefined) {
131
+ config.branch = branch;
132
+ }
133
+ // Legacy fallback for git keys not found in .flowconfig
134
+ if (commit === undefined || push === undefined || branch === undefined) {
135
+ const legacy = readLegacyGitControl(flowDir);
136
+ if (commit === undefined && legacy.commit !== undefined)
137
+ config.commit = legacy.commit;
138
+ if (push === undefined && legacy.push !== undefined)
139
+ config.push = legacy.push;
140
+ if (branch === undefined && legacy.branch !== undefined)
141
+ config.branch = legacy.branch;
142
+ }
143
+ const waveExecution = extractBoolean(content, 'wave_execution');
144
+ if (waveExecution !== undefined)
145
+ config.wave_execution = waveExecution;
146
+ const phaseIsolation = extractBoolean(content, 'phase_isolation');
147
+ if (phaseIsolation !== undefined)
148
+ config.phase_isolation = phaseIsolation;
149
+ const modelRouting = extractBoolean(content, 'model_routing');
150
+ if (modelRouting !== undefined)
151
+ config.model_routing = modelRouting;
152
+ const maxVerifyRetries = extractNumber(content, 'max_verify_retries');
153
+ if (maxVerifyRetries !== undefined) {
154
+ config.max_verify_retries = Math.max(MIN_VERIFY_RETRIES, Math.min(MAX_VERIFY_RETRIES, maxVerifyRetries));
155
+ }
156
+ // Validation cascade: pr → push → commit
157
+ if (config.pr) {
158
+ config.push = true;
159
+ config.commit = true;
160
+ }
161
+ else if (config.push) {
162
+ config.commit = true;
163
+ }
164
+ return config;
165
+ }
166
+ //# sourceMappingURL=flowconfig-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flowconfig-parser.js","sourceRoot":"","sources":["../../../src/cli/state/flowconfig-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Heartbeat state parser — reads heartbeat events and calculates unread count.
3
+ *
4
+ * Parses `.heartbeat-state.json` for the last read timestamp,
5
+ * `.heartbeat-events.jsonl` for event records, and checks
6
+ * `.heartbeat-prompt.md` for pending prompt status.
7
+ */
8
+ import type { HeartbeatSummary } from './types.js';
9
+ /**
10
+ * Get the heartbeat summary for a flow directory.
11
+ *
12
+ * Returns unread event count, pending prompt status, and last read timestamp.
13
+ * Handles all edge cases: missing files, empty files, corrupt JSON.
14
+ */
15
+ export declare function getHeartbeatSummary(flowDir: string): HeartbeatSummary;
16
+ //# sourceMappingURL=heartbeat-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat-state.d.ts","sourceRoot":"","sources":["../../../src/cli/state/heartbeat-state.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAkFnD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAcrE"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Heartbeat state parser — reads heartbeat events and calculates unread count.
3
+ *
4
+ * Parses `.heartbeat-state.json` for the last read timestamp,
5
+ * `.heartbeat-events.jsonl` for event records, and checks
6
+ * `.heartbeat-prompt.md` for pending prompt status.
7
+ */
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ const STATE_FILENAME = '.heartbeat-state.json';
11
+ const EVENTS_FILENAME = '.heartbeat-events.jsonl';
12
+ const PROMPT_FILENAME = '.heartbeat-prompt.md';
13
+ /**
14
+ * Read and parse the heartbeat state file.
15
+ * Returns null if the file is missing, empty, or contains corrupt JSON.
16
+ */
17
+ function readHeartbeatState(flowDir) {
18
+ const filePath = join(flowDir, STATE_FILENAME);
19
+ if (!existsSync(filePath)) {
20
+ return null;
21
+ }
22
+ try {
23
+ const content = readFileSync(filePath, 'utf-8').trim();
24
+ if (content.length === 0) {
25
+ return null;
26
+ }
27
+ const parsed = JSON.parse(content);
28
+ if (!parsed.lastReadTimestamp || typeof parsed.lastReadTimestamp !== 'string') {
29
+ return null;
30
+ }
31
+ return parsed;
32
+ }
33
+ catch {
34
+ // Corrupt JSON — treat as missing
35
+ return null;
36
+ }
37
+ }
38
+ /**
39
+ * Count unread events from the JSONL events file.
40
+ * An event is unread if its timestamp is after the lastReadTimestamp,
41
+ * or if lastReadTimestamp is null (all events are unread).
42
+ */
43
+ function countUnreadEvents(flowDir, lastReadTimestamp) {
44
+ const filePath = join(flowDir, EVENTS_FILENAME);
45
+ if (!existsSync(filePath)) {
46
+ return 0;
47
+ }
48
+ let content;
49
+ try {
50
+ content = readFileSync(filePath, 'utf-8');
51
+ }
52
+ catch {
53
+ return 0;
54
+ }
55
+ const lines = content.split('\n').filter((line) => line.trim().length > 0);
56
+ if (lines.length === 0) {
57
+ return 0;
58
+ }
59
+ // If no last read timestamp, all events are unread
60
+ if (lastReadTimestamp === null) {
61
+ return lines.length;
62
+ }
63
+ const lastReadDate = new Date(lastReadTimestamp);
64
+ let unreadCount = 0;
65
+ for (const line of lines) {
66
+ try {
67
+ const event = JSON.parse(line);
68
+ const eventDate = new Date(event.timestamp);
69
+ if (eventDate > lastReadDate) {
70
+ unreadCount++;
71
+ }
72
+ }
73
+ catch {
74
+ // Skip corrupt lines
75
+ }
76
+ }
77
+ return unreadCount;
78
+ }
79
+ /**
80
+ * Get the heartbeat summary for a flow directory.
81
+ *
82
+ * Returns unread event count, pending prompt status, and last read timestamp.
83
+ * Handles all edge cases: missing files, empty files, corrupt JSON.
84
+ */
85
+ export function getHeartbeatSummary(flowDir) {
86
+ const state = readHeartbeatState(flowDir);
87
+ const lastReadTimestamp = state?.lastReadTimestamp ?? null;
88
+ const unreadCount = countUnreadEvents(flowDir, lastReadTimestamp);
89
+ const promptPath = join(flowDir, PROMPT_FILENAME);
90
+ const hasPrompt = existsSync(promptPath);
91
+ return {
92
+ unread_count: unreadCount,
93
+ has_prompt: hasPrompt,
94
+ last_read_timestamp: lastReadTimestamp,
95
+ };
96
+ }
97
+ //# sourceMappingURL=heartbeat-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat-state.js","sourceRoot":"","sources":["../../../src/cli/state/heartbeat-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { PlanPhase, ModelTier } from './types.js';
2
+ /**
3
+ * Calculate model tiers for each plan phase based on complexity scores.
4
+ *
5
+ * Returns an empty array when model routing is disabled.
6
+ */
7
+ export declare function calculateModelTiers(phases: PlanPhase[], modelRoutingEnabled: boolean): ModelTier[];
8
+ //# sourceMappingURL=model-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-router.d.ts","sourceRoot":"","sources":["../../../src/cli/state/model-router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAC;AAmBvE;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EAAE,EACnB,mBAAmB,EAAE,OAAO,GAC3B,SAAS,EAAE,CAcb"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Map a complexity score to a model tier and model name.
3
+ *
4
+ * - 0-3 -> fast (haiku)
5
+ * - 4-5 -> standard (sonnet)
6
+ * - 6-10 -> powerful (opus)
7
+ */
8
+ function complexityToTier(complexity) {
9
+ if (complexity <= 3) {
10
+ return { tier: 'fast', model: 'haiku' };
11
+ }
12
+ if (complexity <= 5) {
13
+ return { tier: 'standard', model: 'sonnet' };
14
+ }
15
+ return { tier: 'powerful', model: 'opus' };
16
+ }
17
+ /**
18
+ * Calculate model tiers for each plan phase based on complexity scores.
19
+ *
20
+ * Returns an empty array when model routing is disabled.
21
+ */
22
+ export function calculateModelTiers(phases, modelRoutingEnabled) {
23
+ if (!modelRoutingEnabled) {
24
+ return [];
25
+ }
26
+ return phases.map((phase) => {
27
+ const { tier, model } = complexityToTier(phase.complexity);
28
+ return {
29
+ phase: phase.number,
30
+ complexity: phase.complexity,
31
+ tier,
32
+ model,
33
+ };
34
+ });
35
+ }
36
+ //# sourceMappingURL=model-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-router.js","sourceRoot":"","sources":["../../../src/cli/state/model-router.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,UAAkB;IAC1C,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAC1C,CAAC;IACD,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAC/C,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAmB,EACnB,mBAA4B;IAE5B,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC1B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC3D,OAAO;YACL,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,IAAI;YACJ,KAAK;SACN,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Plan markdown parser
3
+ *
4
+ * Parses plan files (flow/plans/plan_*.md) into structured PlanPhase objects.
5
+ * Extracts phase headers, complexity scores, dependencies, tasks, and verify tags.
6
+ */
7
+ import type { PlanPhase } from './types.js';
8
+ /**
9
+ * Parses a plan markdown file and returns an array of PlanPhase objects.
10
+ */
11
+ export declare function parsePlan(planPath: string): PlanPhase[];
12
+ /**
13
+ * Parses plan markdown content (for testability without file I/O).
14
+ */
15
+ export declare function parsePlanContent(content: string): PlanPhase[];
16
+ //# sourceMappingURL=plan-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-parser.d.ts","sourceRoot":"","sources":["../../../src/cli/state/plan-parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,YAAY,CAAC;AAWtD;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAGvD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAiG7D"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Plan markdown parser
3
+ *
4
+ * Parses plan files (flow/plans/plan_*.md) into structured PlanPhase objects.
5
+ * Extracts phase headers, complexity scores, dependencies, tasks, and verify tags.
6
+ */
7
+ import { readFileSync } from 'node:fs';
8
+ const PHASE_HEADER_RE = /^### Phase (\d+):\s*(.+)$/;
9
+ const COMPLEXITY_RE = /\*\*Complexity\*\*:\s*(\d+)\/10/;
10
+ const DEPENDENCIES_RE = /\*\*Dependencies\*\*:\s*(.+)/;
11
+ const TASK_RE = /^- \[[ x]\]\s+(.+)$/;
12
+ const VERIFY_RE = /<verify>(.+)<\/verify>/;
13
+ const PHASE_REF_RE = /Phase\s+(\d+)/gi;
14
+ const DEFAULT_COMPLEXITY = 5;
15
+ /**
16
+ * Parses a plan markdown file and returns an array of PlanPhase objects.
17
+ */
18
+ export function parsePlan(planPath) {
19
+ const content = readFileSync(planPath, 'utf-8');
20
+ return parsePlanContent(content);
21
+ }
22
+ /**
23
+ * Parses plan markdown content (for testability without file I/O).
24
+ */
25
+ export function parsePlanContent(content) {
26
+ const phases = [];
27
+ const lines = content.split('\n');
28
+ let currentPhase = null;
29
+ let lastTaskIndex = -1;
30
+ for (let i = 0; i < lines.length; i++) {
31
+ const line = lines[i];
32
+ const trimmed = line.trim();
33
+ // Phase header
34
+ const headerMatch = trimmed.match(PHASE_HEADER_RE);
35
+ if (headerMatch) {
36
+ // Save previous phase
37
+ if (currentPhase) {
38
+ phases.push(finalizePhase(currentPhase));
39
+ }
40
+ currentPhase = {
41
+ number: parseInt(headerMatch[1], 10),
42
+ name: headerMatch[2].trim(),
43
+ complexity: null,
44
+ dependencies: null,
45
+ tasks: [],
46
+ };
47
+ lastTaskIndex = -1;
48
+ continue;
49
+ }
50
+ if (!currentPhase)
51
+ continue;
52
+ // Complexity
53
+ const complexityMatch = trimmed.match(COMPLEXITY_RE);
54
+ if (complexityMatch) {
55
+ currentPhase.complexity = parseInt(complexityMatch[1], 10);
56
+ continue;
57
+ }
58
+ // Dependencies
59
+ const depsMatch = trimmed.match(DEPENDENCIES_RE);
60
+ if (depsMatch) {
61
+ const depsValue = depsMatch[1].trim();
62
+ if (/^none$/i.test(depsValue)) {
63
+ currentPhase.dependencies = [];
64
+ }
65
+ else {
66
+ const depNumbers = [];
67
+ let match;
68
+ // Reset regex state for each use
69
+ const phaseRefRe = /Phase\s+(\d+)/gi;
70
+ while ((match = phaseRefRe.exec(depsValue)) !== null) {
71
+ depNumbers.push(parseInt(match[1], 10));
72
+ }
73
+ currentPhase.dependencies = depNumbers.length > 0 ? depNumbers : [];
74
+ }
75
+ continue;
76
+ }
77
+ // Task line
78
+ const taskMatch = trimmed.match(TASK_RE);
79
+ if (taskMatch) {
80
+ const taskName = taskMatch[1].trim();
81
+ currentPhase.tasks.push({ index: currentPhase.tasks.length + 1, name: taskName, verify_command: null });
82
+ lastTaskIndex = currentPhase.tasks.length - 1;
83
+ continue;
84
+ }
85
+ // Verify tag (must follow a task line)
86
+ if (lastTaskIndex >= 0) {
87
+ const verifyMatch = trimmed.match(VERIFY_RE);
88
+ if (verifyMatch) {
89
+ currentPhase.tasks[lastTaskIndex].verify_command = verifyMatch[1].trim();
90
+ lastTaskIndex = -1;
91
+ continue;
92
+ }
93
+ // If non-empty, non-verify line after a task, reset lastTaskIndex
94
+ if (trimmed !== '') {
95
+ lastTaskIndex = -1;
96
+ }
97
+ }
98
+ }
99
+ // Save the last phase
100
+ if (currentPhase) {
101
+ phases.push(finalizePhase(currentPhase));
102
+ }
103
+ return phases;
104
+ }
105
+ function finalizePhase(phase) {
106
+ const complexity = phase.complexity ?? DEFAULT_COMPLEXITY;
107
+ // Dependencies: if explicitly set, use them; otherwise sequential fallback
108
+ let dependencies;
109
+ if (phase.dependencies !== null) {
110
+ dependencies = phase.dependencies;
111
+ }
112
+ else {
113
+ // Sequential fallback: depend on previous phase, Phase 1 has no deps
114
+ dependencies = phase.number > 1 ? [phase.number - 1] : [];
115
+ }
116
+ return {
117
+ number: phase.number,
118
+ name: phase.name,
119
+ complexity,
120
+ dependencies,
121
+ tasks: phase.tasks,
122
+ };
123
+ }
124
+ //# sourceMappingURL=plan-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-parser.js","sourceRoot":"","sources":["../../../src/cli/state/plan-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Session state checker — detects which session-start files exist
3
+ * in the flow directory, returning a structured SessionState object.
4
+ */
5
+ import type { SessionState } from './types.js';
6
+ /**
7
+ * Checks existence of all session-start files and returns structured state.
8
+ *
9
+ * Files checked:
10
+ * - ledger.md
11
+ * - brain/index.md
12
+ * - tasklist.md
13
+ * - memory.md
14
+ * - .scratchpad.md
15
+ * - .heartbeat-events.jsonl
16
+ * - .heartbeat-state.json
17
+ * - .heartbeat-prompt.md
18
+ * - STATE.md
19
+ */
20
+ export declare function getSessionState(flowDir: string): SessionState;
21
+ //# sourceMappingURL=session-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-state.d.ts","sourceRoot":"","sources":["../../../src/cli/state/session-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAc7D"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Session state checker — detects which session-start files exist
3
+ * in the flow directory, returning a structured SessionState object.
4
+ */
5
+ import { existsSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ /**
8
+ * Checks existence of all session-start files and returns structured state.
9
+ *
10
+ * Files checked:
11
+ * - ledger.md
12
+ * - brain/index.md
13
+ * - tasklist.md
14
+ * - memory.md
15
+ * - .scratchpad.md
16
+ * - .heartbeat-events.jsonl
17
+ * - .heartbeat-state.json
18
+ * - .heartbeat-prompt.md
19
+ * - STATE.md
20
+ */
21
+ export function getSessionState(flowDir) {
22
+ return {
23
+ files_present: {
24
+ ledger: existsSync(join(flowDir, 'ledger.md')),
25
+ brain_index: existsSync(join(flowDir, 'brain', 'index.md')),
26
+ tasklist: existsSync(join(flowDir, 'tasklist.md')),
27
+ memory: existsSync(join(flowDir, 'memory.md')),
28
+ scratchpad: existsSync(join(flowDir, '.scratchpad.md')),
29
+ heartbeat_events: existsSync(join(flowDir, '.heartbeat-events.jsonl')),
30
+ heartbeat_state: existsSync(join(flowDir, '.heartbeat-state.json')),
31
+ heartbeat_prompt: existsSync(join(flowDir, '.heartbeat-prompt.md')),
32
+ state_md: existsSync(join(flowDir, 'STATE.md')),
33
+ },
34
+ };
35
+ }
36
+ //# sourceMappingURL=session-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-state.js","sourceRoot":"","sources":["../../../src/cli/state/session-state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO;QACL,aAAa,EAAE;YACb,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAC9C,WAAW,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;YAC3D,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;YAClD,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAC9C,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;YACvD,gBAAgB,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;YACtE,eAAe,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;YACnE,gBAAgB,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;YACnE,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;SAChD;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * STATE.md Parser
3
+ *
4
+ * Parses `flow/STATE.md` into a structured ExecutionState object.
5
+ * Uses regex-based line parsing consistent with flowconfig-parser and plan-parser patterns.
6
+ * Returns null if STATE.md doesn't exist.
7
+ */
8
+ import type { ExecutionState } from './types.js';
9
+ /**
10
+ * Parse `flow/STATE.md` into a structured ExecutionState object.
11
+ * Returns null if STATE.md doesn't exist.
12
+ */
13
+ export declare function parseStateMd(flowDir: string): ExecutionState | null;
14
+ /**
15
+ * Parse STATE.md content string (for testability without file I/O).
16
+ */
17
+ export declare function parseStateMdContent(content: string): ExecutionState;
18
+ //# sourceMappingURL=state-md-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-md-parser.d.ts","sourceRoot":"","sources":["../../../src/cli/state/state-md-parser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAqC,cAAc,EAAE,MAAM,YAAY,CAAC;AASpF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAenE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAuEnE"}