@alecsibilia/luca 13.0.0-alpha.1

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 (128) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +47 -0
  3. package/bin/luca.js +3 -0
  4. package/dist/chunks/branch.mjs +47 -0
  5. package/dist/chunks/bun-runtime.mjs +46 -0
  6. package/dist/chunks/checks.mjs +53 -0
  7. package/dist/chunks/claim-verify.mjs +465 -0
  8. package/dist/chunks/classify.mjs +105 -0
  9. package/dist/chunks/confidence.mjs +199 -0
  10. package/dist/chunks/doctor.mjs +158 -0
  11. package/dist/chunks/hook.mjs +696 -0
  12. package/dist/chunks/init.mjs +715 -0
  13. package/dist/chunks/muninndb-health.mjs +66 -0
  14. package/dist/chunks/phase.mjs +38 -0
  15. package/dist/chunks/pr-review.mjs +122 -0
  16. package/dist/chunks/preferences.mjs +61 -0
  17. package/dist/chunks/repair.mjs +111 -0
  18. package/dist/chunks/repo.mjs +58 -0
  19. package/dist/chunks/retro.mjs +86 -0
  20. package/dist/chunks/roadmap.mjs +58 -0
  21. package/dist/chunks/rules.mjs +527 -0
  22. package/dist/chunks/stale-mcp-server.mjs +90 -0
  23. package/dist/chunks/state.mjs +57 -0
  24. package/dist/chunks/stray-local-install.mjs +200 -0
  25. package/dist/chunks/telemetry.mjs +165 -0
  26. package/dist/chunks/todo.mjs +151 -0
  27. package/dist/chunks/vault-init.mjs +300 -0
  28. package/dist/chunks/verification.mjs +95 -0
  29. package/dist/chunks/version.mjs +70 -0
  30. package/dist/chunks/workflow.mjs +47 -0
  31. package/dist/claude/.claude/agents/architect.md +410 -0
  32. package/dist/claude/.claude/agents/build.md +111 -0
  33. package/dist/claude/.claude/agents/discuss.md +93 -0
  34. package/dist/claude/.claude/agents/discussion.md +149 -0
  35. package/dist/claude/.claude/agents/execute.md +416 -0
  36. package/dist/claude/.claude/agents/executor.md +161 -0
  37. package/dist/claude/.claude/agents/fast.md +84 -0
  38. package/dist/claude/.claude/agents/finalize.md +484 -0
  39. package/dist/claude/.claude/agents/learner.md +160 -0
  40. package/dist/claude/.claude/agents/plan-reviewer.md +129 -0
  41. package/dist/claude/.claude/agents/plan.md +96 -0
  42. package/dist/claude/.claude/agents/research.md +327 -0
  43. package/dist/claude/.claude/agents/researcher.md +78 -0
  44. package/dist/claude/.claude/agents/review.md +283 -0
  45. package/dist/claude/.claude/agents/reviewer.md +163 -0
  46. package/dist/claude/.claude/agents/shadow-scanner.md +257 -0
  47. package/dist/claude/.claude/agents/triage.md +230 -0
  48. package/dist/claude/.claude/agents/verifier.md +131 -0
  49. package/dist/claude/.claude/commands/bug-diagnose.md +12 -0
  50. package/dist/claude/.claude/commands/gh-issue-triage.md +14 -0
  51. package/dist/claude/.claude/commands/gh-pr-address.md +235 -0
  52. package/dist/claude/.claude/commands/gh-prepare.md +12 -0
  53. package/dist/claude/.claude/commands/grill-me.md +12 -0
  54. package/dist/claude/.claude/commands/lu-review.md +51 -0
  55. package/dist/claude/.claude/commands/lu.md +75 -0
  56. package/dist/claude/.claude/commands/luca-init.md +14 -0
  57. package/dist/claude/.claude/commands/luca-telemetry-report.md +12 -0
  58. package/dist/claude/.claude/commands/memory-audit.md +12 -0
  59. package/dist/claude/.claude/commands/milestone-new.md +122 -0
  60. package/dist/claude/.claude/commands/phase-discuss.md +45 -0
  61. package/dist/claude/.claude/commands/phase-execute.md +39 -0
  62. package/dist/claude/.claude/commands/phase-plan.md +53 -0
  63. package/dist/claude/.claude/commands/repo-cleanup.md +80 -0
  64. package/dist/claude/.claude/commands/todo-add.md +28 -0
  65. package/dist/claude/.claude/commands/todo-check.md +36 -0
  66. package/dist/claude/.claude/hooks/context-refresher.ts +285 -0
  67. package/dist/claude/.claude/hooks/continuation-messages.ts +215 -0
  68. package/dist/claude/.claude/hooks/pipeline-guard.ts +182 -0
  69. package/dist/claude/.claude/settings.json +41 -0
  70. package/dist/claude/skills/arch-audit/SKILL.md +161 -0
  71. package/dist/claude/skills/autopilot/SKILL.md +1299 -0
  72. package/dist/claude/skills/bug-diagnose/SKILL.md +102 -0
  73. package/dist/claude/skills/choose/SKILL.md +124 -0
  74. package/dist/claude/skills/gh-issue-triage/SKILL.md +97 -0
  75. package/dist/claude/skills/gh-pr-address/SKILL.md +235 -0
  76. package/dist/claude/skills/gh-prepare/SKILL.md +209 -0
  77. package/dist/claude/skills/grill-me/SKILL.md +46 -0
  78. package/dist/claude/skills/lu/SKILL.md +112 -0
  79. package/dist/claude/skills/lu-review/SKILL.md +51 -0
  80. package/dist/claude/skills/luca-init/SKILL.md +91 -0
  81. package/dist/claude/skills/luca-telemetry-report/SKILL.md +145 -0
  82. package/dist/claude/skills/luca-write-surface/SKILL.md +213 -0
  83. package/dist/claude/skills/memory-audit/SKILL.md +217 -0
  84. package/dist/claude/skills/milestone-audit/SKILL.md +545 -0
  85. package/dist/claude/skills/milestone-complete/SKILL.md +168 -0
  86. package/dist/claude/skills/milestone-gaps/SKILL.md +60 -0
  87. package/dist/claude/skills/milestone-new/SKILL.md +125 -0
  88. package/dist/claude/skills/note/SKILL.md +162 -0
  89. package/dist/claude/skills/phase-add/SKILL.md +91 -0
  90. package/dist/claude/skills/phase-assumptions/SKILL.md +92 -0
  91. package/dist/claude/skills/phase-discuss/SKILL.md +165 -0
  92. package/dist/claude/skills/phase-execute/SKILL.md +1786 -0
  93. package/dist/claude/skills/phase-insert/SKILL.md +100 -0
  94. package/dist/claude/skills/phase-plan/SKILL.md +461 -0
  95. package/dist/claude/skills/phase-remove/SKILL.md +113 -0
  96. package/dist/claude/skills/phase-research/SKILL.md +80 -0
  97. package/dist/claude/skills/post-init-tour/SKILL.md +58 -0
  98. package/dist/claude/skills/progress/SKILL.md +271 -0
  99. package/dist/claude/skills/project-new/SKILL.md +609 -0
  100. package/dist/claude/skills/quick/SKILL.md +256 -0
  101. package/dist/claude/skills/rename-audit/SKILL.md +52 -0
  102. package/dist/claude/skills/repo-audit/SKILL.md +88 -0
  103. package/dist/claude/skills/repo-cleanup/SKILL.md +80 -0
  104. package/dist/claude/skills/seed-memory/SKILL.md +235 -0
  105. package/dist/claude/skills/session-pause/SKILL.md +126 -0
  106. package/dist/claude/skills/session-plan/SKILL.md +112 -0
  107. package/dist/claude/skills/session-resume/SKILL.md +75 -0
  108. package/dist/claude/skills/todo-add/SKILL.md +85 -0
  109. package/dist/claude/skills/todo-check/SKILL.md +77 -0
  110. package/dist/claude/skills/workflow-save/SKILL.md +277 -0
  111. package/dist/index.d.mts +33 -0
  112. package/dist/index.d.ts +33 -0
  113. package/dist/index.mjs +69 -0
  114. package/dist/shared/luca.B3Mimc0P.mjs +52 -0
  115. package/dist/shared/luca.B3saVjJm.mjs +163 -0
  116. package/dist/shared/luca.BYdjkfnz.mjs +217 -0
  117. package/dist/shared/luca.BmhNkYe2.mjs +56 -0
  118. package/dist/shared/luca.C4gMUoBd.mjs +358 -0
  119. package/dist/shared/luca.CQ3g1xrD.mjs +19 -0
  120. package/dist/shared/luca.CRmaAfXR.mjs +713 -0
  121. package/dist/shared/luca.CrXzXueR.mjs +57 -0
  122. package/dist/shared/luca.DTomPq7I.mjs +91 -0
  123. package/dist/shared/luca.DjDTeDCi.mjs +1904 -0
  124. package/dist/shared/luca.HZxBTBgD.mjs +201 -0
  125. package/dist/shared/luca.TSMg1t7I.mjs +10 -0
  126. package/dist/shared/luca.dM-MKlNE.mjs +25 -0
  127. package/dist/shared/luca.naWEcQ4B.mjs +7 -0
  128. package/package.json +76 -0
@@ -0,0 +1,713 @@
1
+ import { z } from 'zod';
2
+ import 'node:fs';
3
+ import 'node:fs/promises';
4
+ import 'node:path';
5
+ import 'node:os';
6
+
7
+ const PipelineStepValues = [
8
+ "idle",
9
+ "triage",
10
+ "research",
11
+ "discuss",
12
+ "architect",
13
+ "plan",
14
+ "plan-review",
15
+ "execute",
16
+ "checks",
17
+ "verify",
18
+ "review",
19
+ "learn",
20
+ "milestone",
21
+ "complete"
22
+ ];
23
+ const LEGACY_PIPELINE_STEP_MAP = {
24
+ // Old setup-related steps fold into triage (start of per-phase work).
25
+ classify: "triage",
26
+ configure: "triage",
27
+ "git-setup": "triage",
28
+ roadmap: "triage",
29
+ "phase-order": "triage",
30
+ // Old audit sub-steps fold into review.
31
+ "review-audit": "review",
32
+ "gap-audit": "review",
33
+ // Old cleanup folds into milestone.
34
+ cleanup: "milestone"
35
+ };
36
+
37
+ const ComplexityLevel = z.enum([
38
+ "TRIVIAL",
39
+ "SIMPLE",
40
+ "MODERATE",
41
+ "COMPLEX",
42
+ "CRITICAL"
43
+ ]);
44
+ const OversightMode = z.enum([
45
+ "full-auto",
46
+ "checkpoint",
47
+ "human-in-loop"
48
+ ]);
49
+ const PipelineStepEnum = z.enum(PipelineStepValues);
50
+ const PipelineStep = z.preprocess((val) => {
51
+ if (typeof val === "string" && val in LEGACY_PIPELINE_STEP_MAP) {
52
+ return LEGACY_PIPELINE_STEP_MAP[val];
53
+ }
54
+ return val;
55
+ }, PipelineStepEnum);
56
+ const PhaseStatus = z.enum([
57
+ "pending",
58
+ "in-progress",
59
+ "complete",
60
+ "skipped",
61
+ "blocked"
62
+ ]);
63
+ z.enum([
64
+ "IDLE",
65
+ "PLANNING",
66
+ "EXECUTING",
67
+ "REVIEWING",
68
+ "FINALIZING"
69
+ ]);
70
+ const RoadmapPhaseSchema = z.object({
71
+ name: z.string(),
72
+ deps: z.array(z.string()).default([]),
73
+ status: PhaseStatus.default("pending"),
74
+ complexity: ComplexityLevel.optional()
75
+ });
76
+ const lucaStateSchema = z.object({
77
+ // --- Complexity & oversight ---
78
+ complexity: ComplexityLevel.optional(),
79
+ oversight: OversightMode.default("full-auto"),
80
+ // --- Pipeline progress ---
81
+ pipelineStep: PipelineStep.default("idle"),
82
+ currentPhase: z.number().default(0),
83
+ totalPhases: z.number().default(0),
84
+ phaseSubStep: z.string().optional(),
85
+ // --- Session ---
86
+ sessionId: z.string().optional(),
87
+ // --- Roadmap ---
88
+ roadmap: z.array(RoadmapPhaseSchema).default([]),
89
+ // --- Git ---
90
+ branchName: z.string().optional(),
91
+ issueNumber: z.number().optional(),
92
+ // --- Iteration tracking ---
93
+ checksFixIteration: z.number().default(0),
94
+ verifyIteration: z.number().default(0),
95
+ planReviewIteration: z.number().default(0),
96
+ researchReviewIteration: z.number().default(0),
97
+ reviewIteration: z.number().default(0),
98
+ // --- Budget matrix (resolved from complexity) ---
99
+ maxChecksFixIterations: z.number().default(3),
100
+ maxVerifyIterations: z.number().default(2),
101
+ maxPlanReviewIterations: z.number().default(2),
102
+ maxResearchReviewIterations: z.number().default(2),
103
+ maxReviewIterations: z.number().default(2),
104
+ maxPhases: z.number().default(5),
105
+ // --- Review-mode entry timestamp ---
106
+ reviewStartedAt: z.string().optional(),
107
+ // --- Crash recovery ---
108
+ lockPid: z.number().optional(),
109
+ lockAcquiredAt: z.string().optional(),
110
+ // --- Sandbox paths (workflow-allowed file roots) ---
111
+ sandboxAllowedPaths: z.array(z.string()).default([])
112
+ });
113
+ const lucaStateSchemaTolerant = lucaStateSchema.passthrough();
114
+
115
+ const PIPELINE_STEP_TO_COARSE_PHASE = {
116
+ idle: "IDLE",
117
+ triage: "PLANNING",
118
+ research: "PLANNING",
119
+ discuss: "PLANNING",
120
+ architect: "PLANNING",
121
+ plan: "PLANNING",
122
+ "plan-review": "PLANNING",
123
+ execute: "EXECUTING",
124
+ checks: "EXECUTING",
125
+ verify: "REVIEWING",
126
+ review: "REVIEWING",
127
+ learn: "REVIEWING",
128
+ milestone: "FINALIZING",
129
+ complete: "FINALIZING"
130
+ };
131
+
132
+ function coarsePhaseOf(step) {
133
+ return PIPELINE_STEP_TO_COARSE_PHASE[step];
134
+ }
135
+
136
+ const PHASE_SLUG_RE = /^[0-9]{2}-[a-z](?:[a-z0-9-]*[a-z0-9])?$/;
137
+ const WAVE_FILE_RE = /^[0-9]{2}\.md$/;
138
+ const SEMVER_TAG_RE = /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
139
+ const REVIEWER_NAME_RE = /^[a-z][a-z0-9-]*[a-z0-9]$/;
140
+ const RUN_ID_RE = /^[A-Za-z0-9_-]+$/;
141
+ const LUCA_DIR_ROOT = ".luca";
142
+ const lucaRootPaths = {
143
+ state: `${LUCA_DIR_ROOT}/state.json`,
144
+ config: `${LUCA_DIR_ROOT}/config.json`,
145
+ lock: `${LUCA_DIR_ROOT}/lock.json`,
146
+ ledger: `${LUCA_DIR_ROOT}/ledger.jsonl`
147
+ };
148
+ const PHASE_FILE_PATHS = {
149
+ research: "research.md",
150
+ context: "context.md",
151
+ plan: "plan.md",
152
+ "plan-review": "plan-review.md",
153
+ verify: "verify.json",
154
+ learn: "learn.md",
155
+ confidence: "confidence.jsonl",
156
+ "execute/summary": "execute/summary.md",
157
+ "execute/progress": "execute/progress.jsonl"
158
+ };
159
+
160
+ z.enum([
161
+ // Root-level
162
+ "root.state",
163
+ "root.config",
164
+ "root.lock",
165
+ "root.roadmap",
166
+ "root.ledger",
167
+ // Phase artifacts
168
+ "phase.research",
169
+ "phase.context",
170
+ "phase.plan",
171
+ "phase.plan-review",
172
+ "phase.execute.summary",
173
+ "phase.execute.progress",
174
+ "phase.execute.wave",
175
+ "phase.audit",
176
+ "phase.verify",
177
+ "phase.learn",
178
+ "phase.confidence",
179
+ "phase.raw",
180
+ // Milestones
181
+ "milestone.roadmap",
182
+ "milestone.backlog-snapshot-json",
183
+ "milestone.backlog-snapshot-md",
184
+ "milestone.audit",
185
+ // Telemetry
186
+ "telemetry.run",
187
+ // Archive
188
+ "archive.phase"
189
+ ]);
190
+ const PhaseSlugSchema = z.string().regex(PHASE_SLUG_RE, {
191
+ message: 'Phase slug must be <NN-kebab-case>, e.g. "01-auth-rewrite" (NN zero-padded).'
192
+ });
193
+ z.string().regex(REVIEWER_NAME_RE, {
194
+ message: 'Reviewer name must be kebab-case, e.g. "code-review".'
195
+ });
196
+ z.string().regex(SEMVER_TAG_RE, {
197
+ message: 'Version tag must be SemVer-prefixed with "v", e.g. "v12.0.0".'
198
+ });
199
+ z.number().int().min(0).max(99, { message: "Wave number must fit in two digits (0\u201399)." });
200
+ const RunIdSchema = z.string().regex(RUN_ID_RE, {
201
+ message: "runId must be alphanumeric/kebab."
202
+ });
203
+
204
+ const PIPELINE_TRANSITIONS = {
205
+ idle: ["triage"],
206
+ triage: ["research"],
207
+ research: ["discuss", "research"],
208
+ // re-research allowed
209
+ discuss: ["architect"],
210
+ architect: ["plan"],
211
+ plan: ["plan-review"],
212
+ "plan-review": ["execute", "plan"],
213
+ // re-plan allowed
214
+ execute: ["checks"],
215
+ checks: ["verify", "execute"],
216
+ // fix loop back to execute
217
+ verify: ["review", "checks"],
218
+ // fix loop back to checks
219
+ review: ["learn"],
220
+ learn: ["milestone", "plan"],
221
+ // next phase OR close milestone
222
+ milestone: ["complete"],
223
+ complete: ["idle"]
224
+ // start a fresh session
225
+ };
226
+ function isLegalTransition(from, to) {
227
+ return PIPELINE_TRANSITIONS[from].includes(to);
228
+ }
229
+
230
+ const SYSTEM_DIR_PATTERN = /^\/(etc|usr|var|System|bin|sbin)(\/|$)/;
231
+ const GIT_DIR_PATTERN = /(^|\/)\.git(\/|$)/;
232
+ const HOME_DENIED_SUBDIRS = [".claude", ".luca"];
233
+ const reAnchorless = (re) => re.source.replace(/^\^/, "").replace(/\$$/, "");
234
+ const AUDIT_PATH_PATTERN = new RegExp(
235
+ `^\\.luca/phases/${reAnchorless(PHASE_SLUG_RE)}/audits/${reAnchorless(
236
+ REVIEWER_NAME_RE
237
+ )}\\.md$`
238
+ );
239
+ function classifyWritePath(path, opts = {}) {
240
+ if (GIT_DIR_PATTERN.test(path)) {
241
+ return {
242
+ class: "denied",
243
+ reason: "writes under .git/ are never allowed"
244
+ };
245
+ }
246
+ if (SYSTEM_DIR_PATTERN.test(path)) {
247
+ return {
248
+ class: "denied",
249
+ reason: "writes under system directories (/etc, /usr, /var, /System, /bin, /sbin) are never allowed"
250
+ };
251
+ }
252
+ for (const subdir of HOME_DENIED_SUBDIRS) {
253
+ if (path.startsWith(`~/${subdir}/`) || path === `~/${subdir}`) {
254
+ return {
255
+ class: "denied",
256
+ reason: `writes under ~/${subdir}/ are never allowed`
257
+ };
258
+ }
259
+ if (opts.homedir) {
260
+ const abs = `${opts.homedir.replace(/\/$/, "")}/${subdir}`;
261
+ if (path.startsWith(`${abs}/`) || path === abs) {
262
+ return {
263
+ class: "denied",
264
+ reason: `writes under ${abs}/ (user tooling dir) are never allowed`
265
+ };
266
+ }
267
+ }
268
+ }
269
+ if (path.startsWith(".luca/") || path === ".luca") {
270
+ if (AUDIT_PATH_PATTERN.test(path)) {
271
+ return { class: "planning-audit" };
272
+ }
273
+ return { class: "planning-general" };
274
+ }
275
+ return { class: "code" };
276
+ }
277
+
278
+ z.object({
279
+ pid: z.number().int().positive(),
280
+ acquired_at: z.string().min(1),
281
+ run_id: z.string().min(1),
282
+ /** Best-effort hostname (omitted when `os.hostname()` is unavailable). */
283
+ host: z.string().optional()
284
+ });
285
+
286
+ const SAFE_FREEFORM_SCHEMA = z.string().max(64).regex(/^[\w #\t{}/,.():-]*$/);
287
+ const REGEX_SOURCE_SCHEMA = z.string().min(1).max(128).refine(
288
+ (v) => {
289
+ try {
290
+ new RegExp(v);
291
+ return true;
292
+ } catch {
293
+ return false;
294
+ }
295
+ },
296
+ { message: "must be a valid regex source" }
297
+ ).refine((v) => !/[+*}]\)[+*{]/.test(v), {
298
+ message: "nested quantifiers prohibited (ReDoS guard)"
299
+ });
300
+ const BaseRuleSchema = z.object({
301
+ kind: z.enum(["static", "current-branch-if-matches", "ask"]),
302
+ value: SAFE_FREEFORM_SCHEMA.optional(),
303
+ pattern: REGEX_SOURCE_SCHEMA.optional(),
304
+ fallback: z.union([SAFE_FREEFORM_SCHEMA, z.literal("ask")]).optional()
305
+ });
306
+ const BranchTypeRuleSchema = z.object({
307
+ match: REGEX_SOURCE_SCHEMA,
308
+ template: SAFE_FREEFORM_SCHEMA,
309
+ base: BaseRuleSchema,
310
+ prBase: BaseRuleSchema,
311
+ role: z.enum(["feature", "release", "rc"]).optional()
312
+ });
313
+ const BranchingSectionSchema = z.object({
314
+ types: z.array(SAFE_FREEFORM_SCHEMA).default([
315
+ "feat",
316
+ "fix",
317
+ "refactor",
318
+ "chore",
319
+ "docs",
320
+ "test",
321
+ "style"
322
+ ]),
323
+ template: SAFE_FREEFORM_SCHEMA.default("{type}/{issue}-{slug}"),
324
+ defaultBranch: SAFE_FREEFORM_SCHEMA.default("main"),
325
+ guardedBranches: z.array(SAFE_FREEFORM_SCHEMA).min(1).default(["main"]),
326
+ branchTypes: z.array(BranchTypeRuleSchema).optional(),
327
+ fallback: BranchTypeRuleSchema.optional(),
328
+ confirmBaseBeforeCreate: z.boolean().default(false)
329
+ }).prefault({});
330
+ const CommitsSectionSchema = z.object({
331
+ convention: z.enum(["conventional", "none"]).default("conventional"),
332
+ scopes: z.array(SAFE_FREEFORM_SCHEMA).default([]),
333
+ /**
334
+ * Allowed commit-message types. Distinct from `branching.types` —
335
+ * branching.types governs branch-name prefix; commits.types
336
+ * governs commit-message prefix. They MAY differ for squash-merge
337
+ * repos where every PR squashes to a single `feat:` commit
338
+ * regardless of branch type. Falls back to branching.types when
339
+ * unset.
340
+ */
341
+ types: z.array(SAFE_FREEFORM_SCHEMA).max(20).optional(),
342
+ trailers: z.object({
343
+ coAuthor: z.boolean(),
344
+ issueRef: SAFE_FREEFORM_SCHEMA
345
+ }).optional(),
346
+ subjectMaxLength: z.number().int().min(20).max(200).default(72)
347
+ }).prefault({});
348
+ const PrSectionSchema = z.object({
349
+ titleFormat: SAFE_FREEFORM_SCHEMA.default(
350
+ "{type}({scope}): {description}"
351
+ ),
352
+ baseBranch: SAFE_FREEFORM_SCHEMA.default("main"),
353
+ /**
354
+ * Preferred PR title template — supersedes `titleFormat` when
355
+ * present. `titleFormat` is retained for backward compatibility.
356
+ * When both are set, `titleTemplate` wins.
357
+ */
358
+ titleTemplate: SAFE_FREEFORM_SCHEMA.optional(),
359
+ titleExamples: z.array(SAFE_FREEFORM_SCHEMA).max(5).optional(),
360
+ forbidden: z.array(
361
+ z.object({
362
+ pattern: REGEX_SOURCE_SCHEMA,
363
+ reason: SAFE_FREEFORM_SCHEMA
364
+ })
365
+ ).max(10).optional(),
366
+ bodyTemplate: SAFE_FREEFORM_SCHEMA.optional(),
367
+ draftByDefault: z.boolean().optional()
368
+ }).prefault({});
369
+ const ReleaseSectionSchema = z.object({
370
+ tool: z.enum(["changesets", "none", "semantic-release"]).default("none"),
371
+ versionBump: z.record(z.string(), z.enum(["major", "minor", "patch"])).default({
372
+ feat: "minor",
373
+ fix: "patch",
374
+ chore: "patch",
375
+ refactor: "patch"
376
+ })
377
+ }).prefault({});
378
+ const TrackerSectionSchema = z.object({
379
+ kind: z.enum(["github", "linear", "jira", "none"]).default("github"),
380
+ issuePrefix: SAFE_FREEFORM_SCHEMA.default(""),
381
+ /**
382
+ * Issue-link template used in PR bodies. Distinct from
383
+ * `commits.trailers.issueRef` (the commit-message trailer
384
+ * prefix) — consumers may use the same string for both, but
385
+ * they are conceptually independent.
386
+ */
387
+ linkFormat: SAFE_FREEFORM_SCHEMA.optional()
388
+ }).prefault({});
389
+ const ProjectPreferencesSchema = z.object({
390
+ schemaVersion: z.literal(1).default(1),
391
+ branching: BranchingSectionSchema,
392
+ commits: CommitsSectionSchema,
393
+ pr: PrSectionSchema,
394
+ release: ReleaseSectionSchema,
395
+ tracker: TrackerSectionSchema
396
+ }).prefault({});
397
+ z.enum([
398
+ "branching",
399
+ "commits",
400
+ "pr",
401
+ "release",
402
+ "tracker"
403
+ ]);
404
+ ProjectPreferencesSchema.parse({});
405
+
406
+ const TodoStatus = z.enum(["pending", "backlog", "done"]);
407
+ const TodoIdSchema = z.string().min(1).max(60).regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/, {
408
+ message: "must be kebab-case (lowercase a-z, digits, single dashes)"
409
+ });
410
+ const VerificationRefSchema = z.object({
411
+ criterionId: z.string().min(1).describe(
412
+ "Stable criterion id (e.g. 'ac-03') matching an entry in the active phase's verify.json."
413
+ )
414
+ });
415
+ const TodoSchema = z.object({
416
+ schemaVersion: z.literal(1),
417
+ id: TodoIdSchema,
418
+ title: z.string().min(1).max(200),
419
+ body: z.string().max(8192).optional(),
420
+ status: TodoStatus,
421
+ source: z.string().max(120).optional(),
422
+ metadata: z.record(z.string(), z.unknown()).optional(),
423
+ updatedAt: z.string().datetime({ message: "updatedAt must be ISO 8601 datetime" }),
424
+ verificationRef: VerificationRefSchema.optional()
425
+ });
426
+ function slugFromTitle(title) {
427
+ const slug = title.normalize("NFKD").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60).replace(/-+$/g, "");
428
+ if (slug.length === 0) {
429
+ throw new Error(
430
+ `cannot derive a slug from title "${title}" (no alphanumeric content)`
431
+ );
432
+ }
433
+ return slug;
434
+ }
435
+ const TODO_CONCEPT_PREFIX = "todo:";
436
+ function todoConceptFor(id) {
437
+ return `${TODO_CONCEPT_PREFIX}${id}`;
438
+ }
439
+
440
+ const ShadowScanSeverity = z.enum(["critical", "high", "medium", "low"]);
441
+ const ShadowScanAction = z.enum(["delete", "move", "gitignore"]);
442
+ const ShadowScanMode = z.enum(["quick", "standard", "full"]);
443
+ const ShadowScanFindingSchema = z.object({
444
+ /** Detection category label, e.g. "orphaned-temp-script". */
445
+ category: z.string().min(1),
446
+ severity: ShadowScanSeverity,
447
+ /** Repo-relative path of the flagged file. */
448
+ file_path: z.string().min(1),
449
+ /** What was detected. */
450
+ description: z.string().min(1),
451
+ /** Human-readable remediation recommendation. */
452
+ recommendation: z.string().min(1),
453
+ /** The remediation the apply tool would perform. */
454
+ recommended_action: ShadowScanAction,
455
+ /** Destination path — required for a `move` action. */
456
+ target_path: z.string().min(1).optional(),
457
+ /** Whether the remediation is safe to apply without user confirmation. */
458
+ auto_fixable: z.boolean()
459
+ });
460
+ const ShadowScanSummarySchema = z.object({
461
+ total: z.number().int().min(0),
462
+ critical: z.number().int().min(0),
463
+ high: z.number().int().min(0),
464
+ medium: z.number().int().min(0),
465
+ low: z.number().int().min(0)
466
+ });
467
+ z.object({
468
+ scan_mode: ShadowScanMode,
469
+ /** Detection category numbers that were run for this scan. */
470
+ categories_scanned: z.array(z.number().int()),
471
+ findings: z.array(ShadowScanFindingSchema),
472
+ summary: ShadowScanSummarySchema,
473
+ scanned_at: z.string().datetime({ message: "scanned_at must be ISO 8601 datetime" })
474
+ });
475
+
476
+ const ClassifyComplexityInputSchema = z.object({
477
+ taskDescription: z.string().describe("Description of the development task"),
478
+ estimatedFileCount: z.number().default(0).describe("Estimated number of files affected"),
479
+ crossCuttingConcerns: z.array(z.string()).default([]).describe("Cross-cutting concerns (e.g. auth, state, API changes)"),
480
+ hasBreakingChanges: z.boolean().default(false).describe("Whether the change introduces breaking changes"),
481
+ affectedDomains: z.array(z.string()).default([]).describe("Affected architectural domains")
482
+ });
483
+ z.object({
484
+ complexity: ComplexityLevel,
485
+ reasoning: z.string(),
486
+ factors: z.object({
487
+ fileScope: z.enum(["small", "medium", "large"]),
488
+ dependencyDepth: z.enum(["shallow", "moderate", "deep"]),
489
+ riskLevel: z.enum(["low", "medium", "high"])
490
+ })
491
+ });
492
+
493
+ z.object({
494
+ file: z.string(),
495
+ line: z.number().optional(),
496
+ column: z.number().optional(),
497
+ message: z.string(),
498
+ code: z.string().optional(),
499
+ severity: z.enum(["error", "warning"])
500
+ });
501
+
502
+ const TelemetryRecordSchema = z.object({
503
+ v: z.literal(1),
504
+ // ISO 8601 datetime — aggregator consumers parse durations from these.
505
+ ts: z.iso.datetime(),
506
+ runId: z.string(),
507
+ kind: z.string(),
508
+ phase: z.string().nullable(),
509
+ slug: z.string().nullable(),
510
+ wave: z.number().nullable(),
511
+ complexity: z.string().nullable(),
512
+ oversight: z.string().nullable(),
513
+ durationMs: z.number().nullable(),
514
+ meta: z.record(z.string(), z.unknown())
515
+ });
516
+
517
+ const LedgerEntrySchema = z.object({
518
+ /** Event timestamp (ISO 8601). */
519
+ timestamp: z.iso.datetime(),
520
+ /** Run identifier — correlates ledger entries with telemetry records. */
521
+ runId: z.string(),
522
+ /** Event name (e.g. `mode-transition`, `phase-complete`). */
523
+ event: z.string(),
524
+ /** Free-form per-event payload. */
525
+ data: z.record(z.string(), z.unknown())
526
+ });
527
+
528
+ const VerificationCriterionSchema = z.object({
529
+ /** Stable identifier (e.g. "ac-01", "test-pass"). */
530
+ criterionId: z.string(),
531
+ /** Human-readable description. */
532
+ description: z.string(),
533
+ /** Whether the criterion is satisfied. */
534
+ met: z.boolean(),
535
+ /** File / line / test evidence supporting the verdict. */
536
+ evidence: z.string(),
537
+ /** If not met, what is missing. */
538
+ gap: z.string().optional(),
539
+ /** Whether this criterion blocks proceeding. */
540
+ blocking: z.boolean()
541
+ });
542
+ const CheckResultSchema = z.object({
543
+ name: z.string(),
544
+ status: z.enum(["pass", "fail", "skip", "timeout"]),
545
+ errorCount: z.number(),
546
+ warningCount: z.number(),
547
+ /** Duration in milliseconds. */
548
+ durationMs: z.number().optional()
549
+ });
550
+ const VerificationResultSchema = z.object({
551
+ /** ISO 8601 timestamp (stored verbatim; not parsed for arithmetic). */
552
+ timestamp: z.string(),
553
+ /**
554
+ * Run that produced this result. Stamped on write, validated on read: a
555
+ * stale result from a prior run (mismatched runId) is treated as absent so
556
+ * it cannot satisfy the new run's wave/phase guards. Optional for
557
+ * back-compat with results written before runId stamping.
558
+ */
559
+ runId: z.string().optional(),
560
+ /** Pipeline phase (e.g. "Phase 1: Setup"). */
561
+ phase: z.string().optional(),
562
+ /** Wave / iteration number. */
563
+ wave: z.number(),
564
+ /** Verification depth. */
565
+ mode: z.enum(["quick", "full"]),
566
+ /** Overall verdict. */
567
+ status: z.enum(["PASS", "FAIL", "STALLED"]),
568
+ /** Per-criterion results. */
569
+ criteria: z.array(VerificationCriterionSchema),
570
+ /** Automated check results. */
571
+ checks: z.array(CheckResultSchema),
572
+ /** Convergence assessment. */
573
+ convergence: z.enum(["converging", "stalled", "resolved"]),
574
+ /** Error fingerprints for tracking across iterations. */
575
+ errorFingerprints: z.array(z.string()),
576
+ /** Recommendation to the orchestrator. */
577
+ recommendation: z.enum(["proceed", "fix", "escalate"]),
578
+ /** Free-form notes from the verifier. */
579
+ notes: z.string().optional()
580
+ });
581
+
582
+ const ConfidenceLevelSchema = z.enum(["high", "medium", "low"]);
583
+ const ConfidenceCategorySchema = z.enum([
584
+ "plan-gap",
585
+ "design-choice",
586
+ "convention-unclear",
587
+ "requirement-ambiguous",
588
+ "dependency-unknown",
589
+ "scope-creep"
590
+ ]);
591
+ const ConfidenceEntrySchema = z.object({
592
+ /** Event timestamp (ISO 8601). */
593
+ timestamp: z.iso.datetime(),
594
+ /** Phase name from the plan / roadmap. */
595
+ phase: z.string(),
596
+ /** Wave number within the phase. */
597
+ wave: z.number(),
598
+ /** Task ID or description from the plan. */
599
+ task: z.string(),
600
+ /** How confident the executor was in its decision. */
601
+ confidence: ConfidenceLevelSchema,
602
+ /** What kind of ambiguity was encountered. */
603
+ category: ConfidenceCategorySchema,
604
+ /** What the executor actually decided to do. */
605
+ decision: z.string(),
606
+ /** Other options that were considered. */
607
+ alternatives: z.array(z.string()),
608
+ /** Why this choice was made over the alternatives. */
609
+ reasoning: z.string(),
610
+ /** What could go wrong if this was the wrong call. */
611
+ risk: z.string(),
612
+ /** Which files were affected by this decision. */
613
+ files: z.array(z.string()),
614
+ /** Suggested focus area for a human reviewer. */
615
+ reviewHint: z.string().optional()
616
+ });
617
+
618
+ new Set(Object.keys(PIPELINE_TRANSITIONS));
619
+
620
+ const STEP_TEMPLATES = {
621
+ triage: "Begin triage. Parse the request, classify complexity, and advance to research. Do NOT implement anything. Do NOT modify files. Your only job is to classify and transition.",
622
+ research: "Begin research. Read the existing state and prior artifacts, investigate the affected areas, and save findings to `.luca/phases/<slug>/research.md`. When research is complete, advance to discuss.",
623
+ discuss: "Begin discussion. Gather user decisions for the active phase and persist them as `.luca/phases/<slug>/context.md`. Keep the scope tight \u2014 clarifying questions only.",
624
+ architect: "Begin architecture. Read research + context, then produce a structured implementation plan using goal-backward analysis. When the plan is approved, advance to plan.",
625
+ plan: "Write the phase plan to `.luca/phases/<slug>/plan.md`. Keep tasks atomic and each task verifiable. When the plan is final, advance to plan-review.",
626
+ "plan-review": "Review the plan against the research + context. Validate every task is atomic, verifiable, and traceable. Surface gaps as plan-review notes; do not edit the plan in place.",
627
+ execute: "Begin execution. Read `.luca/phases/<slug>/plan.md` and implement changes in waves. Run `luca checks run` after each wave. Do NOT re-create the plan. When all waves are complete, advance to checks.",
628
+ checks: "Run the verification harness via `luca checks run`. On failure, loop back to execute with a focused fix list. On success, advance to verify.",
629
+ verify: "Verify the changes against the plan and acceptance criteria. Produce `verify.json` with the result; on failure loop back to checks.",
630
+ review: "Review the code changes against the plan. Spawn reviewer subagents for a multi-perspective audit. Produce REVIEW reports under `audits/`. If must-fix issues are found, loop back to execute; otherwise advance to learn.",
631
+ learn: "Capture learnings as patterns/decisions/pitfalls in MuninnDB and as `learn.md`. Then advance to milestone (to close the milestone) or back to plan (to start the next phase).",
632
+ milestone: "Close the milestone. Produce the versioned roadmap + audit snapshot under `.luca/milestones/`. Then advance to complete.",
633
+ complete: "Wrap the session: finalize metrics, surface the PR if appropriate, and advance to idle."
634
+ };
635
+ const ALL_PIPELINE_STEPS_TABLE$1 = {
636
+ idle: true,
637
+ triage: true,
638
+ research: true,
639
+ discuss: true,
640
+ architect: true,
641
+ plan: true,
642
+ "plan-review": true,
643
+ execute: true,
644
+ checks: true,
645
+ verify: true,
646
+ review: true,
647
+ learn: true,
648
+ milestone: true,
649
+ complete: true
650
+ };
651
+ new Set(
652
+ Object.keys(ALL_PIPELINE_STEPS_TABLE$1)
653
+ );
654
+ for (const step of Object.keys(ALL_PIPELINE_STEPS_TABLE$1)) {
655
+ if (step === "idle") continue;
656
+ if (STEP_TEMPLATES[step] === void 0) {
657
+ throw new Error(
658
+ `continuation-messages: STEP_TEMPLATES is missing an entry for pipelineStep '${step}'. Add a template or extend the coarse-phase map if this step shouldn't emit a continuation.`
659
+ );
660
+ }
661
+ }
662
+
663
+ const STEP_REMINDERS = {
664
+ triage: "<luca-reminder>You are in triage. \u226475 words output. Classify \u2192 rationale \u2192 next step. Do NOT implement.</luca-reminder>",
665
+ research: "<luca-reminder>You are in research. Budget: MODERATE \u226410, COMPLEX \u226420, CRITICAL \u226430 tool calls. Synthesis \u2264200 lines.</luca-reminder>",
666
+ discuss: "<luca-reminder>Discuss (read-only). Under 300 words per turn. \u22642 clarifying questions. Persist decisions to context.md.</luca-reminder>",
667
+ architect: "<luca-reminder>You are in architect mode. \u22643 sentences per task. \u2264150 lines PLAN.md total. Validate with plan-reviewer before finishing.</luca-reminder>",
668
+ plan: "<luca-reminder>You are in plan mode. Atomic tasks, each verifiable. Keep PLAN.md \u2264150 lines. No code yet.</luca-reminder>",
669
+ "plan-review": "<luca-reminder>Plan-review (read-only). Validate atomicity/verifiability/traceability. Surface gaps; do not edit the plan in place.</luca-reminder>",
670
+ execute: "<luca-reminder>You are in execute mode. Run `luca checks run` within 1 tool call of wave completion. Stalled \u22652 iterations = stop and escalate. No prose between tool calls.</luca-reminder>",
671
+ checks: "<luca-reminder>You are in checks. Run the verification harness. On failure, loop back to execute with a focused fix list. No prose.</luca-reminder>",
672
+ verify: "<luca-reminder>You are in verify. Compare changes against plan + acceptance criteria. Produce verify.json; on failure loop back to checks.</luca-reminder>",
673
+ review: "<luca-reminder>You are in review mode (read-only). Maximum 5 MUST-FIX items. MUST-FIX = correctness bugs, security, missing requirements ONLY.</luca-reminder>",
674
+ learn: "<luca-reminder>You are in learn mode. Capture patterns/decisions/pitfalls in MuninnDB + learn.md. Be concrete. \u2264200 lines.</luca-reminder>",
675
+ milestone: "<luca-reminder>You are in milestone mode. Close the milestone: versioned roadmap + audit snapshot under .luca/milestones/.</luca-reminder>",
676
+ complete: "<luca-reminder>You are in complete mode. Finalize metrics, surface the PR if appropriate, then advance to idle.</luca-reminder>"
677
+ };
678
+ const ALL_PIPELINE_STEPS_TABLE = {
679
+ idle: true,
680
+ triage: true,
681
+ research: true,
682
+ discuss: true,
683
+ architect: true,
684
+ plan: true,
685
+ "plan-review": true,
686
+ execute: true,
687
+ checks: true,
688
+ verify: true,
689
+ review: true,
690
+ learn: true,
691
+ milestone: true,
692
+ complete: true
693
+ };
694
+ new Set(
695
+ Object.keys(ALL_PIPELINE_STEPS_TABLE)
696
+ );
697
+ for (const step of Object.keys(ALL_PIPELINE_STEPS_TABLE)) {
698
+ if (step === "idle") continue;
699
+ if (STEP_REMINDERS[step] === void 0) {
700
+ throw new Error(
701
+ `context-refresher: STEP_REMINDERS is missing an entry for pipelineStep '${step}'. Add a reminder or extend the coarse-phase map if this step shouldn't emit a reminder.`
702
+ );
703
+ }
704
+ }
705
+ for (const step of Object.keys(STEP_REMINDERS)) {
706
+ if (coarsePhaseOf(step) === "IDLE") {
707
+ throw new Error(
708
+ `context-refresher: STEP_REMINDERS includes step '${step}' whose coarse phase is IDLE. IDLE steps never emit reminders \u2014 drop the entry from STEP_REMINDERS.`
709
+ );
710
+ }
711
+ }
712
+
713
+ export { AUDIT_PATH_PATTERN as A, ClassifyComplexityInputSchema as C, LUCA_DIR_ROOT as L, ProjectPreferencesSchema as P, RunIdSchema as R, ShadowScanFindingSchema as S, TelemetryRecordSchema as T, VerificationRefSchema as V, WAVE_FILE_RE as W, classifyWritePath as a, ConfidenceCategorySchema as b, coarsePhaseOf as c, ConfidenceLevelSchema as d, lucaRootPaths as e, RoadmapPhaseSchema as f, PipelineStep as g, PIPELINE_TRANSITIONS as h, isLegalTransition as i, PIPELINE_STEP_TO_COARSE_PHASE as j, PipelineStepValues as k, lucaStateSchema as l, TodoIdSchema as m, TodoSchema as n, TodoStatus as o, TODO_CONCEPT_PREFIX as p, LedgerEntrySchema as q, ConfidenceEntrySchema as r, slugFromTitle as s, todoConceptFor as t, VerificationResultSchema as u, PHASE_SLUG_RE as v, lucaStateSchemaTolerant as w, PhaseSlugSchema as x, PHASE_FILE_PATHS as y };