@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,66 @@
1
+ import { h as checkMuninndbBinary, d as checkMuninndbService } from '../shared/luca.BYdjkfnz.mjs';
2
+ import 'pathe';
3
+ import 'node:fs';
4
+ import 'node:fs/promises';
5
+ import 'node:os';
6
+ import 'zod';
7
+ import '../shared/luca.DTomPq7I.mjs';
8
+ import '@clack/prompts';
9
+ import 'semver';
10
+
11
+ const muninndbHealthCheck = {
12
+ name: "MuninnDB",
13
+ scope: "global",
14
+ async run() {
15
+ const binary = await checkMuninndbBinary();
16
+ if (!binary.installed) {
17
+ return {
18
+ name: this.name,
19
+ status: "fail",
20
+ message: "MuninnDB binary not found",
21
+ fixCommand: "luca init",
22
+ details: "MuninnDB binary not installed at ~/.luca/bin/muninndb. Run `luca init` to install it."
23
+ };
24
+ }
25
+ if (!binary.executable) {
26
+ return {
27
+ name: this.name,
28
+ status: "fail",
29
+ message: "MuninnDB binary not executable",
30
+ fixCommand: "chmod +x ~/.luca/bin/muninndb",
31
+ details: `Binary found at ${binary.path} but lacks executable permissions.`
32
+ };
33
+ }
34
+ const service = await checkMuninndbService();
35
+ if (!service.running) {
36
+ const versionSuffix2 = binary.version ? ` (${binary.version})` : "";
37
+ return {
38
+ name: this.name,
39
+ status: "warning",
40
+ message: `Binary installed${versionSuffix2}, service not running`,
41
+ fixCommand: "muninn start",
42
+ details: `Binary at ${binary.path}. Start the service with: muninn start`
43
+ };
44
+ }
45
+ if (!service.healthy) {
46
+ return {
47
+ name: this.name,
48
+ status: "warning",
49
+ message: `Service running on port ${service.port} but unhealthy`,
50
+ fixCommand: "Restart MuninnDB",
51
+ details: "MuninnDB process is running but failed the health check. Try restarting it."
52
+ };
53
+ }
54
+ const versionSuffix = binary.version ? ` (${binary.version})` : "";
55
+ const pidSuffix = service.pid ? `, PID ${service.pid}` : "";
56
+ return {
57
+ name: this.name,
58
+ status: "pass",
59
+ message: `Binary installed${versionSuffix}, service healthy (port ${service.port}${pidSuffix})`,
60
+ fixCommand: null,
61
+ details: null
62
+ };
63
+ }
64
+ };
65
+
66
+ export { muninndbHealthCheck };
@@ -0,0 +1,38 @@
1
+ import { defineCommand } from 'citty';
2
+ import 'zod';
3
+ import '../shared/luca.CRmaAfXR.mjs';
4
+ import 'node:fs';
5
+ import 'node:fs/promises';
6
+ import 'node:path';
7
+ import 'node:crypto';
8
+ import 'node:module';
9
+ import 'node:url';
10
+ import 'node:child_process';
11
+ import { r as runWriteHandler, b as lucaPhaseCurrentTool } from '../shared/luca.DjDTeDCi.mjs';
12
+ import 'node:os';
13
+ import '../shared/luca.CrXzXueR.mjs';
14
+ import '../shared/luca.HZxBTBgD.mjs';
15
+ import '../shared/luca.TSMg1t7I.mjs';
16
+ import '../shared/luca.CQ3g1xrD.mjs';
17
+ import '../shared/luca.B3Mimc0P.mjs';
18
+
19
+ const currentCommand = defineCommand({
20
+ meta: {
21
+ name: "current",
22
+ description: "Report the currently active phase: { active, NN, slug, dir }. Returns { active: false } when no phase is active. Use the `dir` field as the base for native Write-tool artifact paths. Pure read; allowed in every pipelineStep."
23
+ },
24
+ async run() {
25
+ await runWriteHandler("phase current", lucaPhaseCurrentTool, {});
26
+ }
27
+ });
28
+ const phaseCommand = defineCommand({
29
+ meta: {
30
+ name: "phase",
31
+ description: "Inspect the active Luca workflow phase"
32
+ },
33
+ subCommands: {
34
+ current: currentCommand
35
+ }
36
+ });
37
+
38
+ export { phaseCommand };
@@ -0,0 +1,122 @@
1
+ import { defineCommand } from 'citty';
2
+ import 'zod';
3
+ import '../shared/luca.CRmaAfXR.mjs';
4
+ import 'node:fs';
5
+ import 'node:fs/promises';
6
+ import 'node:path';
7
+ import 'node:crypto';
8
+ import 'node:module';
9
+ import 'node:url';
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';
12
+ import 'node:os';
13
+ import '../shared/luca.CrXzXueR.mjs';
14
+ import '../shared/luca.HZxBTBgD.mjs';
15
+ import '../shared/luca.TSMg1t7I.mjs';
16
+ import '../shared/luca.CQ3g1xrD.mjs';
17
+ import '../shared/luca.B3Mimc0P.mjs';
18
+
19
+ const filterStaleCommand = defineCommand({
20
+ meta: {
21
+ name: "filter-stale",
22
+ description: "Classify PR review comments against the current working tree and drop those whose cited code has been rewritten. Pure read; phase-agnostic."
23
+ },
24
+ args: {
25
+ file: {
26
+ type: "string",
27
+ required: true,
28
+ description: "Path to a JSON file containing the comments array (gh api pulls/<n>/comments shape)."
29
+ },
30
+ "head-sha": {
31
+ type: "string",
32
+ description: "Override HEAD SHA used for stale detection. Defaults to current git HEAD."
33
+ },
34
+ "max-drift-lines": {
35
+ type: "string",
36
+ description: "Max line drift before a relocated anchor is treated as stale (default 5)."
37
+ }
38
+ },
39
+ async run({ args }) {
40
+ const comments = await readJsonPayload(
41
+ "pr-review filter-stale",
42
+ args.file
43
+ );
44
+ await runWriteHandler(
45
+ "pr-review filter-stale",
46
+ lucaPrReviewFilterStaleTool,
47
+ {
48
+ comments,
49
+ head_sha: args["head-sha"],
50
+ max_drift_lines: args["max-drift-lines"] !== void 0 ? Number(args["max-drift-lines"]) : void 0
51
+ }
52
+ );
53
+ }
54
+ });
55
+ const detectConvergenceCommand = defineCommand({
56
+ meta: {
57
+ name: "detect-convergence",
58
+ description: "Detect cross-perspective convergence: when 2+ independent reviewer perspectives flag the same location, promote weaker findings in that cluster to must-fix. Pure read; phase-agnostic."
59
+ },
60
+ args: {
61
+ file: {
62
+ type: "string",
63
+ required: true,
64
+ description: "Path to a JSON file containing the combined findings array across every reviewer perspective."
65
+ },
66
+ "line-tolerance": {
67
+ type: "string",
68
+ description: "Lines within +/- this distance count as the same location (default 2)."
69
+ }
70
+ },
71
+ async run({ args }) {
72
+ const findings = await readJsonPayload(
73
+ "pr-review detect-convergence",
74
+ args.file
75
+ );
76
+ await runWriteHandler(
77
+ "pr-review detect-convergence",
78
+ lucaPrReviewDetectConvergenceTool,
79
+ {
80
+ findings,
81
+ line_tolerance: args["line-tolerance"] !== void 0 ? Number(args["line-tolerance"]) : void 0
82
+ }
83
+ );
84
+ }
85
+ });
86
+ const regressionCheckCommand = defineCommand({
87
+ meta: {
88
+ name: "regression-check",
89
+ description: "Detect findings introduced by a fix iteration. Compares before/after finding snapshots and flags anything new on a touched path, or any severity escalation. Pure read; phase-agnostic. Exits 1 when regressions are present."
90
+ },
91
+ args: {
92
+ file: {
93
+ type: "string",
94
+ required: true,
95
+ description: "Path to a JSON file with the full payload: { before: Finding[], after: Finding[], touched_paths?: string[], from_sha?: string, to_sha?: string }."
96
+ }
97
+ },
98
+ async run({ args }) {
99
+ const payload = await readJsonPayload(
100
+ "pr-review regression-check",
101
+ args.file
102
+ );
103
+ await runWriteHandler(
104
+ "pr-review regression-check",
105
+ lucaPrReviewRegressionCheckTool,
106
+ payload
107
+ );
108
+ }
109
+ });
110
+ const prReviewCommand = defineCommand({
111
+ meta: {
112
+ name: "pr-review",
113
+ description: "Read-only PR-review analysis for the gh-pr-address flow"
114
+ },
115
+ subCommands: {
116
+ "filter-stale": filterStaleCommand,
117
+ "detect-convergence": detectConvergenceCommand,
118
+ "regression-check": regressionCheckCommand
119
+ }
120
+ });
121
+
122
+ export { prReviewCommand };
@@ -0,0 +1,61 @@
1
+ import { defineCommand } from 'citty';
2
+ import 'zod';
3
+ import '../shared/luca.CRmaAfXR.mjs';
4
+ import 'node:fs';
5
+ import 'node:fs/promises';
6
+ import 'node:path';
7
+ import 'node:crypto';
8
+ import 'node:module';
9
+ import 'node:url';
10
+ import 'node:child_process';
11
+ import { c as readJsonPayload, r as runWriteHandler, f as lucaPreferencesReadTool, g as lucaPreferencesWriteTool } from '../shared/luca.DjDTeDCi.mjs';
12
+ import 'node:os';
13
+ import '../shared/luca.CrXzXueR.mjs';
14
+ import '../shared/luca.HZxBTBgD.mjs';
15
+ import '../shared/luca.TSMg1t7I.mjs';
16
+ import '../shared/luca.CQ3g1xrD.mjs';
17
+ import '../shared/luca.B3Mimc0P.mjs';
18
+
19
+ const readCommand = defineCommand({
20
+ meta: {
21
+ name: "read",
22
+ description: "Read the project preferences object from .luca/config.json#preferences. Returns ProjectPreferencesSchema-validated JSON with defaults applied to unset sections. Pure read; allowed in every pipelineStep."
23
+ },
24
+ async run() {
25
+ await runWriteHandler("preferences read", lucaPreferencesReadTool, {});
26
+ }
27
+ });
28
+ const writeCommand = defineCommand({
29
+ meta: {
30
+ name: "write",
31
+ description: "Update the preferences section of .luca/config.json. Section-level shallow merge; other config keys are preserved. The merged result is validated against ProjectPreferencesSchema before write (rejects unsafe free-form input and ReDoS regex)."
32
+ },
33
+ args: {
34
+ file: {
35
+ type: "string",
36
+ required: true,
37
+ description: "Path to a JSON file containing the partial preferences object. Top-level sections (branching, commits, pr, release, tracker, schemaVersion) overlay existing ones; unspecified sections are left unchanged. Supplied as a file because the object may be large."
38
+ }
39
+ },
40
+ async run({ args }) {
41
+ const preferences = await readJsonPayload(
42
+ "preferences write",
43
+ args.file
44
+ );
45
+ await runWriteHandler("preferences write", lucaPreferencesWriteTool, {
46
+ preferences
47
+ });
48
+ }
49
+ });
50
+ const preferencesCommand = defineCommand({
51
+ meta: {
52
+ name: "preferences",
53
+ description: "Read and update Luca project preferences"
54
+ },
55
+ subCommands: {
56
+ read: readCommand,
57
+ write: writeCommand
58
+ }
59
+ });
60
+
61
+ export { preferencesCommand };
@@ -0,0 +1,111 @@
1
+ import { defineCommand } from 'citty';
2
+ import { existsSync } from 'node:fs';
3
+ import { readFile, rm } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { l as lucaStateSchema } from '../shared/luca.CRmaAfXR.mjs';
6
+ import 'node:crypto';
7
+ import 'node:module';
8
+ import 'node:url';
9
+ import 'node:child_process';
10
+ import 'zod';
11
+ import 'node:os';
12
+
13
+ async function runRepair(opts) {
14
+ const log = opts.log ?? (() => {
15
+ });
16
+ const lucaDir = join(opts.cwd, ".luca");
17
+ if (!existsSync(lucaDir)) {
18
+ return { actions: [], notes: [], errors: [] };
19
+ }
20
+ const actions = [];
21
+ const notes = [];
22
+ const errors = [];
23
+ const lockPath = join(lucaDir, "lock.json");
24
+ if (existsSync(lockPath)) {
25
+ try {
26
+ const raw = await readFile(lockPath, "utf-8");
27
+ const lock = JSON.parse(raw);
28
+ if (typeof lock.pid === "number" && isPidRunning(lock.pid)) {
29
+ const msg = `lock is held by running PID ${lock.pid}`;
30
+ notes.push(msg);
31
+ log(msg);
32
+ } else {
33
+ await rm(lockPath, { force: true });
34
+ const msg = `cleared stale lock (PID ${lock.pid ?? "unknown"})`;
35
+ actions.push(msg);
36
+ log(msg);
37
+ }
38
+ } catch (err) {
39
+ const msg = `failed to read lock.json: ${err.message}`;
40
+ errors.push(msg);
41
+ log(msg);
42
+ }
43
+ }
44
+ const statePath = join(lucaDir, "state.json");
45
+ if (existsSync(statePath)) {
46
+ try {
47
+ const raw = JSON.parse(await readFile(statePath, "utf-8"));
48
+ const parsed = lucaStateSchema.safeParse(raw);
49
+ if (!parsed.success) {
50
+ const msg = `state.json failed schema validation: ${parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`;
51
+ errors.push(msg);
52
+ log(msg);
53
+ }
54
+ } catch (err) {
55
+ errors.push(
56
+ `state.json could not be parsed as JSON: ${err.message}`
57
+ );
58
+ }
59
+ }
60
+ return { actions, notes, errors };
61
+ }
62
+ function isPidRunning(pid) {
63
+ try {
64
+ process.kill(pid, 0);
65
+ return true;
66
+ } catch (err) {
67
+ if (err.code === "EPERM") return true;
68
+ return false;
69
+ }
70
+ }
71
+
72
+ const repairCommand = defineCommand({
73
+ meta: {
74
+ name: "repair",
75
+ description: "Diagnose and recover the project .luca/ directory (clears stale locks, validates state)"
76
+ },
77
+ async run() {
78
+ const cwd = process.cwd();
79
+ const result = await runRepair({
80
+ cwd,
81
+ log: (msg) => {
82
+ console.log(` ${msg}`);
83
+ }
84
+ });
85
+ if (result.actions.length === 0 && result.notes.length === 0 && result.errors.length === 0) {
86
+ console.log("Nothing to repair.");
87
+ return;
88
+ }
89
+ if (result.actions.length > 0) {
90
+ console.log("\n== Actions taken ==");
91
+ for (const action of result.actions) {
92
+ console.log(` ${action}`);
93
+ }
94
+ }
95
+ if (result.notes.length > 0) {
96
+ console.log("\n== Notes (no repair needed) ==");
97
+ for (const note of result.notes) {
98
+ console.log(` ${note}`);
99
+ }
100
+ }
101
+ if (result.errors.length > 0) {
102
+ console.log("\n== Errors (not auto-fixed) ==");
103
+ for (const err of result.errors) {
104
+ console.log(` ${err}`);
105
+ }
106
+ process.exit(1);
107
+ }
108
+ }
109
+ });
110
+
111
+ export { repairCommand };
@@ -0,0 +1,58 @@
1
+ import { defineCommand } from 'citty';
2
+ import 'zod';
3
+ import '../shared/luca.CRmaAfXR.mjs';
4
+ import 'node:fs';
5
+ import 'node:fs/promises';
6
+ import 'node:path';
7
+ import 'node:crypto';
8
+ import 'node:module';
9
+ import 'node:url';
10
+ import 'node:child_process';
11
+ import { c as readJsonPayload, r as runWriteHandler, o as lucaRepoCleanupApplyTool } from '../shared/luca.DjDTeDCi.mjs';
12
+ import 'node:os';
13
+ import '../shared/luca.CrXzXueR.mjs';
14
+ import '../shared/luca.HZxBTBgD.mjs';
15
+ import '../shared/luca.TSMg1t7I.mjs';
16
+ import '../shared/luca.CQ3g1xrD.mjs';
17
+ import '../shared/luca.B3Mimc0P.mjs';
18
+
19
+ const cleanupApplyCommand = defineCommand({
20
+ meta: {
21
+ name: "cleanup-apply",
22
+ description: "Apply a single remediation finding from a luca-shadow-scanner ShadowScanReport. The finding's recommended_action drives what gets applied (delete/move). Requires --confirm; phase-agnostic."
23
+ },
24
+ args: {
25
+ file: {
26
+ type: "string",
27
+ required: true,
28
+ description: "Path to a JSON file containing a single ShadowScanFinding object from a ShadowScanReport."
29
+ },
30
+ confirm: {
31
+ type: "boolean",
32
+ default: false,
33
+ description: "Must be passed to actually apply the remediation. Without it the command is a no-op preview so a stray call cannot delete or move files."
34
+ }
35
+ },
36
+ async run({ args }) {
37
+ const finding = await readJsonPayload("repo cleanup-apply", args.file);
38
+ await runWriteHandler(
39
+ "repo cleanup-apply",
40
+ lucaRepoCleanupApplyTool,
41
+ {
42
+ finding,
43
+ confirm: args.confirm
44
+ }
45
+ );
46
+ }
47
+ });
48
+ const repoCommand = defineCommand({
49
+ meta: {
50
+ name: "repo",
51
+ description: "Repository housekeeping for the Luca workflow"
52
+ },
53
+ subCommands: {
54
+ "cleanup-apply": cleanupApplyCommand
55
+ }
56
+ });
57
+
58
+ export { repoCommand };
@@ -0,0 +1,86 @@
1
+ import { defineCommand } from 'citty';
2
+ import '../shared/luca.CRmaAfXR.mjs';
3
+ import 'node:fs';
4
+ import 'node:fs/promises';
5
+ import 'node:path';
6
+ import 'node:crypto';
7
+ import 'node:module';
8
+ import 'node:url';
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';
12
+ import { l as logger } from '../shared/luca.dM-MKlNE.mjs';
13
+ import 'zod';
14
+ import 'node:os';
15
+ import '../shared/luca.BmhNkYe2.mjs';
16
+ import '../shared/luca.TSMg1t7I.mjs';
17
+ import 'pathe';
18
+ import 'consola';
19
+
20
+ const retroCommand = defineCommand({
21
+ meta: {
22
+ name: "retro",
23
+ description: "Generate a postmortem for a Luca pipeline run."
24
+ },
25
+ args: {
26
+ run: {
27
+ type: "string",
28
+ description: "Run id to analyze (default: the most recent run in the ledger)."
29
+ },
30
+ list: {
31
+ type: "boolean",
32
+ description: "List the runs recorded in .luca/ledger.jsonl."
33
+ },
34
+ json: {
35
+ type: "boolean",
36
+ description: "Emit the full PostmortemReport as JSON instead of Markdown."
37
+ }
38
+ },
39
+ run({ args }) {
40
+ const cwd = process.cwd();
41
+ const runs = listRuns({ cwd });
42
+ if (args.list) {
43
+ if (runs.length === 0) {
44
+ logger.info("No runs recorded in .luca/ledger.jsonl.");
45
+ return;
46
+ }
47
+ for (const r of runs) {
48
+ logger.info(
49
+ `${r.runId} \u2014 ${r.eventCount} event(s), ${r.firstEvent} \u2192 ${r.lastEvent}`
50
+ );
51
+ }
52
+ return;
53
+ }
54
+ if (runs.length === 0) {
55
+ logger.warn(
56
+ "No runs recorded in .luca/ledger.jsonl \u2014 nothing to analyze."
57
+ );
58
+ return;
59
+ }
60
+ let runId = args.run;
61
+ if (!runId) {
62
+ runId = [...runs].sort(
63
+ (a, b) => b.lastEvent.localeCompare(a.lastEvent)
64
+ )[0]?.runId;
65
+ } else if (!runs.some((r) => r.runId === runId)) {
66
+ logger.error(`luca retro: run '${runId}' not found in the ledger.`);
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+ if (!runId) {
71
+ logger.warn("Could not resolve a run to analyze.");
72
+ return;
73
+ }
74
+ const report = analyzeRun(gatherRunArtifacts({ cwd, runId }));
75
+ if (args.json) {
76
+ process.stdout.write(`${JSON.stringify(report, null, 2)}
77
+ `);
78
+ } else {
79
+ process.stdout.write(`${renderPostmortemMarkdown(report)}
80
+ `);
81
+ }
82
+ process.exitCode = computePostmortemExitCode(report);
83
+ }
84
+ });
85
+
86
+ export { retroCommand };
@@ -0,0 +1,58 @@
1
+ import { defineCommand } from 'citty';
2
+ import 'zod';
3
+ import '../shared/luca.CRmaAfXR.mjs';
4
+ import 'node:fs';
5
+ import 'node:fs/promises';
6
+ import 'node:path';
7
+ import 'node:crypto';
8
+ import 'node:module';
9
+ import 'node:url';
10
+ import 'node:child_process';
11
+ import { c as readJsonPayload, r as runWriteHandler, d as lucaRoadmapReadTool, e as lucaRoadmapCreateTool } from '../shared/luca.DjDTeDCi.mjs';
12
+ import 'node:os';
13
+ import '../shared/luca.CrXzXueR.mjs';
14
+ import '../shared/luca.HZxBTBgD.mjs';
15
+ import '../shared/luca.TSMg1t7I.mjs';
16
+ import '../shared/luca.CQ3g1xrD.mjs';
17
+ import '../shared/luca.B3Mimc0P.mjs';
18
+
19
+ const readCommand = defineCommand({
20
+ meta: {
21
+ name: "read",
22
+ description: "Read the roadmap array from .luca/state.json, plus currentPhase and totalPhases for context. Each entry is { name, deps, status, complexity? }. Pure read; allowed in every pipelineStep."
23
+ },
24
+ async run() {
25
+ await runWriteHandler("roadmap read", lucaRoadmapReadTool, {});
26
+ }
27
+ });
28
+ const createCommand = defineCommand({
29
+ meta: {
30
+ name: "create",
31
+ description: "Replace the roadmap in .luca/state.json with a new ordered list of phases. Resets currentPhase to 0; updates totalPhases. Only callable in the idle or triage pipelineStep."
32
+ },
33
+ args: {
34
+ file: {
35
+ type: "string",
36
+ required: true,
37
+ description: "Path to a JSON file containing the phases array: [{ name, deps?, status?, complexity? }, ...]. The array may be large, so it is supplied as a file rather than a flag. Defaults applied: deps=[], status=pending."
38
+ }
39
+ },
40
+ async run({ args }) {
41
+ const phases = await readJsonPayload("roadmap create", args.file);
42
+ await runWriteHandler("roadmap create", lucaRoadmapCreateTool, {
43
+ phases
44
+ });
45
+ }
46
+ });
47
+ const roadmapCommand = defineCommand({
48
+ meta: {
49
+ name: "roadmap",
50
+ description: "Read and replace the Luca workflow roadmap"
51
+ },
52
+ subCommands: {
53
+ read: readCommand,
54
+ create: createCommand
55
+ }
56
+ });
57
+
58
+ export { roadmapCommand };