@rasensio/aidlc 1.5.0 → 1.7.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 (61) hide show
  1. package/dist/cli.js +2 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/gate.d.ts.map +1 -1
  4. package/dist/commands/gate.js +20 -2
  5. package/dist/commands/gate.js.map +1 -1
  6. package/dist/commands/init.js +13 -0
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/metrics.d.ts +10 -0
  9. package/dist/commands/metrics.d.ts.map +1 -0
  10. package/dist/commands/metrics.js +83 -0
  11. package/dist/commands/metrics.js.map +1 -0
  12. package/dist/commands/status.d.ts.map +1 -1
  13. package/dist/commands/status.js +82 -3
  14. package/dist/commands/status.js.map +1 -1
  15. package/dist/commands/transition.d.ts.map +1 -1
  16. package/dist/commands/transition.js +109 -6
  17. package/dist/commands/transition.js.map +1 -1
  18. package/dist/commands/update.d.ts.map +1 -1
  19. package/dist/commands/update.js +13 -0
  20. package/dist/commands/update.js.map +1 -1
  21. package/dist/concurrency/gitattributes.d.ts.map +1 -1
  22. package/dist/concurrency/gitattributes.js +3 -0
  23. package/dist/concurrency/gitattributes.js.map +1 -1
  24. package/dist/core/gate.d.ts +19 -1
  25. package/dist/core/gate.d.ts.map +1 -1
  26. package/dist/core/gate.js +18 -1
  27. package/dist/core/gate.js.map +1 -1
  28. package/dist/core/lifecycle.d.ts.map +1 -1
  29. package/dist/core/lifecycle.js +7 -3
  30. package/dist/core/lifecycle.js.map +1 -1
  31. package/dist/core/types.d.ts +10 -1
  32. package/dist/core/types.d.ts.map +1 -1
  33. package/dist/events/event-bus.d.ts +7 -0
  34. package/dist/events/event-bus.d.ts.map +1 -1
  35. package/dist/events/event-bus.js +36 -1
  36. package/dist/events/event-bus.js.map +1 -1
  37. package/dist/events/shipped-actions.d.ts +17 -0
  38. package/dist/events/shipped-actions.d.ts.map +1 -0
  39. package/dist/events/shipped-actions.js +47 -0
  40. package/dist/events/shipped-actions.js.map +1 -0
  41. package/dist/metrics/report.d.ts +83 -0
  42. package/dist/metrics/report.d.ts.map +1 -0
  43. package/dist/metrics/report.js +286 -0
  44. package/dist/metrics/report.js.map +1 -0
  45. package/dist/tasks/gate-criterion.d.ts +42 -0
  46. package/dist/tasks/gate-criterion.d.ts.map +1 -0
  47. package/dist/tasks/gate-criterion.js +180 -0
  48. package/dist/tasks/gate-criterion.js.map +1 -0
  49. package/dist/tasks/parser.d.ts +30 -0
  50. package/dist/tasks/parser.d.ts.map +1 -0
  51. package/dist/tasks/parser.js +200 -0
  52. package/dist/tasks/parser.js.map +1 -0
  53. package/dist/tasks/status.d.ts +20 -0
  54. package/dist/tasks/status.d.ts.map +1 -0
  55. package/dist/tasks/status.js +41 -0
  56. package/dist/tasks/status.js.map +1 -0
  57. package/dist/tasks/types.d.ts +90 -0
  58. package/dist/tasks/types.d.ts.map +1 -0
  59. package/dist/tasks/types.js +9 -0
  60. package/dist/tasks/types.js.map +1 -0
  61. package/package.json +2 -2
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Tasks gate criterion (FR3): computed live at the command layer after
3
+ * `evaluateGate`, following the traceability precedent — it evaluates even
4
+ * when phase state is `complete` (AC-11) and never touches `evaluateGate`'s
5
+ * contract.
6
+ *
7
+ * Applicability tri-state (DD7):
8
+ * null phase ≠ implementation, phase-implementation.yaml
9
+ * absent (AC-30), or opt-in with no task-shaped
10
+ * lines / missing file (AC-6)
11
+ * result, empty entries only near-misses — warnings surface (AC-5), or
12
+ * the required-scope backstops fired (AC-17, AC-28)
13
+ * result with entries ≥1 valid task — full evaluation
14
+ *
15
+ * Bare AC refs resolve to the owning instance (DD8): a tasks file lives in
16
+ * one instance's state dir, so its bare `AC-n` means this instance's AC-n —
17
+ * traceability's cross-instance uniqueness rule (for free-floating test
18
+ * files) does not transfer.
19
+ *
20
+ * Requirements: task-breakdown/AC-6, AC-11..AC-17, AC-28, AC-30
21
+ */
22
+ import { existsSync, readFileSync } from 'node:fs';
23
+ import { join } from 'node:path';
24
+ import { parse as parseYaml } from 'yaml';
25
+ import { loadRegistry } from '../traceability/gate-criterion.js';
26
+ import { parseTasks } from './parser.js';
27
+ /** Message template for open tasks (DD6). */
28
+ export function openTaskMessage(id, title) {
29
+ return `task T${id} "${title}" is open (tasks)`;
30
+ }
31
+ /** Message template for malformed deferrals (AC-2, DD6). */
32
+ export function malformedDeferralMessage(id) {
33
+ return `task T${id} has a malformed deferral (tasks)`;
34
+ }
35
+ /** Message for the missing/empty required-scope backstops (AC-17, AC-28). */
36
+ export function missingTasksMessage(kind) {
37
+ return kind === 'file'
38
+ ? 'required artifact tasks.md is missing (tasks)'
39
+ : 'tasks.md defines no tasks (tasks)';
40
+ }
41
+ /**
42
+ * Required-scope determination (AC-27, DD5): the template requires tasks.md
43
+ * at design AND the instance's phase-design.yaml carries a tasks.md artifact
44
+ * entry (legacy instances without the entry are legacy-allowed).
45
+ */
46
+ function isRequiredScope(instanceDir, template) {
47
+ if (!template)
48
+ return false;
49
+ const designPhase = template.phases.find((p) => p.name === 'design');
50
+ const templateRequires = designPhase?.required_artifacts?.some((a) => a.name === 'tasks.md');
51
+ if (!templateRequires)
52
+ return false;
53
+ try {
54
+ const state = parseYaml(readFileSync(join(instanceDir, 'phase-design.yaml'), 'utf8'));
55
+ return Boolean(state?.artifacts?.some((a) => a?.name === 'tasks.md'));
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }
61
+ /**
62
+ * Evaluate the tasks criterion for one instance.
63
+ *
64
+ * @param template - Resolved template; null degrades to opt-in semantics
65
+ * with a warning (defensive — both CLI call sites early-exit before this
66
+ * on resolution failure).
67
+ * @returns null when the criterion does not evaluate (AC-6, AC-30);
68
+ * otherwise a result whose `openTasks`/`malformed`/`missing` the caller
69
+ * turns into unsatisfied criteria / gate violations via the message
70
+ * helpers above.
71
+ */
72
+ export function evaluateTasksCriterion(projectRoot, instanceName, phaseName, template) {
73
+ if (phaseName !== 'implementation')
74
+ return null;
75
+ const instanceDir = join(projectRoot, '.aidlc', 'state', instanceName);
76
+ if (!existsSync(join(instanceDir, 'phase-implementation.yaml')))
77
+ return null;
78
+ const tasksPath = `.aidlc/state/${instanceName}/tasks.md`;
79
+ const warnings = [];
80
+ if (template === null) {
81
+ warnings.push('template unresolvable — tasks criterion degrades to opt-in');
82
+ }
83
+ const required = isRequiredScope(instanceDir, template);
84
+ let content = null;
85
+ try {
86
+ content = readFileSync(join(instanceDir, 'tasks.md'), 'utf8');
87
+ }
88
+ catch (err) {
89
+ if (err.code !== 'ENOENT') {
90
+ warnings.push(`tasks.md is unreadable (${err.message}) — treated as missing`);
91
+ }
92
+ if (!required)
93
+ return null;
94
+ return { tasksPath, entries: [], warnings, openTasks: [], malformed: [], missing: 'file' };
95
+ }
96
+ const parsed = parseTasks(content);
97
+ warnings.push(...parsed.warnings);
98
+ if (parsed.tasks.length === 0 && parsed.malformedDeferrals.length === 0) {
99
+ if (required) {
100
+ // AC-28: exists but defines no tasks — near-miss warnings surface.
101
+ return { tasksPath, entries: [], warnings, openTasks: [], malformed: [], missing: 'empty' };
102
+ }
103
+ if (parsed.taskShapedLines === 0)
104
+ return null; // AC-6
105
+ // Tri-state case 2: only near-misses — visible, not silent.
106
+ return { tasksPath, entries: [], warnings, openTasks: [], malformed: [] };
107
+ }
108
+ // Registry linkage (AC-14..16): skipped when this instance defines no ACs.
109
+ const registry = loadRegistry(projectRoot);
110
+ const own = registry.get(instanceName);
111
+ if (!own || own.defs.length === 0) {
112
+ if (parsed.tasks.some((t) => t.acRefs.length > 0)) {
113
+ warnings.push(`instance defines no acceptance criteria — task AC references are not checked`);
114
+ }
115
+ }
116
+ else {
117
+ const ownActive = new Set(own.defs.filter((d) => d.status === 'active').map((d) => d.id));
118
+ const ownById = new Map(own.defs.map((d) => [d.id, d]));
119
+ const claimed = new Set();
120
+ for (const task of parsed.tasks) {
121
+ if (task.acRefs.length === 0) {
122
+ // AC-15: chore tasks are legitimate; the gap is made visible.
123
+ warnings.push(`task T${task.id} references no acceptance criteria`);
124
+ continue;
125
+ }
126
+ for (const ref of task.acRefs) {
127
+ const isSelf = ref.instance === null || ref.instance === instanceName;
128
+ if (isSelf) {
129
+ const def = ownById.get(ref.id);
130
+ if (!def) {
131
+ warnings.push(`task T${task.id} references unknown AC-${ref.id}`);
132
+ }
133
+ else if (def.status === 'retired') {
134
+ warnings.push(`task T${task.id} references retired AC-${ref.id}`);
135
+ }
136
+ else {
137
+ claimed.add(ref.id); // bare and qualified self-refs count (AC-16)
138
+ }
139
+ continue;
140
+ }
141
+ // Cross-instance ref: validated, never satisfies AC-16 (AC-14).
142
+ const other = registry.get(ref.instance);
143
+ const def = other?.defs.find((d) => d.id === ref.id);
144
+ if (!def) {
145
+ warnings.push(`task T${task.id} references unknown ${ref.instance}/AC-${ref.id}`);
146
+ }
147
+ else if (def.status === 'retired') {
148
+ warnings.push(`task T${task.id} references retired ${ref.instance}/AC-${ref.id}`);
149
+ }
150
+ }
151
+ }
152
+ // AC-16: unclaimed active ACs of this instance — decomposition gaps.
153
+ for (const id of [...ownActive].sort((a, b) => a - b)) {
154
+ if (!claimed.has(id)) {
155
+ warnings.push(`AC-${id} is claimed by no task`);
156
+ }
157
+ }
158
+ }
159
+ // Deferred tasks surface as warnings, never failures (AC-13).
160
+ for (const task of parsed.tasks) {
161
+ if (task.state === 'deferred') {
162
+ warnings.push(`task T${task.id} is deferred: ${task.deferReason}`);
163
+ }
164
+ }
165
+ const entries = parsed.tasks.map((t) => ({
166
+ id: t.id,
167
+ state: t.state,
168
+ title: t.title,
169
+ acRefs: t.acRefs.map((r) => (r.instance ? `${r.instance}/AC-${r.id}` : `AC-${r.id}`)),
170
+ ...(t.deferReason !== undefined && { deferReason: t.deferReason }),
171
+ }));
172
+ return {
173
+ tasksPath,
174
+ entries,
175
+ warnings,
176
+ openTasks: parsed.tasks.filter((t) => t.state === 'open').map((t) => t.id),
177
+ malformed: parsed.malformedDeferrals.map((m) => m.id),
178
+ };
179
+ }
180
+ //# sourceMappingURL=gate-criterion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-criterion.js","sourceRoot":"","sources":["../../src/tasks/gate-criterion.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Task-line parser: closed grammar over tasks.md (FR1).
3
+ *
4
+ * Accepted forms (column-0 dash bullets only; indented task-shaped lines are
5
+ * near-misses, F7):
6
+ * - [ ] T<n>: <title>
7
+ * - [ ] T<n>: <title> (AC-1, other-instance/AC-2)
8
+ * - [x] T<n>: <title> (AC-3)
9
+ * - [>] T<n>: <title> [(AC-list)] (deferred YYYY-MM-DD: <reason>)
10
+ *
11
+ * Structural groups are extracted right-to-left (DD2): trailing parenthesized
12
+ * groups are structural when their content is deferral-shaped, keyword-colon,
13
+ * or AC-shaped; the first non-structural group ends the unwind (title prose).
14
+ * An AC-shaped group failing the strict list grammar is a near-miss (F5) —
15
+ * intended refs must never silently drop. Unrecognized keyword-colon groups
16
+ * (e.g. the reserved v2 `owner:`) keep the task and warn (AC-29).
17
+ *
18
+ * Anything task-shaped that fails the strict grammar warns rather than
19
+ * silently dropping out of gate coverage (AC-5).
20
+ *
21
+ * Requirements: task-breakdown/AC-1..AC-5, AC-29
22
+ */
23
+ import type { ParsedTasks } from './types.js';
24
+ /**
25
+ * Parse one tasks.md for task lines.
26
+ *
27
+ * @param content - File content (UTF-8). Never throws.
28
+ */
29
+ export declare function parseTasks(content: string): ParsedTasks;
30
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/tasks/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAkC,MAAM,YAAY,CAAC;AAsH9E;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CA4FvD"}
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Task-line parser: closed grammar over tasks.md (FR1).
3
+ *
4
+ * Accepted forms (column-0 dash bullets only; indented task-shaped lines are
5
+ * near-misses, F7):
6
+ * - [ ] T<n>: <title>
7
+ * - [ ] T<n>: <title> (AC-1, other-instance/AC-2)
8
+ * - [x] T<n>: <title> (AC-3)
9
+ * - [>] T<n>: <title> [(AC-list)] (deferred YYYY-MM-DD: <reason>)
10
+ *
11
+ * Structural groups are extracted right-to-left (DD2): trailing parenthesized
12
+ * groups are structural when their content is deferral-shaped, keyword-colon,
13
+ * or AC-shaped; the first non-structural group ends the unwind (title prose).
14
+ * An AC-shaped group failing the strict list grammar is a near-miss (F5) —
15
+ * intended refs must never silently drop. Unrecognized keyword-colon groups
16
+ * (e.g. the reserved v2 `owner:`) keep the task and warn (AC-29).
17
+ *
18
+ * Anything task-shaped that fails the strict grammar warns rather than
19
+ * silently dropping out of gate coverage (AC-5).
20
+ *
21
+ * Requirements: task-breakdown/AC-1..AC-5, AC-29
22
+ */
23
+ // Loose: any bullet (numbered included, like the AC lint) + checkbox-ish +
24
+ // T<n>-ish token → near-miss candidate (AC-5). Keeps leading whitespace so
25
+ // indented task-shaped lines warn (F7).
26
+ const TASK_SHAPED_RE = /^\s*(?:[-*+]|\d+\.)\s+\[[^\]]?\]\s*T\d+/i;
27
+ // Strict prefix: column-0 dash bullet, exact checkbox, exact ID, colon,
28
+ // non-empty rest (F13).
29
+ const TASK_PREFIX_RE = /^-\s+\[( |x|>)\]\s+T([1-9][0-9]*):\s+(\S.*)$/;
30
+ // A trailing parenthesized group is structural when its content starts with
31
+ // a deferral keyword, a lowercase keyword-colon, or an AC token (F1, F11).
32
+ const STRUCTURAL_SHAPED_RE = /^(?:deferred[ :]|[a-z][a-z-]*:|AC-\d|[a-z0-9-]+\/AC-\d)/;
33
+ const DEFERRAL_RE = /^deferred (\d{4}-\d{2}-\d{2}): (.+)$/;
34
+ const AC_ITEM = String.raw `(?:([a-z0-9-]+)\/)?AC-([1-9][0-9]*)`;
35
+ const AC_LIST_RE = new RegExp(String.raw `^${AC_ITEM}(?:,\s*${AC_ITEM})*$`);
36
+ const AC_ITEM_G = new RegExp(AC_ITEM, 'g');
37
+ // Groups that begin with an AC token belong to the AC-list grammar; failing
38
+ // it is a near-miss (F5), not an AC-29 unrecognized token.
39
+ const AC_SHAPED_GROUP_RE = /^(?:AC-\d|[a-z0-9-]+\/AC-\d)/;
40
+ const STATE_BY_MARKER = { ' ': 'open', x: 'done', '>': 'deferred' };
41
+ // Most-blocking wins on duplicate IDs with conflicting states (AC-3, DD3).
42
+ const BLOCK_RANK = { open: 0, deferred: 1, done: 2 };
43
+ function excerpt(line) {
44
+ const trimmed = line.trim();
45
+ return trimmed.length > 60 ? `${trimmed.slice(0, 57)}...` : trimmed;
46
+ }
47
+ /**
48
+ * Unwind trailing parenthesized groups right-to-left (DD2), classifying each
49
+ * against the normative order `<title> [(AC-list)] [(deferral)]`.
50
+ */
51
+ function extractGroups(rest) {
52
+ const result = {
53
+ title: rest,
54
+ acList: null,
55
+ deferral: null,
56
+ unrecognized: [],
57
+ nearMiss: null,
58
+ };
59
+ const groups = [];
60
+ let remainder = rest;
61
+ for (;;) {
62
+ const m = /^(.*?)\s*\(([^()]*)\)$/.exec(remainder);
63
+ if (!m || !STRUCTURAL_SHAPED_RE.test(m[2]))
64
+ break;
65
+ groups.unshift(m[2]);
66
+ remainder = m[1];
67
+ }
68
+ result.title = remainder;
69
+ // Groups are now in left-to-right order; enforce [AC-list] [deferral].
70
+ let sawDeferral = false;
71
+ for (const content of groups) {
72
+ if (content.startsWith('deferred')) {
73
+ const d = DEFERRAL_RE.exec(content);
74
+ if (!d) {
75
+ result.nearMiss = 'malformed deferral marker';
76
+ return result;
77
+ }
78
+ if (result.deferral) {
79
+ result.nearMiss = 'duplicate deferral marker';
80
+ return result;
81
+ }
82
+ result.deferral = { date: d[1], reason: d[2] };
83
+ sawDeferral = true;
84
+ continue;
85
+ }
86
+ if (sawDeferral) {
87
+ result.nearMiss = 'structural group after the deferral marker';
88
+ return result;
89
+ }
90
+ if (AC_SHAPED_GROUP_RE.test(content)) {
91
+ if (!AC_LIST_RE.test(content)) {
92
+ result.nearMiss = 'malformed AC list';
93
+ return result;
94
+ }
95
+ if (result.acList !== null) {
96
+ result.nearMiss = 'duplicate AC list';
97
+ return result;
98
+ }
99
+ result.acList = content;
100
+ continue;
101
+ }
102
+ // Keyword-colon group with an unrecognized keyword: keep and warn (AC-29).
103
+ result.unrecognized.push(content);
104
+ }
105
+ if (result.title.length === 0) {
106
+ result.nearMiss = 'empty title';
107
+ }
108
+ return result;
109
+ }
110
+ function parseAcRefs(acList) {
111
+ const refs = [];
112
+ for (const m of acList.matchAll(AC_ITEM_G)) {
113
+ refs.push({ instance: m[1] ?? null, id: Number(m[2]) });
114
+ }
115
+ return refs;
116
+ }
117
+ /**
118
+ * Parse one tasks.md for task lines.
119
+ *
120
+ * @param content - File content (UTF-8). Never throws.
121
+ */
122
+ export function parseTasks(content) {
123
+ const warnings = [];
124
+ const malformedDeferrals = [];
125
+ const byId = new Map();
126
+ let taskShapedLines = 0;
127
+ const lines = content.split('\n');
128
+ for (let i = 0; i < lines.length; i++) {
129
+ const line = lines[i];
130
+ const lineNo = i + 1;
131
+ if (!TASK_SHAPED_RE.test(line))
132
+ continue;
133
+ taskShapedLines++;
134
+ const prefix = TASK_PREFIX_RE.exec(line);
135
+ if (!prefix) {
136
+ warnings.push(`line ${lineNo}: "${excerpt(line)}" resembles a task but does not match the grammar`);
137
+ continue;
138
+ }
139
+ const state = STATE_BY_MARKER[prefix[1]];
140
+ const id = Number(prefix[2]);
141
+ const groups = extractGroups(prefix[3]);
142
+ if (groups.nearMiss) {
143
+ // A [>] line whose deferral itself is malformed is the AC-2 parse
144
+ // error, not an ordinary near-miss — it must fail the gate.
145
+ if (state === 'deferred' && groups.nearMiss.includes('deferral')) {
146
+ malformedDeferrals.push({ id, line: lineNo });
147
+ warnings.push(`line ${lineNo}: task T${id} has a malformed deferral marker`);
148
+ }
149
+ else {
150
+ warnings.push(`line ${lineNo}: "${excerpt(line)}" — ${groups.nearMiss}`);
151
+ }
152
+ continue;
153
+ }
154
+ if (state === 'deferred' && !groups.deferral) {
155
+ malformedDeferrals.push({ id, line: lineNo });
156
+ warnings.push(`line ${lineNo}: task T${id} is deferred without a (deferred YYYY-MM-DD: reason) marker`);
157
+ continue;
158
+ }
159
+ if (state !== 'deferred' && groups.deferral) {
160
+ warnings.push(`line ${lineNo}: "${excerpt(line)}" — deferral marker on a ${state} task`);
161
+ continue;
162
+ }
163
+ for (const token of groups.unrecognized) {
164
+ warnings.push(`line ${lineNo}: task T${id} has an unrecognized trailing token "(${token})"`);
165
+ }
166
+ const task = {
167
+ id,
168
+ state,
169
+ title: groups.title,
170
+ acRefs: groups.acList ? parseAcRefs(groups.acList) : [],
171
+ line: lineNo,
172
+ ...(groups.deferral && {
173
+ deferReason: groups.deferral.reason,
174
+ deferDate: groups.deferral.date,
175
+ }),
176
+ };
177
+ const existing = byId.get(id);
178
+ if (existing) {
179
+ warnings.push(`duplicate T${id}: lines ${existing.line} and ${lineNo} (${existing.state === task.state
180
+ ? 'first occurrence wins'
181
+ : 'most-blocking state wins'})`);
182
+ if (BLOCK_RANK[task.state] < BLOCK_RANK[existing.state]) {
183
+ byId.set(id, task);
184
+ }
185
+ continue;
186
+ }
187
+ byId.set(id, task);
188
+ }
189
+ // Sequence gaps (AC-4), over parsed ids.
190
+ if (byId.size > 0) {
191
+ const maxId = Math.max(...byId.keys());
192
+ for (let n = 1; n <= maxId; n++) {
193
+ if (!byId.has(n))
194
+ warnings.push(`T${n} is never defined (sequence gap)`);
195
+ }
196
+ }
197
+ const tasks = [...byId.values()].sort((a, b) => a.id - b.id);
198
+ return { tasks, malformedDeferrals, warnings, taskShapedLines };
199
+ }
200
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/tasks/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Task summary for the `aidlc status` column (task-breakdown AC-21).
3
+ *
4
+ * One file read per task-bearing instance, no glob, no cache (NFR4/DD4 —
5
+ * unlike traceability, there is no repo scan to amortize). Phase visibility
6
+ * (design-or-later, with an implementation anchor for templates without a
7
+ * design phase, F3) is checked by the caller, matching the
8
+ * `isTestingOrLater` precedent.
9
+ */
10
+ import type { TasksSummary } from './types.js';
11
+ /**
12
+ * Read and summarize one instance's tasks.md.
13
+ *
14
+ * @returns null when the file is absent, unreadable, or defines no tasks —
15
+ * the column renders `-`.
16
+ */
17
+ export declare function tasksForStatus(projectRoot: string, instanceName: string): TasksSummary | null;
18
+ /** Format for the status table: `done/total`, plus ` ▸n` when deferred (AC-21). */
19
+ export declare function formatTasks(summary: TasksSummary): string;
20
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/tasks/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAc7F;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAGzD"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Task summary for the `aidlc status` column (task-breakdown AC-21).
3
+ *
4
+ * One file read per task-bearing instance, no glob, no cache (NFR4/DD4 —
5
+ * unlike traceability, there is no repo scan to amortize). Phase visibility
6
+ * (design-or-later, with an implementation anchor for templates without a
7
+ * design phase, F3) is checked by the caller, matching the
8
+ * `isTestingOrLater` precedent.
9
+ */
10
+ import { readFileSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { parseTasks } from './parser.js';
13
+ /**
14
+ * Read and summarize one instance's tasks.md.
15
+ *
16
+ * @returns null when the file is absent, unreadable, or defines no tasks —
17
+ * the column renders `-`.
18
+ */
19
+ export function tasksForStatus(projectRoot, instanceName) {
20
+ let content;
21
+ try {
22
+ content = readFileSync(join(projectRoot, '.aidlc', 'state', instanceName, 'tasks.md'), 'utf8');
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ const { tasks } = parseTasks(content);
28
+ if (tasks.length === 0)
29
+ return null;
30
+ return {
31
+ done: tasks.filter((t) => t.state === 'done').length,
32
+ deferred: tasks.filter((t) => t.state === 'deferred').length,
33
+ total: tasks.length,
34
+ };
35
+ }
36
+ /** Format for the status table: `done/total`, plus ` ▸n` when deferred (AC-21). */
37
+ export function formatTasks(summary) {
38
+ const base = `${summary.done}/${summary.total}`;
39
+ return summary.deferred > 0 ? `${base} ▸${summary.deferred}` : base;
40
+ }
41
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/tasks/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB,EAAE,YAAoB;IACtE,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;IACjG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,MAAM;QACpD,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,MAAM;QAC5D,KAAK,EAAE,KAAK,CAAC,MAAM;KACpB,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,WAAW,CAAC,OAAqB;IAC/C,MAAM,IAAI,GAAG,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAChD,OAAO,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACtE,CAAC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Tasks types: task lines parsed from tasks.md, the gate-criterion result
3
+ * exposed via `aidlc gate --json` (task-breakdown AC-19), and the status
4
+ * column summary (AC-21).
5
+ *
6
+ * Design: design.md (task-breakdown) §1
7
+ */
8
+ export type TaskState = 'open' | 'done' | 'deferred';
9
+ /** One AC reference in a task line's AC list. */
10
+ export interface TaskAcRef {
11
+ /** n in AC-n (≥1, no leading zeros). */
12
+ id: number;
13
+ /**
14
+ * Qualified instance name, or null for a bare token. Bare refs resolve to
15
+ * the owning instance (DD8) — never traceability's uniqueness rule.
16
+ */
17
+ instance: string | null;
18
+ }
19
+ /** A single task line parsed from tasks.md (FR1). */
20
+ export interface TaskLine {
21
+ /** n in T<n> (≥1, no leading zeros). */
22
+ id: number;
23
+ state: TaskState;
24
+ /** Non-empty title prose (empty titles are near-misses). */
25
+ title: string;
26
+ acRefs: TaskAcRef[];
27
+ /** Present iff state === 'deferred'. */
28
+ deferReason?: string;
29
+ /** YYYY-MM-DD, shape-validated only; present iff state === 'deferred'. */
30
+ deferDate?: string;
31
+ /** 1-based line number in tasks.md. */
32
+ line: number;
33
+ }
34
+ /** Parse result for one instance's tasks.md. */
35
+ export interface ParsedTasks {
36
+ /** Ordered by id (NFR3); most-blocking state wins on duplicates (AC-3). */
37
+ tasks: TaskLine[];
38
+ /**
39
+ * `[>]` lines without a well-formed deferral marker (AC-2) — these force
40
+ * the criterion unsatisfied, unlike ordinary near-misses. Only lines whose
41
+ * strict prefix (id included) parsed can land here; a `[>]` line with a
42
+ * broken prefix is an ordinary near-miss (AC-5).
43
+ */
44
+ malformedDeferrals: {
45
+ id: number;
46
+ line: number;
47
+ }[];
48
+ /** Duplicates, near-misses, sequence gaps — ordered by line (NFR3). */
49
+ warnings: string[];
50
+ /**
51
+ * Lines matching the loose task pattern (tasks + malformed + near-misses).
52
+ * Drives the applicability tri-state (DD7): 0 → criterion silent for
53
+ * opt-in instances; >0 with no tasks → warnings-only result.
54
+ */
55
+ taskShapedLines: number;
56
+ }
57
+ /** Per-task row of the gate JSON `tasks` field (AC-19). */
58
+ export interface TaskEntry {
59
+ id: number;
60
+ state: TaskState;
61
+ title: string;
62
+ /** Rendered as written: `AC-3` or `other-instance/AC-3`. */
63
+ acRefs: string[];
64
+ deferReason?: string;
65
+ }
66
+ /** Full tasks result attached to GateCheckResult (AC-19). */
67
+ export interface TasksResult {
68
+ /** Posix-separated, project-root-relative tasks.md path. */
69
+ tasksPath: string;
70
+ /** Sorted by id (NFR3). */
71
+ entries: TaskEntry[];
72
+ /** Ordered by line (NFR3). */
73
+ warnings: string[];
74
+ /** Open ([ ]) task ids — drive gate failure (AC-11). */
75
+ openTasks: number[];
76
+ /** Malformed-deferral task ids (AC-2) — also drive gate failure. */
77
+ malformed: number[];
78
+ /** Set when the AC-17 (file) / AC-28 (empty) backstop fails the gate. */
79
+ missing?: 'file' | 'empty';
80
+ }
81
+ /** Task summary for the `aidlc status` column (AC-21). */
82
+ export interface TasksSummary {
83
+ /** [x] count — deferred is NOT counted here. */
84
+ done: number;
85
+ /** [>] count, rendered as ` ▸n` when > 0. */
86
+ deferred: number;
87
+ /** All task lines, deferred included. */
88
+ total: number;
89
+ }
90
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAErD,iDAAiD;AACjD,MAAM,WAAW,SAAS;IACxB,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACvB,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,CAAC;IACjB,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB;;;;;OAKG;IACH,kBAAkB,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnD,uEAAuE;IACvE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,2DAA2D;AAC3D,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,wDAAwD;IACxD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oEAAoE;IACpE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B;AAED,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;CACf"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tasks types: task lines parsed from tasks.md, the gate-criterion result
3
+ * exposed via `aidlc gate --json` (task-breakdown AC-19), and the status
4
+ * column summary (AC-21).
5
+ *
6
+ * Design: design.md (task-breakdown) §1
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rasensio/aidlc",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "AI Development Lifecycle Framework — structured lifecycle guidance for AI coding agents across platforms",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
@@ -24,7 +24,7 @@
24
24
  "commander": "15.0.0",
25
25
  "picomatch": "4.0.5",
26
26
  "yaml": "2.9.0",
27
- "@rasensio/aidlc-content": "1.5.0"
27
+ "@rasensio/aidlc-content": "1.7.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "22.15.32",