@aipper/aiws 0.0.12 → 0.0.14
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.
- package/package.json +2 -2
- package/src/commands/validate.js +67 -0
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aipper/aiws",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "AI Workspace CLI (init/update/validate) for Claude Code / OpenCode / Codex / iFlow.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"aiws": "./bin/aiws.js"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@aipper/aiws-spec": "0.0.
|
|
10
|
+
"@aipper/aiws-spec": "0.0.14"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"bin",
|
package/src/commands/validate.js
CHANGED
|
@@ -8,6 +8,70 @@ import { runCommand } from "../exec.js";
|
|
|
8
8
|
import { expandManifestEntries } from "../template.js";
|
|
9
9
|
import { loadAiwsPackage } from "../aiws-package.js";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Enforce deterministic submodule branch policy:
|
|
13
|
+
* - If `.gitmodules` exists and declares submodules, each submodule must declare `submodule.<name>.branch`.
|
|
14
|
+
* - This avoids guessing which branch to attach/push for workflows like ws-pull/ws-finish.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} workspaceRoot
|
|
17
|
+
*/
|
|
18
|
+
async function validateSubmoduleBranchPolicy(workspaceRoot) {
|
|
19
|
+
const gitmodules = path.join(workspaceRoot, ".gitmodules");
|
|
20
|
+
if (!(await pathExists(gitmodules))) return;
|
|
21
|
+
|
|
22
|
+
const list = await runCommand("git", ["config", "--file", ".gitmodules", "--get-regexp", "^submodule\\..*\\.path$"], {
|
|
23
|
+
cwd: workspaceRoot,
|
|
24
|
+
});
|
|
25
|
+
if (list.code !== 0) {
|
|
26
|
+
// `.gitmodules` exists but no submodule path entries: treat as ok.
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** @type {Array<{ name: string, path: string }>} */
|
|
31
|
+
const subs = [];
|
|
32
|
+
for (const line of String(list.stdout || "").split("\n")) {
|
|
33
|
+
const t = line.trim();
|
|
34
|
+
if (!t) continue;
|
|
35
|
+
const idx = t.indexOf(" ");
|
|
36
|
+
if (idx <= 0) continue;
|
|
37
|
+
const key = t.slice(0, idx).trim();
|
|
38
|
+
const subPath = t.slice(idx + 1).trim();
|
|
39
|
+
const m = key.match(/^submodule\.([^.]+)\.path$/);
|
|
40
|
+
if (!m) continue;
|
|
41
|
+
const name = m[1] || "";
|
|
42
|
+
if (!name || !subPath) continue;
|
|
43
|
+
subs.push({ name, path: subPath });
|
|
44
|
+
}
|
|
45
|
+
if (subs.length === 0) return;
|
|
46
|
+
|
|
47
|
+
/** @type {Array<{ name: string, path: string }>} */
|
|
48
|
+
const missing = [];
|
|
49
|
+
for (const s of subs) {
|
|
50
|
+
const br = await runCommand("git", ["config", "--file", ".gitmodules", "--get", `submodule.${s.name}.branch`], {
|
|
51
|
+
cwd: workspaceRoot,
|
|
52
|
+
});
|
|
53
|
+
if (br.code !== 0 || !String(br.stdout || "").trim()) {
|
|
54
|
+
missing.push(s);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (missing.length > 0) {
|
|
59
|
+
const lines = missing.map((m) => `- ${m.name} (${m.path}): missing submodule.${m.name}.branch`);
|
|
60
|
+
const hints = missing
|
|
61
|
+
.slice(0, 8)
|
|
62
|
+
.map((m) => `git submodule set-branch --branch main ${m.path}`)
|
|
63
|
+
.join("\n");
|
|
64
|
+
throw new UserError("Submodule branch policy failed: missing `.gitmodules` branch config.", {
|
|
65
|
+
details:
|
|
66
|
+
`${lines.join("\n")}\n\n` +
|
|
67
|
+
"Fix:\n" +
|
|
68
|
+
"- Run `ws-submodule-setup` (recommended), or set per submodule:\n" +
|
|
69
|
+
`${hints}\n\n` +
|
|
70
|
+
"Then commit `.gitmodules` in the superproject.",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
11
75
|
/**
|
|
12
76
|
* @param {string | undefined} v
|
|
13
77
|
*/
|
|
@@ -100,6 +164,9 @@ export async function validateCommand(options) {
|
|
|
100
164
|
// Drift detection.
|
|
101
165
|
await validateDrift({ workspaceRoot, storedManifest: stored, templateManifest: tpl.manifest });
|
|
102
166
|
|
|
167
|
+
// Submodule branch policy (deterministic workflow; avoids guessing target branches).
|
|
168
|
+
await validateSubmoduleBranchPolicy(workspaceRoot);
|
|
169
|
+
|
|
103
170
|
// python3 gate.
|
|
104
171
|
const py = await runCommand("python3", ["--version"], { cwd: workspaceRoot });
|
|
105
172
|
if (py.code !== 0) {
|