@alecsibilia/luca 13.0.0-alpha.2 → 13.0.0-alpha.3

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 (35) hide show
  1. package/dist/chunks/branch.mjs +6 -6
  2. package/dist/chunks/checks.mjs +6 -6
  3. package/dist/chunks/claim-verify.mjs +1 -1
  4. package/dist/chunks/classify.mjs +1 -1
  5. package/dist/chunks/confidence.mjs +6 -6
  6. package/dist/chunks/hook.mjs +27 -9
  7. package/dist/chunks/init.mjs +1 -1
  8. package/dist/chunks/phase.mjs +28 -8
  9. package/dist/chunks/pr-review.mjs +6 -6
  10. package/dist/chunks/preferences.mjs +6 -6
  11. package/dist/chunks/repair.mjs +1 -1
  12. package/dist/chunks/repo.mjs +6 -6
  13. package/dist/chunks/retro.mjs +5 -5
  14. package/dist/chunks/roadmap.mjs +6 -6
  15. package/dist/chunks/rules.mjs +5 -5
  16. package/dist/chunks/state.mjs +6 -6
  17. package/dist/chunks/stray-local-install.mjs +1 -1
  18. package/dist/chunks/telemetry.mjs +1 -1
  19. package/dist/chunks/todo.mjs +6 -6
  20. package/dist/chunks/vault-init.mjs +1 -1
  21. package/dist/chunks/verification.mjs +4 -4
  22. package/dist/chunks/workflow.mjs +6 -6
  23. package/dist/claude/skills/caveman/SKILL.md +58 -0
  24. package/dist/claude/skills/lu/SKILL.md +1 -1
  25. package/dist/claude/skills/milestone-complete/SKILL.md +8 -1
  26. package/dist/index.mjs +1 -1
  27. package/dist/shared/{luca.CrXzXueR.mjs → luca.BH2GZl5z.mjs} +1 -1
  28. package/dist/shared/{luca.BmhNkYe2.mjs → luca.BQXFn5yo.mjs} +2 -2
  29. package/dist/shared/{luca.C4gMUoBd.mjs → luca.BhM9TDAo.mjs} +3 -3
  30. package/dist/shared/{luca.HZxBTBgD.mjs → luca.CuvqWf4b.mjs} +2 -2
  31. package/dist/shared/{luca.CRmaAfXR.mjs → luca.DXUcpbIe.mjs} +5 -4
  32. package/dist/shared/{luca.B3Mimc0P.mjs → luca.Djs7oPPj.mjs} +5 -0
  33. package/dist/shared/{luca.DjDTeDCi.mjs → luca.DykMxS_D.mjs} +125 -16
  34. package/dist/shared/{luca.TSMg1t7I.mjs → luca.pqZahLS5.mjs} +1 -1
  35. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { r as runWriteHandler, q as lucaBranchGuardTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { r as runWriteHandler, t as lucaBranchGuardTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const guardCommand = defineCommand({
20
20
  meta: {
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { c as readJsonPayload, r as runWriteHandler, p as lucaChecksRunTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { e as readJsonPayload, r as runWriteHandler, s as lucaChecksRunTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const runCommand = defineCommand({
20
20
  meta: {
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import { resolve } from 'pathe';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import { join } from 'node:path';
@@ -1,5 +1,5 @@
1
1
  import { defineCommand } from 'citty';
2
- import { C as ClassifyComplexityInputSchema } from '../shared/luca.CRmaAfXR.mjs';
2
+ import { C as ClassifyComplexityInputSchema } from '../shared/luca.DXUcpbIe.mjs';
3
3
  import 'node:fs';
4
4
  import 'node:fs/promises';
5
5
  import 'node:path';
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
- import '../shared/luca.CRmaAfXR.mjs';
3
- import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.CrXzXueR.mjs';
2
+ import '../shared/luca.DXUcpbIe.mjs';
3
+ import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.BH2GZl5z.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,15 +8,15 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { b as renderConfidenceJournalMarkdown, r as readConfidenceJournal, g as getConfidenceSummary } from '../shared/luca.HZxBTBgD.mjs';
11
+ import { b as renderConfidenceJournalMarkdown, r as readConfidenceJournal, g as getConfidenceSummary } from '../shared/luca.CuvqWf4b.mjs';
12
12
  import { l as logger } from '../shared/luca.dM-MKlNE.mjs';
13
13
  import 'zod';
14
- import { c as readJsonPayload, r as runWriteHandler, t as lucaConfidenceLogTool } from '../shared/luca.DjDTeDCi.mjs';
14
+ import { e as readJsonPayload, r as runWriteHandler, v as lucaConfidenceLogTool } from '../shared/luca.DykMxS_D.mjs';
15
15
  import 'node:os';
16
- import '../shared/luca.TSMg1t7I.mjs';
16
+ import '../shared/luca.pqZahLS5.mjs';
17
17
  import 'consola';
18
18
  import '../shared/luca.CQ3g1xrD.mjs';
19
- import '../shared/luca.B3Mimc0P.mjs';
19
+ import '../shared/luca.Djs7oPPj.mjs';
20
20
 
21
21
  async function resolveSlug(opts) {
22
22
  if (opts.explicit) return opts.explicit;
@@ -1,11 +1,11 @@
1
1
  import { defineCommand } from 'citty';
2
- import { c as coarsePhaseOf, a as classifyWritePath, A as AUDIT_PATH_PATTERN, W as WAVE_FILE_RE } from '../shared/luca.CRmaAfXR.mjs';
3
- import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.CrXzXueR.mjs';
2
+ import { c as coarsePhaseOf, a as classifyWritePath, A as AUDIT_PATH_PATTERN, W as WAVE_FILE_RE } from '../shared/luca.DXUcpbIe.mjs';
3
+ import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.BH2GZl5z.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
- import 'node:path';
7
- import { S as STEP_ARTIFACTS } from '../shared/luca.B3Mimc0P.mjs';
8
- import { p as phasePathFor } from '../shared/luca.TSMg1t7I.mjs';
6
+ import { isAbsolute, relative } from 'node:path';
7
+ import { S as STEP_ARTIFACTS } from '../shared/luca.Djs7oPPj.mjs';
8
+ import { p as phasePathFor } from '../shared/luca.pqZahLS5.mjs';
9
9
  import 'node:crypto';
10
10
  import 'node:module';
11
11
  import 'node:url';
@@ -72,6 +72,13 @@ function isToolAllowed({
72
72
  }
73
73
 
74
74
  const READONLY_COMMANDS = /* @__PURE__ */ new Set([
75
+ // Shell navigation/no-ops: mutate shell state, not files — benign for
76
+ // the file/repo-mutation policy this classifier enforces. `cd` is the
77
+ // big one: agents prefix nearly every command with `cd <dir> && …`, so
78
+ // omitting it made every compound command classify as a mutate.
79
+ "cd",
80
+ "pushd",
81
+ "popd",
75
82
  "ls",
76
83
  "cat",
77
84
  "grep",
@@ -195,7 +202,7 @@ const LUCA_READ_VERBS = /* @__PURE__ */ new Set([
195
202
  ]);
196
203
  const LUCA_NOUN_VERBS = {
197
204
  state: /* @__PURE__ */ new Set(["read", "advance"]),
198
- phase: /* @__PURE__ */ new Set(["current"]),
205
+ phase: /* @__PURE__ */ new Set(["current", "advance", "archive"]),
199
206
  roadmap: /* @__PURE__ */ new Set(["read", "create"]),
200
207
  preferences: /* @__PURE__ */ new Set(["read", "write"]),
201
208
  todo: /* @__PURE__ */ new Set(["add", "list", "update"]),
@@ -212,7 +219,7 @@ const LUCA_NOUN_VERBS = {
212
219
  };
213
220
  function classifyLucaCommand(rest) {
214
221
  const noun = rest.find((t) => !t.startsWith("-"));
215
- if (!noun) return void 0;
222
+ if (!noun) return "bash-readonly";
216
223
  const verbs = LUCA_NOUN_VERBS[noun];
217
224
  if (!verbs) return void 0;
218
225
  const afterNoun = rest.slice(rest.indexOf(noun) + 1);
@@ -358,6 +365,16 @@ function classifySubcommand(sub) {
358
365
  };
359
366
  }
360
367
  }
368
+ if (cmd === "sed" || cmd === "awk") {
369
+ const sedInPlace = cmd === "sed" && rest.some((a) => a === "--in-place" || a.startsWith("-i"));
370
+ const awkInPlace = cmd === "awk" && rest.some((a, i) => a === "-i" && rest[i + 1] === "inplace");
371
+ if (!sedInPlace && !awkInPlace) {
372
+ return {
373
+ category: sub.redirect ? "bash-mutate" : "bash-readonly",
374
+ targetPaths: targetsFromRedirect
375
+ };
376
+ }
377
+ }
361
378
  if (MUTATE_COMMANDS.has(cmd)) {
362
379
  const lastArg = cmd === "cp" || cmd === "mv" || cmd === "ln" ? lastNonFlag(rest) : void 0;
363
380
  const sedTarget = cmd === "sed" && rest.includes("-i") ? rest[rest.length - 1] : void 0;
@@ -494,11 +511,12 @@ async function handleStageGateHook(opts) {
494
511
  log(`stage-gate: ${toolName} without file_path \u2014 allowing`);
495
512
  return { exitCode: 0, toolName, toolInput, decision: "allow" };
496
513
  }
497
- const pc = classifyWritePath(targetPath, { homedir });
514
+ const relTarget = isAbsolute(targetPath) ? relative(cwd, targetPath) : targetPath;
515
+ const pc = classifyWritePath(targetPath, { homedir, cwd });
498
516
  if (pc.class === "denied") {
499
517
  pathBlockReason = `${toolName} to '${targetPath}' is always denied: ${pc.reason ?? "forbidden path"}`;
500
518
  } else if (pc.class === "planning-general" || pc.class === "planning-audit") {
501
- const gate = artifactPathGate(targetPath, state.pipelineStep, state);
519
+ const gate = artifactPathGate(relTarget, state.pipelineStep, state);
502
520
  if (gate.kind === "block") {
503
521
  const msg = `stage-gate BLOCK: ${toolName} ${gate.reason} (pipelineStep=${state.pipelineStep})`;
504
522
  log(msg);
@@ -3,7 +3,7 @@ import { defineCommand, runMain } from 'citty';
3
3
  import { existsSync, chmodSync } from 'node:fs';
4
4
  import { mkdir, writeFile, readFile, readdir, copyFile } from 'node:fs/promises';
5
5
  import { join, dirname, delimiter } from 'node:path';
6
- import { l as lucaStateSchema } from '../shared/luca.CRmaAfXR.mjs';
6
+ import { l as lucaStateSchema } from '../shared/luca.DXUcpbIe.mjs';
7
7
  import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { r as runWriteHandler, b as lucaPhaseCurrentTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { r as runWriteHandler, b as lucaPhaseCurrentTool, c as lucaPhaseAdvanceTool, d as lucaPhaseArchiveTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const currentCommand = defineCommand({
20
20
  meta: {
@@ -25,13 +25,33 @@ const currentCommand = defineCommand({
25
25
  await runWriteHandler("phase current", lucaPhaseCurrentTool, {});
26
26
  }
27
27
  });
28
+ const advanceCommand = defineCommand({
29
+ meta: {
30
+ name: "advance",
31
+ description: "Advance the active roadmap phase by one (currentPhase \u2192 currentPhase+1), marking the completed phase done and the next in-progress. Call at the phase boundary (learn step) when more phases remain; the final phase routes to the milestone step."
32
+ },
33
+ async run() {
34
+ await runWriteHandler("phase advance", lucaPhaseAdvanceTool, {});
35
+ }
36
+ });
37
+ const archiveCommand = defineCommand({
38
+ meta: {
39
+ name: "archive",
40
+ description: "Archive all active phase directories (.luca/phases/<slug>/ \u2192 .luca/archive/<slug>/) at milestone close, so the next milestone starts from an empty phases/ dir. Idempotent; skips slugs already archived. Allowed only in the milestone/complete steps."
41
+ },
42
+ async run() {
43
+ await runWriteHandler("phase archive", lucaPhaseArchiveTool, {});
44
+ }
45
+ });
28
46
  const phaseCommand = defineCommand({
29
47
  meta: {
30
48
  name: "phase",
31
- description: "Inspect the active Luca workflow phase"
49
+ description: "Inspect, advance, and archive Luca workflow phases"
32
50
  },
33
51
  subCommands: {
34
- current: currentCommand
52
+ current: currentCommand,
53
+ advance: advanceCommand,
54
+ archive: archiveCommand
35
55
  }
36
56
  });
37
57
 
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { c as readJsonPayload, r as runWriteHandler, k as lucaPrReviewDetectConvergenceTool, m as lucaPrReviewFilterStaleTool, n as lucaPrReviewRegressionCheckTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { e as readJsonPayload, r as runWriteHandler, n as lucaPrReviewDetectConvergenceTool, o as lucaPrReviewFilterStaleTool, p as lucaPrReviewRegressionCheckTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const filterStaleCommand = defineCommand({
20
20
  meta: {
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { c as readJsonPayload, r as runWriteHandler, f as lucaPreferencesReadTool, g as lucaPreferencesWriteTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { e as readJsonPayload, r as runWriteHandler, h as lucaPreferencesReadTool, i as lucaPreferencesWriteTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const readCommand = defineCommand({
20
20
  meta: {
@@ -2,7 +2,7 @@ import { defineCommand } from 'citty';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { readFile, rm } from 'node:fs/promises';
4
4
  import { join } from 'node:path';
5
- import { l as lucaStateSchema } from '../shared/luca.CRmaAfXR.mjs';
5
+ import { l as lucaStateSchema } from '../shared/luca.DXUcpbIe.mjs';
6
6
  import 'node:crypto';
7
7
  import 'node:module';
8
8
  import 'node:url';
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { c as readJsonPayload, r as runWriteHandler, o as lucaRepoCleanupApplyTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { e as readJsonPayload, r as runWriteHandler, q as lucaRepoCleanupApplyTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const cleanupApplyCommand = defineCommand({
20
20
  meta: {
@@ -1,5 +1,5 @@
1
1
  import { defineCommand } from 'citty';
2
- import '../shared/luca.CRmaAfXR.mjs';
2
+ import '../shared/luca.DXUcpbIe.mjs';
3
3
  import 'node:fs';
4
4
  import 'node:fs/promises';
5
5
  import 'node:path';
@@ -7,13 +7,13 @@ import 'node:crypto';
7
7
  import 'node:module';
8
8
  import 'node:url';
9
9
  import 'node:child_process';
10
- import { a as analyzeRun, g as gatherRunArtifacts, r as renderPostmortemMarkdown, c as computePostmortemExitCode } from '../shared/luca.C4gMUoBd.mjs';
11
- import { l as listRuns } from '../shared/luca.HZxBTBgD.mjs';
10
+ import { a as analyzeRun, g as gatherRunArtifacts, r as renderPostmortemMarkdown, c as computePostmortemExitCode } from '../shared/luca.BhM9TDAo.mjs';
11
+ import { l as listRuns } from '../shared/luca.CuvqWf4b.mjs';
12
12
  import { l as logger } from '../shared/luca.dM-MKlNE.mjs';
13
13
  import 'zod';
14
14
  import 'node:os';
15
- import '../shared/luca.BmhNkYe2.mjs';
16
- import '../shared/luca.TSMg1t7I.mjs';
15
+ import '../shared/luca.BQXFn5yo.mjs';
16
+ import '../shared/luca.pqZahLS5.mjs';
17
17
  import 'pathe';
18
18
  import 'consola';
19
19
 
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { c as readJsonPayload, r as runWriteHandler, d as lucaRoadmapReadTool, e as lucaRoadmapCreateTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { e as readJsonPayload, r as runWriteHandler, f as lucaRoadmapReadTool, g as lucaRoadmapCreateTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const readCommand = defineCommand({
20
20
  meta: {
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import { join as join$1 } from 'pathe';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import { existsSync, readdirSync, statSync, readFileSync } from 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import { isAbsolute, resolve, join, extname } from 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import { createRequire } from 'node:module';
9
9
  import { pathToFileURL } from 'node:url';
10
10
  import 'node:child_process';
11
- import { a as analyzeRun, g as gatherRunArtifacts } from '../shared/luca.C4gMUoBd.mjs';
12
- import { l as listRuns } from '../shared/luca.HZxBTBgD.mjs';
11
+ import { a as analyzeRun, g as gatherRunArtifacts } from '../shared/luca.BhM9TDAo.mjs';
12
+ import { l as listRuns } from '../shared/luca.CuvqWf4b.mjs';
13
13
  import { l as logger } from '../shared/luca.dM-MKlNE.mjs';
14
14
  import 'zod';
15
15
  import 'node:os';
16
- import '../shared/luca.BmhNkYe2.mjs';
17
- import '../shared/luca.TSMg1t7I.mjs';
16
+ import '../shared/luca.BQXFn5yo.mjs';
17
+ import '../shared/luca.pqZahLS5.mjs';
18
18
  import 'consola';
19
19
 
20
20
  let tsModuleCache = void 0;
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { r as runWriteHandler, l as lucaStateAdvanceTool, a as lucaStateReadTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { r as runWriteHandler, l as lucaStateAdvanceTool, a as lucaStateReadTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const readCommand = defineCommand({
20
20
  meta: {
@@ -1,7 +1,7 @@
1
1
  import { existsSync, lstatSync } from 'node:fs';
2
2
  import { rm, writeFile, readdir, rmdir } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
- import '../shared/luca.CRmaAfXR.mjs';
4
+ import '../shared/luca.DXUcpbIe.mjs';
5
5
  import 'node:crypto';
6
6
  import 'node:module';
7
7
  import 'node:url';
@@ -1,5 +1,5 @@
1
1
  import { defineCommand } from 'citty';
2
- import { R as RunIdSchema, L as LUCA_DIR_ROOT, T as TelemetryRecordSchema } from '../shared/luca.CRmaAfXR.mjs';
2
+ import { R as RunIdSchema, L as LUCA_DIR_ROOT, T as TelemetryRecordSchema } from '../shared/luca.DXUcpbIe.mjs';
3
3
  import { mkdirSync, appendFileSync } from 'node:fs';
4
4
  import 'node:fs/promises';
5
5
  import { join, dirname } from 'node:path';
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { c as readJsonPayload, r as runWriteHandler, h as lucaTodoUpdateTool, i as lucaTodoListTool, j as lucaTodoAddTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { e as readJsonPayload, r as runWriteHandler, j as lucaTodoUpdateTool, k as lucaTodoListTool, m as lucaTodoAddTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const addCommand = defineCommand({
20
20
  meta: {
@@ -1,5 +1,5 @@
1
1
  import { existsSync, chmodSync, mkdirSync } from 'node:fs';
2
- import '../shared/luca.CRmaAfXR.mjs';
2
+ import '../shared/luca.DXUcpbIe.mjs';
3
3
  import 'node:fs/promises';
4
4
  import 'node:path';
5
5
  import { l as loadCurrentConfig } from '../shared/luca.CQ3g1xrD.mjs';
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
- import '../shared/luca.CRmaAfXR.mjs';
3
- import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.CrXzXueR.mjs';
2
+ import '../shared/luca.DXUcpbIe.mjs';
3
+ import { l as loadCurrentState, r as resolveActiveSlug } from '../shared/luca.BH2GZl5z.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,11 +8,11 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { l as listPhaseSlugs, r as readVerificationResult, a as aggregateVerificationResults } from '../shared/luca.BmhNkYe2.mjs';
11
+ import { l as listPhaseSlugs, r as readVerificationResult, a as aggregateVerificationResults } from '../shared/luca.BQXFn5yo.mjs';
12
12
  import { l as logger } from '../shared/luca.dM-MKlNE.mjs';
13
13
  import 'zod';
14
14
  import 'node:os';
15
- import '../shared/luca.TSMg1t7I.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import 'pathe';
17
17
  import 'consola';
18
18
 
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from 'citty';
2
2
  import 'zod';
3
- import '../shared/luca.CRmaAfXR.mjs';
3
+ import '../shared/luca.DXUcpbIe.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:fs/promises';
6
6
  import 'node:path';
@@ -8,13 +8,13 @@ import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import 'node:child_process';
11
- import { r as runWriteHandler, s as lucaWorkflowResetTool } from '../shared/luca.DjDTeDCi.mjs';
11
+ import { r as runWriteHandler, u as lucaWorkflowResetTool } from '../shared/luca.DykMxS_D.mjs';
12
12
  import 'node:os';
13
- import '../shared/luca.CrXzXueR.mjs';
14
- import '../shared/luca.HZxBTBgD.mjs';
15
- import '../shared/luca.TSMg1t7I.mjs';
13
+ import '../shared/luca.BH2GZl5z.mjs';
14
+ import '../shared/luca.CuvqWf4b.mjs';
15
+ import '../shared/luca.pqZahLS5.mjs';
16
16
  import '../shared/luca.CQ3g1xrD.mjs';
17
- import '../shared/luca.B3Mimc0P.mjs';
17
+ import '../shared/luca.Djs7oPPj.mjs';
18
18
 
19
19
  const resetCommand = defineCommand({
20
20
  meta: {
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: caveman
3
+ description: "Ultra-compressed communication mode. Cuts token usage ~75% by speaking like caveman while keeping full technical accuracy. Supports intensity levels: lite, full (default), ultra. Use when user says \"caveman mode\", \"talk like caveman\", \"use caveman\", \"less tokens\", \"be brief\", or invokes /caveman. Also auto-triggers when token efficiency is requested."
4
+ ---
5
+
6
+ <main>
7
+ # Caveman
8
+
9
+ Respond terse like smart caveman. All technical substance stay. Only fluff die.
10
+
11
+ ## Persistence
12
+
13
+ ACTIVE EVERY RESPONSE. No revert after many turns. No filler drift. Still active if unsure. Off only: "stop caveman" / "normal mode".
14
+
15
+ Default: **full**. Switch: `/caveman lite|full|ultra`.
16
+
17
+ ## Rules
18
+
19
+ Drop: articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), hedging. Fragments OK. Short synonyms (big not extensive, fix not "implement a solution for"). Technical terms exact. Code blocks unchanged. Errors quoted exact.
20
+
21
+ Pattern: `[thing] [action] [reason]. [next step].`
22
+
23
+ Not: "Sure! I'd be happy to help you with that. The issue you're experiencing is likely caused by..."
24
+ Yes: "Bug in auth middleware. Token expiry check use `<` not `<=`. Fix:"
25
+
26
+ ## Intensity
27
+
28
+ | Level | What change |
29
+ |-------|------------|
30
+ | **lite** | No filler/hedging. Keep articles + full sentences. Professional but tight |
31
+ | **full** | Drop articles, fragments OK, short synonyms. Classic caveman |
32
+ | **ultra** | Abbreviate (DB/auth/config/req/res/fn/impl), strip conjunctions, arrows for causality (X → Y), one word when one word enough |
33
+
34
+ Example — "Why React component re-render?"
35
+ - lite: "Your component re-renders because you create a new object reference each render. Wrap it in `useMemo`."
36
+ - full: "New object ref each render. Inline object prop = new ref = re-render. Wrap in `useMemo`."
37
+ - ultra: "Inline obj prop → new ref → re-render. `useMemo`."
38
+
39
+ Example — "Explain database connection pooling."
40
+ - lite: "Connection pooling reuses open connections instead of creating new ones per request. Avoids repeated handshake overhead."
41
+ - full: "Pool reuse open DB connections. No new connection per request. Skip handshake overhead."
42
+ - ultra: "Pool = reuse DB conn. Skip handshake → fast under load."
43
+
44
+ ## Auto-Clarity
45
+
46
+ Drop caveman for: security warnings, irreversible action confirmations, multi-step sequences where fragment order risks misread, user asks to clarify or repeats question. Resume caveman after clear part done.
47
+
48
+ Example — destructive op:
49
+ > **Warning:** This will permanently delete all rows in the `users` table and cannot be undone.
50
+ > ```sql
51
+ > DROP TABLE users;
52
+ > ```
53
+ > Caveman resume. Verify backup exist first.
54
+
55
+ ## Boundaries
56
+
57
+ Code/commits/PRs: write normal. "stop caveman" or "normal mode": revert. Level persist until changed or session end.
58
+ </main>
@@ -80,7 +80,7 @@ Repeat until `pipelineStep` is `complete`:
80
80
  | `checks` | Run `luca checks run --file <commands.json>` with the project's typecheck (and tests, if present). On failure, loop back to `execute`. |
81
81
  | `verify` | Spawn `luca-verifier` (Agent tool). On `recommendation: fix`, loop back to `checks`; on `escalate`, stop and surface to the user. |
82
82
  | `review` | Spawn `luca-reviewer` (Agent tool) — one per perspective, in parallel. |
83
- | `learn` | Spawn `luca-learner` (Agent tool). Then: more phases remain advance to `plan` for the next phase; last phase advance to `milestone`. |
83
+ | `learn` | Spawn `luca-learner` (Agent tool). Then, if more phases remain: run `luca phase advance` (bumps `currentPhase` to the next phase and marks the finished one complete) **before** advancing the step to `plan` the next phase's artifacts resolve against the new `currentPhase`, so skipping this writes them into the wrong (or no) phase dir. On the last phase, do NOT run `luca phase advance`; advance the step to `milestone`. |
84
84
  | `milestone` | Invoke `Skill(skill: "milestone-new")` to close out, or advance to `complete` if no milestone bookkeeping is needed. |
85
85
 
86
86
  ### Oversight
@@ -71,9 +71,16 @@ When updating state during milestone completion, use the `luca` CLI write surfac
71
71
  STATE_JSON=$(luca state read 2>/dev/null || echo '{"initialized":false}')
72
72
  ```
73
73
 
74
- After archiving the milestone, reset workflow state for the next milestone:
74
+ After archiving the milestone, freeze the closing milestone's phase
75
+ directories and reset workflow state for the next milestone:
75
76
 
76
77
  ```bash
78
+ # Move .luca/phases/<slug>/ → .luca/archive/<slug>/ so the next milestone's
79
+ # roadmap starts from an empty phases/ dir (per LUCA_DIR_CONTRACT). Idempotent;
80
+ # skips any slug already present under archive/. Do this BEFORE the next
81
+ # roadmap is created, or stale phase dirs collide on phase number with it.
82
+ luca phase archive 2>/dev/null || true
83
+
77
84
  luca workflow reset 2>/dev/null || true
78
85
  ```
79
86
 
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { defineCommand, runMain as runMain$1 } from 'citty';
2
2
  import 'pathe';
3
3
 
4
4
  async function resolveVersion() {
5
- return "13.0.0-alpha.2";
5
+ return "13.0.0-alpha.3";
6
6
  }
7
7
  const LUCA_VERSION = await resolveVersion();
8
8
 
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
- import { w as lucaStateSchemaTolerant, x as PhaseSlugSchema } from './luca.CRmaAfXR.mjs';
4
+ import { x as lucaStateSchemaTolerant, P as PhaseSlugSchema } from './luca.DXUcpbIe.mjs';
5
5
 
6
6
  async function loadCurrentState(opts) {
7
7
  const statePath = join(opts.cwd, ".luca", "state.json");
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync, readdirSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- import { u as VerificationResultSchema, v as PHASE_SLUG_RE } from './luca.CRmaAfXR.mjs';
4
- import { p as phasePathFor } from './luca.TSMg1t7I.mjs';
3
+ import { v as VerificationResultSchema, w as PHASE_SLUG_RE } from './luca.DXUcpbIe.mjs';
4
+ import { p as phasePathFor } from './luca.pqZahLS5.mjs';
5
5
  import { join as join$1 } from 'pathe';
6
6
  import 'node:fs/promises';
7
7
  import 'node:crypto';
@@ -1,4 +1,4 @@
1
- import './luca.CRmaAfXR.mjs';
1
+ import './luca.DXUcpbIe.mjs';
2
2
  import 'node:fs';
3
3
  import 'node:fs/promises';
4
4
  import 'node:path';
@@ -6,8 +6,8 @@ import 'node:crypto';
6
6
  import 'node:module';
7
7
  import 'node:url';
8
8
  import 'node:child_process';
9
- import { r as readConfidenceJournal, a as readLedgerForRun } from './luca.HZxBTBgD.mjs';
10
- import { l as listPhaseSlugs, r as readVerificationResult } from './luca.BmhNkYe2.mjs';
9
+ import { r as readConfidenceJournal, a as readLedgerForRun } from './luca.CuvqWf4b.mjs';
10
+ import { l as listPhaseSlugs, r as readVerificationResult } from './luca.BQXFn5yo.mjs';
11
11
 
12
12
  function fingerprint(input) {
13
13
  let hash = 0;
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync, mkdirSync, appendFileSync } from 'node:fs';
2
2
  import { join, dirname } from 'node:path';
3
- import { e as lucaRootPaths, q as LedgerEntrySchema, r as ConfidenceEntrySchema } from './luca.CRmaAfXR.mjs';
4
- import { p as phasePathFor } from './luca.TSMg1t7I.mjs';
3
+ import { f as lucaRootPaths, r as LedgerEntrySchema, u as ConfidenceEntrySchema } from './luca.DXUcpbIe.mjs';
4
+ import { p as phasePathFor } from './luca.pqZahLS5.mjs';
5
5
 
6
6
  function appendLedger(opts) {
7
7
  const entry = {
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import 'node:fs';
3
3
  import 'node:fs/promises';
4
- import 'node:path';
4
+ import { isAbsolute, relative } from 'node:path';
5
5
  import 'node:os';
6
6
 
7
7
  const PipelineStepValues = [
@@ -266,8 +266,9 @@ function classifyWritePath(path, opts = {}) {
266
266
  }
267
267
  }
268
268
  }
269
- if (path.startsWith(".luca/") || path === ".luca") {
270
- if (AUDIT_PATH_PATTERN.test(path)) {
269
+ const rel = opts.cwd && isAbsolute(path) ? relative(opts.cwd, path) : path;
270
+ if (rel.startsWith(".luca/") || rel === ".luca") {
271
+ if (AUDIT_PATH_PATTERN.test(rel)) {
271
272
  return { class: "planning-audit" };
272
273
  }
273
274
  return { class: "planning-general" };
@@ -710,4 +711,4 @@ for (const step of Object.keys(STEP_REMINDERS)) {
710
711
  }
711
712
  }
712
713
 
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 };
714
+ export { AUDIT_PATH_PATTERN as A, ClassifyComplexityInputSchema as C, LUCA_DIR_ROOT as L, PhaseSlugSchema as P, RunIdSchema as R, ShadowScanFindingSchema as S, TelemetryRecordSchema as T, VerificationRefSchema as V, WAVE_FILE_RE as W, classifyWritePath as a, ProjectPreferencesSchema as b, coarsePhaseOf as c, ConfidenceCategorySchema as d, ConfidenceLevelSchema as e, lucaRootPaths as f, RoadmapPhaseSchema as g, PipelineStep as h, isLegalTransition as i, PIPELINE_TRANSITIONS as j, PIPELINE_STEP_TO_COARSE_PHASE as k, lucaStateSchema as l, PipelineStepValues as m, TodoIdSchema as n, TodoSchema as o, TodoStatus as p, TODO_CONCEPT_PREFIX as q, LedgerEntrySchema as r, slugFromTitle as s, todoConceptFor as t, ConfidenceEntrySchema as u, VerificationResultSchema as v, PHASE_SLUG_RE as w, lucaStateSchemaTolerant as x, PHASE_FILE_PATHS as y };
@@ -37,6 +37,11 @@ const WRITE_COMMAND_PHASES = {
37
37
  // Phase-restricted structured mutations
38
38
  "roadmap create": ["idle", "triage"],
39
39
  "checks run": ["execute", "checks"],
40
+ // Phase lifecycle: advance at the phase boundary (learn); archive only
41
+ // at milestone close. (The tool descriptors carry matching allowedPhases,
42
+ // but the CLI self-check consults THIS table — runWriteHandler.)
43
+ "phase advance": ["learn"],
44
+ "phase archive": ["milestone", "complete"],
40
45
  // Phase-restricted freeform artifact writes
41
46
  "phase write-research": ["research"],
42
47
  "phase write-context": ["discuss"],
@@ -1,17 +1,22 @@
1
1
  import { z } from 'zod';
2
- import { P as ProjectPreferencesSchema, b as ConfidenceCategorySchema, d as ConfidenceLevelSchema, e as lucaRootPaths, S as ShadowScanFindingSchema, f as RoadmapPhaseSchema, g as PipelineStep, i as isLegalTransition, h as PIPELINE_TRANSITIONS, j as PIPELINE_STEP_TO_COARSE_PHASE, k as PipelineStepValues, m as TodoIdSchema, s as slugFromTitle, n as TodoSchema, t as todoConceptFor, o as TodoStatus, p as TODO_CONCEPT_PREFIX, V as VerificationRefSchema, l as lucaStateSchema } from './luca.CRmaAfXR.mjs';
3
- import { l as loadCurrentState, r as resolveActiveSlug } from './luca.CrXzXueR.mjs';
2
+ import { P as PhaseSlugSchema, L as LUCA_DIR_ROOT, b as ProjectPreferencesSchema, d as ConfidenceCategorySchema, e as ConfidenceLevelSchema, f as lucaRootPaths, S as ShadowScanFindingSchema, g as RoadmapPhaseSchema, h as PipelineStep, i as isLegalTransition, j as PIPELINE_TRANSITIONS, k as PIPELINE_STEP_TO_COARSE_PHASE, m as PipelineStepValues, n as TodoIdSchema, s as slugFromTitle, o as TodoSchema, t as todoConceptFor, p as TodoStatus, q as TODO_CONCEPT_PREFIX, V as VerificationRefSchema, l as lucaStateSchema } from './luca.DXUcpbIe.mjs';
3
+ import { l as loadCurrentState, r as resolveActiveSlug } from './luca.BH2GZl5z.mjs';
4
4
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
5
- import { mkdir, writeFile, rename, rm, readFile, appendFile, unlink } from 'node:fs/promises';
5
+ import { mkdir, writeFile, rename, rm, readFile, readdir, appendFile, unlink } from 'node:fs/promises';
6
6
  import { join, dirname, resolve, relative, sep } from 'node:path';
7
7
  import 'node:crypto';
8
8
  import 'node:module';
9
9
  import 'node:url';
10
10
  import { spawnSync } from 'node:child_process';
11
- import { c as appendConfidenceEntry, d as appendLedger } from './luca.HZxBTBgD.mjs';
12
- import { p as phasePathFor } from './luca.TSMg1t7I.mjs';
11
+ import { c as appendConfidenceEntry, d as appendLedger } from './luca.CuvqWf4b.mjs';
12
+ import { p as phasePathFor } from './luca.pqZahLS5.mjs';
13
13
  import { l as loadCurrentConfig } from './luca.CQ3g1xrD.mjs';
14
- import { S as STEP_ARTIFACTS, W as WRITE_COMMAND_PHASES } from './luca.B3Mimc0P.mjs';
14
+ import { S as STEP_ARTIFACTS, W as WRITE_COMMAND_PHASES } from './luca.Djs7oPPj.mjs';
15
+
16
+ function archivedPhasePathFor(slug) {
17
+ PhaseSlugSchema.parse(slug);
18
+ return `${LUCA_DIR_ROOT}/archive/${slug}`;
19
+ }
15
20
 
16
21
  const PREFERENCE_SECTIONS = [
17
22
  "schemaVersion",
@@ -578,7 +583,7 @@ async function validateVerificationRef(opts) {
578
583
  return null;
579
584
  }
580
585
 
581
- const inputSchema$h = z.object({
586
+ const inputSchema$j = z.object({
582
587
  default_branch: z.string().min(1).default("main").describe(
583
588
  "Branch name that must NOT equal the current branch (typically the repository default branch)."
584
589
  )
@@ -597,7 +602,7 @@ async function readCurrentBranch(cwd) {
597
602
  const lucaBranchGuardTool = {
598
603
  name: "luca_branch_guard",
599
604
  description: "Assert that the current git branch is NOT the repository default branch. Returns isError when on the default branch, otherwise ok=true. Use before committing to prevent accidental main writes.",
600
- inputSchema: inputSchema$h,
605
+ inputSchema: inputSchema$j,
601
606
  async handler(args, ctx) {
602
607
  const current = await readCurrentBranch(ctx.cwd);
603
608
  if (current === null) {
@@ -634,7 +639,7 @@ const commandSchema = z.object({
634
639
  "Optional human-friendly label for this command in the summary output. Defaults to the argv joined by spaces."
635
640
  )
636
641
  });
637
- const inputSchema$g = z.object({
642
+ const inputSchema$i = z.object({
638
643
  commands: z.array(commandSchema).min(1).describe(
639
644
  "Ordered list of commands to run sequentially. Each command runs only if the previous one is still within budget; failures do NOT stop the sequence."
640
645
  ),
@@ -714,7 +719,7 @@ async function runOne(argv, label, cwd, timeoutMs) {
714
719
  const lucaChecksRunTool = {
715
720
  name: "luca_checks_run",
716
721
  description: "Run verification commands (typecheck/tests/lint) sequentially with per-command timeout and SIGTERM/SIGKILL cleanup. Returns structured summary per command. Only callable in execute/checks phases.",
717
- inputSchema: inputSchema$g,
722
+ inputSchema: inputSchema$i,
718
723
  allowedPhases: ["execute", "checks"],
719
724
  async handler(args, ctx) {
720
725
  const results = [];
@@ -732,7 +737,7 @@ const lucaChecksRunTool = {
732
737
  }
733
738
  };
734
739
 
735
- const inputSchema$f = z.object({
740
+ const inputSchema$h = z.object({
736
741
  phase: z.string().min(1).describe("Phase name from the plan / roadmap."),
737
742
  wave: z.number().describe("Wave number within the phase."),
738
743
  task: z.string().min(1).describe("Task ID or description from the plan."),
@@ -752,7 +757,7 @@ const inputSchema$f = z.object({
752
757
  const lucaConfidenceLogTool = {
753
758
  name: "luca_confidence_log",
754
759
  description: "Append a confidence entry to the active phase's confidence.jsonl. One JSONL line per call. Payload matches the canonical ConfidenceEntrySchema (phase, wave, task, confidence, category, decision, alternatives, reasoning, risk, files, reviewHint?).",
755
- inputSchema: inputSchema$f,
760
+ inputSchema: inputSchema$h,
756
761
  async handler(args, ctx) {
757
762
  const state = await loadCurrentState({ cwd: ctx.cwd });
758
763
  const slug = resolveActiveSlug(state);
@@ -790,6 +795,109 @@ const lucaConfidenceLogTool = {
790
795
  }
791
796
  };
792
797
 
798
+ const inputSchema$g = z.object({});
799
+ const lucaPhaseAdvanceTool = {
800
+ name: "luca_phase_advance",
801
+ description: "Advance the active roadmap phase by one (currentPhase \u2192 currentPhase+1), marking the completed phase `complete` and the next `in-progress`. Call at the phase boundary (learn step) when more phases remain; the final phase routes to the milestone step instead. Errors if no phase is active (currentPhase=0) or already at the final phase.",
802
+ inputSchema: inputSchema$g,
803
+ allowedPhases: ["learn"],
804
+ async handler(_args, ctx) {
805
+ const state = await loadCurrentState({ cwd: ctx.cwd });
806
+ const { currentPhase, totalPhases } = state;
807
+ if (currentPhase === 0) {
808
+ return errorResult(
809
+ "no active phase to advance (currentPhase=0). Create a roadmap first (`luca roadmap create`)."
810
+ );
811
+ }
812
+ if (currentPhase >= totalPhases) {
813
+ return errorResult(
814
+ `already at the final phase (${currentPhase}/${totalPhases}); there is no next phase. Advance to the milestone step instead.`
815
+ );
816
+ }
817
+ const roadmap = state.roadmap.map((phase, index) => {
818
+ if (index === currentPhase - 1) {
819
+ return { ...phase, status: "complete" };
820
+ }
821
+ if (index === currentPhase) {
822
+ return { ...phase, status: "in-progress" };
823
+ }
824
+ return phase;
825
+ });
826
+ const next = { ...state, roadmap, currentPhase: currentPhase + 1 };
827
+ const absPath = join(ctx.cwd, lucaRootPaths.state);
828
+ await writeAtomicFile(absPath, JSON.stringify(next, null, 2) + "\n");
829
+ return {
830
+ content: [
831
+ {
832
+ type: "text",
833
+ text: `phase advanced: ${currentPhase} \u2192 ${currentPhase + 1} of ${totalPhases} (phase ${currentPhase} marked complete, phase ${currentPhase + 1} in-progress)`
834
+ }
835
+ ]
836
+ };
837
+ }
838
+ };
839
+ function errorResult(message) {
840
+ return {
841
+ content: [{ type: "text", text: message }],
842
+ isError: true
843
+ };
844
+ }
845
+
846
+ const inputSchema$f = z.object({});
847
+ const lucaPhaseArchiveTool = {
848
+ name: "luca_phase_archive",
849
+ description: "Archive all active phase directories (.luca/phases/<slug>/ \u2192 .luca/archive/<slug>/) at milestone close, so the next milestone starts from an empty phases/ dir. Idempotent: a slug already present under archive/ is skipped, not overwritten. Allowed only in the milestone/complete steps.",
850
+ inputSchema: inputSchema$f,
851
+ allowedPhases: ["milestone", "complete"],
852
+ async handler(_args, ctx) {
853
+ const phasesDir = join(ctx.cwd, ".luca", "phases");
854
+ if (!existsSync(phasesDir)) {
855
+ return ok("no .luca/phases/ directory \u2014 nothing to archive.");
856
+ }
857
+ const entries = await readdir(phasesDir, { withFileTypes: true });
858
+ const archived = [];
859
+ const skipped = [];
860
+ const invalid = [];
861
+ for (const entry of entries) {
862
+ if (!entry.isDirectory()) continue;
863
+ const slug = entry.name;
864
+ let to;
865
+ try {
866
+ to = join(ctx.cwd, archivedPhasePathFor(slug));
867
+ } catch {
868
+ invalid.push(slug);
869
+ continue;
870
+ }
871
+ const from = join(phasesDir, slug);
872
+ if (existsSync(to)) {
873
+ skipped.push(slug);
874
+ continue;
875
+ }
876
+ await mkdir(join(ctx.cwd, ".luca", "archive"), {
877
+ recursive: true
878
+ });
879
+ await rename(from, to);
880
+ archived.push(slug);
881
+ }
882
+ const parts = [`archived ${archived.length} phase(s) \u2192 .luca/archive/`];
883
+ if (archived.length > 0) parts.push(`moved: ${archived.join(", ")}`);
884
+ if (skipped.length > 0) {
885
+ parts.push(
886
+ `skipped (archive entry already exists): ${skipped.join(", ")}`
887
+ );
888
+ }
889
+ if (invalid.length > 0) {
890
+ parts.push(
891
+ `skipped (not a valid phase slug): ${invalid.join(", ")}`
892
+ );
893
+ }
894
+ return ok(parts.join(". "));
895
+ }
896
+ };
897
+ function ok(text) {
898
+ return { content: [{ type: "text", text }] };
899
+ }
900
+
793
901
  const inputSchema$e = z.object({});
794
902
  const lucaPhaseCurrentTool = {
795
903
  name: "luca_phase_current",
@@ -1283,7 +1391,7 @@ const inputSchema$7 = z.object({
1283
1391
  });
1284
1392
  const lucaRoadmapCreateTool = {
1285
1393
  name: "luca_roadmap_create",
1286
- description: "Replace the roadmap in .luca/state.json with a new ordered list of phases. Resets currentPhase to 0; updates totalPhases. Only callable in idle or triage pipelineSteps so an active roadmap cannot be clobbered mid-execution.",
1394
+ description: "Replace the roadmap in .luca/state.json with a new ordered list of phases. Activates phase 1 (currentPhase=1) when non-empty; updates totalPhases. Only callable in idle or triage pipelineSteps so an active roadmap cannot be clobbered mid-execution.",
1287
1395
  inputSchema: inputSchema$7,
1288
1396
  allowedPhases: ["idle", "triage"],
1289
1397
  async handler(args, ctx) {
@@ -1293,11 +1401,12 @@ const lucaRoadmapCreateTool = {
1293
1401
  deps: p.deps ?? [],
1294
1402
  status: p.status ?? "pending"
1295
1403
  }));
1404
+ const currentPhase = phases.length > 0 ? 1 : 0;
1296
1405
  const next = {
1297
1406
  ...state,
1298
1407
  roadmap: phases,
1299
1408
  totalPhases: phases.length,
1300
- currentPhase: 0
1409
+ currentPhase
1301
1410
  };
1302
1411
  const absPath = join(ctx.cwd, lucaRootPaths.state);
1303
1412
  await writeAtomicFile(absPath, JSON.stringify(next, null, 2) + "\n");
@@ -1305,7 +1414,7 @@ const lucaRoadmapCreateTool = {
1305
1414
  content: [
1306
1415
  {
1307
1416
  type: "text",
1308
- text: `wrote .luca/state.json (roadmap replaced with ${phases.length} phase(s); currentPhase reset to 0)`
1417
+ text: `wrote .luca/state.json (roadmap replaced with ${phases.length} phase(s); currentPhase=${currentPhase})`
1309
1418
  }
1310
1419
  ]
1311
1420
  };
@@ -1901,4 +2010,4 @@ async function readJsonPayload(command, filePath) {
1901
2010
  }
1902
2011
  }
1903
2012
 
1904
- export { lucaStateReadTool as a, lucaPhaseCurrentTool as b, readJsonPayload as c, lucaRoadmapReadTool as d, lucaRoadmapCreateTool as e, lucaPreferencesReadTool as f, lucaPreferencesWriteTool as g, lucaTodoUpdateTool as h, lucaTodoListTool as i, lucaTodoAddTool as j, lucaPrReviewDetectConvergenceTool as k, lucaStateAdvanceTool as l, lucaPrReviewFilterStaleTool as m, lucaPrReviewRegressionCheckTool as n, lucaRepoCleanupApplyTool as o, lucaChecksRunTool as p, lucaBranchGuardTool as q, runWriteHandler as r, lucaWorkflowResetTool as s, lucaConfidenceLogTool as t };
2013
+ export { lucaStateReadTool as a, lucaPhaseCurrentTool as b, lucaPhaseAdvanceTool as c, lucaPhaseArchiveTool as d, readJsonPayload as e, lucaRoadmapReadTool as f, lucaRoadmapCreateTool as g, lucaPreferencesReadTool as h, lucaPreferencesWriteTool as i, lucaTodoUpdateTool as j, lucaTodoListTool as k, lucaStateAdvanceTool as l, lucaTodoAddTool as m, lucaPrReviewDetectConvergenceTool as n, lucaPrReviewFilterStaleTool as o, lucaPrReviewRegressionCheckTool as p, lucaRepoCleanupApplyTool as q, runWriteHandler as r, lucaChecksRunTool as s, lucaBranchGuardTool as t, lucaWorkflowResetTool as u, lucaConfidenceLogTool as v };
@@ -1,4 +1,4 @@
1
- import { x as PhaseSlugSchema, L as LUCA_DIR_ROOT, y as PHASE_FILE_PATHS } from './luca.CRmaAfXR.mjs';
1
+ import { P as PhaseSlugSchema, L as LUCA_DIR_ROOT, y as PHASE_FILE_PATHS } from './luca.DXUcpbIe.mjs';
2
2
 
3
3
  function phasePathFor(slug, file) {
4
4
  PhaseSlugSchema.parse(slug);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alecsibilia/luca",
3
3
  "description": "Luca — spec-driven agentic development workflow for Claude Code (umbrella; bundles luca-cli, luca-core, luca-tools)",
4
- "version": "13.0.0-alpha.2",
4
+ "version": "13.0.0-alpha.3",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Alec Sibilia <sibilia.alec@gmail.com>",
7
7
  "homepage": "https://github.com/asibilia/luca-framework#readme",