@event4u/agent-config 9.10.0 → 9.11.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +59 -0
- package/README.md +12 -15
- package/agents/templates/.ai-council.yml.example +481 -0
- package/agents/templates/.ai-video.xml.example +247 -0
- package/dist/agent-src/rules/design-fidelity.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +15 -2
- package/dist/agent-src/skills/fe-design/SKILL.md +10 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +30 -30
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/design.ts +88 -33
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +20 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +20 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +179 -0
- package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +155 -4
- package/dist/agent-src/templates/scripts/work_engine/state.ts +21 -4
- package/dist/cli/initRouting.js +74 -11
- package/dist/cli/initRouting.js.map +1 -1
- package/dist/cli/main.js +14 -3
- package/dist/cli/main.js.map +1 -1
- package/dist/cli-delegate/chunk-4SV3XGFA.js +6910 -0
- package/dist/cli-delegate/chunk-736JCWLM.js +1104 -0
- package/dist/cli-delegate/chunk-7DSAMZFU.js +356 -0
- package/dist/cli-delegate/chunk-7HQ52DHU.js +74 -0
- package/dist/cli-delegate/chunk-BJGXZNPM.js +266 -0
- package/dist/cli-delegate/chunk-FTAISGDQ.js +117 -0
- package/dist/cli-delegate/chunk-GME3Q44L.js +82 -0
- package/dist/cli-delegate/chunk-GRRPEPRN.js +336 -0
- package/dist/cli-delegate/chunk-HJ6DAJHR.js +502 -0
- package/dist/cli-delegate/chunk-IR7P7JWA.js +872 -0
- package/dist/cli-delegate/chunk-J55WI3RR.js +47 -0
- package/dist/cli-delegate/chunk-MCJYCQPF.js +35 -0
- package/dist/cli-delegate/chunk-NDJLNC6Q.js +169 -0
- package/dist/cli-delegate/chunk-OMIVVCG2.js +26 -0
- package/dist/cli-delegate/chunk-OY53J6II.js +7336 -0
- package/dist/cli-delegate/chunk-RDGRHAAB.js +259 -0
- package/dist/cli-delegate/chunk-TFG57JJM.js +1969 -0
- package/dist/cli-delegate/chunk-XX6TOPD7.js +715 -0
- package/dist/cli-delegate/chunk-YMFO6FDN.js +10603 -0
- package/dist/cli-delegate/cmd_analyze_session.js +294 -0
- package/dist/cli-delegate/cmd_conformance.js +646 -0
- package/dist/cli-delegate/cmd_converge.js +326 -0
- package/dist/cli-delegate/cmd_doctor.js +144 -0
- package/dist/cli-delegate/cmd_explain.js +2508 -0
- package/dist/cli-delegate/cmd_export.js +296 -0
- package/dist/cli-delegate/cmd_fleet.js +332 -0
- package/dist/cli-delegate/cmd_memory_get.js +3878 -0
- package/dist/cli-delegate/cmd_migrate.js +11 -0
- package/dist/cli-delegate/cmd_preflight.js +270 -0
- package/dist/cli-delegate/cmd_prune.js +444 -0
- package/dist/cli-delegate/cmd_refresh.js +28 -0
- package/dist/cli-delegate/cmd_settings_check.js +574 -0
- package/dist/cli-delegate/cmd_settings_migrate.js +223 -0
- package/dist/cli-delegate/cmd_sync.js +264 -0
- package/dist/cli-delegate/cmd_uninstall.js +656 -0
- package/dist/cli-delegate/cmd_update.js +425 -0
- package/dist/cli-delegate/cmd_upgrade.js +444 -0
- package/dist/cli-delegate/cmd_validate.js +305 -0
- package/dist/cli-delegate/cmd_versions.js +370 -0
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +14 -7
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +2 -2
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +12 -7
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +4 -3
- package/dist/install/emit_host_rules_cli.js +2 -1
- package/dist/install/emit_host_rules_cli.js.map +1 -1
- package/dist/install/install.mjs +410 -378
- package/dist/install/rule_scope.js +5 -1
- package/dist/install/rule_scope.js.map +1 -1
- package/dist/install/toolDetection.js +40 -12
- package/dist/install/toolDetection.js.map +1 -1
- package/dist/install/wizard-plan.js +2 -2
- package/dist/install/wizard-plan.js.map +1 -1
- package/dist/mcp/registry-manifest.json +1 -1
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1614 -765
- package/dist/router.json +1 -1
- package/package.json +4 -2
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +30 -30
- package/src/agent-src/templates/scripts/work_engine/directives/ui/design.ts +88 -33
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +20 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +20 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +179 -0
- package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +155 -4
- package/src/agent-src/templates/scripts/work_engine/state.ts +21 -4
- package/src/config/discovery/packs.yml +7 -0
- package/src/config/evaluator-budgets.json +1 -1
- package/src/config/pack-size-budget.json +27 -0
- package/src/install/emit_host_rules_cli.ts +2 -1
- package/src/install/rule_scope.ts +5 -1
- package/src/install/toolDetection.ts +39 -8
- package/src/install/wizard-plan.ts +2 -2
- package/src/scripts/_cli/cmd_conformance.ts +2 -1
- package/src/scripts/_cli/cmd_converge.ts +2 -1
- package/src/scripts/_cli/cmd_doctor.ts +214 -13
- package/src/scripts/_cli/cmd_export.ts +2 -1
- package/src/scripts/_cli/cmd_fleet.ts +2 -1
- package/src/scripts/_cli/cmd_migrate.ts +2 -1
- package/src/scripts/_cli/cmd_preflight.ts +2 -1
- package/src/scripts/_cli/cmd_refresh.ts +2 -1
- package/src/scripts/_cli/cmd_update.ts +2 -1
- package/src/scripts/_cli/cmd_upgrade.ts +2 -1
- package/src/scripts/_cli/cmd_versions.ts +2 -1
- package/src/scripts/_cli/detection_report.ts +480 -0
- package/src/scripts/_dispatch.bash +52 -14
- package/src/scripts/_lib/changelog_eras.ts +103 -9
- package/src/scripts/_lib/environment_detector.ts +441 -0
- package/src/scripts/_lib/package_root.ts +72 -0
- package/src/scripts/ai_council/config.ts +15 -7
- package/src/scripts/ai_council/modes.ts +68 -2
- package/src/scripts/ai_council/transport_resolver.ts +331 -0
- package/src/scripts/check_bundle_path_leakage.ts +10 -4
- package/src/scripts/check_dependency_floors.ts +153 -0
- package/src/scripts/check_pack_size.ts +188 -0
- package/src/scripts/council_cli.ts +6 -2
- package/src/scripts/evaluator_umbrella.sh +34 -1
- package/src/scripts/lint_eval_fixture_citations.ts +113 -0
- package/src/scripts/lint_ui_stack_bundles.ts +170 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
AIDER_MARKER,
|
|
4
|
+
CLAUDE_DESKTOP_MARKER,
|
|
5
|
+
CODEX_MARKER,
|
|
6
|
+
CONTINUE_MARKER,
|
|
7
|
+
JETBRAINS_MARKER,
|
|
8
|
+
KILOCODE_MARKER,
|
|
9
|
+
KIRO_MARKER,
|
|
10
|
+
ROOCODE_MARKER,
|
|
11
|
+
ZED_MARKER
|
|
12
|
+
} from "./chunk-YMFO6FDN.js";
|
|
13
|
+
import "./chunk-XX6TOPD7.js";
|
|
14
|
+
import "./chunk-IR7P7JWA.js";
|
|
15
|
+
import "./chunk-GRRPEPRN.js";
|
|
16
|
+
import "./chunk-7DSAMZFU.js";
|
|
17
|
+
import "./chunk-HJ6DAJHR.js";
|
|
18
|
+
import "./chunk-NDJLNC6Q.js";
|
|
19
|
+
import {
|
|
20
|
+
resolvePackageRoot
|
|
21
|
+
} from "./chunk-MCJYCQPF.js";
|
|
22
|
+
import "./chunk-OY53J6II.js";
|
|
23
|
+
import "./chunk-J55WI3RR.js";
|
|
24
|
+
|
|
25
|
+
// src/scripts/_cli/cmd_export.ts
|
|
26
|
+
import process from "node:process";
|
|
27
|
+
import * as fs from "node:fs";
|
|
28
|
+
import * as os from "node:os";
|
|
29
|
+
import * as path from "node:path";
|
|
30
|
+
import * as crypto from "node:crypto";
|
|
31
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
32
|
+
var PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
|
|
33
|
+
var TEMPLATES_DIR = path.join(PACKAGE_ROOT, "dist/agent-src", "templates");
|
|
34
|
+
var ArgparseExit = class extends Error {
|
|
35
|
+
code;
|
|
36
|
+
constructor(code) {
|
|
37
|
+
super(`ArgparseExit(${code})`);
|
|
38
|
+
this.name = "ArgparseExit";
|
|
39
|
+
this.code = code;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
function _stdoutSink() {
|
|
43
|
+
return { write: (t) => process.stdout.write(t) };
|
|
44
|
+
}
|
|
45
|
+
function _stderrSink() {
|
|
46
|
+
return { write: (t) => process.stderr.write(t) };
|
|
47
|
+
}
|
|
48
|
+
function _print(out, line = "") {
|
|
49
|
+
out.write(line + "\n");
|
|
50
|
+
}
|
|
51
|
+
function _ljust(s, width) {
|
|
52
|
+
const len = [...s].length;
|
|
53
|
+
if (len >= width) return s;
|
|
54
|
+
return s + " ".repeat(width - len);
|
|
55
|
+
}
|
|
56
|
+
var FileNotFoundError = class extends Error {
|
|
57
|
+
constructor(message) {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "FileNotFoundError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function _from_template(rel) {
|
|
63
|
+
return () => {
|
|
64
|
+
const p = path.join(TEMPLATES_DIR, rel);
|
|
65
|
+
let isFile;
|
|
66
|
+
try {
|
|
67
|
+
isFile = fs.statSync(p).isFile();
|
|
68
|
+
} catch {
|
|
69
|
+
isFile = false;
|
|
70
|
+
}
|
|
71
|
+
if (!isFile) {
|
|
72
|
+
throw new FileNotFoundError(
|
|
73
|
+
`template missing from package: ${p} (reinstall @event4u/agent-config or report a bug)`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return fs.readFileSync(p, { encoding: "utf-8" });
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function _from_constant(value) {
|
|
80
|
+
return () => value;
|
|
81
|
+
}
|
|
82
|
+
var EXPORT_REGISTRY = {
|
|
83
|
+
roocode: [
|
|
84
|
+
"Roo Code marker (.roo/rules/agent-config.md body)",
|
|
85
|
+
_from_constant(ROOCODE_MARKER)
|
|
86
|
+
],
|
|
87
|
+
"claude-desktop": [
|
|
88
|
+
"Claude Desktop marker (informational, global-scope tool)",
|
|
89
|
+
_from_constant(CLAUDE_DESKTOP_MARKER)
|
|
90
|
+
],
|
|
91
|
+
aider: [
|
|
92
|
+
"Aider marker (manual `read:` wiring documented inline)",
|
|
93
|
+
_from_constant(AIDER_MARKER)
|
|
94
|
+
],
|
|
95
|
+
codex: [
|
|
96
|
+
"Codex CLI marker (informational \u2014 AGENTS.md is canonical)",
|
|
97
|
+
_from_constant(CODEX_MARKER)
|
|
98
|
+
],
|
|
99
|
+
continue: [
|
|
100
|
+
"Continue.dev marker (.continue/rules/agent-config.md body)",
|
|
101
|
+
_from_constant(CONTINUE_MARKER)
|
|
102
|
+
],
|
|
103
|
+
kilocode: [
|
|
104
|
+
"Kilo Code marker (.kilocode/rules/agent-config.md body)",
|
|
105
|
+
_from_constant(KILOCODE_MARKER)
|
|
106
|
+
],
|
|
107
|
+
zed: [
|
|
108
|
+
"Zed marker (informational \u2014 .rules at repo root is canonical)",
|
|
109
|
+
_from_constant(ZED_MARKER)
|
|
110
|
+
],
|
|
111
|
+
jetbrains: [
|
|
112
|
+
"JetBrains AI Assistant marker (.jetbrains/agent-config.md body)",
|
|
113
|
+
_from_constant(JETBRAINS_MARKER)
|
|
114
|
+
],
|
|
115
|
+
kiro: [
|
|
116
|
+
"Kiro marker (.kiro/steering/agent-config.md body)",
|
|
117
|
+
_from_constant(KIRO_MARKER)
|
|
118
|
+
],
|
|
119
|
+
"agents-md": [
|
|
120
|
+
"AGENTS.md template (Thin-Root entry point \u2014 consumer scaffold)",
|
|
121
|
+
_from_template("AGENTS.md")
|
|
122
|
+
],
|
|
123
|
+
"copilot-instructions": [
|
|
124
|
+
"GitHub Copilot Code Review instructions template",
|
|
125
|
+
_from_template("copilot-instructions.md")
|
|
126
|
+
]
|
|
127
|
+
};
|
|
128
|
+
function _list_tools(out) {
|
|
129
|
+
_print(out, "Available tools for `agent-config export --tool <id>`:");
|
|
130
|
+
const keys = Object.keys(EXPORT_REGISTRY);
|
|
131
|
+
const width = Math.max(...keys.map((t) => [...t].length)) + 2;
|
|
132
|
+
const sortedKeys = [...keys].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
133
|
+
for (const tool_id of sortedKeys) {
|
|
134
|
+
const [desc] = EXPORT_REGISTRY[tool_id];
|
|
135
|
+
_print(out, ` ${_ljust(tool_id, width)}${desc}`);
|
|
136
|
+
}
|
|
137
|
+
return 0;
|
|
138
|
+
}
|
|
139
|
+
function _hash(content) {
|
|
140
|
+
return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
|
|
141
|
+
}
|
|
142
|
+
function _rel(p) {
|
|
143
|
+
const cwd = process.cwd();
|
|
144
|
+
const rel = path.relative(cwd, p);
|
|
145
|
+
if (rel === "" || rel !== ".." && !rel.startsWith(".." + path.sep) && !path.isAbsolute(rel)) {
|
|
146
|
+
return rel === "" ? p : rel;
|
|
147
|
+
}
|
|
148
|
+
return p;
|
|
149
|
+
}
|
|
150
|
+
function _write(output, content, opts) {
|
|
151
|
+
const { force, out, err } = opts;
|
|
152
|
+
let exists;
|
|
153
|
+
try {
|
|
154
|
+
fs.lstatSync(output);
|
|
155
|
+
exists = true;
|
|
156
|
+
} catch {
|
|
157
|
+
exists = false;
|
|
158
|
+
}
|
|
159
|
+
if (exists) {
|
|
160
|
+
const existing = fs.readFileSync(output, { encoding: "utf-8" });
|
|
161
|
+
if (_hash(existing) === _hash(content)) {
|
|
162
|
+
_print(out, `\u2139\uFE0F ${_rel(output)} already exported (content matches).`);
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
if (!force) {
|
|
166
|
+
_print(
|
|
167
|
+
err,
|
|
168
|
+
`\u274C refusing to overwrite ${output} \u2014 content differs. Pass --force to replace.`
|
|
169
|
+
);
|
|
170
|
+
return 1;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
174
|
+
fs.writeFileSync(output, content, { encoding: "utf-8" });
|
|
175
|
+
_print(out, `\u2705 exported to ${_rel(output)}`);
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
function _parse(argv, out, err) {
|
|
179
|
+
const prog = "agent-config export";
|
|
180
|
+
const usage = `usage: ${prog} [-h] [--tool ID] [--output PATH] [--force] [--list]
|
|
181
|
+
`;
|
|
182
|
+
const emitError = (msg) => {
|
|
183
|
+
err.write(usage);
|
|
184
|
+
err.write(`${prog}: error: ${msg}
|
|
185
|
+
`);
|
|
186
|
+
throw new ArgparseExit(2);
|
|
187
|
+
};
|
|
188
|
+
const args = { tool: null, output: null, force: false, list: false };
|
|
189
|
+
let i = 0;
|
|
190
|
+
while (i < argv.length) {
|
|
191
|
+
const tok = argv[i];
|
|
192
|
+
if (tok === "-h" || tok === "--help") {
|
|
193
|
+
out.write(usage);
|
|
194
|
+
throw new ArgparseExit(0);
|
|
195
|
+
} else if (tok === "--tool") {
|
|
196
|
+
const val = argv[i + 1];
|
|
197
|
+
if (val === void 0) emitError("argument --tool: expected one argument");
|
|
198
|
+
args.tool = val;
|
|
199
|
+
i += 2;
|
|
200
|
+
} else if (tok.startsWith("--tool=")) {
|
|
201
|
+
args.tool = tok.slice("--tool=".length);
|
|
202
|
+
i += 1;
|
|
203
|
+
} else if (tok === "--output") {
|
|
204
|
+
const val = argv[i + 1];
|
|
205
|
+
if (val === void 0) emitError("argument --output: expected one argument");
|
|
206
|
+
args.output = val;
|
|
207
|
+
i += 2;
|
|
208
|
+
} else if (tok.startsWith("--output=")) {
|
|
209
|
+
args.output = tok.slice("--output=".length);
|
|
210
|
+
i += 1;
|
|
211
|
+
} else if (tok === "--force") {
|
|
212
|
+
args.force = true;
|
|
213
|
+
i += 1;
|
|
214
|
+
} else if (tok === "--list") {
|
|
215
|
+
args.list = true;
|
|
216
|
+
i += 1;
|
|
217
|
+
} else {
|
|
218
|
+
emitError(`unrecognized arguments: ${tok}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return args;
|
|
222
|
+
}
|
|
223
|
+
function _expanduser(p) {
|
|
224
|
+
if (p === "~" || p.startsWith("~/")) {
|
|
225
|
+
return path.join(os.homedir(), p.slice(1));
|
|
226
|
+
}
|
|
227
|
+
if (p === "~" + path.sep || p.startsWith("~" + path.sep)) {
|
|
228
|
+
return path.join(os.homedir(), p.slice(1));
|
|
229
|
+
}
|
|
230
|
+
return p;
|
|
231
|
+
}
|
|
232
|
+
function main(argv = null, options = {}) {
|
|
233
|
+
const out = options.out ?? _stdoutSink();
|
|
234
|
+
const err = options.err ?? _stderrSink();
|
|
235
|
+
const args = _parse(argv ?? process.argv.slice(2), out, err);
|
|
236
|
+
if (args.list) {
|
|
237
|
+
return _list_tools(out);
|
|
238
|
+
}
|
|
239
|
+
if (!args.tool) {
|
|
240
|
+
_print(err, "\u274C --tool is required (see --list for the catalog).");
|
|
241
|
+
return 2;
|
|
242
|
+
}
|
|
243
|
+
if (!args.output) {
|
|
244
|
+
_print(err, "\u274C --output is required (no canonical-path defaults).");
|
|
245
|
+
return 2;
|
|
246
|
+
}
|
|
247
|
+
const entry = EXPORT_REGISTRY[args.tool];
|
|
248
|
+
if (entry === void 0) {
|
|
249
|
+
_print(err, `\u274C unknown tool: ${args.tool} (see --list)`);
|
|
250
|
+
return 2;
|
|
251
|
+
}
|
|
252
|
+
const [, provider] = entry;
|
|
253
|
+
let content;
|
|
254
|
+
try {
|
|
255
|
+
content = provider();
|
|
256
|
+
} catch (exc) {
|
|
257
|
+
if (exc instanceof FileNotFoundError) {
|
|
258
|
+
_print(err, `\u274C ${exc.message}`);
|
|
259
|
+
return 1;
|
|
260
|
+
}
|
|
261
|
+
throw exc;
|
|
262
|
+
}
|
|
263
|
+
const output = path.resolve(_expanduser(args.output));
|
|
264
|
+
return _write(output, content, { force: args.force, out, err });
|
|
265
|
+
}
|
|
266
|
+
var _HERE = fileURLToPath(import.meta.url);
|
|
267
|
+
function _isCliEntry() {
|
|
268
|
+
if (process.argv[1] === void 0) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
272
|
+
if (import.meta.url === argvUrl) {
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
const here = fs.realpathSync(fileURLToPath(import.meta.url));
|
|
277
|
+
const argv = fs.realpathSync(path.resolve(process.argv[1]));
|
|
278
|
+
return here === argv;
|
|
279
|
+
} catch {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (_isCliEntry() || process.argv[1] === _HERE) {
|
|
284
|
+
try {
|
|
285
|
+
process.exitCode = main();
|
|
286
|
+
} catch (exc) {
|
|
287
|
+
if (exc instanceof ArgparseExit) {
|
|
288
|
+
process.exitCode = exc.code;
|
|
289
|
+
} else {
|
|
290
|
+
throw exc;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
export {
|
|
295
|
+
main
|
|
296
|
+
};
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
hasBlockingFinding,
|
|
4
|
+
runPreflight
|
|
5
|
+
} from "./chunk-RDGRHAAB.js";
|
|
6
|
+
import "./chunk-OMIVVCG2.js";
|
|
7
|
+
import {
|
|
8
|
+
resolvePackageRoot
|
|
9
|
+
} from "./chunk-MCJYCQPF.js";
|
|
10
|
+
import {
|
|
11
|
+
require_dist
|
|
12
|
+
} from "./chunk-OY53J6II.js";
|
|
13
|
+
import {
|
|
14
|
+
__toESM
|
|
15
|
+
} from "./chunk-J55WI3RR.js";
|
|
16
|
+
|
|
17
|
+
// src/scripts/_cli/cmd_fleet.ts
|
|
18
|
+
var YAML = __toESM(require_dist(), 1);
|
|
19
|
+
import { spawn } from "node:child_process";
|
|
20
|
+
import * as fs from "node:fs";
|
|
21
|
+
import * as path from "node:path";
|
|
22
|
+
import process from "node:process";
|
|
23
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
24
|
+
var _HERE = fileURLToPath(import.meta.url);
|
|
25
|
+
var PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
|
|
26
|
+
var FleetConfigError = class extends Error {
|
|
27
|
+
};
|
|
28
|
+
function parseFleetSpec(text, baseDir) {
|
|
29
|
+
let raw;
|
|
30
|
+
try {
|
|
31
|
+
raw = YAML.parse(text);
|
|
32
|
+
} catch (exc) {
|
|
33
|
+
throw new FleetConfigError(`fleet config does not parse: ${exc.message}`);
|
|
34
|
+
}
|
|
35
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
36
|
+
throw new FleetConfigError("fleet config must be a mapping with a `repos:` list");
|
|
37
|
+
}
|
|
38
|
+
const obj = raw;
|
|
39
|
+
const reposRaw = obj["repos"];
|
|
40
|
+
if (!Array.isArray(reposRaw) || reposRaw.length === 0) {
|
|
41
|
+
throw new FleetConfigError("`repos:` must be a non-empty list");
|
|
42
|
+
}
|
|
43
|
+
const repos = [];
|
|
44
|
+
for (const [i, entry] of reposRaw.entries()) {
|
|
45
|
+
if (typeof entry === "string") {
|
|
46
|
+
repos.push({ path: path.resolve(baseDir, entry) });
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (entry !== null && typeof entry === "object" && !Array.isArray(entry)) {
|
|
50
|
+
const e = entry;
|
|
51
|
+
const p = e["path"];
|
|
52
|
+
if (typeof p !== "string" || p.length === 0) {
|
|
53
|
+
throw new FleetConfigError(`repos[${i}] is missing a non-empty \`path\``);
|
|
54
|
+
}
|
|
55
|
+
const tools = e["tools"];
|
|
56
|
+
if (tools !== void 0 && typeof tools !== "string") {
|
|
57
|
+
throw new FleetConfigError(`repos[${i}].tools must be a comma-separated string`);
|
|
58
|
+
}
|
|
59
|
+
repos.push({
|
|
60
|
+
path: path.resolve(baseDir, p),
|
|
61
|
+
...typeof tools === "string" ? { tools } : {}
|
|
62
|
+
});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
throw new FleetConfigError(`repos[${i}] must be a path string or a {path, tools} mapping`);
|
|
66
|
+
}
|
|
67
|
+
const mcRaw = obj["max_concurrency"];
|
|
68
|
+
let maxConcurrency = 3;
|
|
69
|
+
if (mcRaw !== void 0) {
|
|
70
|
+
if (typeof mcRaw !== "number" || !Number.isInteger(mcRaw) || mcRaw < 1) {
|
|
71
|
+
throw new FleetConfigError("`max_concurrency` must be a positive integer");
|
|
72
|
+
}
|
|
73
|
+
maxConcurrency = mcRaw;
|
|
74
|
+
}
|
|
75
|
+
return { repos, maxConcurrency };
|
|
76
|
+
}
|
|
77
|
+
function validateFleetReport(obj) {
|
|
78
|
+
const problems = [];
|
|
79
|
+
if (obj === null || typeof obj !== "object") return ["report is not an object"];
|
|
80
|
+
const r = obj;
|
|
81
|
+
if (r["schema_version"] !== 1) problems.push("schema_version must be 1");
|
|
82
|
+
if (typeof r["ts"] !== "string" || Number.isNaN(Date.parse(String(r["ts"])))) {
|
|
83
|
+
problems.push("ts must be an ISO timestamp");
|
|
84
|
+
}
|
|
85
|
+
if (typeof r["max_concurrency"] !== "number") problems.push("max_concurrency must be a number");
|
|
86
|
+
if (r["status"] !== "ok" && r["status"] !== "fail") problems.push("status must be 'ok'|'fail'");
|
|
87
|
+
if (!Array.isArray(r["repos"])) {
|
|
88
|
+
problems.push("repos must be an array");
|
|
89
|
+
return problems;
|
|
90
|
+
}
|
|
91
|
+
const statuses = /* @__PURE__ */ new Set(["ok", "preflight-failed", "install-failed", "conformance-failed"]);
|
|
92
|
+
for (const [i, item] of r["repos"].entries()) {
|
|
93
|
+
const e = item;
|
|
94
|
+
if (typeof e["path"] !== "string") problems.push(`repos[${i}].path must be a string`);
|
|
95
|
+
if (!statuses.has(String(e["status"]))) problems.push(`repos[${i}].status invalid`);
|
|
96
|
+
if (!Array.isArray(e["findings"])) problems.push(`repos[${i}].findings must be an array`);
|
|
97
|
+
if (typeof e["durationMs"] !== "number") problems.push(`repos[${i}].durationMs must be a number`);
|
|
98
|
+
if (e["conformance"] !== null) {
|
|
99
|
+
const c = e["conformance"];
|
|
100
|
+
if (c === null || typeof c !== "object" || typeof c["exit"] !== "number") {
|
|
101
|
+
problems.push(`repos[${i}].conformance must be null or {exit, note}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return problems;
|
|
106
|
+
}
|
|
107
|
+
function defaultFleetCommands(packageRoot = PACKAGE_ROOT) {
|
|
108
|
+
const entry = path.join(packageRoot, "src", "scripts", "agent-config");
|
|
109
|
+
return {
|
|
110
|
+
installArgv: () => ["bash", entry, "refresh", "--project"],
|
|
111
|
+
conformanceArgv: () => ["bash", entry, "conformance"]
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function spawnInRepo(argv, cwd, timeoutMs) {
|
|
115
|
+
return new Promise((resolvePromise) => {
|
|
116
|
+
const child = spawn(argv[0], argv.slice(1), {
|
|
117
|
+
cwd,
|
|
118
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
119
|
+
timeout: timeoutMs
|
|
120
|
+
});
|
|
121
|
+
let stdout = "";
|
|
122
|
+
let stderr = "";
|
|
123
|
+
child.stdout.on("data", (d) => {
|
|
124
|
+
stdout += d.toString("utf8");
|
|
125
|
+
});
|
|
126
|
+
child.stderr.on("data", (d) => {
|
|
127
|
+
stderr += d.toString("utf8");
|
|
128
|
+
});
|
|
129
|
+
child.on("error", (err) => {
|
|
130
|
+
resolvePromise({ exit: 127, stdout, stderr: `${stderr}${err.message}` });
|
|
131
|
+
});
|
|
132
|
+
child.on("close", (code) => {
|
|
133
|
+
resolvePromise({ exit: code ?? 1, stdout, stderr });
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
var PREFLIGHT_POLICY = {
|
|
138
|
+
force: false,
|
|
139
|
+
interactive: false,
|
|
140
|
+
knownPaths: /* @__PURE__ */ new Set(),
|
|
141
|
+
knownPointers: /* @__PURE__ */ new Set(),
|
|
142
|
+
defaultStrategy: "skip"
|
|
143
|
+
};
|
|
144
|
+
async function runOneRepo(repo, commands, timeoutMs) {
|
|
145
|
+
const started = Date.now();
|
|
146
|
+
let findings;
|
|
147
|
+
if (!fs.existsSync(repo.path) || !fs.statSync(repo.path).isDirectory()) {
|
|
148
|
+
findings = [
|
|
149
|
+
{
|
|
150
|
+
id: "permissions",
|
|
151
|
+
severity: "blocking",
|
|
152
|
+
path: repo.path,
|
|
153
|
+
message: "repo path does not exist or is not a directory",
|
|
154
|
+
remedy: "fix the path in fleet.yaml (or clone the repo first)"
|
|
155
|
+
}
|
|
156
|
+
];
|
|
157
|
+
} else {
|
|
158
|
+
findings = runPreflight({
|
|
159
|
+
target: "project",
|
|
160
|
+
root: repo.path,
|
|
161
|
+
sources: [],
|
|
162
|
+
policy: PREFLIGHT_POLICY
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (hasBlockingFinding(findings)) {
|
|
166
|
+
return {
|
|
167
|
+
path: repo.path,
|
|
168
|
+
status: "preflight-failed",
|
|
169
|
+
findings,
|
|
170
|
+
durationMs: Date.now() - started,
|
|
171
|
+
conformance: null
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const install = await spawnInRepo(commands.installArgv(repo), repo.path, timeoutMs);
|
|
175
|
+
if (install.exit !== 0) {
|
|
176
|
+
return {
|
|
177
|
+
path: repo.path,
|
|
178
|
+
status: "install-failed",
|
|
179
|
+
findings,
|
|
180
|
+
durationMs: Date.now() - started,
|
|
181
|
+
conformance: null
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const conf = await spawnInRepo(commands.conformanceArgv(repo), repo.path, timeoutMs);
|
|
185
|
+
const lastLine = conf.stdout.trim().split("\n").filter(Boolean).slice(-1)[0] ?? "";
|
|
186
|
+
return {
|
|
187
|
+
path: repo.path,
|
|
188
|
+
status: conf.exit === 0 ? "ok" : "conformance-failed",
|
|
189
|
+
findings,
|
|
190
|
+
durationMs: Date.now() - started,
|
|
191
|
+
conformance: { exit: conf.exit, note: lastLine.slice(0, 200) }
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
async function pool(items, limit, fn) {
|
|
195
|
+
const results = new Array(items.length);
|
|
196
|
+
let next = 0;
|
|
197
|
+
async function worker() {
|
|
198
|
+
while (next < items.length) {
|
|
199
|
+
const i = next;
|
|
200
|
+
next += 1;
|
|
201
|
+
results[i] = await fn(items[i]);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const workers = Array.from({ length: Math.min(limit, items.length) }, () => worker());
|
|
205
|
+
await Promise.all(workers);
|
|
206
|
+
return results;
|
|
207
|
+
}
|
|
208
|
+
async function runFleet(spec, opts = {}) {
|
|
209
|
+
const commands = opts.commands ?? defaultFleetCommands();
|
|
210
|
+
const timeoutMs = opts.timeoutMs ?? 10 * 60 * 1e3;
|
|
211
|
+
const results = await pool(
|
|
212
|
+
spec.repos,
|
|
213
|
+
spec.maxConcurrency,
|
|
214
|
+
(repo) => runOneRepo(repo, commands, timeoutMs)
|
|
215
|
+
);
|
|
216
|
+
return {
|
|
217
|
+
schema_version: 1,
|
|
218
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
219
|
+
max_concurrency: spec.maxConcurrency,
|
|
220
|
+
repos: results,
|
|
221
|
+
status: results.every((r) => r.status === "ok") ? "ok" : "fail"
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function humanTable(report) {
|
|
225
|
+
const lines = [];
|
|
226
|
+
lines.push(`fleet: ${report.repos.length} repo(s) \xB7 max_concurrency ${report.max_concurrency}`);
|
|
227
|
+
for (const r of report.repos) {
|
|
228
|
+
const sym = r.status === "ok" ? "\u2705" : "\u274C";
|
|
229
|
+
const dur = `${Math.round(r.durationMs / 100) / 10}s`;
|
|
230
|
+
lines.push(` ${sym} ${r.path} \u2014 ${r.status} (${dur})`);
|
|
231
|
+
for (const f of r.findings.filter((x) => x.severity === "blocking")) {
|
|
232
|
+
lines.push(` ${f.id}: ${f.message}`);
|
|
233
|
+
}
|
|
234
|
+
if (r.conformance && r.status === "conformance-failed") {
|
|
235
|
+
lines.push(` conformance exit ${r.conformance.exit}: ${r.conformance.note}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
lines.push(report.status === "ok" ? "\u2705 fleet: all green" : "\u274C fleet: at least one repo failed");
|
|
239
|
+
return lines.join("\n");
|
|
240
|
+
}
|
|
241
|
+
var USAGE = "usage: cmd_fleet [-h] --config fleet.yaml [--json]\n";
|
|
242
|
+
async function main(argv = null) {
|
|
243
|
+
const args = argv !== null ? Array.from(argv) : process.argv.slice(2);
|
|
244
|
+
let configPath = null;
|
|
245
|
+
let json = false;
|
|
246
|
+
let i = 0;
|
|
247
|
+
while (i < args.length) {
|
|
248
|
+
const a = args[i];
|
|
249
|
+
if (a === "-h" || a === "--help") {
|
|
250
|
+
process.stdout.write(USAGE);
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
253
|
+
if (a === "--json") {
|
|
254
|
+
json = true;
|
|
255
|
+
} else if (a === "--config" || a.startsWith("--config=")) {
|
|
256
|
+
if (a.includes("=")) {
|
|
257
|
+
configPath = a.slice(a.indexOf("=") + 1);
|
|
258
|
+
} else {
|
|
259
|
+
configPath = String(args[i + 1] ?? "");
|
|
260
|
+
i += 1;
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
process.stderr.write(USAGE);
|
|
264
|
+
process.stderr.write(`cmd_fleet: error: unrecognized argument ${a}
|
|
265
|
+
`);
|
|
266
|
+
return 2;
|
|
267
|
+
}
|
|
268
|
+
i += 1;
|
|
269
|
+
}
|
|
270
|
+
if (!configPath || !fs.existsSync(configPath)) {
|
|
271
|
+
process.stderr.write(USAGE);
|
|
272
|
+
process.stderr.write(`cmd_fleet: error: --config path missing or not found
|
|
273
|
+
`);
|
|
274
|
+
return 2;
|
|
275
|
+
}
|
|
276
|
+
let spec;
|
|
277
|
+
try {
|
|
278
|
+
spec = parseFleetSpec(fs.readFileSync(configPath, "utf8"), path.dirname(path.resolve(configPath)));
|
|
279
|
+
} catch (exc) {
|
|
280
|
+
if (exc instanceof FleetConfigError) {
|
|
281
|
+
process.stderr.write(`cmd_fleet: error: ${exc.message}
|
|
282
|
+
`);
|
|
283
|
+
return 2;
|
|
284
|
+
}
|
|
285
|
+
throw exc;
|
|
286
|
+
}
|
|
287
|
+
const report = await runFleet(spec);
|
|
288
|
+
if (json) {
|
|
289
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}
|
|
290
|
+
`);
|
|
291
|
+
} else {
|
|
292
|
+
process.stdout.write(`${humanTable(report)}
|
|
293
|
+
`);
|
|
294
|
+
}
|
|
295
|
+
return report.status === "ok" ? 0 : 1;
|
|
296
|
+
}
|
|
297
|
+
function _isCliEntry() {
|
|
298
|
+
if (process.argv[1] === void 0) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
302
|
+
if (import.meta.url === argvUrl) {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const here = fs.realpathSync(fileURLToPath(import.meta.url));
|
|
307
|
+
const argv = fs.realpathSync(path.resolve(process.argv[1]));
|
|
308
|
+
return here === argv;
|
|
309
|
+
} catch {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (_isCliEntry() || process.argv[1] === _HERE) {
|
|
314
|
+
main(process.argv.slice(2)).then(
|
|
315
|
+
(code) => {
|
|
316
|
+
process.exitCode = code;
|
|
317
|
+
},
|
|
318
|
+
(err) => {
|
|
319
|
+
process.stderr.write(`cmd_fleet: fatal: ${err.message}
|
|
320
|
+
`);
|
|
321
|
+
process.exitCode = 2;
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
export {
|
|
326
|
+
FleetConfigError,
|
|
327
|
+
defaultFleetCommands,
|
|
328
|
+
main,
|
|
329
|
+
parseFleetSpec,
|
|
330
|
+
runFleet,
|
|
331
|
+
validateFleetReport
|
|
332
|
+
};
|