openplanr 1.2.7 → 1.3.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 (164) hide show
  1. package/README.md +41 -4
  2. package/dist/agents/task-parser.d.ts.map +1 -1
  3. package/dist/agents/task-parser.js +8 -34
  4. package/dist/agents/task-parser.js.map +1 -1
  5. package/dist/ai/prompts/prompt-builder.d.ts +48 -0
  6. package/dist/ai/prompts/prompt-builder.d.ts.map +1 -1
  7. package/dist/ai/prompts/prompt-builder.js +57 -1
  8. package/dist/ai/prompts/prompt-builder.js.map +1 -1
  9. package/dist/ai/prompts/system-prompts.d.ts +24 -1
  10. package/dist/ai/prompts/system-prompts.d.ts.map +1 -1
  11. package/dist/ai/prompts/system-prompts.js +104 -6
  12. package/dist/ai/prompts/system-prompts.js.map +1 -1
  13. package/dist/ai/schemas/ai-response-schemas.d.ts +68 -0
  14. package/dist/ai/schemas/ai-response-schemas.d.ts.map +1 -1
  15. package/dist/ai/schemas/ai-response-schemas.js +81 -0
  16. package/dist/ai/schemas/ai-response-schemas.js.map +1 -1
  17. package/dist/ai/types.d.ts +2 -0
  18. package/dist/ai/types.d.ts.map +1 -1
  19. package/dist/ai/types.js +4 -0
  20. package/dist/ai/types.js.map +1 -1
  21. package/dist/cli/commands/backlog.d.ts +12 -0
  22. package/dist/cli/commands/backlog.d.ts.map +1 -1
  23. package/dist/cli/commands/backlog.js +88 -2
  24. package/dist/cli/commands/backlog.js.map +1 -1
  25. package/dist/cli/commands/config.d.ts.map +1 -1
  26. package/dist/cli/commands/config.js +8 -2
  27. package/dist/cli/commands/config.js.map +1 -1
  28. package/dist/cli/commands/linear.d.ts +8 -0
  29. package/dist/cli/commands/linear.d.ts.map +1 -0
  30. package/dist/cli/commands/linear.js +550 -0
  31. package/dist/cli/commands/linear.js.map +1 -0
  32. package/dist/cli/commands/quick.d.ts +17 -0
  33. package/dist/cli/commands/quick.d.ts.map +1 -1
  34. package/dist/cli/commands/quick.js +31 -15
  35. package/dist/cli/commands/quick.js.map +1 -1
  36. package/dist/cli/commands/revise.d.ts +24 -0
  37. package/dist/cli/commands/revise.d.ts.map +1 -0
  38. package/dist/cli/commands/revise.js +570 -0
  39. package/dist/cli/commands/revise.js.map +1 -0
  40. package/dist/cli/index.js +4 -0
  41. package/dist/cli/index.js.map +1 -1
  42. package/dist/models/schema.d.ts +43 -0
  43. package/dist/models/schema.d.ts.map +1 -1
  44. package/dist/models/schema.js +49 -0
  45. package/dist/models/schema.js.map +1 -1
  46. package/dist/models/types.d.ts +296 -0
  47. package/dist/models/types.d.ts.map +1 -1
  48. package/dist/services/artifact-gathering.d.ts +4 -0
  49. package/dist/services/artifact-gathering.d.ts.map +1 -1
  50. package/dist/services/artifact-gathering.js +1 -1
  51. package/dist/services/artifact-gathering.js.map +1 -1
  52. package/dist/services/artifact-service.d.ts +12 -1
  53. package/dist/services/artifact-service.d.ts.map +1 -1
  54. package/dist/services/artifact-service.js +49 -6
  55. package/dist/services/artifact-service.js.map +1 -1
  56. package/dist/services/atomic-write-service.d.ts +41 -0
  57. package/dist/services/atomic-write-service.d.ts.map +1 -0
  58. package/dist/services/atomic-write-service.js +87 -0
  59. package/dist/services/atomic-write-service.js.map +1 -0
  60. package/dist/services/audit-log-service.d.ts +47 -0
  61. package/dist/services/audit-log-service.d.ts.map +1 -0
  62. package/dist/services/audit-log-service.js +210 -0
  63. package/dist/services/audit-log-service.js.map +1 -0
  64. package/dist/services/cascade-service.d.ts +62 -0
  65. package/dist/services/cascade-service.d.ts.map +1 -0
  66. package/dist/services/cascade-service.js +189 -0
  67. package/dist/services/cascade-service.js.map +1 -0
  68. package/dist/services/credentials-service.js +2 -2
  69. package/dist/services/credentials-service.js.map +1 -1
  70. package/dist/services/diff-service.d.ts +18 -0
  71. package/dist/services/diff-service.d.ts.map +1 -0
  72. package/dist/services/diff-service.js +35 -0
  73. package/dist/services/diff-service.js.map +1 -0
  74. package/dist/services/evidence-verifier.d.ts +71 -0
  75. package/dist/services/evidence-verifier.d.ts.map +1 -0
  76. package/dist/services/evidence-verifier.js +174 -0
  77. package/dist/services/evidence-verifier.js.map +1 -0
  78. package/dist/services/git-service.d.ts +60 -0
  79. package/dist/services/git-service.d.ts.map +1 -0
  80. package/dist/services/git-service.js +137 -0
  81. package/dist/services/git-service.js.map +1 -0
  82. package/dist/services/graph-integrity.d.ts +35 -0
  83. package/dist/services/graph-integrity.d.ts.map +1 -0
  84. package/dist/services/graph-integrity.js +53 -0
  85. package/dist/services/graph-integrity.js.map +1 -0
  86. package/dist/services/linear/body-formatters.d.ts +69 -0
  87. package/dist/services/linear/body-formatters.d.ts.map +1 -0
  88. package/dist/services/linear/body-formatters.js +183 -0
  89. package/dist/services/linear/body-formatters.js.map +1 -0
  90. package/dist/services/linear/constants.d.ts +61 -0
  91. package/dist/services/linear/constants.d.ts.map +1 -0
  92. package/dist/services/linear/constants.js +84 -0
  93. package/dist/services/linear/constants.js.map +1 -0
  94. package/dist/services/linear/errors.d.ts +14 -0
  95. package/dist/services/linear/errors.d.ts.map +1 -0
  96. package/dist/services/linear/errors.js +106 -0
  97. package/dist/services/linear/errors.js.map +1 -0
  98. package/dist/services/linear/estimate-resolver.d.ts +50 -0
  99. package/dist/services/linear/estimate-resolver.d.ts.map +1 -0
  100. package/dist/services/linear/estimate-resolver.js +82 -0
  101. package/dist/services/linear/estimate-resolver.js.map +1 -0
  102. package/dist/services/linear/plan-builders.d.ts +64 -0
  103. package/dist/services/linear/plan-builders.d.ts.map +1 -0
  104. package/dist/services/linear/plan-builders.js +237 -0
  105. package/dist/services/linear/plan-builders.js.map +1 -0
  106. package/dist/services/linear/scope-loaders.d.ts +79 -0
  107. package/dist/services/linear/scope-loaders.d.ts.map +1 -0
  108. package/dist/services/linear/scope-loaders.js +227 -0
  109. package/dist/services/linear/scope-loaders.js.map +1 -0
  110. package/dist/services/linear/strategy-context.d.ts +66 -0
  111. package/dist/services/linear/strategy-context.d.ts.map +1 -0
  112. package/dist/services/linear/strategy-context.js +121 -0
  113. package/dist/services/linear/strategy-context.js.map +1 -0
  114. package/dist/services/linear-mapping-service.d.ts +11 -0
  115. package/dist/services/linear-mapping-service.d.ts.map +1 -0
  116. package/dist/services/linear-mapping-service.js +220 -0
  117. package/dist/services/linear-mapping-service.js.map +1 -0
  118. package/dist/services/linear-pull-service.d.ts +137 -0
  119. package/dist/services/linear-pull-service.d.ts.map +1 -0
  120. package/dist/services/linear-pull-service.js +720 -0
  121. package/dist/services/linear-pull-service.js.map +1 -0
  122. package/dist/services/linear-push-service.d.ts +86 -0
  123. package/dist/services/linear-push-service.d.ts.map +1 -0
  124. package/dist/services/linear-push-service.js +956 -0
  125. package/dist/services/linear-push-service.js.map +1 -0
  126. package/dist/services/linear-service.d.ts +122 -0
  127. package/dist/services/linear-service.d.ts.map +1 -0
  128. package/dist/services/linear-service.js +361 -0
  129. package/dist/services/linear-service.js.map +1 -0
  130. package/dist/services/prompt-service.d.ts +37 -0
  131. package/dist/services/prompt-service.d.ts.map +1 -1
  132. package/dist/services/prompt-service.js +111 -0
  133. package/dist/services/prompt-service.js.map +1 -1
  134. package/dist/services/revise-apply-service.d.ts +55 -0
  135. package/dist/services/revise-apply-service.d.ts.map +1 -0
  136. package/dist/services/revise-apply-service.js +255 -0
  137. package/dist/services/revise-apply-service.js.map +1 -0
  138. package/dist/services/revise-cache-service.d.ts +46 -0
  139. package/dist/services/revise-cache-service.d.ts.map +1 -0
  140. package/dist/services/revise-cache-service.js +88 -0
  141. package/dist/services/revise-cache-service.js.map +1 -0
  142. package/dist/services/revise-plan-service.d.ts +38 -0
  143. package/dist/services/revise-plan-service.d.ts.map +1 -0
  144. package/dist/services/revise-plan-service.js +151 -0
  145. package/dist/services/revise-plan-service.js.map +1 -0
  146. package/dist/services/revise-service.d.ts +115 -0
  147. package/dist/services/revise-service.d.ts.map +1 -0
  148. package/dist/services/revise-service.js +294 -0
  149. package/dist/services/revise-service.js.map +1 -0
  150. package/dist/services/template-sections.d.ts +28 -0
  151. package/dist/services/template-sections.d.ts.map +1 -0
  152. package/dist/services/template-sections.js +55 -0
  153. package/dist/services/template-sections.js.map +1 -0
  154. package/dist/templates/backlog/backlog-item.md.hbs +3 -0
  155. package/dist/templates/quick/quick-task.md.hbs +6 -0
  156. package/dist/utils/diff.d.ts +47 -0
  157. package/dist/utils/diff.d.ts.map +1 -0
  158. package/dist/utils/diff.js +278 -0
  159. package/dist/utils/diff.js.map +1 -0
  160. package/dist/utils/markdown.d.ts +23 -0
  161. package/dist/utils/markdown.d.ts.map +1 -1
  162. package/dist/utils/markdown.js +79 -0
  163. package/dist/utils/markdown.js.map +1 -1
  164. package/package.json +3 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-sections.d.ts","sourceRoot":"","sources":["../../src/services/template-sections.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA6BvD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAEtF"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Canonical section lists per artifact type.
3
+ *
4
+ * The revise prompt uses these to give the agent a *soft* conformance hint:
5
+ * "these are the sections a ${type} artifact canonically has — don't invent
6
+ * new ones; flag instead." This prevents the failure mode where the agent
7
+ * helpfully adds something like `## Relevant Files` to an epic (a task-level
8
+ * convention) when there is no drift justifying it.
9
+ *
10
+ * The lists mirror what the Handlebars templates in `src/templates/<type>/`
11
+ * actually emit. Kept hardcoded rather than parsed from the .hbs files at
12
+ * runtime because:
13
+ *
14
+ * 1. Handlebars templates contain `{{ }}` interpolation that would need
15
+ * stripping before we could grep `## ` headings.
16
+ * 2. If a template gains a new section, we want an explicit review step
17
+ * in this file, not silent pickup.
18
+ * 3. Parsing templates would couple revise to handlebars internals.
19
+ *
20
+ * When you add or rename a template section, update the matching entry here.
21
+ */
22
+ const CANONICAL_SECTIONS = {
23
+ epic: [
24
+ 'Business Value',
25
+ 'Target Users',
26
+ 'Problem Statement',
27
+ 'Solution Overview',
28
+ 'Success Criteria',
29
+ 'Key Features',
30
+ 'Dependencies',
31
+ 'Risks',
32
+ 'Features',
33
+ ],
34
+ feature: [
35
+ 'Overview',
36
+ 'Functional Requirements',
37
+ 'User Stories',
38
+ 'Dependencies',
39
+ 'Technical Considerations',
40
+ 'Risks',
41
+ 'Success Metrics',
42
+ ],
43
+ story: ['User Story', 'Acceptance Criteria', 'Additional Notes', 'Tasks'],
44
+ task: ['Artifact Sources', 'Tasks', 'Acceptance Criteria Mapping', 'Relevant Files', 'Notes'],
45
+ // `quick`, `backlog`, `sprint`, `adr`, `checklist` — no canonical list
46
+ // enforced. Revise will skip the template-structure hint for these types.
47
+ };
48
+ /**
49
+ * Return the canonical section list for an artifact type, or `undefined`
50
+ * when the type has no enforced convention (e.g., `backlog`).
51
+ */
52
+ export function getCanonicalSections(type) {
53
+ return CANONICAL_SECTIONS[type];
54
+ }
55
+ //# sourceMappingURL=template-sections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-sections.js","sourceRoot":"","sources":["../../src/services/template-sections.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,MAAM,kBAAkB,GAAqD;IAC3E,IAAI,EAAE;QACJ,gBAAgB;QAChB,cAAc;QACd,mBAAmB;QACnB,mBAAmB;QACnB,kBAAkB;QAClB,cAAc;QACd,cAAc;QACd,OAAO;QACP,UAAU;KACX;IACD,OAAO,EAAE;QACP,UAAU;QACV,yBAAyB;QACzB,cAAc;QACd,cAAc;QACd,0BAA0B;QAC1B,OAAO;QACP,iBAAiB;KAClB;IACD,KAAK,EAAE,CAAC,YAAY,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,OAAO,CAAC;IACzE,IAAI,EAAE,CAAC,kBAAkB,EAAE,OAAO,EAAE,6BAA6B,EAAE,gBAAgB,EAAE,OAAO,CAAC;IAC7F,uEAAuE;IACvE,0EAA0E;CAC3E,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAkB;IACrD,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC"}
@@ -6,6 +6,9 @@ tags: [{{#each tags}}"{{this}}"{{#unless @last}}, {{/unless}}{{/each}}]
6
6
  status: "open"
7
7
  created: "{{date}}"
8
8
  updated: "{{date}}"
9
+ {{#if epicId}}
10
+ epicId: "{{epicId}}"
11
+ {{/if}}
9
12
  ---
10
13
 
11
14
  # {{id}}: {{title}}
@@ -4,6 +4,12 @@ title: "{{title}}"
4
4
  created: "{{date}}"
5
5
  updated: "{{date}}"
6
6
  status: "pending"
7
+ {{#if epicId}}
8
+ epicId: "{{epicId}}"
9
+ {{/if}}
10
+ {{#if sourceBacklog}}
11
+ sourceBacklog: "{{sourceBacklog}}"
12
+ {{/if}}
7
13
  ---
8
14
 
9
15
  # {{id}}: {{title}}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Minimal line-based unified diff for revise preview.
3
+ *
4
+ * Implements a Wagner–Fischer LCS over lines, then prints hunks with
5
+ * `+` / `-` prefixes. Not a general-purpose diff tool — scoped to small
6
+ * planning artifacts (typically <1K lines), where O(m×n) time/memory is
7
+ * comfortable. Line equality is exact after trimming trailing newlines.
8
+ *
9
+ * We don't pull in an npm diff library because (a) the algorithm is small,
10
+ * (b) the format we emit is fixed and narrow, and (c) keeping the
11
+ * dependency footprint tight is a stated project preference.
12
+ */
13
+ export interface UnifiedDiffOptions {
14
+ /** Number of unchanged context lines around each change. Default: 3. */
15
+ context?: number;
16
+ /** Labels printed on the file-header `---` / `+++` rows. */
17
+ oldLabel?: string;
18
+ newLabel?: string;
19
+ }
20
+ /**
21
+ * Compute a unified diff between two strings. Empty string on either side
22
+ * is valid. Trailing newlines are normalized so a file that ends in `\n`
23
+ * does not spuriously diff against one that does not.
24
+ */
25
+ export declare function unifiedDiff(oldText: string, newText: string, options?: UnifiedDiffOptions): string;
26
+ export interface ApplyDiffResult {
27
+ ok: boolean;
28
+ /** New content when ok=true. */
29
+ result?: string;
30
+ /** Human-readable reason when ok=false (mismatched context, malformed hunk, etc.). */
31
+ error?: string;
32
+ /** Zero-based index of the first hunk that failed, when ok=false. */
33
+ failedHunkIndex?: number;
34
+ }
35
+ /**
36
+ * Apply a unified diff to source text. Strict: every hunk's context and
37
+ * removed lines must match the source exactly (after trailing-newline
38
+ * normalization) or the entire apply fails. No fuzzing. This matches what
39
+ * the revise replay path wants — "the diff we planned for is still valid"
40
+ * is a binary question.
41
+ *
42
+ * Accepts the same format our own `unifiedDiff` emits (standard unified
43
+ * with `---`/`+++` headers and `@@ -A,B +C,D @@` hunk markers) so a diff
44
+ * round-trips through this pair without surprises.
45
+ */
46
+ export declare function applyUnifiedDiff(source: string, diffText: string): ApplyDiffResult;
47
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/utils/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,kBAAuB,GAC/B,MAAM,CAsBR;AAuDD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CAiFlF"}
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Minimal line-based unified diff for revise preview.
3
+ *
4
+ * Implements a Wagner–Fischer LCS over lines, then prints hunks with
5
+ * `+` / `-` prefixes. Not a general-purpose diff tool — scoped to small
6
+ * planning artifacts (typically <1K lines), where O(m×n) time/memory is
7
+ * comfortable. Line equality is exact after trimming trailing newlines.
8
+ *
9
+ * We don't pull in an npm diff library because (a) the algorithm is small,
10
+ * (b) the format we emit is fixed and narrow, and (c) keeping the
11
+ * dependency footprint tight is a stated project preference.
12
+ */
13
+ /**
14
+ * Compute a unified diff between two strings. Empty string on either side
15
+ * is valid. Trailing newlines are normalized so a file that ends in `\n`
16
+ * does not spuriously diff against one that does not.
17
+ */
18
+ export function unifiedDiff(oldText, newText, options = {}) {
19
+ const contextLines = options.context ?? 3;
20
+ const oldLines = splitLines(oldText);
21
+ const newLines = splitLines(newText);
22
+ const items = lcsDiff(oldLines, newLines);
23
+ const hunks = buildHunks(items, contextLines);
24
+ if (hunks.length === 0)
25
+ return ''; // identical
26
+ const out = [];
27
+ out.push(`--- ${options.oldLabel ?? 'a'}`);
28
+ out.push(`+++ ${options.newLabel ?? 'b'}`);
29
+ for (const hunk of hunks) {
30
+ const oldLen = hunk.items.filter((i) => i.kind !== 'add').length;
31
+ const newLen = hunk.items.filter((i) => i.kind !== 'remove').length;
32
+ out.push(`@@ -${hunk.oldStart + 1},${oldLen} +${hunk.newStart + 1},${newLen} @@`);
33
+ for (const it of hunk.items) {
34
+ const prefix = it.kind === 'add' ? '+' : it.kind === 'remove' ? '-' : ' ';
35
+ out.push(`${prefix}${it.line}`);
36
+ }
37
+ }
38
+ return out.join('\n');
39
+ }
40
+ function splitLines(s) {
41
+ if (s.length === 0)
42
+ return [];
43
+ // Preserve empty-trailing-line behavior: drop a single trailing '' so the
44
+ // diff of "a\n" vs "a" is empty rather than noisy.
45
+ const lines = s.split('\n');
46
+ if (lines.length > 0 && lines[lines.length - 1] === '')
47
+ lines.pop();
48
+ return lines;
49
+ }
50
+ /**
51
+ * Build a sequence of DiffItems from two line arrays using LCS backtracking.
52
+ */
53
+ function lcsDiff(a, b) {
54
+ const m = a.length;
55
+ const n = b.length;
56
+ // dp[i][j] = length of LCS of a[0..i) and b[0..j)
57
+ const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
58
+ for (let i = 0; i < m; i++) {
59
+ for (let j = 0; j < n; j++) {
60
+ dp[i + 1][j + 1] = a[i] === b[j] ? dp[i][j] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
61
+ }
62
+ }
63
+ const items = [];
64
+ let i = m;
65
+ let j = n;
66
+ while (i > 0 && j > 0) {
67
+ if (a[i - 1] === b[j - 1]) {
68
+ items.push({ kind: 'same', line: a[i - 1] });
69
+ i--;
70
+ j--;
71
+ }
72
+ else if (dp[i - 1][j] >= dp[i][j - 1]) {
73
+ items.push({ kind: 'remove', line: a[i - 1] });
74
+ i--;
75
+ }
76
+ else {
77
+ items.push({ kind: 'add', line: b[j - 1] });
78
+ j--;
79
+ }
80
+ }
81
+ while (i > 0) {
82
+ items.push({ kind: 'remove', line: a[--i] });
83
+ }
84
+ while (j > 0) {
85
+ items.push({ kind: 'add', line: b[--j] });
86
+ }
87
+ items.reverse();
88
+ return items;
89
+ }
90
+ /**
91
+ * Apply a unified diff to source text. Strict: every hunk's context and
92
+ * removed lines must match the source exactly (after trailing-newline
93
+ * normalization) or the entire apply fails. No fuzzing. This matches what
94
+ * the revise replay path wants — "the diff we planned for is still valid"
95
+ * is a binary question.
96
+ *
97
+ * Accepts the same format our own `unifiedDiff` emits (standard unified
98
+ * with `---`/`+++` headers and `@@ -A,B +C,D @@` hunk markers) so a diff
99
+ * round-trips through this pair without surprises.
100
+ */
101
+ export function applyUnifiedDiff(source, diffText) {
102
+ const sourceLines = splitLines(source);
103
+ const hunks = parseHunks(diffText);
104
+ if (hunks === null) {
105
+ return { ok: false, error: 'malformed diff (could not locate any @@ hunk header)' };
106
+ }
107
+ // Build the result line-by-line, walking source with a cursor and
108
+ // replacing chunks that fall inside each hunk.
109
+ const out = [];
110
+ let cursor = 0; // 0-based position in sourceLines
111
+ for (let h = 0; h < hunks.length; h++) {
112
+ const hunk = hunks[h];
113
+ const hunkStart = hunk.oldStart - 1; // diff hunks are 1-based
114
+ if (hunkStart < cursor) {
115
+ return {
116
+ ok: false,
117
+ error: `hunk ${h + 1} (@@ -${hunk.oldStart},${hunk.oldLen}) overlaps or precedes previous hunk`,
118
+ failedHunkIndex: h,
119
+ };
120
+ }
121
+ if (hunkStart > sourceLines.length) {
122
+ return {
123
+ ok: false,
124
+ error: `hunk ${h + 1} starts at line ${hunk.oldStart} but source has only ${sourceLines.length} lines`,
125
+ failedHunkIndex: h,
126
+ };
127
+ }
128
+ // Emit unchanged source lines up to the hunk start.
129
+ while (cursor < hunkStart) {
130
+ out.push(sourceLines[cursor++]);
131
+ }
132
+ // Walk the hunk body. Verify every context and removed line matches
133
+ // the corresponding source line; emit context + added lines into out.
134
+ for (const item of hunk.items) {
135
+ if (item.kind === 'same') {
136
+ if (sourceLines[cursor] !== item.line) {
137
+ return {
138
+ ok: false,
139
+ error: `hunk ${h + 1} context mismatch at source line ${cursor + 1}: expected "${item.line}" but found "${sourceLines[cursor] ?? '<eof>'}"`,
140
+ failedHunkIndex: h,
141
+ };
142
+ }
143
+ out.push(item.line);
144
+ cursor++;
145
+ }
146
+ else if (item.kind === 'remove') {
147
+ if (sourceLines[cursor] !== item.line) {
148
+ return {
149
+ ok: false,
150
+ error: `hunk ${h + 1} removal mismatch at source line ${cursor + 1}: expected "${item.line}" but found "${sourceLines[cursor] ?? '<eof>'}"`,
151
+ failedHunkIndex: h,
152
+ };
153
+ }
154
+ cursor++; // skip the removed source line
155
+ }
156
+ else {
157
+ // 'add' — contribute to the new stream without advancing cursor
158
+ out.push(item.line);
159
+ }
160
+ }
161
+ }
162
+ // Emit any remaining unchanged source lines after the last hunk.
163
+ while (cursor < sourceLines.length) {
164
+ out.push(sourceLines[cursor++]);
165
+ }
166
+ // Our unified-diff emitter does not carry the "\ No newline at end of
167
+ // file" marker, so we can't distinguish "result ends with \n" from
168
+ // "result does not" when only the diff and source are in hand. We pick
169
+ // a rule that's safe for the workload we actually serve — revise
170
+ // writes markdown artifacts, which conventionally end with a trailing
171
+ // newline. Policy: empty result stays empty; non-empty result always
172
+ // ends with a single trailing newline.
173
+ const joined = out.join('\n');
174
+ if (joined.length === 0)
175
+ return { ok: true, result: '' };
176
+ return { ok: true, result: `${joined}\n` };
177
+ }
178
+ /** Parse unified-diff text into hunks. Returns null when no hunk header is found. */
179
+ function parseHunks(diffText) {
180
+ const lines = diffText.split('\n');
181
+ const hunks = [];
182
+ const hunkHeaderRe = /^@@\s+-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s+@@/;
183
+ let current = null;
184
+ for (const line of lines) {
185
+ // Skip file headers; they are informational, not part of any hunk.
186
+ if (line.startsWith('---') || line.startsWith('+++'))
187
+ continue;
188
+ const header = hunkHeaderRe.exec(line);
189
+ if (header) {
190
+ if (current)
191
+ hunks.push(current);
192
+ current = {
193
+ oldStart: Number(header[1]),
194
+ oldLen: header[2] === undefined ? 1 : Number(header[2]),
195
+ newStart: Number(header[3]),
196
+ newLen: header[4] === undefined ? 1 : Number(header[4]),
197
+ items: [],
198
+ };
199
+ continue;
200
+ }
201
+ if (!current)
202
+ continue; // lines before the first header are ignored
203
+ if (line.length === 0) {
204
+ // An empty line inside a hunk represents a blank context line. The
205
+ // leading-space prefix gets stripped by some tools / MD code-fences,
206
+ // so we tolerate bare empty lines and treat them as context.
207
+ current.items.push({ kind: 'same', line: '' });
208
+ continue;
209
+ }
210
+ const prefix = line[0];
211
+ const body = line.slice(1);
212
+ if (prefix === ' ')
213
+ current.items.push({ kind: 'same', line: body });
214
+ else if (prefix === '+')
215
+ current.items.push({ kind: 'add', line: body });
216
+ else if (prefix === '-')
217
+ current.items.push({ kind: 'remove', line: body });
218
+ // Any other prefix (e.g., '\\' for "") is
219
+ // ignored; we don't round-trip that marker.
220
+ }
221
+ if (current)
222
+ hunks.push(current);
223
+ return hunks.length > 0 ? hunks : null;
224
+ }
225
+ /** Group items into hunks that include `context` unchanged lines around each change. */
226
+ function buildHunks(items, context) {
227
+ const hunks = [];
228
+ let oldIdx = 0;
229
+ let newIdx = 0;
230
+ // First pass: mark index of every item in old/new streams
231
+ const marks = items.map((it) => {
232
+ const m = { item: it, oldIdx, newIdx };
233
+ if (it.kind !== 'add')
234
+ oldIdx++;
235
+ if (it.kind !== 'remove')
236
+ newIdx++;
237
+ return m;
238
+ });
239
+ let i = 0;
240
+ while (i < marks.length) {
241
+ if (marks[i].item.kind === 'same') {
242
+ i++;
243
+ continue;
244
+ }
245
+ // Change region: expand left by `context`, then run forward including
246
+ // intermediate small same-runs (≤ 2*context apart → merge).
247
+ const start = Math.max(0, i - context);
248
+ let end = i;
249
+ while (end < marks.length) {
250
+ if (marks[end].item.kind !== 'same') {
251
+ end++;
252
+ continue;
253
+ }
254
+ // Look ahead: is the next change within 2*context?
255
+ let sameRun = 0;
256
+ let k = end;
257
+ while (k < marks.length && marks[k].item.kind === 'same') {
258
+ sameRun++;
259
+ k++;
260
+ }
261
+ if (k >= marks.length || sameRun > 2 * context) {
262
+ // Close the hunk after `context` trailing same-lines.
263
+ end += Math.min(context, sameRun);
264
+ break;
265
+ }
266
+ end = k;
267
+ }
268
+ const slice = marks.slice(start, Math.min(end, marks.length));
269
+ hunks.push({
270
+ oldStart: marks[start].oldIdx,
271
+ newStart: marks[start].newIdx,
272
+ items: slice.map((s) => s.item),
273
+ });
274
+ i = end;
275
+ }
276
+ return hunks;
277
+ }
278
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/utils/diff.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,31 @@
1
1
  import type { ArtifactFrontmatter } from '../models/types.js';
2
+ /** A single line from an OpenPlanr/Linear task list (`- [x] **1.0** ...`). */
3
+ export interface TaskCheckboxLine {
4
+ id: string;
5
+ title: string;
6
+ done: boolean;
7
+ parentId: string | null;
8
+ depth: number;
9
+ lineIndex: number;
10
+ /** The full text of the line (including leading whitespace). */
11
+ lineText: string;
12
+ }
2
13
  export interface ParsedMarkdown {
3
14
  data: ArtifactFrontmatter;
4
15
  content: string;
5
16
  }
6
17
  export declare function parseMarkdown(raw: string): ParsedMarkdown;
7
18
  export declare function toMarkdownWithFrontmatter(data: ArtifactFrontmatter, content: string): string;
19
+ /**
20
+ * Parse OpenPlanr task list checkbox lines (same format as `parseTaskMarkdown` in `task-parser.ts`).
21
+ * Exposes 0-based `lineIndex` (the array index into `content.split('\n')`).
22
+ */
23
+ export declare function parseTaskCheckboxLines(content: string): TaskCheckboxLine[];
24
+ /** Serialize a reconciled id→done map: `1.0:1,1.1:0,2.0:1` (ids sorted with numeric sort). */
25
+ export declare function serializeTaskCheckboxReconciled(m: ReadonlyMap<string, boolean> | Readonly<Record<string, boolean>>): string;
26
+ export declare function parseTaskCheckboxReconciled(s: string | undefined): Map<string, boolean>;
27
+ /**
28
+ * Apply new done states to matching `N.M` task lines; preserves non-matching lines and all other text.
29
+ */
30
+ export declare function applyTaskCheckboxStateMap(content: string, idToDone: ReadonlyMap<string, boolean>): string;
8
31
  //# sourceMappingURL=markdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/utils/markdown.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAWzD;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAG5F"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/utils/markdown.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAWzD;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAG5F;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAgC1E;AAID,8FAA8F;AAC9F,wBAAgB,+BAA+B,CAC7C,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAClE,MAAM,CAOR;AAED,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAUvF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,MAAM,CAaR"}
@@ -14,4 +14,83 @@ export function toMarkdownWithFrontmatter(data, content) {
14
14
  const yamlStr = YAML.stringify(data).trimEnd();
15
15
  return `---\n${yamlStr}\n---\n${content}`;
16
16
  }
17
+ /**
18
+ * Parse OpenPlanr task list checkbox lines (same format as `parseTaskMarkdown` in `task-parser.ts`).
19
+ * Exposes 0-based `lineIndex` (the array index into `content.split('\n')`).
20
+ */
21
+ export function parseTaskCheckboxLines(content) {
22
+ const lines = content.split('\n');
23
+ const tasks = [];
24
+ let currentGroupId = null;
25
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
26
+ const line = lines[lineIndex];
27
+ if (line === undefined) {
28
+ continue;
29
+ }
30
+ const match = line.match(/^(\s*)- \[(x| )]\s+\*{0,2}(\d+\.\d+)\*{0,2}\s+(.+)$/);
31
+ if (!match)
32
+ continue;
33
+ const indent = match[1].length;
34
+ const done = match[2] === 'x';
35
+ const id = match[3];
36
+ const title = match[4].trim();
37
+ const depth = indent > 0 ? 1 : 0;
38
+ if (depth === 0) {
39
+ currentGroupId = id;
40
+ }
41
+ tasks.push({
42
+ id,
43
+ title,
44
+ done,
45
+ parentId: depth === 0 ? null : currentGroupId,
46
+ depth,
47
+ lineIndex,
48
+ lineText: line,
49
+ });
50
+ }
51
+ return tasks;
52
+ }
53
+ const RECONCILED_PART = /^\d+\.\d+:[01]$/;
54
+ /** Serialize a reconciled id→done map: `1.0:1,1.1:0,2.0:1` (ids sorted with numeric sort). */
55
+ export function serializeTaskCheckboxReconciled(m) {
56
+ const entries = m instanceof Map ? [...m.entries()] : Object.entries(m);
57
+ return entries
58
+ .filter(([k, v]) => typeof v === 'boolean' && k.includes('.'))
59
+ .sort((a, b) => a[0].localeCompare(b[0], undefined, { numeric: true }))
60
+ .map(([k, v]) => `${k}:${v ? 1 : 0}`)
61
+ .join(',');
62
+ }
63
+ export function parseTaskCheckboxReconciled(s) {
64
+ const m = new Map();
65
+ if (!s?.trim())
66
+ return m;
67
+ for (const part of s.split(/[,;]/)) {
68
+ const p = part.trim();
69
+ if (!p || !RECONCILED_PART.test(p))
70
+ continue;
71
+ const [id, b] = p.split(':');
72
+ m.set(id, b === '1');
73
+ }
74
+ return m;
75
+ }
76
+ /**
77
+ * Apply new done states to matching `N.M` task lines; preserves non-matching lines and all other text.
78
+ */
79
+ export function applyTaskCheckboxStateMap(content, idToDone) {
80
+ if (idToDone.size === 0)
81
+ return content;
82
+ return content
83
+ .split('\n')
84
+ .map((line) => {
85
+ const m2 = line.match(/^(\s*)- \[(x| )]\s+\*{0,2}(\d+\.\d+)\*{0,2}\s+(.+)$/);
86
+ if (!m2)
87
+ return line;
88
+ const id = m2[3];
89
+ if (!idToDone.has(id))
90
+ return line;
91
+ const want = idToDone.get(id) ? 'x' : ' ';
92
+ return line.replace(/- \[(x| )]/, `- [${want}]`);
93
+ })
94
+ .join('\n');
95
+ }
17
96
  //# sourceMappingURL=markdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/utils/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAQxB,MAAM,iBAAiB,GAAG,iEAAiE,CAAC;AAE5F,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,IAAI,EAAE,EAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAC3D,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAEzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACvC,OAAO,EAAE,IAAI,EAAE,IAA2B,EAAE,OAAO,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,IAAyB,EAAE,OAAe;IAClF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;IAC/C,OAAO,QAAQ,OAAO,UAAU,OAAO,EAAE,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/utils/markdown.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openplanr",
3
- "version": "1.2.7",
4
- "description": "AI-powered planning CLI — backlog, sprints, task templates, estimation, GitHub sync, and AI agent rules for Cursor, Claude Code, and Codex",
3
+ "version": "1.3.0",
4
+ "description": "AI-powered planning CLI — backlog, sprints, task templates, estimation, GitHub and Linear sync, and AI agent rules for Cursor, Claude Code, and Codex",
5
5
  "type": "module",
6
6
  "main": "./dist/cli/index.js",
7
7
  "types": "./dist/cli/index.d.ts",
@@ -73,6 +73,7 @@
73
73
  "dependencies": {
74
74
  "@anthropic-ai/sdk": "^0.81.0",
75
75
  "@inquirer/prompts": "^8.3.2",
76
+ "@linear/sdk": "^65.2.0",
76
77
  "@napi-rs/keyring": "^1.2.0",
77
78
  "chalk": "^5.3.0",
78
79
  "commander": "^14.0.3",