@lovrozagar/grunt 0.4.2 → 0.5.0
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/.agents/agents/orchestrator.md +8 -7
- package/.agents/agents/thinker.md +6 -5
- package/.agents/skills/commit-and-push/SKILL.md +3 -3
- package/.agents/skills/explain/SKILL.md +1 -0
- package/.agents/skills/implement-plan/SKILL.md +116 -0
- package/.agents/skills/write-plan/SKILL.md +82 -0
- package/.claude/agents/orchestrator.md +8 -7
- package/.claude/agents/thinker.md +6 -5
- package/.claude/skills/commit-and-push/SKILL.md +3 -3
- package/.claude/skills/explain/SKILL.md +1 -0
- package/.claude/skills/implement-plan/SKILL.md +116 -0
- package/.claude/skills/write-plan/SKILL.md +82 -0
- package/.codex/agents/orchestrator.toml +8 -7
- package/.codex/agents/thinker.toml +6 -5
- package/.grok/agents/orchestrator.md +8 -7
- package/.grok/agents/thinker.md +6 -5
- package/.grok/skills/commit-and-push/SKILL.md +3 -3
- package/.grok/skills/explain/SKILL.md +1 -0
- package/.grok/skills/implement-plan/SKILL.md +45 -17
- package/.grok/skills/write-plan/SKILL.md +11 -11
- package/.rulesync/reference/INDEX.md +43 -0
- package/.rulesync/reference/cascade.md +11 -9
- package/.rulesync/reference/law.md +9 -0
- package/.rulesync/reference/map.md +10 -5
- package/.rulesync/reference/output.md +13 -8
- package/{.grok/skills/shared → .rulesync/reference}/plan-format.md +2 -1
- package/.rulesync/reference/refs-map.md +14 -0
- package/.rulesync/reference/skills-map.md +20 -0
- package/.rulesync/rules/CLAUDE.md +12 -10
- package/.rulesync/rules/overview.md +12 -10
- package/.rulesync/skills/commit-and-push/SKILL.md +3 -3
- package/.rulesync/skills/explain/SKILL.md +1 -0
- package/.rulesync/skills/implement-plan/SKILL.md +124 -0
- package/.rulesync/skills/write-plan/SKILL.md +88 -0
- package/.rulesync/subagents/orchestrator.md +8 -7
- package/.rulesync/subagents/thinker.md +6 -5
- package/AGENTS.md +12 -10
- package/CHANGELOG.md +23 -0
- package/CLAUDE.md +12 -10
- package/README.md +14 -10
- package/cli/init.mjs +20 -1
- package/cli/init.test.ts +81 -4
- package/package.json +4 -4
- package/scripts/doctor.mjs +64 -2
- package/scripts/emit-maps.mjs +422 -0
- package/scripts/guarded-roots.mjs +4 -7
- package/scripts/pipeline.mjs +67 -0
- package/scripts/skill-conflicts.mjs +71 -0
package/cli/init.mjs
CHANGED
|
@@ -2,6 +2,11 @@ import { execFileSync } from "node:child_process"
|
|
|
2
2
|
import fs from "node:fs"
|
|
3
3
|
import path from "node:path"
|
|
4
4
|
import { fileURLToPath } from "node:url"
|
|
5
|
+
import {
|
|
6
|
+
WORKSPACE_SKILLS_REL,
|
|
7
|
+
findSkillContentConflicts,
|
|
8
|
+
formatSkillConflictWarn,
|
|
9
|
+
} from "../scripts/skill-conflicts.mjs"
|
|
5
10
|
|
|
6
11
|
const PKG_ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
7
12
|
|
|
@@ -9,10 +14,12 @@ const PRODUCT_SCRIPTS = [
|
|
|
9
14
|
"check-globals.mjs",
|
|
10
15
|
"emit-agent-shell-tools.mjs",
|
|
11
16
|
"emit-gemini.mjs",
|
|
17
|
+
"emit-maps.mjs",
|
|
12
18
|
"guarded-roots.mjs",
|
|
13
19
|
"emit-mcp-policy.mjs",
|
|
14
20
|
"gate-fat-tools.mjs",
|
|
15
21
|
"hooks-union.mjs",
|
|
22
|
+
"pipeline.mjs",
|
|
16
23
|
"grunt-job.mjs",
|
|
17
24
|
"parse-need.mjs",
|
|
18
25
|
"persist-handoff.mjs",
|
|
@@ -23,6 +30,7 @@ const PRODUCT_SCRIPTS = [
|
|
|
23
30
|
"sync-global-settings.mjs",
|
|
24
31
|
"browser.mjs",
|
|
25
32
|
"doctor.mjs",
|
|
33
|
+
"skill-conflicts.mjs",
|
|
26
34
|
"scrub-text",
|
|
27
35
|
]
|
|
28
36
|
|
|
@@ -377,7 +385,7 @@ export function mergePackageJson(dest, pkgRoot) {
|
|
|
377
385
|
const srcPkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8"))
|
|
378
386
|
destPkg.scripts = { ...(destPkg.scripts || {}) }
|
|
379
387
|
for (const [k, v] of Object.entries(srcPkg.scripts || {})) {
|
|
380
|
-
if (k === "test") continue
|
|
388
|
+
if (k === "test" || k.endsWith(":raw")) continue
|
|
381
389
|
destPkg.scripts[k] = mergeScriptValue(k, v, destPkg.scripts[k])
|
|
382
390
|
}
|
|
383
391
|
destPkg.devDependencies = { ...(destPkg.devDependencies || {}) }
|
|
@@ -406,6 +414,17 @@ export function init(dest, { pkgRoot: pkgRootOpt, execFileSync: exec = execFileS
|
|
|
406
414
|
const self = samePath(dest, pkgRoot)
|
|
407
415
|
|
|
408
416
|
phase("merge", () => {
|
|
417
|
+
const wsSkills = path.join(dest, WORKSPACE_SKILLS_REL)
|
|
418
|
+
const pkgSkills = path.join(pkgRoot, WORKSPACE_SKILLS_REL)
|
|
419
|
+
if (!samePath(wsSkills, pkgSkills)) {
|
|
420
|
+
for (const c of findSkillContentConflicts({
|
|
421
|
+
workspaceSkillsDir: wsSkills,
|
|
422
|
+
packagedSkillsDir: pkgSkills,
|
|
423
|
+
})) {
|
|
424
|
+
console.warn(formatSkillConflictWarn(c.name))
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
409
428
|
for (const dir of COPY_DIRS) {
|
|
410
429
|
const src = path.join(pkgRoot, dir)
|
|
411
430
|
const d = path.join(dest, dir)
|
package/cli/init.test.ts
CHANGED
|
@@ -44,10 +44,12 @@ const PRODUCT_FILES = [
|
|
|
44
44
|
"check-globals.mjs",
|
|
45
45
|
"emit-agent-shell-tools.mjs",
|
|
46
46
|
"emit-gemini.mjs",
|
|
47
|
+
"emit-maps.mjs",
|
|
47
48
|
"guarded-roots.mjs",
|
|
48
49
|
"emit-mcp-policy.mjs",
|
|
49
50
|
"gate-fat-tools.mjs",
|
|
50
51
|
"hooks-union.mjs",
|
|
52
|
+
"pipeline.mjs",
|
|
51
53
|
"grunt-job.mjs",
|
|
52
54
|
"parse-need.mjs",
|
|
53
55
|
"persist-handoff.mjs",
|
|
@@ -58,6 +60,7 @@ const PRODUCT_FILES = [
|
|
|
58
60
|
"sync-global-settings.mjs",
|
|
59
61
|
"browser.mjs",
|
|
60
62
|
"doctor.mjs",
|
|
63
|
+
"skill-conflicts.mjs",
|
|
61
64
|
];
|
|
62
65
|
|
|
63
66
|
const SRC_CLAUDE_SETTINGS = {
|
|
@@ -495,8 +498,15 @@ describe("snapshot/remerge guarded roots", () => {
|
|
|
495
498
|
fs.writeFileSync(path.join(dest, "AGENTS.md"), "fresh ssot\n");
|
|
496
499
|
});
|
|
497
500
|
runGuardedRoots("generate", { cwd: dest, exec });
|
|
498
|
-
expect(exec).
|
|
499
|
-
|
|
501
|
+
expect(exec.mock.calls.map((c) => c[0])).toEqual([
|
|
502
|
+
"rulesync generate -t claudecode,codexcli,antigravity-cli,grokcli -f rules,subagents,skills",
|
|
503
|
+
"rulesync generate -t claudecode,codexcli,antigravity-cli -f hooks",
|
|
504
|
+
"node scripts/emit-mcp-policy.mjs",
|
|
505
|
+
"node scripts/emit-gemini.mjs",
|
|
506
|
+
"node scripts/emit-agent-shell-tools.mjs",
|
|
507
|
+
"node scripts/emit-maps.mjs",
|
|
508
|
+
"node scripts/hooks-union.mjs",
|
|
509
|
+
]);
|
|
500
510
|
expect(fs.readFileSync(path.join(dest, "AGENTS.md"), "utf8")).toBe(
|
|
501
511
|
"<!-- grunt:begin -->\nfresh ssot\n<!-- grunt:end -->\nkeep me\n",
|
|
502
512
|
);
|
|
@@ -595,8 +605,12 @@ describe("snapshot/remerge guarded roots", () => {
|
|
|
595
605
|
return stop;
|
|
596
606
|
},
|
|
597
607
|
});
|
|
598
|
-
expect(exec).
|
|
599
|
-
|
|
608
|
+
expect(exec.mock.calls.map((c) => c[0])).toEqual([
|
|
609
|
+
"node scripts/emit-mcp-policy.mjs",
|
|
610
|
+
"node scripts/emit-gemini.mjs",
|
|
611
|
+
"node scripts/emit-agent-shell-tools.mjs",
|
|
612
|
+
"rulesync generate -t claudecode,codexcli,antigravity-cli,grokcli -f rules,subagents,skills --watch",
|
|
613
|
+
]);
|
|
600
614
|
expect(stop).toHaveBeenCalledTimes(1);
|
|
601
615
|
expect(fs.readFileSync(path.join(dest, "AGENTS.md"), "utf8")).toBe(
|
|
602
616
|
"<!-- grunt:begin -->\nwatch2\n<!-- grunt:end -->\nkeep me\n",
|
|
@@ -952,6 +966,45 @@ describe("mergePackageJson", () => {
|
|
|
952
966
|
warnSpy.mockRestore();
|
|
953
967
|
});
|
|
954
968
|
|
|
969
|
+
it("does not merge :raw scripts from src", () => {
|
|
970
|
+
const pkgRoot = stubPkgRoot({
|
|
971
|
+
name: "fixture-pkg",
|
|
972
|
+
scripts: {
|
|
973
|
+
"rulesync:generate": "node ./scripts/guarded-roots.mjs generate",
|
|
974
|
+
"rulesync:generate:raw": "echo raw",
|
|
975
|
+
"rulesync:check:raw": "echo check-raw",
|
|
976
|
+
"rulesync:watch:raw": "echo watch-raw",
|
|
977
|
+
},
|
|
978
|
+
devDependencies: { "smol-toml": "^1.8.0", rulesync: "latest" },
|
|
979
|
+
});
|
|
980
|
+
const dest = tmp("pj-raw-src-");
|
|
981
|
+
mergePackageJson(dest, pkgRoot);
|
|
982
|
+
const out = JSON.parse(fs.readFileSync(path.join(dest, "package.json"), "utf8"));
|
|
983
|
+
expect(out.scripts["rulesync:generate"]).toBe("node ./scripts/guarded-roots.mjs generate");
|
|
984
|
+
expect(out.scripts["rulesync:generate:raw"]).toBeUndefined();
|
|
985
|
+
expect(out.scripts["rulesync:check:raw"]).toBeUndefined();
|
|
986
|
+
expect(out.scripts["rulesync:watch:raw"]).toBeUndefined();
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
it("leaves dest-only :raw keys", () => {
|
|
990
|
+
const pkgRoot = stubPkgRoot({
|
|
991
|
+
name: "fixture-pkg",
|
|
992
|
+
scripts: { "rulesync:generate": "node ./scripts/guarded-roots.mjs generate" },
|
|
993
|
+
devDependencies: { "smol-toml": "^1.8.0", rulesync: "latest" },
|
|
994
|
+
});
|
|
995
|
+
const dest = tmp("pj-raw-dest-");
|
|
996
|
+
fs.writeFileSync(
|
|
997
|
+
path.join(dest, "package.json"),
|
|
998
|
+
JSON.stringify({
|
|
999
|
+
scripts: { "rulesync:generate:raw": "echo consumer-raw" },
|
|
1000
|
+
}),
|
|
1001
|
+
);
|
|
1002
|
+
mergePackageJson(dest, pkgRoot);
|
|
1003
|
+
const out = JSON.parse(fs.readFileSync(path.join(dest, "package.json"), "utf8"));
|
|
1004
|
+
expect(out.scripts["rulesync:generate"]).toBe("node ./scripts/guarded-roots.mjs generate");
|
|
1005
|
+
expect(out.scripts["rulesync:generate:raw"]).toBe("echo consumer-raw");
|
|
1006
|
+
});
|
|
1007
|
+
|
|
955
1008
|
it("replaces a grunt-owned script with no suffix", () => {
|
|
956
1009
|
const pkgRoot = stubPkgRoot({
|
|
957
1010
|
name: "fixture-pkg",
|
|
@@ -1262,6 +1315,30 @@ describe("init", () => {
|
|
|
1262
1315
|
["merge", "stop"],
|
|
1263
1316
|
]);
|
|
1264
1317
|
});
|
|
1318
|
+
|
|
1319
|
+
it("warns when dest skill differs from packaged then force-overwrites; keeps extras", () => {
|
|
1320
|
+
const pkgRoot = stubPkgRoot();
|
|
1321
|
+
const pkgSkill = path.join(pkgRoot, ".rulesync", "skills", "parent");
|
|
1322
|
+
fs.mkdirSync(pkgSkill, { recursive: true });
|
|
1323
|
+
fs.writeFileSync(path.join(pkgSkill, "SKILL.md"), "grunt-parent\n");
|
|
1324
|
+
const dest = tmp("grunt-sk-conflict-");
|
|
1325
|
+
const destSkill = path.join(dest, ".rulesync", "skills", "parent");
|
|
1326
|
+
const destExtra = path.join(dest, ".rulesync", "skills", "my-extra");
|
|
1327
|
+
fs.mkdirSync(destSkill, { recursive: true });
|
|
1328
|
+
fs.mkdirSync(destExtra, { recursive: true });
|
|
1329
|
+
fs.writeFileSync(path.join(destSkill, "SKILL.md"), "custom-parent\n");
|
|
1330
|
+
fs.writeFileSync(path.join(destExtra, "SKILL.md"), "keep-me\n");
|
|
1331
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
1332
|
+
init(dest, { pkgRoot, execFileSync: vi.fn(), skipGlobals: true });
|
|
1333
|
+
expect(
|
|
1334
|
+
warnSpy.mock.calls.some(
|
|
1335
|
+
(c) => String(c[0]).includes("parent") && String(c[0]).includes("re-init overwrites"),
|
|
1336
|
+
),
|
|
1337
|
+
).toBe(true);
|
|
1338
|
+
warnSpy.mockRestore();
|
|
1339
|
+
expect(fs.readFileSync(path.join(destSkill, "SKILL.md"), "utf8")).toBe("grunt-parent\n");
|
|
1340
|
+
expect(fs.readFileSync(path.join(destExtra, "SKILL.md"), "utf8")).toBe("keep-me\n");
|
|
1341
|
+
});
|
|
1265
1342
|
});
|
|
1266
1343
|
|
|
1267
1344
|
describe("destAlreadyInited / shouldAutoSkipGlobals", () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lovrozagar/grunt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Multi-agent orchestrator SoT — deep-merge rulesync trees, product scripts, and generate pipeline into a consumer repo",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -27,10 +27,12 @@
|
|
|
27
27
|
"scripts/check-globals.mjs",
|
|
28
28
|
"scripts/emit-agent-shell-tools.mjs",
|
|
29
29
|
"scripts/emit-gemini.mjs",
|
|
30
|
+
"scripts/emit-maps.mjs",
|
|
30
31
|
"scripts/guarded-roots.mjs",
|
|
31
32
|
"scripts/emit-mcp-policy.mjs",
|
|
32
33
|
"scripts/gate-fat-tools.mjs",
|
|
33
34
|
"scripts/hooks-union.mjs",
|
|
35
|
+
"scripts/pipeline.mjs",
|
|
34
36
|
"scripts/grunt-job.mjs",
|
|
35
37
|
"scripts/parse-need.mjs",
|
|
36
38
|
"scripts/persist-handoff.mjs",
|
|
@@ -41,6 +43,7 @@
|
|
|
41
43
|
"scripts/sync-global-settings.mjs",
|
|
42
44
|
"scripts/browser.mjs",
|
|
43
45
|
"scripts/doctor.mjs",
|
|
46
|
+
"scripts/skill-conflicts.mjs",
|
|
44
47
|
"scripts/scrub-text",
|
|
45
48
|
".rulesync",
|
|
46
49
|
".grok",
|
|
@@ -63,11 +66,8 @@
|
|
|
63
66
|
},
|
|
64
67
|
"scripts": {
|
|
65
68
|
"rulesync:generate": "node ./scripts/guarded-roots.mjs generate",
|
|
66
|
-
"rulesync:generate:raw": "rulesync generate -t claudecode,codexcli,antigravity-cli,grokcli -f rules,subagents,skills && rulesync generate -t claudecode,codexcli,antigravity-cli -f hooks && node scripts/emit-mcp-policy.mjs && node scripts/emit-gemini.mjs && node scripts/emit-agent-shell-tools.mjs && node scripts/hooks-union.mjs",
|
|
67
69
|
"rulesync:watch": "node ./scripts/guarded-roots.mjs watch",
|
|
68
|
-
"rulesync:watch:raw": "node scripts/emit-mcp-policy.mjs && node scripts/emit-gemini.mjs && node scripts/emit-agent-shell-tools.mjs && rulesync generate -t claudecode,codexcli,antigravity-cli,grokcli -f rules,subagents,skills --watch",
|
|
69
70
|
"rulesync:check": "node ./scripts/guarded-roots.mjs check",
|
|
70
|
-
"rulesync:check:raw": "rulesync generate -t claudecode,codexcli,antigravity-cli,grokcli -f rules,skills --check && rulesync generate -t codexcli,antigravity-cli,grokcli -f subagents --check && rulesync generate -t claudecode,codexcli,antigravity-cli -f hooks --check && node scripts/emit-mcp-policy.mjs --check && node scripts/emit-gemini.mjs --check && node scripts/emit-agent-shell-tools.mjs --check && node scripts/check-globals.mjs && node scripts/hooks-union.mjs --check",
|
|
71
71
|
"hooks:union": "node scripts/hooks-union.mjs",
|
|
72
72
|
"hooks:check": "node scripts/hooks-union.mjs --check",
|
|
73
73
|
"doctor": "node ./scripts/doctor.mjs",
|
package/scripts/doctor.mjs
CHANGED
|
@@ -4,6 +4,12 @@ import { execFileSync } from "node:child_process";
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
+
import {
|
|
8
|
+
PACKAGED_SKILLS_REL,
|
|
9
|
+
WORKSPACE_SKILLS_REL,
|
|
10
|
+
findSkillContentConflicts,
|
|
11
|
+
formatSkillConflictWarn,
|
|
12
|
+
} from "./skill-conflicts.mjs";
|
|
7
13
|
|
|
8
14
|
export const CHROMIUM_BINS = [
|
|
9
15
|
"chromium",
|
|
@@ -23,6 +29,12 @@ const RTK_DOCS = "https://www.rtk-ai.app/docs/getting-started/installation/";
|
|
|
23
29
|
const LP_INSTALL_SH = "curl -fsSL https://pkg.lightpanda.io/install.sh | bash";
|
|
24
30
|
const RULESYNC_SCHEMA = "rulesync schema doctor: npm run rulesync:doctor";
|
|
25
31
|
const REQUIRED = ["node", "npm", "git", "rtk", "rulesync", "lightpanda", "chromium"];
|
|
32
|
+
export const REQUIRED_MAP_FILES = [
|
|
33
|
+
{ name: "INDEX.md", rel: ".rulesync/reference/INDEX.md" },
|
|
34
|
+
{ name: "skills-map.md", rel: ".rulesync/reference/skills-map.md" },
|
|
35
|
+
{ name: "refs-map.md", rel: ".rulesync/reference/refs-map.md" },
|
|
36
|
+
{ name: "law.md", rel: ".rulesync/reference/law.md" },
|
|
37
|
+
];
|
|
26
38
|
|
|
27
39
|
export function nodeMajor(version) {
|
|
28
40
|
const m = String(version || "").match(/(\d+)/);
|
|
@@ -158,12 +170,35 @@ export function installHints(id, platform = process.platform) {
|
|
|
158
170
|
}
|
|
159
171
|
|
|
160
172
|
function row(name, status, extra = "") {
|
|
161
|
-
const a = String(name).padEnd(
|
|
173
|
+
const a = String(name).padEnd(14);
|
|
162
174
|
const b = String(status).padEnd(18);
|
|
163
175
|
const c = extra ? String(extra).trim() : "";
|
|
164
176
|
return c ? `${a} ${b} ${c}` : `${a} ${b}`;
|
|
165
177
|
}
|
|
166
178
|
|
|
179
|
+
function mapFilePresent(cwd, rel) {
|
|
180
|
+
try {
|
|
181
|
+
return fs.statSync(path.join(cwd, rel)).isFile();
|
|
182
|
+
} catch {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function isDir(abs) {
|
|
188
|
+
try {
|
|
189
|
+
return fs.statSync(abs).isDirectory();
|
|
190
|
+
} catch {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Product SoT: reference tree or skills (emit-maps in play). No .rulesync / no those trees → bins-only. */
|
|
196
|
+
export function mapsRequired(cwd) {
|
|
197
|
+
const rs = path.join(cwd || "", ".rulesync");
|
|
198
|
+
if (!isDir(rs)) return false;
|
|
199
|
+
return isDir(path.join(rs, "reference")) || isDir(path.join(rs, "skills"));
|
|
200
|
+
}
|
|
201
|
+
|
|
167
202
|
export function runDoctor({
|
|
168
203
|
cwd = process.cwd(),
|
|
169
204
|
pathEnv = process.env.PATH,
|
|
@@ -232,10 +267,37 @@ export function runDoctor({
|
|
|
232
267
|
}
|
|
233
268
|
}
|
|
234
269
|
|
|
270
|
+
const missingMaps = [];
|
|
271
|
+
if (mapsRequired(cwd)) {
|
|
272
|
+
for (const f of REQUIRED_MAP_FILES) {
|
|
273
|
+
if (mapFilePresent(cwd, f.rel)) {
|
|
274
|
+
lines.push(row(f.name, "ok", f.rel));
|
|
275
|
+
} else {
|
|
276
|
+
missingMaps.push(f);
|
|
277
|
+
lines.push(row(f.name, "missing", f.rel));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (missingMaps.length) {
|
|
281
|
+
lines.push(`maps missing: ${missingMaps.map((f) => f.name).join(", ")}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const skillConflicts = findSkillContentConflicts({
|
|
286
|
+
workspaceSkillsDir: path.join(cwd || "", WORKSPACE_SKILLS_REL),
|
|
287
|
+
packagedSkillsDir: path.join(cwd || "", PACKAGED_SKILLS_REL),
|
|
288
|
+
});
|
|
289
|
+
if (skillConflicts.length) {
|
|
290
|
+
lines.push("");
|
|
291
|
+
lines.push("skill conflicts (warn; re-init overwrites grunt-owned names):");
|
|
292
|
+
for (const c of skillConflicts) {
|
|
293
|
+
lines.push(formatSkillConflictWarn(c.name));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
235
297
|
lines.push("");
|
|
236
298
|
lines.push(RULESYNC_SCHEMA);
|
|
237
299
|
const stdout = `${lines.join("\n")}\n`;
|
|
238
|
-
return { code: missingRequired.length ? 1 : 0, stdout, stderr: "" };
|
|
300
|
+
return { code: missingRequired.length || missingMaps.length ? 1 : 0, stdout, stderr: "" };
|
|
239
301
|
}
|
|
240
302
|
|
|
241
303
|
function main() {
|