@alecsibilia/luca 13.0.0-alpha.7 → 13.0.0-alpha.8

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.
@@ -13,6 +13,7 @@ async function executeDoctor(options = {}) {
13
13
  const { legacyPackageCheck } = await import('./legacy-package.mjs');
14
14
  const { strayLocalInstallCheck } = await import('./stray-local-install.mjs');
15
15
  const { configVersionSkewCheck } = await import('./config-version-skew.mjs');
16
+ const { vaultConfigLocationCheck } = await import('./vault-config-location.mjs');
16
17
  const allChecks = [
17
18
  // Prerequisites
18
19
  bunRuntimeCheck,
@@ -24,7 +25,8 @@ async function executeDoctor(options = {}) {
24
25
  legacyPackageCheck,
25
26
  // Project (cwd-dependent)
26
27
  strayLocalInstallCheck,
27
- configVersionSkewCheck
28
+ configVersionSkewCheck,
29
+ vaultConfigLocationCheck
28
30
  ];
29
31
  const checks = scope ? allChecks.filter((check) => check.scope === scope) : allChecks;
30
32
  if (checks.length === 0) {
@@ -45,8 +45,12 @@ async function writeProjectSkeleton(opts) {
45
45
  contents: JSON.stringify(
46
46
  {
47
47
  lucaVersion: LUCA_VERSION,
48
- vault: null,
49
- oversight: "full-auto"
48
+ oversight: "full-auto",
49
+ // Canonical vault location is `muninn.vault` (see
50
+ // resolveRepoVault + the vault-routing rule). `luca
51
+ // vault:init` fills this in later; the placeholder makes the
52
+ // canonical home discoverable in a fresh config.
53
+ muninn: { vault: null }
50
54
  },
51
55
  null,
52
56
  2
@@ -0,0 +1,96 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { writeFile, readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+
5
+ const CHECK_NAME = "Vault config location";
6
+ function configPath() {
7
+ return join(process.cwd(), ".luca", "config.json");
8
+ }
9
+ async function readConfig() {
10
+ const p = configPath();
11
+ if (!existsSync(p)) return null;
12
+ try {
13
+ const raw = JSON.parse(await readFile(p, "utf-8"));
14
+ return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+ function nonEmptyTrimmed(v) {
20
+ if (typeof v === "string") {
21
+ const trimmed = v.trim();
22
+ if (trimmed.length > 0) return trimmed;
23
+ }
24
+ return void 0;
25
+ }
26
+ function muninnVaultOf(config) {
27
+ const muninn = config.muninn;
28
+ if (muninn && typeof muninn === "object" && !Array.isArray(muninn)) {
29
+ return nonEmptyTrimmed(muninn.vault);
30
+ }
31
+ return void 0;
32
+ }
33
+ const vaultConfigLocationCheck = {
34
+ name: CHECK_NAME,
35
+ scope: "project",
36
+ async run() {
37
+ const pass = (message) => ({
38
+ name: CHECK_NAME,
39
+ status: "pass",
40
+ message,
41
+ fixCommand: null,
42
+ details: null
43
+ });
44
+ const config = await readConfig();
45
+ if (config === null) {
46
+ return pass("no .luca/config.json to check");
47
+ }
48
+ if (!("vault" in config)) {
49
+ return pass("no legacy top-level vault key present");
50
+ }
51
+ const topLevel = nonEmptyTrimmed(config.vault);
52
+ const muninnVault = muninnVaultOf(config);
53
+ const wouldFold = topLevel !== void 0 && muninnVault === void 0;
54
+ const detail = wouldFold ? `It carries "${topLevel}" and muninn.vault is unset \u2014 \`--fix\` folds it into muninn.vault, then removes the top-level key.` : `\`--fix\` removes it (muninn.vault is the source of truth).`;
55
+ return {
56
+ name: CHECK_NAME,
57
+ status: "warning",
58
+ message: "config.json has a top-level `vault` key (canonical location is `muninn.vault`)",
59
+ fixCommand: "luca doctor --fix",
60
+ details: [
61
+ `.luca/config.json stores a top-level \`vault\` key. The canonical location is \`muninn.vault\`; the top-level key is only read as a legacy fallback.`,
62
+ detail
63
+ ].join("\n ")
64
+ };
65
+ },
66
+ async fix() {
67
+ const config = await readConfig();
68
+ if (config === null || !("vault" in config)) {
69
+ return { applied: [], errors: [] };
70
+ }
71
+ try {
72
+ const topLevel = nonEmptyTrimmed(config.vault);
73
+ const muninnVault = muninnVaultOf(config);
74
+ const next = { ...config };
75
+ const applied = [];
76
+ if (topLevel !== void 0 && muninnVault === void 0) {
77
+ const existingMuninn = config.muninn && typeof config.muninn === "object" && !Array.isArray(config.muninn) ? config.muninn : {};
78
+ next.muninn = { ...existingMuninn, vault: topLevel };
79
+ applied.push(`Folded top-level vault "${topLevel}" \u2192 muninn.vault`);
80
+ }
81
+ delete next.vault;
82
+ applied.push("Removed stale top-level `vault` key from .luca/config.json");
83
+ await writeFile(configPath(), JSON.stringify(next, null, 2) + "\n");
84
+ return { applied, errors: [] };
85
+ } catch (err) {
86
+ return {
87
+ applied: [],
88
+ errors: [
89
+ `Failed to normalize .luca/config.json vault location: ${err.message}`
90
+ ]
91
+ };
92
+ }
93
+ }
94
+ };
95
+
96
+ export { vaultConfigLocationCheck };
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.7";
5
+ return "13.0.0-alpha.8";
6
6
  }
7
7
  const LUCA_VERSION = await resolveVersion();
8
8
 
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.7",
4
+ "version": "13.0.0-alpha.8",
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",