@eddacraft/anvil-aps 0.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.
Files changed (121) hide show
  1. package/AGENTS.md +155 -0
  2. package/LICENSE +14 -0
  3. package/README.md +57 -0
  4. package/TODO.md +40 -0
  5. package/dist/filter/context-bundle.d.ts +81 -0
  6. package/dist/filter/context-bundle.d.ts.map +1 -0
  7. package/dist/filter/context-bundle.js +230 -0
  8. package/dist/filter/index.d.ts +85 -0
  9. package/dist/filter/index.d.ts.map +1 -0
  10. package/dist/filter/index.js +169 -0
  11. package/dist/index.d.ts +16 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +15 -0
  14. package/dist/loader/index.d.ts +80 -0
  15. package/dist/loader/index.d.ts.map +1 -0
  16. package/dist/loader/index.js +253 -0
  17. package/dist/parser/index.d.ts +24 -0
  18. package/dist/parser/index.d.ts.map +1 -0
  19. package/dist/parser/index.js +22 -0
  20. package/dist/parser/parse-document.d.ts +17 -0
  21. package/dist/parser/parse-document.d.ts.map +1 -0
  22. package/dist/parser/parse-document.js +219 -0
  23. package/dist/parser/parse-index.d.ts +31 -0
  24. package/dist/parser/parse-index.d.ts.map +1 -0
  25. package/dist/parser/parse-index.js +251 -0
  26. package/dist/parser/parse-task.d.ts +30 -0
  27. package/dist/parser/parse-task.d.ts.map +1 -0
  28. package/dist/parser/parse-task.js +261 -0
  29. package/dist/state/index.d.ts +307 -0
  30. package/dist/state/index.d.ts.map +1 -0
  31. package/dist/state/index.js +689 -0
  32. package/dist/templates/generator.d.ts +71 -0
  33. package/dist/templates/generator.d.ts.map +1 -0
  34. package/dist/templates/generator.js +723 -0
  35. package/dist/templates/index.d.ts +5 -0
  36. package/dist/templates/index.d.ts.map +1 -0
  37. package/dist/templates/index.js +4 -0
  38. package/dist/types/index.d.ts +131 -0
  39. package/dist/types/index.d.ts.map +1 -0
  40. package/dist/types/index.js +107 -0
  41. package/dist/validator/index.d.ts +83 -0
  42. package/dist/validator/index.d.ts.map +1 -0
  43. package/dist/validator/index.js +611 -0
  44. package/docs/APS-Anvil-Integration.md +750 -0
  45. package/docs/APS-Conventions.md +635 -0
  46. package/docs/APS-NonGoals.md +455 -0
  47. package/docs/APS-Planning-Spec-v0.1.md +362 -0
  48. package/examples/README.md +170 -0
  49. package/examples/feature-auth.aps.md +87 -0
  50. package/examples/refactor-error-handling.aps.md +119 -0
  51. package/examples/system-ecommerce/APS.md +57 -0
  52. package/examples/system-ecommerce/modules/auth.aps.md +38 -0
  53. package/examples/system-ecommerce/modules/cart.aps.md +53 -0
  54. package/examples/system-ecommerce/modules/payments.aps.md +68 -0
  55. package/examples/system-ecommerce/modules/products.aps.md +53 -0
  56. package/package.json +34 -0
  57. package/project.json +37 -0
  58. package/scripts/generate-templates.js +33 -0
  59. package/src/filter/context-bundle.ts +312 -0
  60. package/src/filter/filter.test.ts +317 -0
  61. package/src/filter/index.ts +249 -0
  62. package/src/index.ts +16 -0
  63. package/src/loader/index.ts +364 -0
  64. package/src/loader/loader.test.ts +224 -0
  65. package/src/parser/__fixtures__/invalid-task-id-not-padded.aps.md +7 -0
  66. package/src/parser/__fixtures__/invalid-task-id.aps.md +8 -0
  67. package/src/parser/__fixtures__/minimal-task.aps.md +7 -0
  68. package/src/parser/__fixtures__/non-scope-hyphenated.aps.md +10 -0
  69. package/src/parser/__fixtures__/simple-index.aps.md +35 -0
  70. package/src/parser/__fixtures__/simple-plan.aps.md +19 -0
  71. package/src/parser/index.ts +30 -0
  72. package/src/parser/parse-document.test.ts +603 -0
  73. package/src/parser/parse-document.ts +262 -0
  74. package/src/parser/parse-index.test.ts +316 -0
  75. package/src/parser/parse-index.ts +298 -0
  76. package/src/parser/parse-task.test.ts +476 -0
  77. package/src/parser/parse-task.ts +325 -0
  78. package/src/state/__fixtures__/invalid-plan.aps.md +9 -0
  79. package/src/state/__fixtures__/test-plan.aps.md +20 -0
  80. package/src/state/index.ts +879 -0
  81. package/src/state/state.test.ts +645 -0
  82. package/src/templates/generator.test.ts +378 -0
  83. package/src/templates/generator.ts +776 -0
  84. package/src/templates/index.ts +5 -0
  85. package/src/types/index.ts +168 -0
  86. package/src/validator/__fixtures__/broken-links.aps.md +10 -0
  87. package/src/validator/__fixtures__/circular-deps-index.aps.md +26 -0
  88. package/src/validator/__fixtures__/circular-modules/module-a.aps.md +9 -0
  89. package/src/validator/__fixtures__/circular-modules/module-b.aps.md +9 -0
  90. package/src/validator/__fixtures__/circular-modules/module-c.aps.md +9 -0
  91. package/src/validator/__fixtures__/dup-modules/module-a.aps.md +9 -0
  92. package/src/validator/__fixtures__/dup-modules/module-b.aps.md +9 -0
  93. package/src/validator/__fixtures__/duplicate-ids-index.aps.md +15 -0
  94. package/src/validator/__fixtures__/invalid-task-id.aps.md +17 -0
  95. package/src/validator/__fixtures__/missing-confidence.aps.md +9 -0
  96. package/src/validator/__fixtures__/missing-h1.aps.md +5 -0
  97. package/src/validator/__fixtures__/missing-intent.aps.md +9 -0
  98. package/src/validator/__fixtures__/missing-modules-section.aps.md +7 -0
  99. package/src/validator/__fixtures__/missing-tasks-section.aps.md +7 -0
  100. package/src/validator/__fixtures__/modules/auth.aps.md +17 -0
  101. package/src/validator/__fixtures__/modules/payments.aps.md +13 -0
  102. package/src/validator/__fixtures__/scope-mismatch.aps.md +14 -0
  103. package/src/validator/__fixtures__/valid-index.aps.md +24 -0
  104. package/src/validator/__fixtures__/valid-leaf.aps.md +22 -0
  105. package/src/validator/index.ts +776 -0
  106. package/src/validator/validator.test.ts +269 -0
  107. package/templates/index-full.md +94 -0
  108. package/templates/index-minimal.md +16 -0
  109. package/templates/index-template.md +63 -0
  110. package/templates/leaf-full.md +76 -0
  111. package/templates/leaf-minimal.md +14 -0
  112. package/templates/leaf-template.md +55 -0
  113. package/templates/simple-full.md +56 -0
  114. package/templates/simple-minimal.md +14 -0
  115. package/templates/simple-template.md +30 -0
  116. package/tsconfig.json +19 -0
  117. package/tsconfig.lib.json +14 -0
  118. package/tsconfig.lib.tsbuildinfo +1 -0
  119. package/tsconfig.spec.json +9 -0
  120. package/tsconfig.tsbuildinfo +1 -0
  121. package/vitest.config.ts +15 -0
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Task parsing utilities
3
+ * Extracts task information from Markdown AST nodes
4
+ */
5
+ import { ParseError } from '../types/index.js';
6
+ /**
7
+ * Extract task ID and title from H3 heading text
8
+ * Format: "SCOPE-NUMBER: Task title"
9
+ * - Scope: 1-10 uppercase alphanumeric characters
10
+ * - Number: 3-digit zero-padded (001-999)
11
+ */
12
+ export function parseTaskHeading(heading) {
13
+ if (heading.depth !== 3) {
14
+ throw new ParseError('Task headings must be H3 (###)', undefined, undefined, 'parseTaskHeading');
15
+ }
16
+ const text = extractPlainText(heading);
17
+ // Extract ID and title - ID must match TASK_ID_REGEX format
18
+ const match = text.match(/^([A-Z0-9]{1,10}-\d{3}):\s*(.+)$/);
19
+ if (!match) {
20
+ throw new ParseError(`Invalid task heading format. Expected "SCOPE-NNN: Title" (e.g., AUTH-001), got: "${text}"`, undefined, undefined, 'parseTaskHeading');
21
+ }
22
+ return {
23
+ id: match[1],
24
+ title: match[2].trim(),
25
+ };
26
+ }
27
+ /**
28
+ * Extract plain text from AST node (handles inline formatting)
29
+ */
30
+ function extractPlainText(node) {
31
+ if ('value' in node && typeof node.value === 'string') {
32
+ return node.value;
33
+ }
34
+ if ('children' in node && Array.isArray(node.children)) {
35
+ return node.children.map((child) => extractPlainText(child)).join('');
36
+ }
37
+ return '';
38
+ }
39
+ /**
40
+ * Parse task fields from paragraph and list nodes
41
+ * Fields are in format: **FieldName:** value
42
+ */
43
+ export function parseTaskFields(paragraphs, lists) {
44
+ const fields = {};
45
+ let lastField = null;
46
+ let inlineInputs = null;
47
+ // First pass: extract all field key-value pairs from paragraphs
48
+ for (const para of paragraphs) {
49
+ const fieldMatches = extractFieldsFromParagraph(para);
50
+ for (const [key, value] of Object.entries(fieldMatches)) {
51
+ // Handle Inputs specially - may be inline text or followed by a list
52
+ if (key === 'Inputs') {
53
+ if (value.trim() === '') {
54
+ // Empty value - expect a list to follow
55
+ lastField = key;
56
+ }
57
+ else {
58
+ // Inline text value - store for later (list takes precedence if present)
59
+ inlineInputs = value.trim();
60
+ lastField = key;
61
+ }
62
+ continue;
63
+ }
64
+ assignField(fields, key, value);
65
+ lastField = key;
66
+ }
67
+ }
68
+ // Second pass: handle Inputs field
69
+ // Lists take precedence over inline text
70
+ if (lastField === 'Inputs' && lists.length > 0) {
71
+ fields.inputs = extractListItems(lists[0]);
72
+ }
73
+ else if (inlineInputs !== null) {
74
+ // Use inline text as a single-item array
75
+ fields.inputs = [inlineInputs];
76
+ }
77
+ return fields;
78
+ }
79
+ /**
80
+ * Extract field key-value pairs from a paragraph containing bold markers
81
+ */
82
+ function extractFieldsFromParagraph(para) {
83
+ const fields = {};
84
+ let currentKey = '';
85
+ let currentValue = '';
86
+ let inField = false;
87
+ for (const child of para.children) {
88
+ if (child.type === 'strong') {
89
+ // Check if this strong node contains a field name
90
+ const strongText = extractPlainText(child);
91
+ const fieldMatch = strongText.match(/^([\w-]+(?:\s+[\w-]+)*):$/);
92
+ if (fieldMatch) {
93
+ // Save previous field if exists (even if value is empty)
94
+ if (currentKey) {
95
+ fields[currentKey] = currentValue.trim().replace(/\s+/g, ' ');
96
+ }
97
+ currentKey = fieldMatch[1];
98
+ currentValue = '';
99
+ inField = true;
100
+ }
101
+ }
102
+ else if (inField) {
103
+ // Extract text from any phrasing content node (text, inlineCode, etc.)
104
+ // This handles validation commands in backticks and other inline formatting
105
+ if (child.type === 'break') {
106
+ // Convert breaks to spaces to handle multi-line values
107
+ currentValue += ' ';
108
+ }
109
+ else {
110
+ currentValue += extractPlainText(child);
111
+ }
112
+ }
113
+ }
114
+ // Save last field (even if value is empty)
115
+ if (currentKey) {
116
+ fields[currentKey] = currentValue.trim().replace(/\s+/g, ' ');
117
+ }
118
+ return fields;
119
+ }
120
+ /**
121
+ * Assign a parsed field value to the appropriate Task property
122
+ */
123
+ function assignField(task, key, value) {
124
+ const normalizedKey = key.replace(/\s+/g, '');
125
+ switch (normalizedKey) {
126
+ case 'Intent':
127
+ task.intent = value;
128
+ break;
129
+ case 'ExpectedOutcome':
130
+ task.expectedOutcome = value;
131
+ break;
132
+ case 'Validation':
133
+ case 'Test':
134
+ // Support both "Validation:" and "Test:" field names per APS spec
135
+ task.validation = value;
136
+ break;
137
+ case 'Confidence':
138
+ task.confidence = parseConfidence(value);
139
+ break;
140
+ case 'Scopes':
141
+ task.scopes = parseCommaSeparated(value);
142
+ break;
143
+ case 'NonScope':
144
+ case 'Non-scope':
145
+ task.nonScope = parseCommaSeparated(value);
146
+ break;
147
+ case 'Files':
148
+ task.files = parseCommaSeparated(value);
149
+ break;
150
+ case 'Tags':
151
+ task.tags = parseCommaSeparated(value);
152
+ break;
153
+ case 'Dependencies':
154
+ task.dependencies = parseCommaSeparated(value);
155
+ break;
156
+ case 'Risks':
157
+ task.risks = parseCommaSeparated(value);
158
+ break;
159
+ case 'Packages': {
160
+ // Monorepo support: list of affected packages
161
+ const trimmed = value.trim();
162
+ if (!trimmed || trimmed.toLowerCase() === '(none)') {
163
+ task.packages = [];
164
+ }
165
+ else {
166
+ task.packages = parseCommaSeparated(value);
167
+ }
168
+ break;
169
+ }
170
+ case 'Link':
171
+ task.link = value;
172
+ break;
173
+ case 'Status':
174
+ task.status = parseStatus(value);
175
+ break;
176
+ // 'Inputs' is handled separately as a list
177
+ }
178
+ }
179
+ /**
180
+ * Parse confidence value from string
181
+ */
182
+ function parseConfidence(value) {
183
+ const normalized = value.toLowerCase().trim();
184
+ if (normalized === 'low' || normalized === 'medium' || normalized === 'high') {
185
+ return normalized;
186
+ }
187
+ return 'medium'; // default
188
+ }
189
+ /**
190
+ * Parse task status from string
191
+ */
192
+ function parseStatus(value) {
193
+ const normalized = value.toLowerCase().trim();
194
+ if (normalized === 'open' ||
195
+ normalized === 'locked' ||
196
+ normalized === 'completed' ||
197
+ normalized === 'cancelled') {
198
+ return normalized;
199
+ }
200
+ return 'open'; // default
201
+ }
202
+ /**
203
+ * Parse comma-separated list into array
204
+ */
205
+ function parseCommaSeparated(value) {
206
+ return value
207
+ .split(',')
208
+ .map((item) => item.trim())
209
+ .filter((item) => item.length > 0);
210
+ }
211
+ /**
212
+ * Extract list items as strings
213
+ */
214
+ function extractListItems(list) {
215
+ const items = [];
216
+ for (const item of list.children) {
217
+ if (item.type === 'listItem' && item.children.length > 0) {
218
+ const firstChild = item.children[0];
219
+ if (firstChild && firstChild.type === 'paragraph') {
220
+ items.push(extractPlainText(firstChild));
221
+ }
222
+ }
223
+ }
224
+ return items;
225
+ }
226
+ /**
227
+ * Parse a complete task from AST nodes
228
+ * @param heading - H3 heading node with task ID and title
229
+ * @param content - Array of paragraph and list nodes containing task fields
230
+ * @param sourcePath - Optional source file path
231
+ * @param lineNumber - Optional line number where task starts
232
+ */
233
+ export function parseTask(heading, content, sourcePath, lineNumber) {
234
+ const { id, title } = parseTaskHeading(heading);
235
+ const paragraphs = content.filter((node) => node.type === 'paragraph');
236
+ const lists = content.filter((node) => node.type === 'list');
237
+ const fields = parseTaskFields(paragraphs, lists);
238
+ if (!fields.intent) {
239
+ throw new ParseError(`Task ${id} is missing required field: Intent`, sourcePath, lineNumber, 'parseTask');
240
+ }
241
+ return {
242
+ id,
243
+ title,
244
+ intent: fields.intent,
245
+ expectedOutcome: fields.expectedOutcome,
246
+ validation: fields.validation,
247
+ confidence: fields.confidence ?? 'medium',
248
+ scopes: fields.scopes,
249
+ nonScope: fields.nonScope,
250
+ files: fields.files,
251
+ tags: fields.tags,
252
+ dependencies: fields.dependencies,
253
+ inputs: fields.inputs,
254
+ risks: fields.risks,
255
+ packages: fields.packages,
256
+ link: fields.link,
257
+ status: fields.status,
258
+ sourcePath,
259
+ sourceLineNumber: lineNumber,
260
+ };
261
+ }
@@ -0,0 +1,307 @@
1
+ /**
2
+ * State module - Task state management and locking functionality
3
+ *
4
+ * Manages `.anvil/state.json` for tracking task execution states.
5
+ * Provides TaskLocker for locking tasks for execution with:
6
+ * - First-lock-wins concurrent lock handling
7
+ * - Execution plan JSON generation with hash and provenance
8
+ * - Lock/unlock/status operations
9
+ */
10
+ import { z } from 'zod';
11
+ import { type Task, type TaskStatus } from '../types/index.js';
12
+ /**
13
+ * Source location of a task in a planning document
14
+ */
15
+ export declare const TaskSourceSchema: z.ZodObject<{
16
+ file: z.ZodString;
17
+ line: z.ZodOptional<z.ZodNumber>;
18
+ }, z.core.$strip>;
19
+ export type TaskSource = z.infer<typeof TaskSourceSchema>;
20
+ /**
21
+ * State of a single task
22
+ */
23
+ export declare const TaskStateSchema: z.ZodObject<{
24
+ status: z.ZodEnum<{
25
+ open: "open";
26
+ locked: "locked";
27
+ completed: "completed";
28
+ cancelled: "cancelled";
29
+ }>;
30
+ locked_at: z.ZodOptional<z.ZodString>;
31
+ locked_by: z.ZodOptional<z.ZodString>;
32
+ execution_file: z.ZodOptional<z.ZodString>;
33
+ source: z.ZodOptional<z.ZodObject<{
34
+ file: z.ZodString;
35
+ line: z.ZodOptional<z.ZodNumber>;
36
+ }, z.core.$strip>>;
37
+ completed_at: z.ZodOptional<z.ZodString>;
38
+ cancelled_at: z.ZodOptional<z.ZodString>;
39
+ }, z.core.$strip>;
40
+ export type TaskState = z.infer<typeof TaskStateSchema>;
41
+ /**
42
+ * Full state file schema (.anvil/state.json)
43
+ */
44
+ export declare const StateFileSchema: z.ZodObject<{
45
+ version: z.ZodDefault<z.ZodString>;
46
+ tasks: z.ZodRecord<z.ZodString, z.ZodObject<{
47
+ status: z.ZodEnum<{
48
+ open: "open";
49
+ locked: "locked";
50
+ completed: "completed";
51
+ cancelled: "cancelled";
52
+ }>;
53
+ locked_at: z.ZodOptional<z.ZodString>;
54
+ locked_by: z.ZodOptional<z.ZodString>;
55
+ execution_file: z.ZodOptional<z.ZodString>;
56
+ source: z.ZodOptional<z.ZodObject<{
57
+ file: z.ZodString;
58
+ line: z.ZodOptional<z.ZodNumber>;
59
+ }, z.core.$strip>>;
60
+ completed_at: z.ZodOptional<z.ZodString>;
61
+ cancelled_at: z.ZodOptional<z.ZodString>;
62
+ }, z.core.$strip>>;
63
+ }, z.core.$strip>;
64
+ export type StateFile = z.infer<typeof StateFileSchema>;
65
+ /**
66
+ * Provenance information for execution plans
67
+ */
68
+ export declare const ProvenanceSchema: z.ZodObject<{
69
+ locked_by: z.ZodString;
70
+ locked_at: z.ZodString;
71
+ git_commit: z.ZodOptional<z.ZodString>;
72
+ git_branch: z.ZodOptional<z.ZodString>;
73
+ source_file: z.ZodString;
74
+ source_line: z.ZodOptional<z.ZodNumber>;
75
+ }, z.core.$strip>;
76
+ export type Provenance = z.infer<typeof ProvenanceSchema>;
77
+ /**
78
+ * Execution plan JSON schema (per-task, written to .anvil/executions/)
79
+ */
80
+ export declare const ExecutionPlanSchema: z.ZodObject<{
81
+ version: z.ZodDefault<z.ZodString>;
82
+ task_id: z.ZodString;
83
+ title: z.ZodString;
84
+ intent: z.ZodString;
85
+ expected_outcome: z.ZodOptional<z.ZodString>;
86
+ confidence: z.ZodEnum<{
87
+ low: "low";
88
+ medium: "medium";
89
+ high: "high";
90
+ }>;
91
+ scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
92
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
93
+ dependencies: z.ZodOptional<z.ZodArray<z.ZodString>>;
94
+ inputs: z.ZodOptional<z.ZodArray<z.ZodString>>;
95
+ content_hash: z.ZodString;
96
+ provenance: z.ZodObject<{
97
+ locked_by: z.ZodString;
98
+ locked_at: z.ZodString;
99
+ git_commit: z.ZodOptional<z.ZodString>;
100
+ git_branch: z.ZodOptional<z.ZodString>;
101
+ source_file: z.ZodString;
102
+ source_line: z.ZodOptional<z.ZodNumber>;
103
+ }, z.core.$strip>;
104
+ }, z.core.$strip>;
105
+ export type ExecutionPlan = z.infer<typeof ExecutionPlanSchema>;
106
+ /**
107
+ * Get the path to the state file
108
+ */
109
+ export declare function getStateFilePath(projectRoot: string): string;
110
+ /**
111
+ * Get the path to the executions directory
112
+ */
113
+ export declare function getExecutionsDir(projectRoot: string): string;
114
+ /**
115
+ * Read the state file, returning empty state if it doesn't exist
116
+ */
117
+ export declare function readStateFile(projectRoot: string): Promise<StateFile>;
118
+ /**
119
+ * Write the state file, creating directories if needed
120
+ */
121
+ export declare function writeStateFile(projectRoot: string, state: StateFile): Promise<void>;
122
+ /**
123
+ * Get the state of a specific task
124
+ */
125
+ export declare function getTaskState(projectRoot: string, taskId: string): Promise<TaskState | undefined>;
126
+ /**
127
+ * Update the state of a specific task
128
+ */
129
+ export declare function updateTaskState(projectRoot: string, taskId: string, taskState: TaskState): Promise<void>;
130
+ /**
131
+ * Generate execution plan JSON for a task
132
+ */
133
+ export declare function createExecutionPlan(task: Task, provenance: Provenance): ExecutionPlan;
134
+ /**
135
+ * Compute SHA-256 hash of task content
136
+ */
137
+ export declare function computeTaskHash(task: Task): string;
138
+ /**
139
+ * Get execution plan file path for a task
140
+ */
141
+ export declare function getExecutionPlanPath(projectRoot: string, taskId: string): string;
142
+ /**
143
+ * Write execution plan to file
144
+ */
145
+ export declare function writeExecutionPlan(projectRoot: string, plan: ExecutionPlan): Promise<string>;
146
+ /**
147
+ * Read execution plan from file.
148
+ * Verifies the stored content_hash matches the recomputed hash.
149
+ * If the hash does not match, the plan is still returned but a
150
+ * `hashMismatch` flag is set on the result.
151
+ */
152
+ export declare function readExecutionPlan(projectRoot: string, taskId: string): Promise<(ExecutionPlan & {
153
+ hashMismatch?: boolean;
154
+ }) | undefined>;
155
+ /**
156
+ * Delete execution plan file
157
+ */
158
+ export declare function deleteExecutionPlan(projectRoot: string, taskId: string): Promise<void>;
159
+ /**
160
+ * Get current user name
161
+ */
162
+ export declare function getCurrentUser(): string;
163
+ /**
164
+ * Get git commit hash (if in a git repo)
165
+ */
166
+ export declare function getGitCommit(projectRoot: string): string | undefined;
167
+ /**
168
+ * Get git branch name (if in a git repo)
169
+ */
170
+ export declare function getGitBranch(projectRoot: string): string | undefined;
171
+ /**
172
+ * Create provenance info for a task
173
+ */
174
+ export declare function createProvenance(task: Task, projectRoot: string, user?: string): Provenance;
175
+ /**
176
+ * Error thrown by state operations
177
+ */
178
+ export declare class StateError extends Error {
179
+ readonly path?: string | undefined;
180
+ readonly taskId?: string | undefined;
181
+ constructor(message: string, path?: string | undefined, taskId?: string | undefined);
182
+ }
183
+ /**
184
+ * Result of a lock operation
185
+ */
186
+ export interface LockResult {
187
+ success: boolean;
188
+ taskId: string;
189
+ executionPlanPath?: string;
190
+ error?: string;
191
+ }
192
+ /**
193
+ * Result of an unlock operation
194
+ */
195
+ export interface UnlockResult {
196
+ success: boolean;
197
+ taskId: string;
198
+ previousStatus?: TaskStatus;
199
+ error?: string;
200
+ }
201
+ /**
202
+ * Task status information
203
+ */
204
+ export interface TaskStatusInfo {
205
+ taskId: string;
206
+ status: TaskStatus;
207
+ lockedAt?: string;
208
+ lockedBy?: string;
209
+ executionFile?: string;
210
+ source?: TaskSource;
211
+ completedAt?: string;
212
+ cancelledAt?: string;
213
+ }
214
+ /**
215
+ * Options for TaskLocker
216
+ */
217
+ export interface TaskLockerOptions {
218
+ /** Project root directory */
219
+ projectRoot: string;
220
+ /** Path to the planning document */
221
+ planPath: string;
222
+ /** User name for provenance (defaults to current user) */
223
+ user?: string;
224
+ /** Skip validation before locking */
225
+ skipValidation?: boolean;
226
+ }
227
+ /**
228
+ * TaskLocker - Manages task locking for execution
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * const locker = new TaskLocker({
233
+ * projectRoot: '/path/to/project',
234
+ * planPath: 'docs/planning/APS.md',
235
+ * });
236
+ *
237
+ * // Lock a task
238
+ * const result = await locker.lock('AUTH-001');
239
+ * if (result.success) {
240
+ * console.log(`Task locked, execution plan: ${result.executionPlanPath}`);
241
+ * }
242
+ *
243
+ * // Check status
244
+ * const status = await locker.getStatus('AUTH-001');
245
+ *
246
+ * // Unlock (cancel) a task
247
+ * await locker.unlock('AUTH-001');
248
+ * ```
249
+ */
250
+ export declare class TaskLocker {
251
+ private projectRoot;
252
+ private planPath;
253
+ private user;
254
+ private skipValidation;
255
+ private plan;
256
+ constructor(options: TaskLockerOptions);
257
+ /**
258
+ * Load the plan (validates first unless skipValidation is true)
259
+ */
260
+ private loadPlan;
261
+ /**
262
+ * Find a task by ID in the loaded plan
263
+ */
264
+ private findTask;
265
+ /**
266
+ * Lock a task for execution
267
+ *
268
+ * - Validates planning doc first (unless skipValidation)
269
+ * - Snapshots task definition
270
+ * - Generates execution plan JSON with hash and provenance
271
+ * - Updates state.json
272
+ * - First lock wins (fails if already locked)
273
+ */
274
+ lock(taskId: string): Promise<LockResult>;
275
+ /**
276
+ * Unlock (cancel) a locked task
277
+ *
278
+ * - Moves task to 'cancelled' status
279
+ * - Removes execution plan file
280
+ */
281
+ unlock(taskId: string): Promise<UnlockResult>;
282
+ /**
283
+ * Mark a task as completed
284
+ */
285
+ complete(taskId: string): Promise<UnlockResult>;
286
+ /**
287
+ * Get the status of a specific task
288
+ */
289
+ getStatus(taskId: string): Promise<TaskStatusInfo | undefined>;
290
+ /**
291
+ * Get status of all tasks in the plan
292
+ */
293
+ getAllStatus(): Promise<TaskStatusInfo[]>;
294
+ /**
295
+ * Get summary of task statuses
296
+ */
297
+ getStatusSummary(): Promise<Record<TaskStatus, number>>;
298
+ }
299
+ /**
300
+ * Format task status for display
301
+ */
302
+ export declare function formatTaskStatus(status: TaskStatusInfo): string;
303
+ /**
304
+ * Format all task statuses for display
305
+ */
306
+ export declare function formatAllTaskStatus(statuses: TaskStatusInfo[]): string;
307
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"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"}