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,84 @@
1
+ /**
2
+ * Linear integration constants + id-shape validators + input-safety helpers.
3
+ *
4
+ * All field-limit values here are enforced at the SDK-wrapper layer in
5
+ * `src/services/linear-service.ts` so that every caller gets the guard for
6
+ * free. Shape validators (`isLikelyLinear*Id`) fence off stale frontmatter
7
+ * before it reaches the Linear API.
8
+ */
9
+ import { logger } from '../../utils/logger.js';
10
+ /** Credential-service provider key under which the Linear PAT is stored. */
11
+ export const LINEAR_CREDENTIAL_KEY = 'linear';
12
+ /**
13
+ * Linear's backend enforces per-field length limits on every create/update
14
+ * mutation. Defend at the SDK-wrapper layer so callers don't have to think
15
+ * about them. Names / titles: confirmed or best-known caps; descriptions:
16
+ * conservative floors well under Linear's real ceilings (markdown + HTML
17
+ * are both accepted; real limits are in the tens of thousands).
18
+ */
19
+ export const LINEAR_FIELD_LIMITS = {
20
+ /** ProjectMilestone.name — confirmed 80 by `Argument Validation Error`. */
21
+ milestoneName: 80,
22
+ /** IssueLabel.name — Linear team labels cap ~64 chars. */
23
+ labelName: 64,
24
+ /** Project.name — generous cap. */
25
+ projectName: 256,
26
+ /** Issue.title — Linear issue title cap ~255. */
27
+ issueTitle: 255,
28
+ /** Project.description — conservative floor; real Linear ceiling is higher. */
29
+ projectDescription: 50_000,
30
+ /** ProjectMilestone.description. */
31
+ milestoneDescription: 50_000,
32
+ /** IssueLabel.description — labels rarely need long descriptions. */
33
+ labelDescription: 500,
34
+ /** Issue.description (markdown body). */
35
+ issueDescription: 65_000,
36
+ };
37
+ /**
38
+ * Truncate a string to Linear's character limit for a given field. Logs a
39
+ * warning on truncation so the operator can spot it in the push output.
40
+ */
41
+ export function truncateForLinear(value, maxLen, fieldLabel) {
42
+ const trimmed = value.trim();
43
+ if (trimmed.length <= maxLen)
44
+ return trimmed;
45
+ const truncated = trimmed.slice(0, maxLen);
46
+ logger.warn(`${fieldLabel} truncated from ${trimmed.length} → ${maxLen} chars to satisfy Linear's limit.`);
47
+ return truncated;
48
+ }
49
+ /**
50
+ * Non-empty guard for required Linear name/title fields. Fails fast with an
51
+ * actionable message before the API would reject the call.
52
+ */
53
+ export function requireNonEmpty(value, fieldLabel) {
54
+ const trimmed = typeof value === 'string' ? value.trim() : '';
55
+ if (!trimmed) {
56
+ throw new Error(`${fieldLabel} is empty — Linear requires a non-empty value. Add a title to the OpenPlanr artifact and re-run.`);
57
+ }
58
+ return trimmed;
59
+ }
60
+ /**
61
+ * Heuristic: Linear workflow state id (uuid) vs human-readable state name.
62
+ * The `/i` flag is intentional — Linear's API canonicalizes UUIDs to
63
+ * lowercase, but defensive acceptance of uppercase hex matches RFC 4122
64
+ * and protects against tools that normalize differently.
65
+ */
66
+ export function isLikelyLinearWorkflowStateId(s) {
67
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(s.trim());
68
+ }
69
+ /**
70
+ * Validate that a value plausibly identifies a Linear issue. Two valid shapes:
71
+ * 1. UUIDv4 (e.g. `9b2f4c3e-...`) — canonical API form
72
+ * 2. Linear identifier (e.g. `ENG-42`) — human-readable, also accepted by `client.issue()`
73
+ * Anything else is treated as stale/corrupted frontmatter and skipped before
74
+ * hitting the API.
75
+ */
76
+ export function isLikelyLinearIssueId(s) {
77
+ const trimmed = s.trim();
78
+ if (trimmed.length === 0)
79
+ return false;
80
+ if (isLikelyLinearWorkflowStateId(trimmed))
81
+ return true;
82
+ return /^[A-Z]{2,}-\d+$/.test(trimmed);
83
+ }
84
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/services/linear/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE/C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAiB,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,2EAA2E;IAC3E,aAAa,EAAE,EAAE;IACjB,0DAA0D;IAC1D,SAAS,EAAE,EAAE;IACb,mCAAmC;IACnC,WAAW,EAAE,GAAG;IAChB,iDAAiD;IACjD,UAAU,EAAE,GAAG;IACf,+EAA+E;IAC/E,kBAAkB,EAAE,MAAM;IAC1B,oCAAoC;IACpC,oBAAoB,EAAE,MAAM;IAC5B,qEAAqE;IACrE,gBAAgB,EAAE,GAAG;IACrB,yCAAyC;IACzC,gBAAgB,EAAE,MAAM;CAChB,CAAC;AAEX;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,MAAc,EAAE,UAAkB;IACjF,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,OAAO,CAAC;IAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,CAAC,IAAI,CACT,GAAG,UAAU,mBAAmB,OAAO,CAAC,MAAM,MAAM,MAAM,mCAAmC,CAC9F,CAAC;IACF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAgC,EAAE,UAAkB;IAClF,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,kGAAkG,CAChH,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,CAAS;IACrD,OAAO,4EAA4E,CAAC,IAAI,CACtF,CAAC,CAAC,IAAI,EAAE,CACT,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,CAAS;IAC7C,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACzB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,6BAA6B,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,OAAO,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Linear error classification, user-facing mapping, and retry wrapper.
3
+ *
4
+ * Two responsibilities:
5
+ * 1. Map raw SDK errors to user-friendly messages (branded guidance for
6
+ * auth / network / rate-limit; surfaced friendly SDK message for other
7
+ * classified types; sanitized fallback for unclassified errors).
8
+ * 2. Wrap Linear calls with small exponential backoff that honours
9
+ * `RatelimitedLinearError.retryAfter`.
10
+ */
11
+ /** Wraps a Linear call with small exponential backoff on rate limit / network errors. */
12
+ export declare function withLinearRetry<T>(op: string, fn: () => Promise<T>, retries?: number): Promise<T>;
13
+ export declare function mapLinearError(err: unknown, context: string): Error;
14
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/services/linear/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAgCH,yFAAyF;AACzF,wBAAsB,eAAe,CAAC,CAAC,EACrC,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,MAAwB,GAChC,OAAO,CAAC,CAAC,CAAC,CA4BZ;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CA6CnE"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Linear error classification, user-facing mapping, and retry wrapper.
3
+ *
4
+ * Two responsibilities:
5
+ * 1. Map raw SDK errors to user-friendly messages (branded guidance for
6
+ * auth / network / rate-limit; surfaced friendly SDK message for other
7
+ * classified types; sanitized fallback for unclassified errors).
8
+ * 2. Wrap Linear calls with small exponential backoff that honours
9
+ * `RatelimitedLinearError.retryAfter`.
10
+ */
11
+ import { LinearError, LinearErrorType, RatelimitedLinearError } from '@linear/sdk';
12
+ import { logger } from '../../utils/logger.js';
13
+ const DEFAULT_RETRIES = 3;
14
+ /**
15
+ * Extract the first user-facing message from a LinearError. The SDK exposes
16
+ * per-GraphQL-error `.message` strings on `errors[]` — these are backend-
17
+ * authored user descriptions (e.g., "Milestone already exists with this
18
+ * name"). Falls back to `err.message` and finally to the error `type`.
19
+ * Safe to surface — this is not the raw query/variables.
20
+ */
21
+ function extractLinearFriendlyMessage(err) {
22
+ const first = err.errors?.[0]?.message?.trim();
23
+ if (first)
24
+ return first;
25
+ const top = err.message?.trim();
26
+ if (top)
27
+ return top;
28
+ const type = err.type;
29
+ return type || undefined;
30
+ }
31
+ function isRetriableLinearError(err) {
32
+ if (err instanceof LinearError) {
33
+ const t = err.type ?? LinearErrorType.Unknown;
34
+ return t === LinearErrorType.Ratelimited || t === LinearErrorType.NetworkError;
35
+ }
36
+ if (err instanceof Error && err.name === 'AbortError')
37
+ return true;
38
+ return false;
39
+ }
40
+ /** Wraps a Linear call with small exponential backoff on rate limit / network errors. */
41
+ export async function withLinearRetry(op, fn, retries = DEFAULT_RETRIES) {
42
+ let last;
43
+ for (let attempt = 0; attempt <= retries; attempt++) {
44
+ try {
45
+ return await fn();
46
+ }
47
+ catch (err) {
48
+ last = err;
49
+ if (attempt < retries && isRetriableLinearError(err)) {
50
+ // Prefer Linear's own `Retry-After` when the error is a rate-limit
51
+ // (surfaced on the `RatelimitedLinearError` subclass as a seconds
52
+ // value). Fall back to exponential backoff for network errors and
53
+ // when the server didn't advertise a retry hint. Use `Math.max` so
54
+ // we respect both: never retry sooner than Linear asked, never
55
+ // faster than our own backoff schedule.
56
+ const retryAfterMs = err instanceof RatelimitedLinearError && typeof err.retryAfter === 'number'
57
+ ? Math.max(0, err.retryAfter) * 1000
58
+ : 0;
59
+ const backoffMs = Math.min(30_000, 500 * 2 ** attempt);
60
+ const waitMs = Math.max(retryAfterMs, backoffMs);
61
+ logger.dim(`Linear ${op}: retrying in ${waitMs}ms (attempt ${attempt + 1}/${retries})...`);
62
+ await new Promise((r) => setTimeout(r, waitMs));
63
+ continue;
64
+ }
65
+ throw mapLinearError(err, op);
66
+ }
67
+ }
68
+ throw mapLinearError(last, op);
69
+ }
70
+ export function mapLinearError(err, context) {
71
+ if (err instanceof Error && err.name === 'AbortError') {
72
+ return new Error(`Network error while ${context}: request was cancelled or timed out.`);
73
+ }
74
+ if (err instanceof LinearError) {
75
+ const t = err.type ?? LinearErrorType.Unknown;
76
+ if (t === LinearErrorType.AuthenticationError) {
77
+ return new Error(`Linear rejected this token while ${context}. Create a new PAT at https://linear.app/settings/account/security (app, read, write as needed) and run \`planr linear init\` again.`);
78
+ }
79
+ if (t === LinearErrorType.NetworkError) {
80
+ return new Error(`Cannot reach Linear while ${context}. Check your network connection, try again, and see https://status.linear.app for outages.`);
81
+ }
82
+ if (t === LinearErrorType.Ratelimited) {
83
+ return new Error('Linear rate limit reached. Wait about 1–2 minutes (longer if you are polling heavily), then retry. See https://status.linear.app if issues persist.');
84
+ }
85
+ // For other classified LinearError types (Forbidden, InvalidInput, UserError,
86
+ // FeatureNotAccessible, Internal, LockTimeout, UsageLimitExceeded, Graphql,
87
+ // Other, Bootstrap, Unknown) surface the SDK's friendly .message string —
88
+ // backend-authored user descriptions like "Milestone name already exists
89
+ // in project" or "Input invalid: projectId". Also log the full object at
90
+ // debug level for --verbose diagnostics.
91
+ logger.debug(`Linear error (${context}, type=${t})`, err);
92
+ const friendly = extractLinearFriendlyMessage(err);
93
+ const suffix = friendly ? `: ${friendly}` : '';
94
+ if (t === LinearErrorType.Forbidden) {
95
+ return new Error(`Permission denied while ${context}${suffix}. Your token may be missing the required scope, or your user cannot access this resource.`);
96
+ }
97
+ return new Error(`Linear error while ${context} (${t})${suffix}`);
98
+ }
99
+ // Unknown / unclassified error class: log the full object at debug level so
100
+ // operators can inspect it with `--verbose`, but do NOT surface the raw
101
+ // message to end users — could contain arbitrary response bodies.
102
+ logger.debug(`Linear error (${context})`, err);
103
+ const klass = err instanceof Error ? err.constructor.name : 'Unknown';
104
+ return new Error(`Linear error while ${context} (${klass}). Re-run with --verbose for diagnostic details.`);
105
+ }
106
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/services/linear/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE/C,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B;;;;;;GAMG;AACH,SAAS,4BAA4B,CAAC,GAAgB;IACpD,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;IAChC,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IACpB,MAAM,IAAI,GAAI,GAAyB,CAAC,IAAI,CAAC;IAC7C,OAAO,IAAI,IAAI,SAAS,CAAC;AAC3B,CAAC;AAED,SAAS,sBAAsB,CAAC,GAAY;IAC1C,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAI,GAAyB,CAAC,IAAI,IAAI,eAAe,CAAC,OAAO,CAAC;QACrE,OAAO,CAAC,KAAK,eAAe,CAAC,WAAW,IAAI,CAAC,KAAK,eAAe,CAAC,YAAY,CAAC;IACjF,CAAC;IACD,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IACnE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,EAAU,EACV,EAAoB,EACpB,UAAkB,eAAe;IAEjC,IAAI,IAAa,CAAC;IAClB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,GAAG,CAAC;YACX,IAAI,OAAO,GAAG,OAAO,IAAI,sBAAsB,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrD,mEAAmE;gBACnE,kEAAkE;gBAClE,kEAAkE;gBAClE,mEAAmE;gBACnE,+DAA+D;gBAC/D,wCAAwC;gBACxC,MAAM,YAAY,GAChB,GAAG,YAAY,sBAAsB,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ;oBACzE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI;oBACpC,CAAC,CAAC,CAAC,CAAC;gBACR,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC;gBACvD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;gBACjD,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,iBAAiB,MAAM,eAAe,OAAO,GAAG,CAAC,IAAI,OAAO,MAAM,CAAC,CAAC;gBAC3F,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;gBAChD,SAAS;YACX,CAAC;YACD,MAAM,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,MAAM,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAY,EAAE,OAAe;IAC1D,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACtD,OAAO,IAAI,KAAK,CAAC,uBAAuB,OAAO,uCAAuC,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAI,GAAyB,CAAC,IAAI,IAAI,eAAe,CAAC,OAAO,CAAC;QACrE,IAAI,CAAC,KAAK,eAAe,CAAC,mBAAmB,EAAE,CAAC;YAC9C,OAAO,IAAI,KAAK,CACd,oCAAoC,OAAO,sIAAsI,CAClL,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,KAAK,eAAe,CAAC,YAAY,EAAE,CAAC;YACvC,OAAO,IAAI,KAAK,CACd,6BAA6B,OAAO,4FAA4F,CACjI,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,KAAK,eAAe,CAAC,WAAW,EAAE,CAAC;YACtC,OAAO,IAAI,KAAK,CACd,qJAAqJ,CACtJ,CAAC;QACJ,CAAC;QACD,8EAA8E;QAC9E,4EAA4E;QAC5E,0EAA0E;QAC1E,yEAAyE;QACzE,yEAAyE;QACzE,yCAAyC;QACzC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,4BAA4B,CAAC,GAAG,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,IAAI,CAAC,KAAK,eAAe,CAAC,SAAS,EAAE,CAAC;YACpC,OAAO,IAAI,KAAK,CACd,2BAA2B,OAAO,GAAG,MAAM,2FAA2F,CACvI,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,KAAK,CAAC,sBAAsB,OAAO,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,4EAA4E;IAC5E,wEAAwE;IACxE,kEAAkE;IAClE,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,GAAG,EAAE,GAAG,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,OAAO,IAAI,KAAK,CACd,sBAAsB,OAAO,KAAK,KAAK,kDAAkD,CAC1F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Scale-aware snapping from OpenPlanr `storyPoints` → Linear `estimate` field.
3
+ *
4
+ * Linear's estimate field is numeric and must match the team's configured
5
+ * scale (`fibonacci`, `linear`, `exponential`, or `tShirt`). A value that
6
+ * isn't on the scale is rejected by the API, so we snap to the nearest
7
+ * allowed value before sending. Callers use the returned snap event to emit
8
+ * a debug log once per transformation.
9
+ *
10
+ * Scales mirror Linear's own SDK values — see `LinearIssueEstimationType`
11
+ * in `src/models/types.ts`.
12
+ */
13
+ import type { LinearIssueEstimationType } from '../../models/types.js';
14
+ /**
15
+ * Result of resolving a local estimate for a push. Exactly one of
16
+ * `estimate` (mapped value, ready to send to Linear) or `reason` (why the
17
+ * field is being omitted) is populated.
18
+ */
19
+ export type EstimateResolution = {
20
+ kind: 'mapped';
21
+ estimate: number;
22
+ originalValue: number;
23
+ snapped: boolean;
24
+ } | {
25
+ kind: 'skip-not-used';
26
+ } | {
27
+ kind: 'skip-t-shirt';
28
+ } | {
29
+ kind: 'skip-no-local-value';
30
+ } | {
31
+ kind: 'skip-invalid-value';
32
+ rawValue: unknown;
33
+ };
34
+ /**
35
+ * Resolve a local `storyPoints` (or `estimatedPoints`) value to a Linear
36
+ * `estimate` value given the team's scale.
37
+ *
38
+ * Precedence for the raw local value:
39
+ * 1. `frontmatter.estimatedPoints` — canonical name written by
40
+ * `planr estimate --save` (see `src/cli/commands/estimate.ts`).
41
+ * 2. `frontmatter.storyPoints` — alias accepted for hand-edited files or
42
+ * direct AI-response copies that used the schema field name verbatim.
43
+ *
44
+ * Returns one of:
45
+ * - `mapped` — include `estimate: <value>` in the push input
46
+ * - `skip-*` — omit the `estimate` field; `kind` carries the reason for
47
+ * logging / dry-run display
48
+ */
49
+ export declare function resolveEstimateForPush(frontmatter: Record<string, unknown>, scale: LinearIssueEstimationType | string | undefined): EstimateResolution;
50
+ //# sourceMappingURL=estimate-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate-resolver.d.ts","sourceRoot":"","sources":["../../../src/services/linear/estimate-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAqBvE;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,KAAK,EAAE,yBAAyB,GAAG,MAAM,GAAG,SAAS,GACpD,kBAAkB,CAyCpB"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Scale-aware snapping from OpenPlanr `storyPoints` → Linear `estimate` field.
3
+ *
4
+ * Linear's estimate field is numeric and must match the team's configured
5
+ * scale (`fibonacci`, `linear`, `exponential`, or `tShirt`). A value that
6
+ * isn't on the scale is rejected by the API, so we snap to the nearest
7
+ * allowed value before sending. Callers use the returned snap event to emit
8
+ * a debug log once per transformation.
9
+ *
10
+ * Scales mirror Linear's own SDK values — see `LinearIssueEstimationType`
11
+ * in `src/models/types.ts`.
12
+ */
13
+ const FIBONACCI_SCALE = [0, 1, 2, 3, 5, 8, 13, 21];
14
+ const LINEAR_SCALE = [0, 1, 2, 3, 4, 5];
15
+ const EXPONENTIAL_SCALE = [0, 1, 2, 4, 8, 16];
16
+ function snapToNearest(value, scale) {
17
+ let best = scale[0];
18
+ let bestDistance = Math.abs(value - best);
19
+ for (const candidate of scale) {
20
+ const distance = Math.abs(value - candidate);
21
+ // Break ties toward the larger value — under-estimating is a common
22
+ // planning bias; snapping up ("4 is really a 5") leans against it.
23
+ if (distance < bestDistance || (distance === bestDistance && candidate > best)) {
24
+ best = candidate;
25
+ bestDistance = distance;
26
+ }
27
+ }
28
+ return best;
29
+ }
30
+ /**
31
+ * Resolve a local `storyPoints` (or `estimatedPoints`) value to a Linear
32
+ * `estimate` value given the team's scale.
33
+ *
34
+ * Precedence for the raw local value:
35
+ * 1. `frontmatter.estimatedPoints` — canonical name written by
36
+ * `planr estimate --save` (see `src/cli/commands/estimate.ts`).
37
+ * 2. `frontmatter.storyPoints` — alias accepted for hand-edited files or
38
+ * direct AI-response copies that used the schema field name verbatim.
39
+ *
40
+ * Returns one of:
41
+ * - `mapped` — include `estimate: <value>` in the push input
42
+ * - `skip-*` — omit the `estimate` field; `kind` carries the reason for
43
+ * logging / dry-run display
44
+ */
45
+ export function resolveEstimateForPush(frontmatter, scale) {
46
+ if (scale === 'notUsed' || !scale) {
47
+ return { kind: 'skip-not-used' };
48
+ }
49
+ if (scale === 'tShirt') {
50
+ // No safe numeric → XS/S/M/L/XL mapping without user config. Skip.
51
+ return { kind: 'skip-t-shirt' };
52
+ }
53
+ const rawLocal = frontmatter.estimatedPoints !== undefined
54
+ ? frontmatter.estimatedPoints
55
+ : frontmatter.storyPoints;
56
+ if (rawLocal === undefined || rawLocal === null || rawLocal === '') {
57
+ return { kind: 'skip-no-local-value' };
58
+ }
59
+ const parsed = typeof rawLocal === 'number' ? rawLocal : Number(rawLocal);
60
+ if (!Number.isFinite(parsed) || parsed < 0) {
61
+ return { kind: 'skip-invalid-value', rawValue: rawLocal };
62
+ }
63
+ const allowed = scale === 'fibonacci'
64
+ ? FIBONACCI_SCALE
65
+ : scale === 'linear'
66
+ ? LINEAR_SCALE
67
+ : scale === 'exponential'
68
+ ? EXPONENTIAL_SCALE
69
+ : undefined;
70
+ if (!allowed) {
71
+ // Unknown scale value returned by Linear — skip rather than guess.
72
+ return { kind: 'skip-not-used' };
73
+ }
74
+ const snapped = snapToNearest(parsed, allowed);
75
+ return {
76
+ kind: 'mapped',
77
+ estimate: snapped,
78
+ originalValue: parsed,
79
+ snapped: snapped !== parsed,
80
+ };
81
+ }
82
+ //# sourceMappingURL=estimate-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate-resolver.js","sourceRoot":"","sources":["../../../src/services/linear/estimate-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Pure plan-building for `planr linear push --dry-run`. Takes loaded scopes
3
+ * and returns `LinearPushPlan` objects with per-kind row counts. No Linear
4
+ * API calls; no mutations. Epic-scope plans cascade rows for linked QT/BL.
5
+ */
6
+ import type { Epic, Feature, OpenPlanrConfig, UserStory } from '../../models/types.js';
7
+ import { type ScopedFeature, type ScopedTaskFile } from './scope-loaders.js';
8
+ export type LinearPushItemKind = 'project' | 'feature' | 'story' | 'taskList' | 'quickTask' | 'backlogItem';
9
+ export type LinearPushAction = 'create' | 'update' | 'skip';
10
+ /** Scope of a granular push — what subtree `runLinearPush(artifactId)` touches. */
11
+ export type LinearPushScope = 'epic' | 'feature' | 'story' | 'taskFile' | 'quick' | 'backlog';
12
+ export interface LinearPushPlanRow {
13
+ kind: LinearPushItemKind;
14
+ /** Epic id, feature id, story id, or task-file id for this row. */
15
+ artifactId: string;
16
+ title: string;
17
+ action: LinearPushAction;
18
+ detail?: string;
19
+ }
20
+ export interface LinearPushPlan {
21
+ /** The artifact the user pointed `planr linear push` at (any supported prefix). */
22
+ rootArtifactId: string;
23
+ /** The epic that owns this push's subtree; `undefined` for standalone QT/BL pushes. */
24
+ epicId?: string;
25
+ scope: LinearPushScope;
26
+ rows: LinearPushPlanRow[];
27
+ /** Counts by kind for non-`skip` rows. Missing kinds are 0. */
28
+ counts: {
29
+ project: number;
30
+ features: number;
31
+ stories: number;
32
+ taskLists: number;
33
+ quickTasks: number;
34
+ backlogItems: number;
35
+ total: number;
36
+ };
37
+ }
38
+ /**
39
+ * Extract the linked epic id from QT / BL frontmatter. Canonical field is
40
+ * `epicId`; `parentEpic` is accepted as a compat alias for hand-authored
41
+ * files. Empty strings are normalised to `undefined`.
42
+ */
43
+ export declare function getLinkedEpicId(fm: Record<string, unknown>): string | undefined;
44
+ export declare function projectRow(epic: Epic): LinearPushPlanRow;
45
+ export declare function featureRow(f: Feature): LinearPushPlanRow;
46
+ export declare function storyRow(s: UserStory): LinearPushPlanRow;
47
+ export declare function taskListPlanRow(featureId: string, taskFiles: ScopedTaskFile[], hasBody: boolean, hadIssue: boolean): LinearPushPlanRow;
48
+ export declare function applyUpdateOnly(rows: LinearPushPlanRow[], updateOnly: boolean): LinearPushPlanRow[];
49
+ export declare function summarizePlan(rootArtifactId: string, epicId: string | undefined, scope: LinearPushScope, rows: LinearPushPlanRow[]): LinearPushPlan;
50
+ export declare function buildFeaturePlanRows(projectDir: string, config: OpenPlanrConfig, sf: ScopedFeature): Promise<LinearPushPlanRow[]>;
51
+ export declare function buildEpicPlanRows(projectDir: string, config: OpenPlanrConfig, epicScope: {
52
+ epic: Epic;
53
+ features: ScopedFeature[];
54
+ }): Promise<LinearPushPlanRow[]>;
55
+ /**
56
+ * Build a push preview (and counts) for `planr linear push --dry-run` at any
57
+ * granularity. Accepts any supported artifact id prefix (EPIC/FEAT/US/TASK/
58
+ * QT/BL); returns `null` when the artifact can't be resolved or is not
59
+ * pushable (ADR/SPRINT/checklist).
60
+ */
61
+ export declare function buildLinearPushPlan(projectDir: string, config: OpenPlanrConfig, artifactId: string, options?: {
62
+ updateOnly?: boolean;
63
+ }): Promise<LinearPushPlan | null>;
64
+ //# sourceMappingURL=plan-builders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-builders.d.ts","sourceRoot":"","sources":["../../../src/services/linear/plan-builders.ts"],"names":[],"mappings":"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"}