sqlew 4.0.5 → 4.1.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/CHANGELOG.md +1805 -1782
- package/README.md +409 -468
- package/assets/claude-md-snippets/plan-mode-integration.md +17 -6
- package/assets/config.example.toml +282 -284
- package/assets/sample-agents/README.md +36 -40
- package/assets/sample-agents/sqlew-architect.md +321 -322
- package/assets/sample-agents/sqlew-researcher.md +292 -293
- package/assets/sample-agents/sqlew-scrum-master.md +286 -287
- package/assets/sample-commands/README.md +56 -57
- package/assets/sample-skills/sqlew-plan-guidance/SKILL.md +33 -26
- package/dist/cli/hooks/check-completion.d.ts +19 -0
- package/dist/cli/hooks/check-completion.d.ts.map +1 -0
- package/dist/cli/hooks/check-completion.js +104 -0
- package/dist/cli/hooks/check-completion.js.map +1 -0
- package/dist/cli/hooks/init-hooks.d.ts +35 -0
- package/dist/cli/hooks/init-hooks.d.ts.map +1 -0
- package/dist/cli/hooks/init-hooks.js +425 -0
- package/dist/cli/hooks/init-hooks.js.map +1 -0
- package/dist/cli/hooks/mark-done.d.ts +25 -0
- package/dist/cli/hooks/mark-done.d.ts.map +1 -0
- package/dist/cli/hooks/mark-done.js +128 -0
- package/dist/cli/hooks/mark-done.js.map +1 -0
- package/dist/cli/hooks/plan-id-utils.d.ts +83 -0
- package/dist/cli/hooks/plan-id-utils.d.ts.map +1 -0
- package/dist/cli/hooks/plan-id-utils.js +183 -0
- package/dist/cli/hooks/plan-id-utils.js.map +1 -0
- package/dist/cli/hooks/save.d.ts +23 -0
- package/dist/cli/hooks/save.d.ts.map +1 -0
- package/dist/cli/hooks/save.js +90 -0
- package/dist/cli/hooks/save.js.map +1 -0
- package/dist/cli/hooks/stdin-parser.d.ts +139 -0
- package/dist/cli/hooks/stdin-parser.d.ts.map +1 -0
- package/dist/cli/hooks/stdin-parser.js +127 -0
- package/dist/cli/hooks/stdin-parser.js.map +1 -0
- package/dist/cli/hooks/suggest.d.ts +19 -0
- package/dist/cli/hooks/suggest.d.ts.map +1 -0
- package/dist/cli/hooks/suggest.js +157 -0
- package/dist/cli/hooks/suggest.js.map +1 -0
- package/dist/cli/hooks/track-plan.d.ts +36 -0
- package/dist/cli/hooks/track-plan.d.ts.map +1 -0
- package/dist/cli/hooks/track-plan.js +152 -0
- package/dist/cli/hooks/track-plan.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +56 -16
- package/dist/cli.js.map +1 -1
- package/dist/config/global-config.d.ts +187 -0
- package/dist/config/global-config.d.ts.map +1 -0
- package/dist/config/global-config.js +206 -0
- package/dist/config/global-config.js.map +1 -0
- package/dist/config/loader.d.ts +42 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +96 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/constants.d.ts +4 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +10 -0
- package/dist/constants.js.map +1 -1
- package/dist/database/operations/queries.d.ts.map +1 -1
- package/dist/database/operations/queries.js +11 -2
- package/dist/database/operations/queries.js.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/init-agents.js +0 -1
- package/dist/init-agents.js.map +1 -1
- package/dist/init-skills.d.ts +4 -3
- package/dist/init-skills.d.ts.map +1 -1
- package/dist/init-skills.js +10 -3
- package/dist/init-skills.js.map +1 -1
- package/dist/server/setup.d.ts +8 -0
- package/dist/server/setup.d.ts.map +1 -1
- package/dist/server/setup.js +141 -21
- package/dist/server/setup.js.map +1 -1
- package/dist/sync-agents.d.ts.map +1 -1
- package/dist/sync-agents.js +48 -3
- package/dist/sync-agents.js.map +1 -1
- package/dist/sync-commands.d.ts.map +1 -1
- package/dist/sync-commands.js +43 -3
- package/dist/sync-commands.js.map +1 -1
- package/dist/tools/constraints/actions/get.d.ts.map +1 -1
- package/dist/tools/constraints/actions/get.js +5 -8
- package/dist/tools/constraints/actions/get.js.map +1 -1
- package/dist/tools/constraints/help/help.d.ts.map +1 -1
- package/dist/tools/constraints/help/help.js +1 -6
- package/dist/tools/constraints/help/help.js.map +1 -1
- package/dist/tools/context/actions/get.d.ts.map +1 -1
- package/dist/tools/context/actions/get.js.map +1 -1
- package/dist/tools/context/actions/search-layer.d.ts.map +1 -1
- package/dist/tools/context/actions/search-layer.js +5 -3
- package/dist/tools/context/actions/search-layer.js.map +1 -1
- package/dist/tools/context/actions/set-from-policy.d.ts +2 -1
- package/dist/tools/context/actions/set-from-policy.d.ts.map +1 -1
- package/dist/tools/context/actions/set-from-policy.js.map +1 -1
- package/dist/tools/context/help/help.d.ts.map +1 -1
- package/dist/tools/context/help/help.js +1 -7
- package/dist/tools/context/help/help.js.map +1 -1
- package/dist/tools/context/internal/queries.d.ts.map +1 -1
- package/dist/tools/context/internal/queries.js +5 -2
- package/dist/tools/context/internal/queries.js.map +1 -1
- package/dist/tools/context/types.d.ts +1 -1
- package/dist/tools/context/types.d.ts.map +1 -1
- package/dist/tools/files/actions/get.d.ts.map +1 -1
- package/dist/tools/files/actions/get.js +4 -6
- package/dist/tools/files/actions/get.js.map +1 -1
- package/dist/tools/files/help/help.d.ts.map +1 -1
- package/dist/tools/files/help/help.js +1 -6
- package/dist/tools/files/help/help.js.map +1 -1
- package/dist/tools/suggest/help/constraint-help.d.ts.map +1 -1
- package/dist/tools/suggest/help/constraint-help.js +0 -2
- package/dist/tools/suggest/help/constraint-help.js.map +1 -1
- package/dist/tools/suggest/internal/constraint-queries.d.ts.map +1 -1
- package/dist/tools/suggest/internal/constraint-queries.js +12 -5
- package/dist/tools/suggest/internal/constraint-queries.js.map +1 -1
- package/dist/tools/suggest/internal/queries.js +2 -2
- package/dist/tools/suggest/internal/queries.js.map +1 -1
- package/dist/tools/tasks/help/help.d.ts.map +1 -1
- package/dist/tools/tasks/help/help.js +0 -6
- package/dist/tools/tasks/help/help.js.map +1 -1
- package/dist/tools/tasks/help/use-case.d.ts.map +1 -1
- package/dist/tools/tasks/help/use-case.js +0 -1
- package/dist/tools/tasks/help/use-case.js.map +1 -1
- package/dist/tools/tasks/watcher/status.d.ts.map +1 -1
- package/dist/tools/tasks/watcher/status.js +5 -1
- package/dist/tools/tasks/watcher/status.js.map +1 -1
- package/dist/types/decision/params.d.ts +7 -6
- package/dist/types/decision/params.d.ts.map +1 -1
- package/dist/types/decision/templates.d.ts +3 -2
- package/dist/types/decision/templates.d.ts.map +1 -1
- package/dist/types/view-entities.d.ts +2 -1
- package/dist/types/view-entities.d.ts.map +1 -1
- package/dist/types.d.ts +19 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/enum-converter.d.ts +72 -0
- package/dist/utils/enum-converter.d.ts.map +1 -0
- package/dist/utils/enum-converter.js +76 -0
- package/dist/utils/enum-converter.js.map +1 -0
- package/dist/utils/hook-queue.d.ts +81 -0
- package/dist/utils/hook-queue.d.ts.map +1 -0
- package/dist/utils/hook-queue.js +156 -0
- package/dist/utils/hook-queue.js.map +1 -0
- package/dist/utils/project-root.d.ts +9 -2
- package/dist/utils/project-root.d.ts.map +1 -1
- package/dist/utils/project-root.js +16 -2
- package/dist/utils/project-root.js.map +1 -1
- package/dist/utils/tag-parser.d.ts.map +1 -1
- package/dist/utils/tag-parser.js +6 -0
- package/dist/utils/tag-parser.js.map +1 -1
- package/dist/utils/validators.d.ts +1 -1
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/utils/validators.js +1 -1
- package/dist/utils/validators.js.map +1 -1
- package/dist/utils/vcs-adapter.d.ts +44 -0
- package/dist/utils/vcs-adapter.d.ts.map +1 -1
- package/dist/utils/vcs-adapter.js +88 -0
- package/dist/utils/vcs-adapter.js.map +1 -1
- package/dist/utils/view-queries.d.ts.map +1 -1
- package/dist/utils/view-queries.js +9 -19
- package/dist/utils/view-queries.js.map +1 -1
- package/dist/watcher/base-watcher.d.ts +69 -0
- package/dist/watcher/base-watcher.d.ts.map +1 -0
- package/dist/watcher/base-watcher.js +130 -0
- package/dist/watcher/base-watcher.js.map +1 -0
- package/dist/watcher/index.d.ts +3 -0
- package/dist/watcher/index.d.ts.map +1 -1
- package/dist/watcher/index.js +2 -0
- package/dist/watcher/index.js.map +1 -1
- package/dist/watcher/queue-watcher.d.ts +64 -0
- package/dist/watcher/queue-watcher.d.ts.map +1 -0
- package/dist/watcher/queue-watcher.js +187 -0
- package/dist/watcher/queue-watcher.js.map +1 -0
- package/docs/ADR_CONCEPTS.md +140 -0
- package/docs/CONFIGURATION.md +922 -925
- package/docs/CROSS_DATABASE.md +153 -0
- package/docs/DATABASE_AUTH.md +70 -356
- package/docs/HOOKS_GUIDE.md +159 -0
- package/docs/SLASH_COMMANDS.md +329 -337
- package/docs/TASK_SYSTEM_DEPRECATED.md +88 -0
- package/docs/changelogs/CHANGELOG_ARCHIVE_v3.4_and_older.md +293 -296
- package/docs/cli/DATA_EXPORT_IMPORT.md +699 -700
- package/docs/cli/README.md +276 -277
- package/package.json +123 -124
- package/docs/ACCEPTANCE_CRITERIA.md +0 -625
- package/docs/AI_AGENT_GUIDE.md +0 -299
- package/docs/ARCHITECTURE.md +0 -167
- package/docs/AUTO_FILE_TRACKING.md +0 -841
- package/docs/BATCH_VALIDATION.md +0 -617
- package/docs/BEST_PRACTICES.md +0 -168
- package/docs/CONSTRAINT_INTELLIGENCE.md +0 -339
- package/docs/DECISION_CONTEXT.md +0 -697
- package/docs/DECISION_INTELLIGENCE.md +0 -605
- package/docs/GIT_AWARE_AUTO_COMPLETE.md +0 -646
- package/docs/MIGRATION_GUIDE_V3.9.0.md +0 -371
- package/docs/SHARED_CONCEPTS.md +0 -225
- package/docs/SPECIALIZED_AGENTS.md +0 -126
- package/docs/TASK_ACTIONS.md +0 -1177
- package/docs/TASK_OVERVIEW.md +0 -452
- package/docs/TASK_PRUNING.md +0 -594
- package/docs/TOOL_REFERENCE.md +0 -1077
- package/docs/TOOL_SELECTION.md +0 -83
- package/docs/WORKFLOWS.md +0 -941
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan ID utilities for YAML frontmatter manipulation
|
|
3
|
+
*
|
|
4
|
+
* Handles reading and writing sqlew-plan-id in markdown files.
|
|
5
|
+
* Uses YAML frontmatter format (--- delimited section at top of file).
|
|
6
|
+
*
|
|
7
|
+
* @since v4.1.0
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Parsed frontmatter data
|
|
11
|
+
*/
|
|
12
|
+
export interface Frontmatter {
|
|
13
|
+
/** Raw frontmatter content (between --- delimiters) */
|
|
14
|
+
raw: string;
|
|
15
|
+
/** Parsed key-value pairs */
|
|
16
|
+
data: Record<string, string>;
|
|
17
|
+
/** Content after frontmatter */
|
|
18
|
+
content: string;
|
|
19
|
+
/** Whether the file had frontmatter */
|
|
20
|
+
hasFrontmatter: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parse YAML frontmatter from markdown content
|
|
24
|
+
*
|
|
25
|
+
* @param content - Full file content
|
|
26
|
+
* @returns Parsed frontmatter and content
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseFrontmatter(content: string): Frontmatter;
|
|
29
|
+
/**
|
|
30
|
+
* Serialize frontmatter data back to string
|
|
31
|
+
*
|
|
32
|
+
* @param data - Key-value pairs to serialize
|
|
33
|
+
* @returns YAML frontmatter string (without delimiters)
|
|
34
|
+
*/
|
|
35
|
+
export declare function serializeFrontmatter(data: Record<string, string>): string;
|
|
36
|
+
/**
|
|
37
|
+
* Build file content with frontmatter
|
|
38
|
+
*
|
|
39
|
+
* @param data - Frontmatter key-value pairs
|
|
40
|
+
* @param content - Main content after frontmatter
|
|
41
|
+
* @returns Complete file content
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildFileWithFrontmatter(data: Record<string, string>, content: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Get plan ID from a markdown file
|
|
46
|
+
*
|
|
47
|
+
* @param filePath - Path to markdown file
|
|
48
|
+
* @returns Plan ID or null if not found
|
|
49
|
+
*/
|
|
50
|
+
export declare function getPlanId(filePath: string): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* Set or add plan ID to a markdown file
|
|
53
|
+
*
|
|
54
|
+
* If the file has no frontmatter, adds one.
|
|
55
|
+
* If the file has frontmatter without plan ID, adds the ID.
|
|
56
|
+
* If the file already has a plan ID, does nothing.
|
|
57
|
+
*
|
|
58
|
+
* @param filePath - Path to markdown file
|
|
59
|
+
* @param planId - Plan ID to set (generates UUID if not provided)
|
|
60
|
+
* @returns The plan ID that was set or already existed
|
|
61
|
+
*/
|
|
62
|
+
export declare function ensurePlanId(filePath: string, planId?: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Check if a file has a plan ID
|
|
65
|
+
*
|
|
66
|
+
* @param filePath - Path to markdown file
|
|
67
|
+
* @returns true if file has a plan ID
|
|
68
|
+
*/
|
|
69
|
+
export declare function hasPlanId(filePath: string): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Generate a new plan ID (UUID v4)
|
|
72
|
+
*
|
|
73
|
+
* @returns New UUID
|
|
74
|
+
*/
|
|
75
|
+
export declare function generatePlanId(): string;
|
|
76
|
+
/**
|
|
77
|
+
* Extract plan file name from a full path
|
|
78
|
+
*
|
|
79
|
+
* @param filePath - Full path to plan file
|
|
80
|
+
* @returns File name only (e.g., "rippling-spinning-eagle.md")
|
|
81
|
+
*/
|
|
82
|
+
export declare function extractPlanFileName(filePath: string): string;
|
|
83
|
+
//# sourceMappingURL=plan-id-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-id-utils.d.ts","sourceRoot":"","sources":["../../../src/cli/hooks/plan-id-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAmBH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,cAAc,EAAE,OAAO,CAAC;CACzB;AAMD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAwD7D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAIzE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAG9F;AAMD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYzD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CA6BtE;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI5D"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan ID utilities for YAML frontmatter manipulation
|
|
3
|
+
*
|
|
4
|
+
* Handles reading and writing sqlew-plan-id in markdown files.
|
|
5
|
+
* Uses YAML frontmatter format (--- delimited section at top of file).
|
|
6
|
+
*
|
|
7
|
+
* @since v4.1.0
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
10
|
+
import { randomUUID } from 'crypto';
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Constants
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/** YAML frontmatter delimiter */
|
|
15
|
+
const FRONTMATTER_DELIMITER = '---';
|
|
16
|
+
/** Key for plan ID in frontmatter */
|
|
17
|
+
const PLAN_ID_KEY = 'sqlew-plan-id';
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Parsing
|
|
20
|
+
// ============================================================================
|
|
21
|
+
/**
|
|
22
|
+
* Parse YAML frontmatter from markdown content
|
|
23
|
+
*
|
|
24
|
+
* @param content - Full file content
|
|
25
|
+
* @returns Parsed frontmatter and content
|
|
26
|
+
*/
|
|
27
|
+
export function parseFrontmatter(content) {
|
|
28
|
+
const lines = content.split('\n');
|
|
29
|
+
// Check if file starts with ---
|
|
30
|
+
if (lines[0]?.trim() !== FRONTMATTER_DELIMITER) {
|
|
31
|
+
return {
|
|
32
|
+
raw: '',
|
|
33
|
+
data: {},
|
|
34
|
+
content,
|
|
35
|
+
hasFrontmatter: false,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// Find closing ---
|
|
39
|
+
let endIndex = -1;
|
|
40
|
+
for (let i = 1; i < lines.length; i++) {
|
|
41
|
+
if (lines[i]?.trim() === FRONTMATTER_DELIMITER) {
|
|
42
|
+
endIndex = i;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (endIndex === -1) {
|
|
47
|
+
// No closing delimiter - treat as no frontmatter
|
|
48
|
+
return {
|
|
49
|
+
raw: '',
|
|
50
|
+
data: {},
|
|
51
|
+
content,
|
|
52
|
+
hasFrontmatter: false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// Extract frontmatter content
|
|
56
|
+
const frontmatterLines = lines.slice(1, endIndex);
|
|
57
|
+
const raw = frontmatterLines.join('\n');
|
|
58
|
+
const data = {};
|
|
59
|
+
// Parse simple key: value pairs
|
|
60
|
+
for (const line of frontmatterLines) {
|
|
61
|
+
const match = line.match(/^([^:]+):\s*(.*)$/);
|
|
62
|
+
if (match) {
|
|
63
|
+
const key = match[1].trim();
|
|
64
|
+
const value = match[2].trim();
|
|
65
|
+
data[key] = value;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Extract content after frontmatter
|
|
69
|
+
const restContent = lines.slice(endIndex + 1).join('\n');
|
|
70
|
+
return {
|
|
71
|
+
raw,
|
|
72
|
+
data,
|
|
73
|
+
content: restContent,
|
|
74
|
+
hasFrontmatter: true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Serialize frontmatter data back to string
|
|
79
|
+
*
|
|
80
|
+
* @param data - Key-value pairs to serialize
|
|
81
|
+
* @returns YAML frontmatter string (without delimiters)
|
|
82
|
+
*/
|
|
83
|
+
export function serializeFrontmatter(data) {
|
|
84
|
+
return Object.entries(data)
|
|
85
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
86
|
+
.join('\n');
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Build file content with frontmatter
|
|
90
|
+
*
|
|
91
|
+
* @param data - Frontmatter key-value pairs
|
|
92
|
+
* @param content - Main content after frontmatter
|
|
93
|
+
* @returns Complete file content
|
|
94
|
+
*/
|
|
95
|
+
export function buildFileWithFrontmatter(data, content) {
|
|
96
|
+
const frontmatter = serializeFrontmatter(data);
|
|
97
|
+
return `${FRONTMATTER_DELIMITER}\n${frontmatter}\n${FRONTMATTER_DELIMITER}\n${content}`;
|
|
98
|
+
}
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// Plan ID Operations
|
|
101
|
+
// ============================================================================
|
|
102
|
+
/**
|
|
103
|
+
* Get plan ID from a markdown file
|
|
104
|
+
*
|
|
105
|
+
* @param filePath - Path to markdown file
|
|
106
|
+
* @returns Plan ID or null if not found
|
|
107
|
+
*/
|
|
108
|
+
export function getPlanId(filePath) {
|
|
109
|
+
if (!existsSync(filePath)) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
114
|
+
const frontmatter = parseFrontmatter(content);
|
|
115
|
+
return frontmatter.data[PLAN_ID_KEY] || null;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Set or add plan ID to a markdown file
|
|
123
|
+
*
|
|
124
|
+
* If the file has no frontmatter, adds one.
|
|
125
|
+
* If the file has frontmatter without plan ID, adds the ID.
|
|
126
|
+
* If the file already has a plan ID, does nothing.
|
|
127
|
+
*
|
|
128
|
+
* @param filePath - Path to markdown file
|
|
129
|
+
* @param planId - Plan ID to set (generates UUID if not provided)
|
|
130
|
+
* @returns The plan ID that was set or already existed
|
|
131
|
+
*/
|
|
132
|
+
export function ensurePlanId(filePath, planId) {
|
|
133
|
+
if (!existsSync(filePath)) {
|
|
134
|
+
throw new Error(`File not found: ${filePath}`);
|
|
135
|
+
}
|
|
136
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
137
|
+
const frontmatter = parseFrontmatter(content);
|
|
138
|
+
// If already has plan ID, return it
|
|
139
|
+
if (frontmatter.data[PLAN_ID_KEY]) {
|
|
140
|
+
return frontmatter.data[PLAN_ID_KEY];
|
|
141
|
+
}
|
|
142
|
+
// Generate new ID if not provided
|
|
143
|
+
const newPlanId = planId || randomUUID();
|
|
144
|
+
// Add plan ID to frontmatter data
|
|
145
|
+
const newData = {
|
|
146
|
+
[PLAN_ID_KEY]: newPlanId,
|
|
147
|
+
...frontmatter.data,
|
|
148
|
+
};
|
|
149
|
+
// Build new file content
|
|
150
|
+
const newContent = buildFileWithFrontmatter(newData, frontmatter.content);
|
|
151
|
+
// Write back to file
|
|
152
|
+
writeFileSync(filePath, newContent, 'utf-8');
|
|
153
|
+
return newPlanId;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if a file has a plan ID
|
|
157
|
+
*
|
|
158
|
+
* @param filePath - Path to markdown file
|
|
159
|
+
* @returns true if file has a plan ID
|
|
160
|
+
*/
|
|
161
|
+
export function hasPlanId(filePath) {
|
|
162
|
+
return getPlanId(filePath) !== null;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Generate a new plan ID (UUID v4)
|
|
166
|
+
*
|
|
167
|
+
* @returns New UUID
|
|
168
|
+
*/
|
|
169
|
+
export function generatePlanId() {
|
|
170
|
+
return randomUUID();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Extract plan file name from a full path
|
|
174
|
+
*
|
|
175
|
+
* @param filePath - Full path to plan file
|
|
176
|
+
* @returns File name only (e.g., "rippling-spinning-eagle.md")
|
|
177
|
+
*/
|
|
178
|
+
export function extractPlanFileName(filePath) {
|
|
179
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
180
|
+
const parts = normalizedPath.split('/');
|
|
181
|
+
return parts[parts.length - 1] || '';
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=plan-id-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-id-utils.js","sourceRoot":"","sources":["../../../src/cli/hooks/plan-id-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Save Hook Command
|
|
3
|
+
*
|
|
4
|
+
* PostToolUse hook for ExitPlanMode - enqueues decision status update.
|
|
5
|
+
* When plan mode exits, enqueues update from draft to in_progress.
|
|
6
|
+
* Actual DB operations happen when MCP server processes the queue.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* echo '{"tool_name": "ExitPlanMode"}' | sqlew save
|
|
10
|
+
*
|
|
11
|
+
* @since v4.1.0
|
|
12
|
+
* @updated v4.1.0 - Changed trigger from Edit|Write to ExitPlanMode only (zero delay on code edits)
|
|
13
|
+
* @updated v4.1.0 - File queue architecture (no DB operations in hooks)
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Main save command entry point
|
|
17
|
+
*
|
|
18
|
+
* Called as PostToolUse hook when ExitPlanMode completes.
|
|
19
|
+
* Enqueues decision status update if a plan is being tracked.
|
|
20
|
+
* No DB operations - fast execution (<100ms).
|
|
21
|
+
*/
|
|
22
|
+
export declare function saveCommand(): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=save.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../../../src/cli/hooks/save.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAoBH;;;;;;GAMG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA+DjD"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Save Hook Command
|
|
3
|
+
*
|
|
4
|
+
* PostToolUse hook for ExitPlanMode - enqueues decision status update.
|
|
5
|
+
* When plan mode exits, enqueues update from draft to in_progress.
|
|
6
|
+
* Actual DB operations happen when MCP server processes the queue.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* echo '{"tool_name": "ExitPlanMode"}' | sqlew save
|
|
10
|
+
*
|
|
11
|
+
* @since v4.1.0
|
|
12
|
+
* @updated v4.1.0 - Changed trigger from Edit|Write to ExitPlanMode only (zero delay on code edits)
|
|
13
|
+
* @updated v4.1.0 - File queue architecture (no DB operations in hooks)
|
|
14
|
+
*/
|
|
15
|
+
import { readStdinJson, sendContinue, getProjectPath } from './stdin-parser.js';
|
|
16
|
+
import { loadCurrentPlan, saveCurrentPlan } from '../../config/global-config.js';
|
|
17
|
+
import { enqueueDecisionUpdate } from '../../utils/hook-queue.js';
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Constants
|
|
20
|
+
// ============================================================================
|
|
21
|
+
/** Decision key prefix for plan-based decisions */
|
|
22
|
+
const PLAN_DECISION_PREFIX = 'plan/implementation';
|
|
23
|
+
/** Status for in-progress decisions */
|
|
24
|
+
const IN_PROGRESS_STATUS = 'in_progress';
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Main Entry Point
|
|
27
|
+
// ============================================================================
|
|
28
|
+
/**
|
|
29
|
+
* Main save command entry point
|
|
30
|
+
*
|
|
31
|
+
* Called as PostToolUse hook when ExitPlanMode completes.
|
|
32
|
+
* Enqueues decision status update if a plan is being tracked.
|
|
33
|
+
* No DB operations - fast execution (<100ms).
|
|
34
|
+
*/
|
|
35
|
+
export async function saveCommand() {
|
|
36
|
+
try {
|
|
37
|
+
const input = await readStdinJson();
|
|
38
|
+
// Only process ExitPlanMode tool
|
|
39
|
+
const toolName = input.tool_name;
|
|
40
|
+
if (toolName !== 'ExitPlanMode') {
|
|
41
|
+
sendContinue();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const projectPath = getProjectPath(input);
|
|
45
|
+
if (!projectPath) {
|
|
46
|
+
sendContinue();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Check if there's a current plan being tracked
|
|
50
|
+
const planInfo = loadCurrentPlan(projectPath);
|
|
51
|
+
if (!planInfo) {
|
|
52
|
+
// No plan being tracked - continue without action
|
|
53
|
+
sendContinue();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Check if already recorded for this plan
|
|
57
|
+
if (planInfo.recorded) {
|
|
58
|
+
// Already recorded - no need to record again
|
|
59
|
+
sendContinue();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Build decision key from plan file name
|
|
63
|
+
const planName = planInfo.plan_file.replace(/\.md$/, '');
|
|
64
|
+
const decisionKey = `${PLAN_DECISION_PREFIX}/${planName}`;
|
|
65
|
+
// Enqueue status update (no DB operations here)
|
|
66
|
+
enqueueDecisionUpdate(projectPath, {
|
|
67
|
+
key: decisionKey,
|
|
68
|
+
value: `Implementation in progress for plan: ${planInfo.plan_file}`,
|
|
69
|
+
status: IN_PROGRESS_STATUS,
|
|
70
|
+
layer: 'cross-cutting',
|
|
71
|
+
tags: ['plan', 'implementation', 'active', planInfo.plan_id.slice(0, 8)],
|
|
72
|
+
});
|
|
73
|
+
// Mark plan as recorded
|
|
74
|
+
const updatedInfo = {
|
|
75
|
+
...planInfo,
|
|
76
|
+
recorded: true,
|
|
77
|
+
decision_pending: false,
|
|
78
|
+
plan_updated_at: new Date().toISOString(),
|
|
79
|
+
};
|
|
80
|
+
saveCurrentPlan(projectPath, updatedInfo);
|
|
81
|
+
sendContinue(`[sqlew] Queued decision update for plan: ${planInfo.plan_file} (will process on MCP startup)`);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
// On error, log to stderr but continue execution
|
|
85
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
86
|
+
console.error(`[sqlew save] Error: ${message}`);
|
|
87
|
+
sendContinue();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=save.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save.js","sourceRoot":"","sources":["../../../src/cli/hooks/save.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAwB,MAAM,+BAA+B,CAAC;AACvG,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,mDAAmD;AACnD,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAEnD,uCAAuC;AACvC,MAAM,kBAAkB,GAAG,aAAsB,CAAC;AAElD,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;QAEpC,iCAAiC;QACjC,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC;QACjC,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;YAChC,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,gDAAgD;QAChD,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,kDAAkD;YAClD,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,0CAA0C;QAC1C,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACtB,6CAA6C;YAC7C,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,yCAAyC;QACzC,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACzD,MAAM,WAAW,GAAG,GAAG,oBAAoB,IAAI,QAAQ,EAAE,CAAC;QAE1D,gDAAgD;QAChD,qBAAqB,CAAC,WAAW,EAAE;YACjC,GAAG,EAAE,WAAW;YAChB,KAAK,EAAE,wCAAwC,QAAQ,CAAC,SAAS,EAAE;YACnE,MAAM,EAAE,kBAAkB;YAC1B,KAAK,EAAE,eAAe;YACtB,IAAI,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SACzE,CAAC,CAAC;QAEH,wBAAwB;QACxB,MAAM,WAAW,GAAoB;YACnC,GAAG,QAAQ;YACX,QAAQ,EAAE,IAAI;YACd,gBAAgB,EAAE,KAAK;YACvB,eAAe,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAC1C,CAAC;QACF,eAAe,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAE1C,YAAY,CACV,4CAA4C,QAAQ,CAAC,SAAS,gCAAgC,CAC/F,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,iDAAiD;QACjD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAC;QAChD,YAAY,EAAE,CAAC;IACjB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Hooks stdin parser
|
|
3
|
+
*
|
|
4
|
+
* Parses JSON input from Claude Code Hooks.
|
|
5
|
+
* Hooks receive data via stdin in JSON format.
|
|
6
|
+
*
|
|
7
|
+
* @since v4.1.0
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Tool input for various Claude Code tools
|
|
11
|
+
*/
|
|
12
|
+
export interface ToolInput {
|
|
13
|
+
/** File path (Edit, Write tools) */
|
|
14
|
+
file_path?: string;
|
|
15
|
+
/** Command (Bash tool) */
|
|
16
|
+
command?: string;
|
|
17
|
+
/** Description (Task tool) */
|
|
18
|
+
description?: string;
|
|
19
|
+
/** Prompt (Task tool) */
|
|
20
|
+
prompt?: string;
|
|
21
|
+
/** Subagent type (Task tool) */
|
|
22
|
+
subagent_type?: string;
|
|
23
|
+
/** Todos (TodoWrite tool) */
|
|
24
|
+
todos?: TodoItem[];
|
|
25
|
+
/** Generic key-value pairs */
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Todo item from TodoWrite tool
|
|
30
|
+
*/
|
|
31
|
+
export interface TodoItem {
|
|
32
|
+
/** Todo content */
|
|
33
|
+
content: string;
|
|
34
|
+
/** Todo status: pending, in_progress, completed */
|
|
35
|
+
status: 'pending' | 'in_progress' | 'completed';
|
|
36
|
+
/** Active form description */
|
|
37
|
+
activeForm: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Tool response from PostToolUse
|
|
41
|
+
*/
|
|
42
|
+
export interface ToolResponse {
|
|
43
|
+
/** Whether the tool completed successfully */
|
|
44
|
+
completed?: boolean;
|
|
45
|
+
/** Summary of what was done */
|
|
46
|
+
summary?: string;
|
|
47
|
+
/** Output content */
|
|
48
|
+
output?: string;
|
|
49
|
+
/** Generic key-value pairs */
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Hook input from Claude Code
|
|
54
|
+
*/
|
|
55
|
+
export interface HookInput {
|
|
56
|
+
/** Session ID (changes on resume) */
|
|
57
|
+
session_id?: string;
|
|
58
|
+
/** Current working directory */
|
|
59
|
+
cwd?: string;
|
|
60
|
+
/** Hook event name */
|
|
61
|
+
hook_event_name?: 'PreToolUse' | 'PostToolUse' | 'SessionStart' | 'SessionEnd' | 'Stop' | 'SubagentStop';
|
|
62
|
+
/** Tool name being called */
|
|
63
|
+
tool_name?: string;
|
|
64
|
+
/** Tool input parameters */
|
|
65
|
+
tool_input?: ToolInput;
|
|
66
|
+
/** Tool response (PostToolUse only) */
|
|
67
|
+
tool_response?: ToolResponse;
|
|
68
|
+
/** Transcript path */
|
|
69
|
+
transcript_path?: string;
|
|
70
|
+
/** Permission mode */
|
|
71
|
+
permission_mode?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Hook output to Claude Code
|
|
75
|
+
*/
|
|
76
|
+
export interface HookOutput {
|
|
77
|
+
/** Whether to continue execution */
|
|
78
|
+
continue?: boolean;
|
|
79
|
+
/** Reason for stopping (if continue=false) */
|
|
80
|
+
stopReason?: string;
|
|
81
|
+
/** Additional context to inject */
|
|
82
|
+
additionalContext?: string;
|
|
83
|
+
/** System message to add */
|
|
84
|
+
systemMessage?: string;
|
|
85
|
+
/** Whether to suppress output */
|
|
86
|
+
suppressOutput?: boolean;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Read and parse JSON from stdin
|
|
90
|
+
*
|
|
91
|
+
* Claude Code Hooks send data via stdin in JSON format.
|
|
92
|
+
* This function reads all stdin and parses it as JSON.
|
|
93
|
+
*
|
|
94
|
+
* @returns Parsed hook input
|
|
95
|
+
* @throws Error if stdin is empty or invalid JSON
|
|
96
|
+
*/
|
|
97
|
+
export declare function readStdinJson(): Promise<HookInput>;
|
|
98
|
+
/**
|
|
99
|
+
* Write hook output to stdout
|
|
100
|
+
*
|
|
101
|
+
* @param output - Hook output to send
|
|
102
|
+
*/
|
|
103
|
+
export declare function writeHookOutput(output: HookOutput): void;
|
|
104
|
+
/**
|
|
105
|
+
* Send a continue response
|
|
106
|
+
*
|
|
107
|
+
* @param additionalContext - Optional context to inject
|
|
108
|
+
* @param systemMessage - Optional system message
|
|
109
|
+
*/
|
|
110
|
+
export declare function sendContinue(additionalContext?: string, systemMessage?: string): void;
|
|
111
|
+
/**
|
|
112
|
+
* Send a block response (exit code 2)
|
|
113
|
+
*
|
|
114
|
+
* @param reason - Reason for blocking
|
|
115
|
+
*/
|
|
116
|
+
export declare function sendBlock(reason: string): void;
|
|
117
|
+
/**
|
|
118
|
+
* Check if the hook input is for a plan file
|
|
119
|
+
*
|
|
120
|
+
* @param input - Hook input
|
|
121
|
+
* @returns true if the tool is operating on a plan file
|
|
122
|
+
*/
|
|
123
|
+
export declare function isPlanFile(input: HookInput): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Check if all todos are completed
|
|
126
|
+
*
|
|
127
|
+
* @param input - Hook input
|
|
128
|
+
* @returns true if all todos have status "completed"
|
|
129
|
+
*/
|
|
130
|
+
export declare function areAllTodosCompleted(input: HookInput): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Get project path from hook input
|
|
133
|
+
* Uses cwd from input or falls back to CLAUDE_PROJECT_DIR
|
|
134
|
+
*
|
|
135
|
+
* @param input - Hook input
|
|
136
|
+
* @returns Project path or undefined
|
|
137
|
+
*/
|
|
138
|
+
export declare function getProjectPath(input: HookInput): string | undefined;
|
|
139
|
+
//# sourceMappingURL=stdin-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdin-parser.d.ts","sourceRoot":"","sources":["../../../src/cli/hooks/stdin-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,8BAA8B;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;IAChD,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,qCAAqC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,eAAe,CAAC,EAAE,YAAY,GAAG,aAAa,GAAG,cAAc,GAAG,YAAY,GAAG,MAAM,GAAG,cAAc,CAAC;IACzG,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,uCAAuC;IACvC,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,sBAAsB;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sBAAsB;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4BAA4B;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAMD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,SAAS,CAAC,CAoCxD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAExD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CASrF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAG9C;AAMD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CASpD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAO9D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAEnE"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Hooks stdin parser
|
|
3
|
+
*
|
|
4
|
+
* Parses JSON input from Claude Code Hooks.
|
|
5
|
+
* Hooks receive data via stdin in JSON format.
|
|
6
|
+
*
|
|
7
|
+
* @since v4.1.0
|
|
8
|
+
*/
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Parsing
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Read and parse JSON from stdin
|
|
14
|
+
*
|
|
15
|
+
* Claude Code Hooks send data via stdin in JSON format.
|
|
16
|
+
* This function reads all stdin and parses it as JSON.
|
|
17
|
+
*
|
|
18
|
+
* @returns Parsed hook input
|
|
19
|
+
* @throws Error if stdin is empty or invalid JSON
|
|
20
|
+
*/
|
|
21
|
+
export async function readStdinJson() {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
let data = '';
|
|
24
|
+
// Set encoding for text input
|
|
25
|
+
process.stdin.setEncoding('utf8');
|
|
26
|
+
// Read all data from stdin
|
|
27
|
+
process.stdin.on('data', (chunk) => {
|
|
28
|
+
data += chunk;
|
|
29
|
+
});
|
|
30
|
+
// Parse when stdin closes
|
|
31
|
+
process.stdin.on('end', () => {
|
|
32
|
+
if (!data.trim()) {
|
|
33
|
+
// Empty stdin - return empty object
|
|
34
|
+
resolve({});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const parsed = JSON.parse(data);
|
|
39
|
+
resolve(parsed);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
reject(new Error(`Invalid JSON input: ${error instanceof Error ? error.message : String(error)}`));
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
// Handle errors
|
|
46
|
+
process.stdin.on('error', (error) => {
|
|
47
|
+
reject(new Error(`Failed to read stdin: ${error.message}`));
|
|
48
|
+
});
|
|
49
|
+
// Resume stdin (it might be paused)
|
|
50
|
+
process.stdin.resume();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Write hook output to stdout
|
|
55
|
+
*
|
|
56
|
+
* @param output - Hook output to send
|
|
57
|
+
*/
|
|
58
|
+
export function writeHookOutput(output) {
|
|
59
|
+
console.log(JSON.stringify(output));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Send a continue response
|
|
63
|
+
*
|
|
64
|
+
* @param additionalContext - Optional context to inject
|
|
65
|
+
* @param systemMessage - Optional system message
|
|
66
|
+
*/
|
|
67
|
+
export function sendContinue(additionalContext, systemMessage) {
|
|
68
|
+
const output = { continue: true };
|
|
69
|
+
if (additionalContext) {
|
|
70
|
+
output.additionalContext = additionalContext;
|
|
71
|
+
}
|
|
72
|
+
if (systemMessage) {
|
|
73
|
+
output.systemMessage = systemMessage;
|
|
74
|
+
}
|
|
75
|
+
writeHookOutput(output);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Send a block response (exit code 2)
|
|
79
|
+
*
|
|
80
|
+
* @param reason - Reason for blocking
|
|
81
|
+
*/
|
|
82
|
+
export function sendBlock(reason) {
|
|
83
|
+
console.error(reason);
|
|
84
|
+
process.exit(2);
|
|
85
|
+
}
|
|
86
|
+
// ============================================================================
|
|
87
|
+
// Helpers
|
|
88
|
+
// ============================================================================
|
|
89
|
+
/**
|
|
90
|
+
* Check if the hook input is for a plan file
|
|
91
|
+
*
|
|
92
|
+
* @param input - Hook input
|
|
93
|
+
* @returns true if the tool is operating on a plan file
|
|
94
|
+
*/
|
|
95
|
+
export function isPlanFile(input) {
|
|
96
|
+
const filePath = input.tool_input?.file_path;
|
|
97
|
+
if (!filePath) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
// Check if the path matches .claude/plans/*.md pattern
|
|
101
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
102
|
+
return /\.claude\/plans\/[^/]+\.md$/.test(normalizedPath);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if all todos are completed
|
|
106
|
+
*
|
|
107
|
+
* @param input - Hook input
|
|
108
|
+
* @returns true if all todos have status "completed"
|
|
109
|
+
*/
|
|
110
|
+
export function areAllTodosCompleted(input) {
|
|
111
|
+
const todos = input.tool_input?.todos;
|
|
112
|
+
if (!todos || !Array.isArray(todos) || todos.length === 0) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return todos.every((todo) => todo.status === 'completed');
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get project path from hook input
|
|
119
|
+
* Uses cwd from input or falls back to CLAUDE_PROJECT_DIR
|
|
120
|
+
*
|
|
121
|
+
* @param input - Hook input
|
|
122
|
+
* @returns Project path or undefined
|
|
123
|
+
*/
|
|
124
|
+
export function getProjectPath(input) {
|
|
125
|
+
return input.cwd || process.env.CLAUDE_PROJECT_DIR;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=stdin-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdin-parser.js","sourceRoot":"","sources":["../../../src/cli/hooks/stdin-parser.ts"],"names":[],"mappings":"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"}
|