@harness-engineering/cli 4.3.3 → 6.0.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/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +3 -1
- package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +5 -0
- package/dist/agents/skills/claude-code/harness-rollback/SKILL.md +124 -0
- package/dist/agents/skills/claude-code/harness-rollback/skill.yaml +52 -0
- package/dist/agents/skills/claude-code/product-requirements/SKILL.md +150 -0
- package/dist/agents/skills/claude-code/product-requirements/skill.yaml +70 -0
- package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +3 -1
- package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +5 -0
- package/dist/agents/skills/codex/harness-rollback/SKILL.md +124 -0
- package/dist/agents/skills/codex/harness-rollback/skill.yaml +52 -0
- package/dist/agents/skills/codex/product-requirements/SKILL.md +150 -0
- package/dist/agents/skills/codex/product-requirements/skill.yaml +70 -0
- package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +3 -1
- package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +5 -0
- package/dist/agents/skills/cursor/harness-rollback/SKILL.md +124 -0
- package/dist/agents/skills/cursor/harness-rollback/skill.yaml +52 -0
- package/dist/agents/skills/cursor/product-requirements/SKILL.md +150 -0
- package/dist/agents/skills/cursor/product-requirements/skill.yaml +70 -0
- package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +3 -1
- package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +5 -0
- package/dist/agents/skills/gemini-cli/harness-rollback/SKILL.md +124 -0
- package/dist/agents/skills/gemini-cli/harness-rollback/skill.yaml +52 -0
- package/dist/agents/skills/gemini-cli/product-requirements/SKILL.md +150 -0
- package/dist/agents/skills/gemini-cli/product-requirements/skill.yaml +70 -0
- package/dist/{agents-md-N4ULMUAK.js → agents-md-OTKZE5HH.js} +4 -4
- package/dist/{analyzer-XRCV63KC-WGRHW2ZM.js → analyzer-XRCV63KC-FALMS3MO.js} +2 -2
- package/dist/{architecture-OIMIBDJC.js → architecture-3VYDN7MQ.js} +5 -5
- package/dist/{assess-project-ITSB6W4L.js → assess-project-27X2FSZZ.js} +1 -1
- package/dist/bin/harness-mcp.js +15 -15
- package/dist/bin/harness.js +25 -25
- package/dist/{check-phase-gate-GN4X7HT6.js → check-phase-gate-IXLFZ6YH.js} +5 -5
- package/dist/{chunk-MEDRUIRO.js → chunk-354MCPT3.js} +3 -3
- package/dist/{chunk-5BUHPOCP.js → chunk-3H7JA24B.js} +7 -7
- package/dist/{chunk-PT65VY4S.js → chunk-3MKQKNY3.js} +6 -6
- package/dist/{chunk-LP764MGR.js → chunk-6Y6M3AZA.js} +3 -3
- package/dist/{chunk-D7A5JR7M.js → chunk-BMNHLKBA.js} +2 -2
- package/dist/{chunk-CRHQYBDA.js → chunk-CTMHHMHQ.js} +101 -4
- package/dist/{chunk-MIZQY35D.js → chunk-D7QXGI6E.js} +2 -2
- package/dist/{chunk-F3GNBRGL.js → chunk-EFWRZHZ7.js} +101 -97
- package/dist/{chunk-LTYVAKWK.js → chunk-IOJGLIEQ.js} +20 -2
- package/dist/{chunk-CMU4DNLY.js → chunk-IXGYIQSR.js} +1 -1
- package/dist/{chunk-6NEJPS7W.js → chunk-JJLOWMGC.js} +2 -2
- package/dist/{chunk-73QZ43DF.js → chunk-KPBGAB35.js} +2 -2
- package/dist/{chunk-HJYAXAYQ.js → chunk-L5UKNGC5.js} +2 -2
- package/dist/{chunk-VJDSB7CI.js → chunk-LHWBQD7F.js} +24 -1
- package/dist/{chunk-JZL2O3RC.js → chunk-LISEPDVT.js} +5 -5
- package/dist/{chunk-NEMB36N4.js → chunk-MEIUXTFY.js} +2 -2
- package/dist/{chunk-7RH2NTLA.js → chunk-NZ5AXKRA.js} +1 -1
- package/dist/{chunk-H5GN7R43.js → chunk-QHFXVVUY.js} +2 -2
- package/dist/{chunk-U2NOOATF.js → chunk-S2ETJDQJ.js} +6 -6
- package/dist/{chunk-574JCBYH.js → chunk-TM4KFUWP.js} +2 -2
- package/dist/{chunk-YVI7ZV73.js → chunk-VGDZAWCJ.js} +803 -214
- package/dist/{chunk-TKPAOB2T.js → chunk-VRA64HYI.js} +2 -2
- package/dist/{chunk-T46G6YNI.js → chunk-WAFTJFT3.js} +3 -3
- package/dist/{chunk-GTHL3TRZ.js → chunk-XF6RE3JQ.js} +2 -2
- package/dist/{chunk-XKILFNRK.js → chunk-XNHKXELN.js} +2 -2
- package/dist/{ci-workflow-PA3WL6WK.js → ci-workflow-Y5GBKNZP.js} +4 -4
- package/dist/{dist-BWFFVKEW.js → dist-4CZLCE33.js} +7 -3
- package/dist/{dist-ISDDHDOR.js → dist-S3KCRI7X.js} +3 -1
- package/dist/{docs-HOTWQJQF.js → docs-3MWDPK4S.js} +5 -5
- package/dist/{engine-MVG2SPGD.js → engine-RJXQ5DHK.js} +4 -4
- package/dist/{entropy-3B4U2BTF.js → entropy-OX5LSM4S.js} +5 -5
- package/dist/{feedback-WIWWDVUC.js → feedback-OODAP2G2.js} +1 -1
- package/dist/{generate-agent-definitions-KPRHY6X3.js → generate-agent-definitions-CCREQZEA.js} +5 -5
- package/dist/hooks/adoption-tracker.js +41 -25
- package/dist/hooks/pre-compact-state.js +45 -27
- package/dist/hooks/sentinel-post.js +125 -102
- package/dist/hooks/sentinel-pre.js +70 -53
- package/dist/hooks/telemetry-reporter.js +44 -25
- package/dist/index.d.ts +66 -0
- package/dist/index.js +25 -25
- package/dist/{loader-SPJ2ZGYW.js → loader-ZICOJBVX.js} +4 -4
- package/dist/{mcp-VSSIWTII.js → mcp-XX6EIBLL.js} +15 -15
- package/dist/{performance-JYFS27B3.js → performance-OLZVGMAY.js} +5 -5
- package/dist/{review-pipeline-BDT6Y6QV.js → review-pipeline-3QPHMWPC.js} +4 -4
- package/dist/{runtime-ZEPHPPQJ.js → runtime-ZFFIH76Z.js} +4 -4
- package/dist/{security-FWSDTTEW.js → security-7YW3UK2C.js} +1 -1
- package/dist/{state-events-PBDNQPXT.js → state-events-PTWAEGJ2.js} +4 -4
- package/dist/{validate-XIMNCIKR.js → validate-H5SB7X3Z.js} +5 -5
- package/dist/{validate-cross-check-H2OUHTID.js → validate-cross-check-YYVYMSPA.js} +4 -4
- package/package.json +8 -8
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generateRuntime
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TM4KFUWP.js";
|
|
4
4
|
import {
|
|
5
5
|
generateAgentsMd
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-VRA64HYI.js";
|
|
7
7
|
import {
|
|
8
8
|
generateCIWorkflow
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-XF6RE3JQ.js";
|
|
10
10
|
import {
|
|
11
11
|
readHarnessState
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-MEIUXTFY.js";
|
|
13
13
|
import {
|
|
14
14
|
runCrossCheck
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-D7QXGI6E.js";
|
|
16
16
|
import {
|
|
17
17
|
createGenerateAgentDefinitionsCommand,
|
|
18
18
|
generateAgentDefinitions
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-IXGYIQSR.js";
|
|
20
20
|
import {
|
|
21
21
|
toKebabCase
|
|
22
22
|
} from "./chunk-KET4QQZB.js";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from "./chunk-YYFSFSB3.js";
|
|
27
27
|
import {
|
|
28
28
|
TemplateEngine
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-JJLOWMGC.js";
|
|
30
30
|
import {
|
|
31
31
|
generate,
|
|
32
32
|
validate
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
import {
|
|
38
38
|
listPersonas,
|
|
39
39
|
loadPersona
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-KPBGAB35.js";
|
|
41
41
|
import {
|
|
42
42
|
runPersona
|
|
43
43
|
} from "./chunk-GISMXMVL.js";
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
OutputFormatter,
|
|
52
52
|
OutputMode,
|
|
53
53
|
createCheckPhaseGateCommand
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-6Y6M3AZA.js";
|
|
55
55
|
import {
|
|
56
56
|
appendFrameworkAgents,
|
|
57
57
|
captureHealthSnapshot,
|
|
@@ -79,7 +79,7 @@ import {
|
|
|
79
79
|
runSecurityCraft,
|
|
80
80
|
runSpecCraft,
|
|
81
81
|
runTestCraft
|
|
82
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-EFWRZHZ7.js";
|
|
83
83
|
import {
|
|
84
84
|
VALID_PLATFORMS
|
|
85
85
|
} from "./chunk-3ISINLYT.js";
|
|
@@ -108,7 +108,7 @@ import {
|
|
|
108
108
|
BranchingConfigSchema,
|
|
109
109
|
findConfigFile,
|
|
110
110
|
resolveConfig
|
|
111
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-IOJGLIEQ.js";
|
|
112
112
|
import {
|
|
113
113
|
logger
|
|
114
114
|
} from "./chunk-EBJQ6N4M.js";
|
|
@@ -146,6 +146,7 @@ import {
|
|
|
146
146
|
checkRoadmapAggregateDrift,
|
|
147
147
|
checkRoadmapHealth,
|
|
148
148
|
checkTaint,
|
|
149
|
+
classifyRevert,
|
|
149
150
|
clearTaint,
|
|
150
151
|
computeHotspots,
|
|
151
152
|
computeOverallSeverity,
|
|
@@ -225,7 +226,7 @@ import {
|
|
|
225
226
|
writeConfig,
|
|
226
227
|
writeLockfile,
|
|
227
228
|
writeRegeneratedRoadmap
|
|
228
|
-
} from "./chunk-
|
|
229
|
+
} from "./chunk-CTMHHMHQ.js";
|
|
229
230
|
import {
|
|
230
231
|
CLI_VERSION
|
|
231
232
|
} from "./chunk-BM3PWGXQ.js";
|
|
@@ -238,14 +239,14 @@ import {
|
|
|
238
239
|
detectDocDrift,
|
|
239
240
|
generateSuggestions,
|
|
240
241
|
validateDependencies
|
|
241
|
-
} from "./chunk-
|
|
242
|
+
} from "./chunk-NZ5AXKRA.js";
|
|
242
243
|
import {
|
|
243
244
|
Err,
|
|
244
245
|
INDEXED_FILE_KINDS,
|
|
245
246
|
INSIGHTS_KEYS,
|
|
246
247
|
Ok,
|
|
247
248
|
init_dist
|
|
248
|
-
} from "./chunk-
|
|
249
|
+
} from "./chunk-LHWBQD7F.js";
|
|
249
250
|
import {
|
|
250
251
|
DEFAULT_SKIP_DIRS,
|
|
251
252
|
DesignConstraintAdapter,
|
|
@@ -262,7 +263,7 @@ import {
|
|
|
262
263
|
} from "./chunk-KFQGP6VL.js";
|
|
263
264
|
|
|
264
265
|
// src/index.ts
|
|
265
|
-
import { Command as
|
|
266
|
+
import { Command as Command133 } from "commander";
|
|
266
267
|
|
|
267
268
|
// src/commands/add.ts
|
|
268
269
|
init_dist3();
|
|
@@ -453,7 +454,7 @@ function registerSkillsCommand(adoption) {
|
|
|
453
454
|
const globalOpts = cmd.optsWithGlobals();
|
|
454
455
|
const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
|
|
455
456
|
const cwd = process.cwd();
|
|
456
|
-
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-
|
|
457
|
+
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-4CZLCE33.js");
|
|
457
458
|
const records = readAdoptionRecords(cwd);
|
|
458
459
|
if (records.length === 0) {
|
|
459
460
|
if (globalOpts.json) {
|
|
@@ -489,7 +490,7 @@ function registerRecentCommand(adoption) {
|
|
|
489
490
|
const globalOpts = cmd.optsWithGlobals();
|
|
490
491
|
const limit = Math.max(parseInt(opts.limit, 10) || 20, 1);
|
|
491
492
|
const cwd = process.cwd();
|
|
492
|
-
const { readAdoptionRecords } = await import("./dist-
|
|
493
|
+
const { readAdoptionRecords } = await import("./dist-4CZLCE33.js");
|
|
493
494
|
const records = readAdoptionRecords(cwd);
|
|
494
495
|
if (records.length === 0) {
|
|
495
496
|
if (globalOpts.json) {
|
|
@@ -567,7 +568,7 @@ function registerSkillCommand(adoption) {
|
|
|
567
568
|
adoption.command("skill <name>").description("Show detail for a specific skill").action(async (name, _opts, cmd) => {
|
|
568
569
|
const globalOpts = cmd.optsWithGlobals();
|
|
569
570
|
const cwd = process.cwd();
|
|
570
|
-
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-
|
|
571
|
+
const { readAdoptionRecords, aggregateBySkill } = await import("./dist-4CZLCE33.js");
|
|
571
572
|
const records = readAdoptionRecords(cwd);
|
|
572
573
|
const skillRecords = records.filter((r) => r.skill === name);
|
|
573
574
|
if (skillRecords.length === 0) {
|
|
@@ -601,7 +602,7 @@ function registerRetrospectiveCommand(adoption) {
|
|
|
601
602
|
adoption.command("retrospective").description("Generate a catalog retrospective from adoption telemetry").option("--inactive-days <n>", "Inactivity threshold in days (default: 90)", "90").option("--top <n>", "Rows per ranked section (default: 10)", "10").option("--out <path>", "Output file path (default: docs/retrospectives/YYYY-MM-DD.md)").option("--no-write", "Print the report to stdout instead of writing a file").action(async (opts, cmd) => {
|
|
602
603
|
const globalOpts = cmd.optsWithGlobals();
|
|
603
604
|
const cwd = process.cwd();
|
|
604
|
-
const { readAdoptionRecords, getCatalogRetrospectiveReport, renderRetrospectiveMarkdown } = await import("./dist-
|
|
605
|
+
const { readAdoptionRecords, getCatalogRetrospectiveReport, renderRetrospectiveMarkdown } = await import("./dist-4CZLCE33.js");
|
|
605
606
|
const records = readAdoptionRecords(cwd);
|
|
606
607
|
const catalogSkills = discoverCatalogSkills(cwd);
|
|
607
608
|
const report = getCatalogRetrospectiveReport(records, {
|
|
@@ -5248,16 +5249,9 @@ function createRemoveCommand() {
|
|
|
5248
5249
|
import { Command as Command41 } from "commander";
|
|
5249
5250
|
import * as fs13 from "fs";
|
|
5250
5251
|
import * as path27 from "path";
|
|
5251
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
5252
|
-
var __dirname3 = path27.dirname(fileURLToPath3(import.meta.url));
|
|
5253
5252
|
var ALIASES = {
|
|
5254
5253
|
sentinel: ["sentinel-pre", "sentinel-post"]
|
|
5255
5254
|
};
|
|
5256
|
-
function hookSourceDir() {
|
|
5257
|
-
const d = path27.resolve(__dirname3, "..", "..", "hooks");
|
|
5258
|
-
if (fs13.existsSync(d)) return d;
|
|
5259
|
-
throw new Error(`Hook scripts not found: ${d}`);
|
|
5260
|
-
}
|
|
5261
5255
|
function readJson(p) {
|
|
5262
5256
|
return fs13.existsSync(p) ? JSON.parse(fs13.readFileSync(p, "utf-8")) : {};
|
|
5263
5257
|
}
|
|
@@ -5271,7 +5265,7 @@ function registerHook(s, ev, matcher, name) {
|
|
|
5271
5265
|
function addHooks(hookName, projectDir) {
|
|
5272
5266
|
const names = ALIASES[hookName] ?? [hookName];
|
|
5273
5267
|
const result = { added: [], alreadyInstalled: [], notFound: [] };
|
|
5274
|
-
const srcDir =
|
|
5268
|
+
const srcDir = resolveHookSourceDir();
|
|
5275
5269
|
const destDir = path27.join(projectDir, ".harness", "hooks");
|
|
5276
5270
|
fs13.mkdirSync(destDir, { recursive: true });
|
|
5277
5271
|
const claudeDir = path27.join(projectDir, ".claude");
|
|
@@ -6209,7 +6203,7 @@ function createInsightsCommand() {
|
|
|
6209
6203
|
return new Command46("insights").description("Composite project report \u2014 health, entropy, decay, attention, impact.").option("--json", "Emit JSON to stdout instead of pretty text").option("--skip <list>", `Comma-separated keys to skip (${INSIGHTS_KEYS.join(",")})`).action(async (opts) => {
|
|
6210
6204
|
const cwd = process.cwd();
|
|
6211
6205
|
const skip = parseSkip2(opts.skip);
|
|
6212
|
-
const { composeInsights } = await import("./dist-
|
|
6206
|
+
const { composeInsights } = await import("./dist-4CZLCE33.js");
|
|
6213
6207
|
const report = await composeInsights(cwd, { skip });
|
|
6214
6208
|
if (opts.json) {
|
|
6215
6209
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -7944,10 +7938,10 @@ function reportDispatcher() {
|
|
|
7944
7938
|
function realGit(args, cwd) {
|
|
7945
7939
|
return execFileSync4("git", args, { cwd, encoding: "utf-8" }).toString().trim();
|
|
7946
7940
|
}
|
|
7947
|
-
function createFixDispatcher(resolveBackend,
|
|
7941
|
+
function createFixDispatcher(resolveBackend, git2 = realGit) {
|
|
7948
7942
|
return createAgentDispatcher({
|
|
7949
7943
|
resolveBackend,
|
|
7950
|
-
git,
|
|
7944
|
+
git: git2,
|
|
7951
7945
|
logger: {
|
|
7952
7946
|
info: (message) => logger.info(message),
|
|
7953
7947
|
warn: (message) => logger.warn(message)
|
|
@@ -8320,7 +8314,7 @@ function createMcpCommand() {
|
|
|
8320
8314
|
parseBudget
|
|
8321
8315
|
).action(async (opts) => {
|
|
8322
8316
|
const [{ startServer: startServer2, getToolDefinitions: getToolDefinitions2 }, { selectTier }] = await Promise.all([
|
|
8323
|
-
import("./mcp-
|
|
8317
|
+
import("./mcp-XX6EIBLL.js"),
|
|
8324
8318
|
import("./tool-tiers-OKK5FE57.js")
|
|
8325
8319
|
]);
|
|
8326
8320
|
if (opts.tools && opts.tools.length > 0) {
|
|
@@ -8862,7 +8856,7 @@ function updateReferences(plan) {
|
|
|
8862
8856
|
}
|
|
8863
8857
|
async function prompt(question, def = "n") {
|
|
8864
8858
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
8865
|
-
const answer = await new Promise((
|
|
8859
|
+
const answer = await new Promise((resolve49) => rl.question(question, resolve49));
|
|
8866
8860
|
rl.close();
|
|
8867
8861
|
return (answer.trim() || def).toLowerCase();
|
|
8868
8862
|
}
|
|
@@ -9051,7 +9045,7 @@ function createMigrateCommand() {
|
|
|
9051
9045
|
// src/commands/models.ts
|
|
9052
9046
|
init_dist3();
|
|
9053
9047
|
import { Command as Command66 } from "commander";
|
|
9054
|
-
import { resolve as
|
|
9048
|
+
import { resolve as resolve30 } from "path";
|
|
9055
9049
|
import { defaultFetchModels } from "@harness-engineering/orchestrator";
|
|
9056
9050
|
function errorResult(message, partial) {
|
|
9057
9051
|
return {
|
|
@@ -9169,7 +9163,7 @@ function formatProbe(result) {
|
|
|
9169
9163
|
return lines.join("\n");
|
|
9170
9164
|
}
|
|
9171
9165
|
function projectRoot() {
|
|
9172
|
-
return
|
|
9166
|
+
return resolve30(process.env["HARNESS_PROJECT_ROOT"] ?? process.cwd());
|
|
9173
9167
|
}
|
|
9174
9168
|
function summarizeModelProposal(p) {
|
|
9175
9169
|
const base = { id: p.id, status: p.status, proposedBy: p.proposedBy, createdAt: p.createdAt };
|
|
@@ -9430,7 +9424,7 @@ import { Command as Command69 } from "commander";
|
|
|
9430
9424
|
init_dist3();
|
|
9431
9425
|
import { Command as Command68 } from "commander";
|
|
9432
9426
|
import { randomBytes } from "crypto";
|
|
9433
|
-
import { resolve as
|
|
9427
|
+
import { resolve as resolve31 } from "path";
|
|
9434
9428
|
import { SinkRegistry, SinkConfigError, wrapAsEnvelope } from "@harness-engineering/orchestrator";
|
|
9435
9429
|
function makeTestEvent(message) {
|
|
9436
9430
|
return {
|
|
@@ -9482,7 +9476,7 @@ async function runNotificationsTest(sinkId, opts, projectRoot3 = process.cwd())
|
|
|
9482
9476
|
function createNotificationsTestSubcommand() {
|
|
9483
9477
|
return new Command68("test").description("Send a synthetic notification.test event through the named sink").argument("<sink-id>", "Sink id from harness.config.json `notifications.sinks[].id`").option("--message <text>", "Override the default test message").action(async (sinkId, opts, cmd) => {
|
|
9484
9478
|
const globalOpts = cmd.optsWithGlobals();
|
|
9485
|
-
const projectRoot3 = typeof globalOpts["cwd"] === "string" ?
|
|
9479
|
+
const projectRoot3 = typeof globalOpts["cwd"] === "string" ? resolve31(globalOpts["cwd"]) : process.cwd();
|
|
9486
9480
|
const result = await runNotificationsTest(sinkId, opts, projectRoot3);
|
|
9487
9481
|
if (globalOpts["json"]) {
|
|
9488
9482
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -9507,7 +9501,12 @@ function createNotificationsCommand() {
|
|
|
9507
9501
|
// src/commands/orchestrator.ts
|
|
9508
9502
|
import { Command as Command70 } from "commander";
|
|
9509
9503
|
import * as path50 from "path";
|
|
9510
|
-
import {
|
|
9504
|
+
import {
|
|
9505
|
+
Orchestrator,
|
|
9506
|
+
WorkflowLoader as WorkflowLoader2,
|
|
9507
|
+
launchTUI,
|
|
9508
|
+
discoverCandidates
|
|
9509
|
+
} from "@harness-engineering/orchestrator";
|
|
9511
9510
|
function createOrchestratorCommand() {
|
|
9512
9511
|
const orchestrator = new Command70("orchestrator");
|
|
9513
9512
|
orchestrator.command("run").description("Run the orchestrator daemon").option("-w, --workflow <path>", "Path to harness.orchestrator.md", "harness.orchestrator.md").option("--headless", "Run without TUI (server-only mode for use with web dashboard)").action(async (opts) => {
|
|
@@ -9520,7 +9519,7 @@ function createOrchestratorCommand() {
|
|
|
9520
9519
|
}
|
|
9521
9520
|
const { config, promptTemplate, warnings } = result.value;
|
|
9522
9521
|
for (const w of warnings) logger.warn(w);
|
|
9523
|
-
const daemon = new Orchestrator(config, promptTemplate);
|
|
9522
|
+
const daemon = new Orchestrator(config, promptTemplate, { discoverCandidates });
|
|
9524
9523
|
const shutdown = () => {
|
|
9525
9524
|
daemon.stop();
|
|
9526
9525
|
process.exit(ExitCode.SUCCESS);
|
|
@@ -9551,7 +9550,7 @@ function registerBenchCommand(perf) {
|
|
|
9551
9550
|
perf.command("bench [glob]").description("Run benchmarks via vitest bench").action(async (glob2, _opts, cmd) => {
|
|
9552
9551
|
const globalOpts = cmd.optsWithGlobals();
|
|
9553
9552
|
const cwd = process.cwd();
|
|
9554
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
9553
|
+
const { BenchmarkRunner } = await import("./dist-4CZLCE33.js");
|
|
9555
9554
|
const runner = new BenchmarkRunner();
|
|
9556
9555
|
const benchFiles = runner.discover(cwd, glob2);
|
|
9557
9556
|
if (benchFiles.length === 0) {
|
|
@@ -9615,7 +9614,7 @@ async function runBaselinesShow(globalOpts) {
|
|
|
9615
9614
|
}
|
|
9616
9615
|
async function runBaselinesUpdate(globalOpts) {
|
|
9617
9616
|
const cwd = process.cwd();
|
|
9618
|
-
const { BenchmarkRunner } = await import("./dist-
|
|
9617
|
+
const { BenchmarkRunner } = await import("./dist-4CZLCE33.js");
|
|
9619
9618
|
const runner = new BenchmarkRunner();
|
|
9620
9619
|
const manager = new BaselineManager(cwd);
|
|
9621
9620
|
logger.info("Running benchmarks to update baselines...");
|
|
@@ -9656,7 +9655,7 @@ function registerReportCommand(perf) {
|
|
|
9656
9655
|
perf.command("report").description("Full performance report with metrics, trends, and hotspots").action(async (_opts, cmd) => {
|
|
9657
9656
|
const globalOpts = cmd.optsWithGlobals();
|
|
9658
9657
|
const cwd = process.cwd();
|
|
9659
|
-
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-
|
|
9658
|
+
const { EntropyAnalyzer: EntropyAnalyzer2 } = await import("./dist-4CZLCE33.js");
|
|
9660
9659
|
const analyzer = new EntropyAnalyzer2({
|
|
9661
9660
|
rootDir: path51.resolve(cwd),
|
|
9662
9661
|
analyze: { complexity: true, coupling: true }
|
|
@@ -10443,9 +10442,9 @@ function createPreMergeBriefCommand() {
|
|
|
10443
10442
|
// src/commands/proposals.ts
|
|
10444
10443
|
init_dist3();
|
|
10445
10444
|
import { Command as Command78 } from "commander";
|
|
10446
|
-
import { resolve as
|
|
10445
|
+
import { resolve as resolve35 } from "path";
|
|
10447
10446
|
function projectRoot2() {
|
|
10448
|
-
return
|
|
10447
|
+
return resolve35(process.env["HARNESS_PROJECT_ROOT"] ?? process.cwd());
|
|
10449
10448
|
}
|
|
10450
10449
|
function summarizeProposal(p) {
|
|
10451
10450
|
const base = {
|
|
@@ -10679,7 +10678,7 @@ async function runPublishAnalyses(opts) {
|
|
|
10679
10678
|
const nameToExternalId = await buildNameToExternalIdMap(projectPath);
|
|
10680
10679
|
if (!nameToExternalId) return process.exit(1);
|
|
10681
10680
|
const { AnalysisArchive } = await import("@harness-engineering/orchestrator");
|
|
10682
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
10681
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-4CZLCE33.js");
|
|
10683
10682
|
const archive = new AnalysisArchive(path53.join(projectPath, ".harness", "analyses"));
|
|
10684
10683
|
const analyses = await archive.list();
|
|
10685
10684
|
if (analyses.length === 0) {
|
|
@@ -10723,7 +10722,7 @@ import { Command as Command81 } from "commander";
|
|
|
10723
10722
|
// src/commands/pulse/run.ts
|
|
10724
10723
|
init_dist3();
|
|
10725
10724
|
import { readFileSync as readFileSync19, mkdirSync as mkdirSync16, writeFileSync as writeFileSync20 } from "fs";
|
|
10726
|
-
import { dirname as
|
|
10725
|
+
import { dirname as dirname18, join as join43, resolve as resolve37 } from "path";
|
|
10727
10726
|
import { Command as Command80 } from "commander";
|
|
10728
10727
|
async function runPulseRunCommand(opts) {
|
|
10729
10728
|
const startedAt = Date.now();
|
|
@@ -10756,7 +10755,7 @@ async function runPulseRunCommand(opts) {
|
|
|
10756
10755
|
const now = /* @__PURE__ */ new Date();
|
|
10757
10756
|
const ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}_${String(now.getHours()).padStart(2, "0")}-${String(now.getMinutes()).padStart(2, "0")}`;
|
|
10758
10757
|
const filePath = join43(opts.outputDir, `${ts}.md`);
|
|
10759
|
-
mkdirSync16(
|
|
10758
|
+
mkdirSync16(dirname18(filePath), { recursive: true });
|
|
10760
10759
|
writeFileSync20(filePath, report);
|
|
10761
10760
|
const headlines = extractHeadlines(report);
|
|
10762
10761
|
return emit2(
|
|
@@ -10799,8 +10798,8 @@ function createRunCommand2() {
|
|
|
10799
10798
|
async (options) => {
|
|
10800
10799
|
const nonInteractive = options.nonInteractive === true || !process.stdout.isTTY;
|
|
10801
10800
|
const status = await runPulseRunCommand({
|
|
10802
|
-
configPath:
|
|
10803
|
-
outputDir:
|
|
10801
|
+
configPath: resolve37(process.cwd(), options.config),
|
|
10802
|
+
outputDir: resolve37(process.cwd(), options.outputDir),
|
|
10804
10803
|
nonInteractive,
|
|
10805
10804
|
lookback: options.lookback
|
|
10806
10805
|
});
|
|
@@ -11782,11 +11781,435 @@ function createRoadmapCommand() {
|
|
|
11782
11781
|
return roadmap;
|
|
11783
11782
|
}
|
|
11784
11783
|
|
|
11784
|
+
// src/commands/rollback.ts
|
|
11785
|
+
init_dist3();
|
|
11786
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
11787
|
+
import { Command as Command90, Option as Option3, InvalidArgumentError } from "commander";
|
|
11788
|
+
|
|
11789
|
+
// src/rollback/compose.ts
|
|
11790
|
+
var ROLLBACK_LABEL = "harness:rollback";
|
|
11791
|
+
function buildRevertBody(d, originalTitle, reason) {
|
|
11792
|
+
const lines = [
|
|
11793
|
+
`## Automated rollback proposal`,
|
|
11794
|
+
``,
|
|
11795
|
+
`**Trigger:** ${d.trigger}`,
|
|
11796
|
+
`**Target PR:** #${d.targetPr} \u2014 ${originalTitle}`,
|
|
11797
|
+
`**Revert-ready:** ${d.revertReady}`,
|
|
11798
|
+
d.blastRadius !== void 0 ? `**Blast radius:** ${d.blastRadius}` : void 0,
|
|
11799
|
+
// #4: surface the human-provided --reason when present (help text promises it).
|
|
11800
|
+
reason && reason.trim() !== "" ? `**Reason:** ${reason.trim()}` : void 0,
|
|
11801
|
+
``,
|
|
11802
|
+
`### Classification`,
|
|
11803
|
+
...d.reasons.map((r) => `- ${r}`)
|
|
11804
|
+
];
|
|
11805
|
+
if (d.migrationWarnings.length > 0) {
|
|
11806
|
+
lines.push(
|
|
11807
|
+
``,
|
|
11808
|
+
`### Migration / irreversibility warnings`,
|
|
11809
|
+
...d.migrationWarnings.map((w) => `- ${w}`)
|
|
11810
|
+
);
|
|
11811
|
+
}
|
|
11812
|
+
if (d.dependentMerges.length > 0) {
|
|
11813
|
+
lines.push(
|
|
11814
|
+
``,
|
|
11815
|
+
`### Dependent later merges`,
|
|
11816
|
+
`- ${d.dependentMerges.map((n) => `#${n}`).join(", ")}`
|
|
11817
|
+
);
|
|
11818
|
+
}
|
|
11819
|
+
return lines.filter((l) => l !== void 0).join("\n");
|
|
11820
|
+
}
|
|
11821
|
+
async function composeRevertPr(decision, originalTitle, opts) {
|
|
11822
|
+
if (!decision.revertReady) return { action: decision.action };
|
|
11823
|
+
const body = buildRevertBody(decision, originalTitle, opts.reason);
|
|
11824
|
+
if (opts.dryRun) {
|
|
11825
|
+
const print = opts.print ?? ((s) => process.stdout.write(`${s}
|
|
11826
|
+
`));
|
|
11827
|
+
print(body);
|
|
11828
|
+
return { action: "proposed" };
|
|
11829
|
+
}
|
|
11830
|
+
const existing = await opts.gh.findOpenRevertPr(decision.targetPr, ROLLBACK_LABEL);
|
|
11831
|
+
if (existing !== null) {
|
|
11832
|
+
return { action: "skipped", ...existing.url ? { prUrl: existing.url } : {} };
|
|
11833
|
+
}
|
|
11834
|
+
const prUrl = await opts.gh.openPr({
|
|
11835
|
+
title: `revert: ${originalTitle} (automated rollback)`,
|
|
11836
|
+
body,
|
|
11837
|
+
label: ROLLBACK_LABEL,
|
|
11838
|
+
targetPr: decision.targetPr
|
|
11839
|
+
});
|
|
11840
|
+
return { action: "proposed", prUrl };
|
|
11841
|
+
}
|
|
11842
|
+
|
|
11843
|
+
// src/rollback/breadcrumb.ts
|
|
11844
|
+
import { appendFileSync, mkdirSync as mkdirSync19 } from "fs";
|
|
11845
|
+
import { dirname as dirname20, join as join50 } from "path";
|
|
11846
|
+
var ROLLBACK_EVENTS_FILE = join50(".harness", "signals", "rollback-events.jsonl");
|
|
11847
|
+
async function appendRollbackEvent(event, opts = {}) {
|
|
11848
|
+
const root = opts.root ?? process.cwd();
|
|
11849
|
+
const ts = (opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString()))();
|
|
11850
|
+
const file = join50(root, ROLLBACK_EVENTS_FILE);
|
|
11851
|
+
mkdirSync19(dirname20(file), { recursive: true });
|
|
11852
|
+
appendFileSync(file, `${JSON.stringify({ ...event, ts })}
|
|
11853
|
+
`, "utf-8");
|
|
11854
|
+
}
|
|
11855
|
+
async function linkRollbackEventToGraph(event, opts = {}) {
|
|
11856
|
+
const root = opts.root ?? process.cwd();
|
|
11857
|
+
try {
|
|
11858
|
+
const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-STFGYKZH.js");
|
|
11859
|
+
const store = await loadGraphStore2(root);
|
|
11860
|
+
if (!store) return;
|
|
11861
|
+
const ts = (opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString()))();
|
|
11862
|
+
const nodeId = `rollback_event:${event.targetPr}:${ts}`;
|
|
11863
|
+
store.addNode({
|
|
11864
|
+
id: nodeId,
|
|
11865
|
+
type: "learning",
|
|
11866
|
+
name: `rollback ${event.action} for PR #${event.targetPr}`,
|
|
11867
|
+
metadata: { kind: "rollback_event", ...event, ts },
|
|
11868
|
+
lastModified: ts
|
|
11869
|
+
});
|
|
11870
|
+
const outcomes = store.findNodes({ type: "execution_outcome" });
|
|
11871
|
+
const target = outcomes.find(
|
|
11872
|
+
(n) => n.metadata.pr === event.targetPr
|
|
11873
|
+
);
|
|
11874
|
+
if (target) {
|
|
11875
|
+
store.addEdge({ from: nodeId, to: target.id, type: "references" });
|
|
11876
|
+
}
|
|
11877
|
+
await store.save(join50(root, ".harness", "graph"));
|
|
11878
|
+
} catch {
|
|
11879
|
+
}
|
|
11880
|
+
}
|
|
11881
|
+
|
|
11882
|
+
// src/rollback/io.ts
|
|
11883
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
11884
|
+
var git = (args) => execFileSync8("git", args, { encoding: "utf-8" }).toString();
|
|
11885
|
+
var nodeGitSeam = {
|
|
11886
|
+
run: (args) => git(args).trim(),
|
|
11887
|
+
tryMergeTree: (args) => {
|
|
11888
|
+
try {
|
|
11889
|
+
const stdout = execFileSync8("git", args, {
|
|
11890
|
+
encoding: "utf-8",
|
|
11891
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
11892
|
+
}).toString();
|
|
11893
|
+
return { status: 0, stdout };
|
|
11894
|
+
} catch (err) {
|
|
11895
|
+
const e = err;
|
|
11896
|
+
return { status: e?.status ?? 1, stdout: e?.stdout?.toString?.() ?? "" };
|
|
11897
|
+
}
|
|
11898
|
+
}
|
|
11899
|
+
};
|
|
11900
|
+
var gh = (args) => execFileSync8("gh", args, { encoding: "utf-8" }).toString();
|
|
11901
|
+
function parseConflictPaths(stdout) {
|
|
11902
|
+
const lines = stdout.split("\n");
|
|
11903
|
+
const paths = /* @__PURE__ */ new Set();
|
|
11904
|
+
for (let i = 1; i < lines.length; i++) {
|
|
11905
|
+
const line = lines[i];
|
|
11906
|
+
if (line === void 0 || line.trim() === "") break;
|
|
11907
|
+
const tab = line.indexOf(" ");
|
|
11908
|
+
if (tab === -1) continue;
|
|
11909
|
+
const path81 = line.slice(tab + 1).trim();
|
|
11910
|
+
if (path81) paths.add(path81);
|
|
11911
|
+
}
|
|
11912
|
+
return [...paths];
|
|
11913
|
+
}
|
|
11914
|
+
async function computeRevertDryRun(mergeSha, gitSeam = nodeGitSeam) {
|
|
11915
|
+
const revList = gitSeam.run(["rev-list", "--parents", "-n", "1", mergeSha]);
|
|
11916
|
+
const parents = revList.trim().split(/\s+/).slice(1);
|
|
11917
|
+
if (parents.length === 0) {
|
|
11918
|
+
throw new Error(`cannot revert ${mergeSha}: commit has no parent (root commit)`);
|
|
11919
|
+
}
|
|
11920
|
+
const parent = parents[0];
|
|
11921
|
+
const { status, stdout } = gitSeam.tryMergeTree([
|
|
11922
|
+
"merge-tree",
|
|
11923
|
+
"--write-tree",
|
|
11924
|
+
"--merge-base",
|
|
11925
|
+
mergeSha,
|
|
11926
|
+
"HEAD",
|
|
11927
|
+
parent
|
|
11928
|
+
]);
|
|
11929
|
+
if (status === 0) return { clean: true, conflictPaths: [] };
|
|
11930
|
+
if (status === 1) return { clean: false, conflictPaths: parseConflictPaths(stdout) };
|
|
11931
|
+
throw new Error(
|
|
11932
|
+
`git merge-tree failed for ${mergeSha} (exit ${status})${stdout ? `: ${stdout.trim()}` : ""}`
|
|
11933
|
+
);
|
|
11934
|
+
}
|
|
11935
|
+
async function revertDryRun(mergeSha) {
|
|
11936
|
+
return computeRevertDryRun(mergeSha, nodeGitSeam);
|
|
11937
|
+
}
|
|
11938
|
+
async function resolveTarget(pr) {
|
|
11939
|
+
const raw = gh(["pr", "view", String(pr), "--json", "mergeCommit,files,title"]);
|
|
11940
|
+
const parsed = JSON.parse(raw);
|
|
11941
|
+
return {
|
|
11942
|
+
mergeSha: parsed.mergeCommit?.oid ?? "",
|
|
11943
|
+
changedFiles: (parsed.files ?? []).map((f) => f.path),
|
|
11944
|
+
title: parsed.title ?? `PR #${pr}`
|
|
11945
|
+
};
|
|
11946
|
+
}
|
|
11947
|
+
async function listLaterMerges(pr) {
|
|
11948
|
+
const targetRaw = gh(["pr", "view", String(pr), "--json", "mergedAt"]);
|
|
11949
|
+
const targetMergedAt = JSON.parse(targetRaw).mergedAt;
|
|
11950
|
+
if (!targetMergedAt) return [];
|
|
11951
|
+
const raw = gh([
|
|
11952
|
+
"pr",
|
|
11953
|
+
"list",
|
|
11954
|
+
"--state",
|
|
11955
|
+
"merged",
|
|
11956
|
+
"--limit",
|
|
11957
|
+
"100",
|
|
11958
|
+
"--json",
|
|
11959
|
+
"number,files,mergedAt"
|
|
11960
|
+
]);
|
|
11961
|
+
const list = JSON.parse(raw);
|
|
11962
|
+
return list.filter((p) => p.number !== pr && p.mergedAt > targetMergedAt).map((p) => ({ pr: p.number, changedFiles: (p.files ?? []).map((f) => f.path) }));
|
|
11963
|
+
}
|
|
11964
|
+
function createNodeRollbackIO() {
|
|
11965
|
+
return { revertDryRun, resolveTarget, listLaterMerges };
|
|
11966
|
+
}
|
|
11967
|
+
|
|
11968
|
+
// src/rollback/sweep.ts
|
|
11969
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
11970
|
+
import { SignalTimelineStore } from "@harness-engineering/signals";
|
|
11971
|
+
var WINDOW_UNIT_MS = {
|
|
11972
|
+
h: 36e5,
|
|
11973
|
+
d: 864e5,
|
|
11974
|
+
w: 6048e5
|
|
11975
|
+
};
|
|
11976
|
+
function parseWindow(window) {
|
|
11977
|
+
const match = /^(\d+)([hdw])$/.exec(window);
|
|
11978
|
+
if (!match) throw new Error(`invalid window: ${window}`);
|
|
11979
|
+
const count = Number.parseInt(match[1] ?? "", 10);
|
|
11980
|
+
const unit = match[2];
|
|
11981
|
+
return count * WINDOW_UNIT_MS[unit];
|
|
11982
|
+
}
|
|
11983
|
+
function detectCrossing(points, rule) {
|
|
11984
|
+
const prev = points.at(-2);
|
|
11985
|
+
const curr = points.at(-1);
|
|
11986
|
+
if (!prev || !curr) return false;
|
|
11987
|
+
if (rule.direction === "above") {
|
|
11988
|
+
return prev.value < rule.threshold && curr.value >= rule.threshold;
|
|
11989
|
+
}
|
|
11990
|
+
return prev.value > rule.threshold && curr.value <= rule.threshold;
|
|
11991
|
+
}
|
|
11992
|
+
function windowStart(now, window) {
|
|
11993
|
+
return new Date(now.getTime() - parseWindow(window)).toISOString();
|
|
11994
|
+
}
|
|
11995
|
+
function pointsInWindow(points, now, window) {
|
|
11996
|
+
const startDate = windowStart(now, window).slice(0, 10);
|
|
11997
|
+
const nowDate = now.toISOString().slice(0, 10);
|
|
11998
|
+
return points.filter((p) => p.date >= startDate && p.date <= nowDate);
|
|
11999
|
+
}
|
|
12000
|
+
async function runRollbackSweep(signals, deps) {
|
|
12001
|
+
const now = (deps.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
12002
|
+
for (const [name, rule] of Object.entries(signals)) {
|
|
12003
|
+
const pts = pointsInWindow(deps.readTimeline(name), now, rule.window);
|
|
12004
|
+
const crossed = detectCrossing(pts, rule);
|
|
12005
|
+
const forwarded = [];
|
|
12006
|
+
if (crossed) {
|
|
12007
|
+
const prs = await deps.resolveMergedPrs(windowStart(now, rule.window), now.toISOString());
|
|
12008
|
+
for (const pr of prs) {
|
|
12009
|
+
const decision = await deps.evaluate(pr);
|
|
12010
|
+
forwarded.push({
|
|
12011
|
+
pr,
|
|
12012
|
+
action: decision.action,
|
|
12013
|
+
...decision.prUrl ? { prUrl: decision.prUrl } : {}
|
|
12014
|
+
});
|
|
12015
|
+
}
|
|
12016
|
+
}
|
|
12017
|
+
deps.report?.({ signal: name, window: rule.window, crossed, forwarded });
|
|
12018
|
+
}
|
|
12019
|
+
}
|
|
12020
|
+
function createTimelineReader(root) {
|
|
12021
|
+
const store = new SignalTimelineStore(root);
|
|
12022
|
+
return (name) => store.read(name);
|
|
12023
|
+
}
|
|
12024
|
+
function createPrResolver() {
|
|
12025
|
+
return async (startIso, nowIso) => {
|
|
12026
|
+
try {
|
|
12027
|
+
const raw = execFileSync9(
|
|
12028
|
+
"gh",
|
|
12029
|
+
[
|
|
12030
|
+
"pr",
|
|
12031
|
+
"list",
|
|
12032
|
+
"--state",
|
|
12033
|
+
"merged",
|
|
12034
|
+
"--search",
|
|
12035
|
+
`merged:${startIso}..${nowIso}`,
|
|
12036
|
+
"--json",
|
|
12037
|
+
"number",
|
|
12038
|
+
"--limit",
|
|
12039
|
+
"100"
|
|
12040
|
+
],
|
|
12041
|
+
{ encoding: "utf-8" }
|
|
12042
|
+
);
|
|
12043
|
+
return JSON.parse(raw).map((p) => p.number);
|
|
12044
|
+
} catch {
|
|
12045
|
+
return [];
|
|
12046
|
+
}
|
|
12047
|
+
};
|
|
12048
|
+
}
|
|
12049
|
+
|
|
12050
|
+
// src/commands/rollback.ts
|
|
12051
|
+
async function runRollbackEvaluate(args, deps) {
|
|
12052
|
+
const trigger = args.trigger ?? "signal";
|
|
12053
|
+
const target = await deps.io.resolveTarget(args.pr);
|
|
12054
|
+
const laterMerges = await deps.io.listLaterMerges(args.pr);
|
|
12055
|
+
const decision = await classifyRevert(
|
|
12056
|
+
{
|
|
12057
|
+
targetPr: args.pr,
|
|
12058
|
+
trigger,
|
|
12059
|
+
mergeSha: target.mergeSha,
|
|
12060
|
+
changedFiles: target.changedFiles,
|
|
12061
|
+
laterMerges
|
|
12062
|
+
},
|
|
12063
|
+
deps.io
|
|
12064
|
+
);
|
|
12065
|
+
const composed = await composeRevertPr(decision, target.title, {
|
|
12066
|
+
gh: deps.gh,
|
|
12067
|
+
...args.dryRun ? { dryRun: true } : {},
|
|
12068
|
+
...deps.print ? { print: deps.print } : {},
|
|
12069
|
+
...args.reason !== void 0 ? { reason: args.reason } : {}
|
|
12070
|
+
});
|
|
12071
|
+
const finalDecision = {
|
|
12072
|
+
...decision,
|
|
12073
|
+
action: composed.action,
|
|
12074
|
+
...composed.prUrl ? { prUrl: composed.prUrl } : {}
|
|
12075
|
+
};
|
|
12076
|
+
await appendRollbackEvent(
|
|
12077
|
+
{
|
|
12078
|
+
targetPr: finalDecision.targetPr,
|
|
12079
|
+
trigger: finalDecision.trigger,
|
|
12080
|
+
revertReady: finalDecision.revertReady,
|
|
12081
|
+
action: finalDecision.action,
|
|
12082
|
+
...finalDecision.prUrl ? { prUrl: finalDecision.prUrl } : {},
|
|
12083
|
+
// #4: record the human-provided reason on the breadcrumb (help text promises it).
|
|
12084
|
+
...args.reason !== void 0 ? { reason: args.reason } : {}
|
|
12085
|
+
},
|
|
12086
|
+
deps.root !== void 0 ? { root: deps.root } : {}
|
|
12087
|
+
);
|
|
12088
|
+
return finalDecision;
|
|
12089
|
+
}
|
|
12090
|
+
var gh2 = (args) => execFileSync10("gh", args, { encoding: "utf-8" }).toString();
|
|
12091
|
+
function referencesTargetPr(text, targetPr) {
|
|
12092
|
+
if (!text) return false;
|
|
12093
|
+
return new RegExp(`(?<!\\d)#${targetPr}(?!\\d)`).test(text);
|
|
12094
|
+
}
|
|
12095
|
+
function findOpenRevertPrNode(targetPr) {
|
|
12096
|
+
try {
|
|
12097
|
+
const raw = gh2([
|
|
12098
|
+
"pr",
|
|
12099
|
+
"list",
|
|
12100
|
+
"--state",
|
|
12101
|
+
"open",
|
|
12102
|
+
"--label",
|
|
12103
|
+
ROLLBACK_LABEL,
|
|
12104
|
+
"--search",
|
|
12105
|
+
`#${targetPr}`,
|
|
12106
|
+
"--json",
|
|
12107
|
+
"number,url,body,title"
|
|
12108
|
+
]);
|
|
12109
|
+
const list = JSON.parse(raw);
|
|
12110
|
+
const match = list.find(
|
|
12111
|
+
(p) => referencesTargetPr(p.body, targetPr) || referencesTargetPr(p.title, targetPr)
|
|
12112
|
+
);
|
|
12113
|
+
return match ? { number: match.number, url: match.url } : null;
|
|
12114
|
+
} catch {
|
|
12115
|
+
return null;
|
|
12116
|
+
}
|
|
12117
|
+
}
|
|
12118
|
+
function createGhSeam() {
|
|
12119
|
+
return {
|
|
12120
|
+
async findOpenRevertPr(targetPr) {
|
|
12121
|
+
return findOpenRevertPrNode(targetPr);
|
|
12122
|
+
},
|
|
12123
|
+
async openPr({ title, body, label }) {
|
|
12124
|
+
return execFileSync10(
|
|
12125
|
+
"gh",
|
|
12126
|
+
["pr", "create", "--title", title, "--body-file", "-", "--label", label],
|
|
12127
|
+
{ input: body, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
12128
|
+
).toString().trim();
|
|
12129
|
+
}
|
|
12130
|
+
};
|
|
12131
|
+
}
|
|
12132
|
+
function summarizeSweepReport(r) {
|
|
12133
|
+
if (!r.crossed) {
|
|
12134
|
+
return `rollback sweep: ${r.signal} (${r.window}) \u2014 no crossing`;
|
|
12135
|
+
}
|
|
12136
|
+
if (r.forwarded.length === 0) {
|
|
12137
|
+
return `rollback sweep: ${r.signal} (${r.window}) \u2014 crossed, no PRs in window`;
|
|
12138
|
+
}
|
|
12139
|
+
const parts = r.forwarded.map((f) => `#${f.pr} \u2192 ${f.action}${f.prUrl ? ` (${f.prUrl})` : ""}`);
|
|
12140
|
+
return `rollback sweep: ${r.signal} (${r.window}) \u2014 crossed; forwarded ${parts.join(", ")}`;
|
|
12141
|
+
}
|
|
12142
|
+
async function runRollbackSweepCommand(deps) {
|
|
12143
|
+
const cfg = deps.resolveConfig();
|
|
12144
|
+
if (!cfg.ok) {
|
|
12145
|
+
deps.warn(`rollback sweep: config error, breaker inactive: ${cfg.error.message}`);
|
|
12146
|
+
}
|
|
12147
|
+
const signals = cfg.ok ? cfg.value.rollback?.signals ?? {} : {};
|
|
12148
|
+
await deps.runSweep(signals, {
|
|
12149
|
+
readTimeline: deps.makeReader(deps.root),
|
|
12150
|
+
resolveMergedPrs: deps.makeResolver(),
|
|
12151
|
+
evaluate: deps.evaluate,
|
|
12152
|
+
report: (r) => deps.info(summarizeSweepReport(r))
|
|
12153
|
+
});
|
|
12154
|
+
}
|
|
12155
|
+
function createRollbackCommand() {
|
|
12156
|
+
const rollback = new Command90("rollback").description(
|
|
12157
|
+
"Post-ship revert circuit breaker (propose-only in v1)"
|
|
12158
|
+
);
|
|
12159
|
+
rollback.command("evaluate").description("Classify a merged PR for revert-readiness and, if ready, propose a revert PR").requiredOption("--pr <n>", "target merged PR number", (v) => {
|
|
12160
|
+
const n = Number.parseInt(v, 10);
|
|
12161
|
+
if (Number.isNaN(n)) throw new InvalidArgumentError("--pr must be a number");
|
|
12162
|
+
return n;
|
|
12163
|
+
}).addOption(
|
|
12164
|
+
new Option3("--trigger <trigger>", "what fired this evaluation").choices(["signal", "eval"]).default("signal")
|
|
12165
|
+
).option("--reason <str>", "human-readable reason recorded on the proposal").option("--dry-run", "print the revert PR body without opening a PR", false).action(async (opts) => {
|
|
12166
|
+
const reason = opts.reason;
|
|
12167
|
+
const dryRun = opts.dryRun;
|
|
12168
|
+
const decision = await runRollbackEvaluate(
|
|
12169
|
+
{
|
|
12170
|
+
pr: opts.pr,
|
|
12171
|
+
trigger: opts.trigger,
|
|
12172
|
+
...reason !== void 0 ? { reason } : {},
|
|
12173
|
+
...dryRun !== void 0 ? { dryRun } : {}
|
|
12174
|
+
},
|
|
12175
|
+
{ io: createNodeRollbackIO(), gh: createGhSeam() }
|
|
12176
|
+
);
|
|
12177
|
+
await linkRollbackEventToGraph({
|
|
12178
|
+
targetPr: decision.targetPr,
|
|
12179
|
+
trigger: decision.trigger,
|
|
12180
|
+
revertReady: decision.revertReady,
|
|
12181
|
+
action: decision.action,
|
|
12182
|
+
...decision.prUrl ? { prUrl: decision.prUrl } : {}
|
|
12183
|
+
});
|
|
12184
|
+
logger.info(JSON.stringify(decision, null, 2));
|
|
12185
|
+
});
|
|
12186
|
+
rollback.command("sweep").description(
|
|
12187
|
+
"Read the signal timeline and propose reverts for threshold crossings (signal arm)"
|
|
12188
|
+
).action(async () => {
|
|
12189
|
+
await runRollbackSweepCommand({
|
|
12190
|
+
resolveConfig,
|
|
12191
|
+
runSweep: runRollbackSweep,
|
|
12192
|
+
makeReader: createTimelineReader,
|
|
12193
|
+
makeResolver: createPrResolver,
|
|
12194
|
+
evaluate: (pr) => runRollbackEvaluate(
|
|
12195
|
+
{ pr, trigger: "signal" },
|
|
12196
|
+
{ io: createNodeRollbackIO(), gh: createGhSeam() }
|
|
12197
|
+
),
|
|
12198
|
+
root: process.cwd(),
|
|
12199
|
+
// #S4: per-signal summary on stdout so the sweep's work is auditable.
|
|
12200
|
+
info: (line) => logger.info(line),
|
|
12201
|
+
// #I2: config error → disarm warning on stderr, never silent.
|
|
12202
|
+
warn: (line) => logger.error(line)
|
|
12203
|
+
});
|
|
12204
|
+
});
|
|
12205
|
+
return rollback;
|
|
12206
|
+
}
|
|
12207
|
+
|
|
11785
12208
|
// src/commands/routing/index.ts
|
|
11786
|
-
import { Command as
|
|
12209
|
+
import { Command as Command96 } from "commander";
|
|
11787
12210
|
|
|
11788
12211
|
// src/commands/routing/config.ts
|
|
11789
|
-
import { Command as
|
|
12212
|
+
import { Command as Command91 } from "commander";
|
|
11790
12213
|
|
|
11791
12214
|
// src/commands/routing/http-client.ts
|
|
11792
12215
|
function orchestratorBase() {
|
|
@@ -11851,7 +12274,7 @@ function renderHuman(data) {
|
|
|
11851
12274
|
}
|
|
11852
12275
|
}
|
|
11853
12276
|
function createConfigCommand() {
|
|
11854
|
-
return new
|
|
12277
|
+
return new Command91("config").description("Print active routing config and resolved fallback chains").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
|
|
11855
12278
|
const r = await getJson("/api/v1/routing/config");
|
|
11856
12279
|
if (!r.ok) {
|
|
11857
12280
|
if (r.status === 0) {
|
|
@@ -11877,7 +12300,13 @@ function createConfigCommand() {
|
|
|
11877
12300
|
}
|
|
11878
12301
|
|
|
11879
12302
|
// src/commands/routing/trace.ts
|
|
11880
|
-
import { Command as
|
|
12303
|
+
import { Command as Command92 } from "commander";
|
|
12304
|
+
var COMPLEXITY_VALUES = ["trivial", "simple", "moderate", "complex"];
|
|
12305
|
+
var RISK_VALUES = ["low", "high"];
|
|
12306
|
+
function validateEnum(flag, value, allowed) {
|
|
12307
|
+
if (value === void 0 || allowed.includes(value)) return null;
|
|
12308
|
+
return `Invalid ${flag} "${value}". Allowed values: ${allowed.join(", ")}.`;
|
|
12309
|
+
}
|
|
11881
12310
|
function buildUseCase(opts) {
|
|
11882
12311
|
if (opts.skill) {
|
|
11883
12312
|
return opts.mode ? { kind: "skill", skillName: opts.skill, cognitiveMode: opts.mode } : { kind: "skill", skillName: opts.skill };
|
|
@@ -11896,41 +12325,60 @@ function renderHuman2(r) {
|
|
|
11896
12325
|
for (const step of r.decision.resolutionPath) {
|
|
11897
12326
|
console.log(` ${step.source}:${step.candidate} -> ${step.outcome}`);
|
|
11898
12327
|
}
|
|
12328
|
+
if (r.tierRequired !== void 0) {
|
|
12329
|
+
console.log(`Tier required: ${r.tierRequired}`);
|
|
12330
|
+
}
|
|
12331
|
+
if (r.estCostUsd !== void 0) {
|
|
12332
|
+
console.log(`Est cost: $${r.estCostUsd.toFixed(4)}`);
|
|
12333
|
+
}
|
|
11899
12334
|
}
|
|
11900
|
-
function
|
|
11901
|
-
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
11907
|
-
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
11918
|
-
|
|
11919
|
-
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
return;
|
|
11927
|
-
}
|
|
11928
|
-
if (r.body) renderHuman2(r.body);
|
|
12335
|
+
function traceErrorMessage(r) {
|
|
12336
|
+
if (r.status === 0) {
|
|
12337
|
+
return `Failed to reach orchestrator at ${orchestratorBase()}: ${r.error ?? "unknown error"}`;
|
|
12338
|
+
}
|
|
12339
|
+
if (r.status === 503) {
|
|
12340
|
+
return "Routing observability not available \u2014 orchestrator has no BackendRouter (legacy single-backend config)";
|
|
12341
|
+
}
|
|
12342
|
+
return `Trace failed (${r.status}): ${r.error ?? ""}`;
|
|
12343
|
+
}
|
|
12344
|
+
async function runTrace(opts) {
|
|
12345
|
+
const useCase = buildUseCase(opts);
|
|
12346
|
+
if (!useCase) {
|
|
12347
|
+
logger.error("Either --skill <name> or --mode <m> is required");
|
|
12348
|
+
process.exit(ExitCode.ERROR);
|
|
12349
|
+
return;
|
|
12350
|
+
}
|
|
12351
|
+
const enumError = validateEnum("--complexity", opts.complexity, COMPLEXITY_VALUES) ?? validateEnum("--risk", opts.risk, RISK_VALUES);
|
|
12352
|
+
if (enumError) {
|
|
12353
|
+
logger.error(enumError);
|
|
12354
|
+
process.exit(ExitCode.ERROR);
|
|
12355
|
+
return;
|
|
12356
|
+
}
|
|
12357
|
+
const r = await postJson("/api/v1/routing/trace", {
|
|
12358
|
+
useCase,
|
|
12359
|
+
...opts.complexity ? { complexity: opts.complexity } : {},
|
|
12360
|
+
...opts.risk ? { risk: opts.risk } : {}
|
|
11929
12361
|
});
|
|
12362
|
+
if (!r.ok) {
|
|
12363
|
+
logger.error(traceErrorMessage(r));
|
|
12364
|
+
process.exit(ExitCode.ERROR);
|
|
12365
|
+
return;
|
|
12366
|
+
}
|
|
12367
|
+
if (opts.json) {
|
|
12368
|
+
console.log(JSON.stringify(r.body, null, 2));
|
|
12369
|
+
return;
|
|
12370
|
+
}
|
|
12371
|
+
if (r.body) renderHuman2(r.body);
|
|
12372
|
+
}
|
|
12373
|
+
function createTraceCommand() {
|
|
12374
|
+
return new Command92("trace").description("Dry-run a routing decision without dispatching (Spec B F7)").option("--skill <name>", "Skill name to trace").option("--mode <m>", "Cognitive mode to trace (or attach to --skill per spec D12)").option(
|
|
12375
|
+
"--complexity <level>",
|
|
12376
|
+
"Synthetic complexity (trivial|simple|moderate|complex) \u2014 dry-run only"
|
|
12377
|
+
).option("--risk <band>", "Synthetic risk band (low|high) \u2014 dry-run only").option("--json", "Emit JSON to stdout instead of human-readable text").action(runTrace);
|
|
11930
12378
|
}
|
|
11931
12379
|
|
|
11932
12380
|
// src/commands/routing/decisions.ts
|
|
11933
|
-
import { Command as
|
|
12381
|
+
import { Command as Command93 } from "commander";
|
|
11934
12382
|
function summarizeUseCase(uc) {
|
|
11935
12383
|
switch (uc.kind) {
|
|
11936
12384
|
case "skill":
|
|
@@ -11978,7 +12426,7 @@ function buildQuery(opts) {
|
|
|
11978
12426
|
return q ? `?${q}` : "";
|
|
11979
12427
|
}
|
|
11980
12428
|
function createDecisionsCommand() {
|
|
11981
|
-
return new
|
|
12429
|
+
return new Command93("decisions").description("List recent routing decisions from the orchestrator ring buffer (Spec B F8)").option("--skill <name>", "Filter by useCase.skillName").option("--mode <m>", "Filter by useCase.cognitiveMode").option("--backend <name>", "Filter by chosen backendName").option("--last <N>", "Limit to the N most recent decisions").option("--json", "Emit JSON to stdout instead of human-readable text").action(
|
|
11982
12430
|
async (opts) => {
|
|
11983
12431
|
const query = buildQuery(opts);
|
|
11984
12432
|
const r = await getJson(`/api/v1/routing/decisions${query}`);
|
|
@@ -12006,22 +12454,162 @@ function createDecisionsCommand() {
|
|
|
12006
12454
|
);
|
|
12007
12455
|
}
|
|
12008
12456
|
|
|
12457
|
+
// src/commands/routing/telemetry.ts
|
|
12458
|
+
import { Command as Command94 } from "commander";
|
|
12459
|
+
var TIERS = ["fast", "standard", "strong"];
|
|
12460
|
+
function shortIso2(iso) {
|
|
12461
|
+
const tail = iso.split("T")[1] ?? iso;
|
|
12462
|
+
return tail.replace("Z", "");
|
|
12463
|
+
}
|
|
12464
|
+
function renderHuman4(data, tableLimit) {
|
|
12465
|
+
if (data.decisions.length === 0) {
|
|
12466
|
+
console.log("(no routing telemetry \u2014 AMR is off or no decisions recorded yet)");
|
|
12467
|
+
return;
|
|
12468
|
+
}
|
|
12469
|
+
const byTier = /* @__PURE__ */ new Map();
|
|
12470
|
+
for (const t of TIERS) byTier.set(t, { count: 0, cost: 0 });
|
|
12471
|
+
for (const d of data.decisions) {
|
|
12472
|
+
const bucket = byTier.get(d.tierRequired);
|
|
12473
|
+
if (bucket) {
|
|
12474
|
+
bucket.count += 1;
|
|
12475
|
+
bucket.cost += d.estCostUsd;
|
|
12476
|
+
}
|
|
12477
|
+
}
|
|
12478
|
+
console.log(`Decisions (retained ring): ${data.decisions.length}`);
|
|
12479
|
+
console.log(`Ring spend total: $${data.spentUsd.toFixed(4)}`);
|
|
12480
|
+
console.log("");
|
|
12481
|
+
console.log("TIER COUNT SHARE COST");
|
|
12482
|
+
for (const t of TIERS) {
|
|
12483
|
+
const b = byTier.get(t);
|
|
12484
|
+
const share = Math.round(b.count / data.decisions.length * 100);
|
|
12485
|
+
console.log(
|
|
12486
|
+
`${t.padEnd(9)} ${String(b.count).padStart(5)} ${String(share).padStart(4)}% $${b.cost.toFixed(4)}`
|
|
12487
|
+
);
|
|
12488
|
+
}
|
|
12489
|
+
console.log("");
|
|
12490
|
+
const rows = tableLimit !== void 0 ? data.decisions.slice(0, tableLimit) : data.decisions;
|
|
12491
|
+
console.log(
|
|
12492
|
+
`TIMESTAMP TIER BACKEND COST${tableLimit !== void 0 ? ` (latest ${rows.length} of ${data.decisions.length})` : ""}`
|
|
12493
|
+
);
|
|
12494
|
+
for (const d of rows) {
|
|
12495
|
+
const ts = shortIso2(d.decisionTs).padEnd(13);
|
|
12496
|
+
const tier = d.tierRequired.padEnd(9);
|
|
12497
|
+
const be = d.backend.padEnd(15);
|
|
12498
|
+
console.log(`${ts} ${tier} ${be} $${d.estCostUsd.toFixed(4)}`);
|
|
12499
|
+
}
|
|
12500
|
+
}
|
|
12501
|
+
function createTelemetryCommand() {
|
|
12502
|
+
return new Command94("telemetry").description("Routing telemetry: per-decision tier/backend/cost + tier distribution (AMR)").option("--last <N>", "Show only the N most recent decisions in the per-decision table").option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
|
|
12503
|
+
const r = await getJson("/api/v1/routing/telemetry");
|
|
12504
|
+
if (!r.ok) {
|
|
12505
|
+
if (r.status === 0) {
|
|
12506
|
+
logger.error(
|
|
12507
|
+
`Failed to reach orchestrator at ${orchestratorBase()}: ${r.error ?? "unknown error"}`
|
|
12508
|
+
);
|
|
12509
|
+
} else {
|
|
12510
|
+
logger.error(`Request failed (${r.status}): ${r.error ?? ""}`);
|
|
12511
|
+
}
|
|
12512
|
+
process.exit(ExitCode.ERROR);
|
|
12513
|
+
return;
|
|
12514
|
+
}
|
|
12515
|
+
const body = r.body ?? { decisions: [], spentUsd: 0 };
|
|
12516
|
+
if (opts.json) {
|
|
12517
|
+
console.log(JSON.stringify(body, null, 2));
|
|
12518
|
+
return;
|
|
12519
|
+
}
|
|
12520
|
+
const tableLimit = opts.last && Number.isFinite(Number(opts.last)) && Number(opts.last) > 0 ? Math.floor(Number(opts.last)) : void 0;
|
|
12521
|
+
renderHuman4(body, tableLimit);
|
|
12522
|
+
});
|
|
12523
|
+
}
|
|
12524
|
+
|
|
12525
|
+
// src/commands/routing/status.ts
|
|
12526
|
+
import { Command as Command95 } from "commander";
|
|
12527
|
+
function bar(pct, width = 24) {
|
|
12528
|
+
const clamped = Math.max(0, Math.min(100, pct));
|
|
12529
|
+
const filled = Math.round(clamped / 100 * width);
|
|
12530
|
+
return `[${"#".repeat(filled)}${"-".repeat(width - filled)}]`;
|
|
12531
|
+
}
|
|
12532
|
+
function renderHuman5(s) {
|
|
12533
|
+
if (!s.active) {
|
|
12534
|
+
console.log("Adaptive routing: OFF (no routing.policy configured \u2014 dispatch is unchanged)");
|
|
12535
|
+
return;
|
|
12536
|
+
}
|
|
12537
|
+
console.log("Adaptive routing: ON");
|
|
12538
|
+
if (s.budget) {
|
|
12539
|
+
const b = s.budget;
|
|
12540
|
+
const state = b.exhausted ? "EXHAUSTED (hard cap \u2014 forcing fast / surfacing to steward)" : b.degrading ? "DEGRADING (clamping tiers down)" : "ok";
|
|
12541
|
+
console.log("");
|
|
12542
|
+
console.log("Budget:");
|
|
12543
|
+
console.log(
|
|
12544
|
+
` $${b.spentUsd.toFixed(4)} / $${b.capUsd.toFixed(2)} ${bar(b.spentPct)} ${b.spentPct}%`
|
|
12545
|
+
);
|
|
12546
|
+
console.log(` degrade at ${b.degradeAtPct}% \u2192 ${state}`);
|
|
12547
|
+
} else {
|
|
12548
|
+
console.log("Budget: (none configured)");
|
|
12549
|
+
}
|
|
12550
|
+
console.log("");
|
|
12551
|
+
if (s.escalation.length === 0) {
|
|
12552
|
+
console.log("Escalation: (no units have climbed above the fast floor)");
|
|
12553
|
+
} else {
|
|
12554
|
+
console.log(`Escalation: ${s.escalation.length} unit(s) climbed`);
|
|
12555
|
+
console.log(" UNIT FLOOR");
|
|
12556
|
+
for (const u of s.escalation) {
|
|
12557
|
+
console.log(` ${u.coherenceUnit.padEnd(38)} ${u.floor}`);
|
|
12558
|
+
}
|
|
12559
|
+
}
|
|
12560
|
+
console.log("");
|
|
12561
|
+
console.log(
|
|
12562
|
+
`Allowlist: ${s.allowedProviders && s.allowedProviders.length > 0 ? s.allowedProviders.join(", ") : "(all providers allowed)"}`
|
|
12563
|
+
);
|
|
12564
|
+
}
|
|
12565
|
+
function createStatusCommand() {
|
|
12566
|
+
return new Command95("status").description(
|
|
12567
|
+
"Live routing status: budget spend-vs-cap, escalated units, provider allowlist (AMR)"
|
|
12568
|
+
).option("--json", "Emit JSON to stdout instead of human-readable text").action(async (opts) => {
|
|
12569
|
+
const r = await getJson("/api/v1/routing/status");
|
|
12570
|
+
if (!r.ok) {
|
|
12571
|
+
if (r.status === 0) {
|
|
12572
|
+
logger.error(
|
|
12573
|
+
`Failed to reach orchestrator at ${orchestratorBase()}: ${r.error ?? "unknown error"}`
|
|
12574
|
+
);
|
|
12575
|
+
} else {
|
|
12576
|
+
logger.error(`Request failed (${r.status}): ${r.error ?? ""}`);
|
|
12577
|
+
}
|
|
12578
|
+
process.exit(ExitCode.ERROR);
|
|
12579
|
+
return;
|
|
12580
|
+
}
|
|
12581
|
+
const body = r.body ?? {
|
|
12582
|
+
active: false,
|
|
12583
|
+
budget: null,
|
|
12584
|
+
escalation: [],
|
|
12585
|
+
allowedProviders: null
|
|
12586
|
+
};
|
|
12587
|
+
if (opts.json) {
|
|
12588
|
+
console.log(JSON.stringify(body, null, 2));
|
|
12589
|
+
return;
|
|
12590
|
+
}
|
|
12591
|
+
renderHuman5(body);
|
|
12592
|
+
});
|
|
12593
|
+
}
|
|
12594
|
+
|
|
12009
12595
|
// src/commands/routing/index.ts
|
|
12010
12596
|
function createRoutingCommand() {
|
|
12011
|
-
const cmd = new
|
|
12012
|
-
"Inspect routing config, trace decisions, and read
|
|
12597
|
+
const cmd = new Command96("routing").description(
|
|
12598
|
+
"Inspect routing config, trace decisions, and read AMR telemetry + status"
|
|
12013
12599
|
);
|
|
12014
12600
|
cmd.addCommand(createConfigCommand());
|
|
12015
12601
|
cmd.addCommand(createTraceCommand());
|
|
12016
12602
|
cmd.addCommand(createDecisionsCommand());
|
|
12603
|
+
cmd.addCommand(createTelemetryCommand());
|
|
12604
|
+
cmd.addCommand(createStatusCommand());
|
|
12017
12605
|
return cmd;
|
|
12018
12606
|
}
|
|
12019
12607
|
|
|
12020
12608
|
// src/commands/scan-config.ts
|
|
12021
12609
|
init_dist3();
|
|
12022
|
-
import { Command as
|
|
12610
|
+
import { Command as Command97 } from "commander";
|
|
12023
12611
|
import { existsSync as existsSync31, readFileSync as readFileSync22, writeFileSync as writeFileSync23 } from "fs";
|
|
12024
|
-
import { join as
|
|
12612
|
+
import { join as join51, relative as relative4 } from "path";
|
|
12025
12613
|
var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
|
|
12026
12614
|
function stripHighSeverityPatterns(content, injectionFindings) {
|
|
12027
12615
|
const highLines = /* @__PURE__ */ new Set();
|
|
@@ -12078,7 +12666,7 @@ async function runScanConfig(targetDir, options) {
|
|
|
12078
12666
|
const scanner = new SecurityScanner(parseSecurityConfig({}));
|
|
12079
12667
|
const results = [];
|
|
12080
12668
|
for (const configFile of CONFIG_FILES) {
|
|
12081
|
-
const result = scanSingleFile(
|
|
12669
|
+
const result = scanSingleFile(join51(targetDir, configFile), targetDir, scanner, options);
|
|
12082
12670
|
if (result) results.push(result);
|
|
12083
12671
|
}
|
|
12084
12672
|
return { exitCode: computeScanExitCode(results), results };
|
|
@@ -12108,7 +12696,7 @@ function formatTextOutput(result) {
|
|
|
12108
12696
|
}
|
|
12109
12697
|
}
|
|
12110
12698
|
function createScanConfigCommand() {
|
|
12111
|
-
const command = new
|
|
12699
|
+
const command = new Command97("scan-config").description(
|
|
12112
12700
|
"Scan CLAUDE.md, AGENTS.md, .gemini/settings.json, and skill.yaml for prompt injection patterns"
|
|
12113
12701
|
).option("--path <dir>", "Target directory to scan (default: cwd)").option("--fix", "Strip high-severity patterns from files in-place").action(async (opts, cmd) => {
|
|
12114
12702
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -12126,7 +12714,7 @@ function createScanConfigCommand() {
|
|
|
12126
12714
|
|
|
12127
12715
|
// src/commands/search.ts
|
|
12128
12716
|
init_dist();
|
|
12129
|
-
import { Command as
|
|
12717
|
+
import { Command as Command98 } from "commander";
|
|
12130
12718
|
function parseFileKinds(raw) {
|
|
12131
12719
|
if (!raw) return void 0;
|
|
12132
12720
|
const set = /* @__PURE__ */ new Set();
|
|
@@ -12147,7 +12735,7 @@ function fmtBytes(n) {
|
|
|
12147
12735
|
return n.toFixed(0);
|
|
12148
12736
|
}
|
|
12149
12737
|
function createSearchCommand() {
|
|
12150
|
-
return new
|
|
12738
|
+
return new Command98("search").description("Full-text search over archived + live session content.").argument(
|
|
12151
12739
|
"<query>",
|
|
12152
12740
|
"FTS5 query (bare words AND-joined; quotes/AND/OR/NOT/column: for advanced syntax)"
|
|
12153
12741
|
).option("-n, --limit <n>", "Max results", "20").option("--archived-only", "Skip live sessions, only search archived ones").option("--json", "Emit JSON to stdout instead of pretty text").option(
|
|
@@ -12207,9 +12795,9 @@ function createSearchCommand() {
|
|
|
12207
12795
|
}
|
|
12208
12796
|
|
|
12209
12797
|
// src/commands/security-craft.ts
|
|
12210
|
-
import { Command as
|
|
12798
|
+
import { Command as Command99 } from "commander";
|
|
12211
12799
|
function createSecurityCraftCommand() {
|
|
12212
|
-
return new
|
|
12800
|
+
return new Command99("security-craft").description(
|
|
12213
12801
|
"LLM-judgment critique of security posture (TS/JS source). Sixth non-design craft-pipeline ceiling skill (the final sub-project). AST-driven signal detection fires only on files with security-relevant constructs; conservative confidence defaults manage the FP risk inherent in judgment-based security."
|
|
12214
12802
|
).option("-f, --files <files...>", "Optional file scope (overrides discovery)").option("-p, --packages <names...>", "Restrict to specific packages under packages/").option("--max-files <n>", "Cap source-file count (default: 100)").option("--max-signals-per-file <n>", "Cap per-file signal critique (default: 10)").action(async (opts, cmd) => {
|
|
12215
12803
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -12275,7 +12863,7 @@ ${file}`);
|
|
|
12275
12863
|
}
|
|
12276
12864
|
|
|
12277
12865
|
// src/commands/setup.ts
|
|
12278
|
-
import { Command as
|
|
12866
|
+
import { Command as Command100 } from "commander";
|
|
12279
12867
|
import * as fs38 from "fs";
|
|
12280
12868
|
import * as os9 from "os";
|
|
12281
12869
|
import * as path62 from "path";
|
|
@@ -12314,10 +12902,10 @@ function prompt2(question) {
|
|
|
12314
12902
|
input: process.stdin,
|
|
12315
12903
|
output: process.stdout
|
|
12316
12904
|
});
|
|
12317
|
-
return new Promise((
|
|
12905
|
+
return new Promise((resolve49) => {
|
|
12318
12906
|
rl.question(question, (answer) => {
|
|
12319
12907
|
rl.close();
|
|
12320
|
-
|
|
12908
|
+
resolve49(answer.trim().toLowerCase());
|
|
12321
12909
|
});
|
|
12322
12910
|
});
|
|
12323
12911
|
}
|
|
@@ -12326,10 +12914,10 @@ function promptRaw(question) {
|
|
|
12326
12914
|
input: process.stdin,
|
|
12327
12915
|
output: process.stdout
|
|
12328
12916
|
});
|
|
12329
|
-
return new Promise((
|
|
12917
|
+
return new Promise((resolve49) => {
|
|
12330
12918
|
rl.question(question, (answer) => {
|
|
12331
12919
|
rl.close();
|
|
12332
|
-
|
|
12920
|
+
resolve49(answer.trim());
|
|
12333
12921
|
});
|
|
12334
12922
|
});
|
|
12335
12923
|
}
|
|
@@ -12620,7 +13208,7 @@ async function runSetup(cwd) {
|
|
|
12620
13208
|
return { steps, success };
|
|
12621
13209
|
}
|
|
12622
13210
|
function createSetupCommand() {
|
|
12623
|
-
return new
|
|
13211
|
+
return new Command100("setup").description("Configure harness environment: slash commands, MCP, and more").action(async () => {
|
|
12624
13212
|
const cwd = process.cwd();
|
|
12625
13213
|
console.log("");
|
|
12626
13214
|
console.log(` ${chalk16.bold("harness setup")}`);
|
|
@@ -12643,7 +13231,7 @@ function createSetupCommand() {
|
|
|
12643
13231
|
|
|
12644
13232
|
// src/commands/share.ts
|
|
12645
13233
|
init_dist3();
|
|
12646
|
-
import { Command as
|
|
13234
|
+
import { Command as Command101 } from "commander";
|
|
12647
13235
|
import * as fs39 from "fs";
|
|
12648
13236
|
import * as path63 from "path";
|
|
12649
13237
|
import { parse as parseYaml3 } from "yaml";
|
|
@@ -12702,16 +13290,16 @@ Create a constraints.yaml in your project root to define what to share.`
|
|
|
12702
13290
|
logger.success(`Bundle written to ${outputPath}`);
|
|
12703
13291
|
}
|
|
12704
13292
|
function createShareCommand() {
|
|
12705
|
-
return new
|
|
13293
|
+
return new Command101("share").description("Extract and publish a constraints bundle from constraints.yaml").argument("[path]", "Path to the project root", ".").option("-o, --output <dir>", "Output directory for the bundle", ".").action(async (projectPath, options) => {
|
|
12706
13294
|
await runShareAction(projectPath, options);
|
|
12707
13295
|
});
|
|
12708
13296
|
}
|
|
12709
13297
|
|
|
12710
13298
|
// src/commands/skill/index.ts
|
|
12711
|
-
import { Command as
|
|
13299
|
+
import { Command as Command109 } from "commander";
|
|
12712
13300
|
|
|
12713
13301
|
// src/commands/skill/list.ts
|
|
12714
|
-
import { Command as
|
|
13302
|
+
import { Command as Command102 } from "commander";
|
|
12715
13303
|
import * as fs40 from "fs";
|
|
12716
13304
|
import * as path64 from "path";
|
|
12717
13305
|
import { parse } from "yaml";
|
|
@@ -12814,7 +13402,7 @@ function printSkillsVerbose(skills) {
|
|
|
12814
13402
|
for (const s of skills) printSkillEntry(s);
|
|
12815
13403
|
}
|
|
12816
13404
|
function createListCommand3() {
|
|
12817
|
-
return new
|
|
13405
|
+
return new Command102("list").description("List available skills").option("--installed", "Show only community-installed skills").option("--local", "Show only project-local skills").option("--all", "Show all skills (default)").action(async (opts, cmd) => {
|
|
12818
13406
|
const globalOpts = cmd.optsWithGlobals();
|
|
12819
13407
|
const skills = collectSkills({ filter: resolveFilter(opts) });
|
|
12820
13408
|
if (globalOpts.json) {
|
|
@@ -12829,13 +13417,13 @@ function createListCommand3() {
|
|
|
12829
13417
|
}
|
|
12830
13418
|
|
|
12831
13419
|
// src/commands/skill/run.ts
|
|
12832
|
-
import { Command as
|
|
13420
|
+
import { Command as Command103 } from "commander";
|
|
12833
13421
|
import * as fs41 from "fs";
|
|
12834
13422
|
import * as path65 from "path";
|
|
12835
13423
|
import { parse as parse2 } from "yaml";
|
|
12836
13424
|
|
|
12837
13425
|
// src/skill/complexity.ts
|
|
12838
|
-
import { execFileSync as
|
|
13426
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
12839
13427
|
function evaluateSignals(signals) {
|
|
12840
13428
|
if (signals.fileCount >= 3) return "thorough";
|
|
12841
13429
|
if (signals.newDir) return "thorough";
|
|
@@ -12847,17 +13435,17 @@ function evaluateSignals(signals) {
|
|
|
12847
13435
|
}
|
|
12848
13436
|
function detectComplexity(projectPath) {
|
|
12849
13437
|
try {
|
|
12850
|
-
const base =
|
|
13438
|
+
const base = execFileSync11("git", ["merge-base", "HEAD", "main"], {
|
|
12851
13439
|
cwd: projectPath,
|
|
12852
13440
|
encoding: "utf-8",
|
|
12853
13441
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12854
13442
|
}).trim();
|
|
12855
|
-
const diffFiles =
|
|
13443
|
+
const diffFiles = execFileSync11("git", ["diff", "--name-only", base], {
|
|
12856
13444
|
cwd: projectPath,
|
|
12857
13445
|
encoding: "utf-8",
|
|
12858
13446
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12859
13447
|
}).trim().split("\n").filter(Boolean);
|
|
12860
|
-
const diffStat =
|
|
13448
|
+
const diffStat = execFileSync11("git", ["diff", "--stat", base], {
|
|
12861
13449
|
cwd: projectPath,
|
|
12862
13450
|
encoding: "utf-8",
|
|
12863
13451
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -12977,7 +13565,7 @@ function resolvePhaseState(metadata, projectPath, phase) {
|
|
|
12977
13565
|
}
|
|
12978
13566
|
async function appendProjectState(content, metadata, projectPath, hasPathOpt) {
|
|
12979
13567
|
if (!metadata?.state.persistent || !hasPathOpt) return content;
|
|
12980
|
-
const { readHarnessState: readHarnessState2, isEmptyHarnessState } = await import("./state-events-
|
|
13568
|
+
const { readHarnessState: readHarnessState2, isEmptyHarnessState } = await import("./state-events-PTWAEGJ2.js");
|
|
12981
13569
|
const stateResult = await readHarnessState2(projectPath);
|
|
12982
13570
|
if (!stateResult.ok || isEmptyHarnessState(stateResult.value)) return content;
|
|
12983
13571
|
const stateContent = JSON.stringify(stateResult.value, null, 2);
|
|
@@ -13043,14 +13631,14 @@ async function runSkill(name, opts) {
|
|
|
13043
13631
|
process.exit(ExitCode.SUCCESS);
|
|
13044
13632
|
}
|
|
13045
13633
|
function createRunCommand3() {
|
|
13046
|
-
return new
|
|
13634
|
+
return new Command103("run").description("Run a skill (outputs SKILL.md content with context preamble)").argument("<name>", "Skill name (e.g., harness-tdd)").option("--path <path>", "Project root path for context injection").option("--complexity <level>", "Rigor level: fast, standard, thorough", "standard").option("--phase <name>", "Start at a specific phase (for re-entry)").option("--party", "Enable multi-perspective evaluation").option(
|
|
13047
13635
|
"--backend <name>",
|
|
13048
13636
|
"Spec B: one-shot routing override forwarded to the orchestrator as HARNESS_BACKEND_OVERRIDE"
|
|
13049
13637
|
).action(async (name, opts) => runSkill(name, opts));
|
|
13050
13638
|
}
|
|
13051
13639
|
|
|
13052
13640
|
// src/commands/skill/validate.ts
|
|
13053
|
-
import { Command as
|
|
13641
|
+
import { Command as Command104 } from "commander";
|
|
13054
13642
|
import * as fs42 from "fs";
|
|
13055
13643
|
import * as path66 from "path";
|
|
13056
13644
|
import { parse as parse3 } from "yaml";
|
|
@@ -13114,7 +13702,7 @@ function validateSkillEntry(name, skillsDir, errors) {
|
|
|
13114
13702
|
}
|
|
13115
13703
|
}
|
|
13116
13704
|
function createValidateCommand2() {
|
|
13117
|
-
return new
|
|
13705
|
+
return new Command104("validate").description("Validate all skill.yaml files and SKILL.md structure").action(async (_opts, cmd) => {
|
|
13118
13706
|
const globalOpts = cmd.optsWithGlobals();
|
|
13119
13707
|
const skillsDir = resolveSkillsDir();
|
|
13120
13708
|
if (!fs42.existsSync(skillsDir)) {
|
|
@@ -13144,7 +13732,7 @@ function createValidateCommand2() {
|
|
|
13144
13732
|
}
|
|
13145
13733
|
|
|
13146
13734
|
// src/commands/skill/info.ts
|
|
13147
|
-
import { Command as
|
|
13735
|
+
import { Command as Command105 } from "commander";
|
|
13148
13736
|
import * as fs43 from "fs";
|
|
13149
13737
|
import * as path67 from "path";
|
|
13150
13738
|
import { parse as parse4 } from "yaml";
|
|
@@ -13189,7 +13777,7 @@ function printSkillInfo(skill) {
|
|
|
13189
13777
|
console.log(`Persistent: ${skill.state.persistent}`);
|
|
13190
13778
|
}
|
|
13191
13779
|
function createInfoCommand() {
|
|
13192
|
-
return new
|
|
13780
|
+
return new Command105("info").description("Show metadata for a skill").argument("<name>", "Skill name (e.g., harness-tdd)").action(async (name, _opts, cmd) => {
|
|
13193
13781
|
const globalOpts = cmd.optsWithGlobals();
|
|
13194
13782
|
const loaded = loadSkillMetadata2(name);
|
|
13195
13783
|
if (!loaded.ok) {
|
|
@@ -13206,7 +13794,7 @@ function createInfoCommand() {
|
|
|
13206
13794
|
}
|
|
13207
13795
|
|
|
13208
13796
|
// src/commands/skill/search.ts
|
|
13209
|
-
import { Command as
|
|
13797
|
+
import { Command as Command106 } from "commander";
|
|
13210
13798
|
async function runSearch(query, opts) {
|
|
13211
13799
|
const results = await searchNpmRegistry(query, opts.registry);
|
|
13212
13800
|
return results.filter((r) => {
|
|
@@ -13251,13 +13839,13 @@ async function runSearchAction(query, opts, globalOpts) {
|
|
|
13251
13839
|
}
|
|
13252
13840
|
}
|
|
13253
13841
|
function createSearchCommand2() {
|
|
13254
|
-
return new
|
|
13842
|
+
return new Command106("search").description("Search for community skills on the @harness-skills registry").argument("<query>", "Search query").option("--platform <platform>", "Filter by platform (e.g., claude-code)").option("--trigger <trigger>", "Filter by trigger type (e.g., manual, automatic)").option("--registry <url>", "Use a custom npm registry URL").action(async (query, opts, cmd) => {
|
|
13255
13843
|
await runSearchAction(query, opts, cmd.optsWithGlobals());
|
|
13256
13844
|
});
|
|
13257
13845
|
}
|
|
13258
13846
|
|
|
13259
13847
|
// src/commands/skill/create.ts
|
|
13260
|
-
import { Command as
|
|
13848
|
+
import { Command as Command107 } from "commander";
|
|
13261
13849
|
import * as path68 from "path";
|
|
13262
13850
|
import * as fs44 from "fs";
|
|
13263
13851
|
import YAML from "yaml";
|
|
@@ -13377,7 +13965,7 @@ Next steps:`);
|
|
|
13377
13965
|
logger.info(` 3. Run: harness skills publish`);
|
|
13378
13966
|
}
|
|
13379
13967
|
function createCreateCommand() {
|
|
13380
|
-
return new
|
|
13968
|
+
return new Command107("create").description("Scaffold a new community skill").argument("<name>", "Skill name (kebab-case)").option("--description <desc>", "Skill description").option("--type <type>", "Skill type: rigid or flexible", "flexible").option("--platforms <platforms>", "Comma-separated platforms (default: claude-code)").option("--triggers <triggers>", "Comma-separated triggers (default: manual)").option("--output-dir <dir>", "Output directory (default: agents/skills/claude-code/)").action(async (name, opts, cmd) => {
|
|
13381
13969
|
const globalOpts = cmd.optsWithGlobals();
|
|
13382
13970
|
try {
|
|
13383
13971
|
const result = runCreate(name, {
|
|
@@ -13400,10 +13988,10 @@ function createCreateCommand() {
|
|
|
13400
13988
|
}
|
|
13401
13989
|
|
|
13402
13990
|
// src/commands/skill/publish.ts
|
|
13403
|
-
import { Command as
|
|
13991
|
+
import { Command as Command108 } from "commander";
|
|
13404
13992
|
import * as fs46 from "fs";
|
|
13405
13993
|
import * as path70 from "path";
|
|
13406
|
-
import { execFileSync as
|
|
13994
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
13407
13995
|
|
|
13408
13996
|
// src/registry/validator.ts
|
|
13409
13997
|
import * as fs45 from "fs";
|
|
@@ -13557,7 +14145,7 @@ ${skillMdContent}`;
|
|
|
13557
14145
|
if (opts.registry) {
|
|
13558
14146
|
publishArgs.push("--registry", opts.registry);
|
|
13559
14147
|
}
|
|
13560
|
-
|
|
14148
|
+
execFileSync12("npm", publishArgs, {
|
|
13561
14149
|
cwd: skillDir,
|
|
13562
14150
|
stdio: "pipe",
|
|
13563
14151
|
timeout: 6e4
|
|
@@ -13569,7 +14157,7 @@ ${skillMdContent}`;
|
|
|
13569
14157
|
};
|
|
13570
14158
|
}
|
|
13571
14159
|
function createPublishCommand() {
|
|
13572
|
-
return new
|
|
14160
|
+
return new Command108("publish").description("Validate and publish a skill to @harness-skills on npm").option("--dry-run", "Run validation and generate package.json without publishing").option("--dir <dir>", "Skill directory (default: current directory)").option("--registry <url>", "Use a custom npm registry URL").action(async (opts, cmd) => {
|
|
13573
14161
|
const globalOpts = cmd.optsWithGlobals();
|
|
13574
14162
|
const skillDir = opts.dir || process.cwd();
|
|
13575
14163
|
try {
|
|
@@ -13594,7 +14182,7 @@ function createPublishCommand() {
|
|
|
13594
14182
|
|
|
13595
14183
|
// src/commands/skill/index.ts
|
|
13596
14184
|
function createSkillCommand() {
|
|
13597
|
-
const command = new
|
|
14185
|
+
const command = new Command109("skill").description("Skill management commands");
|
|
13598
14186
|
command.addCommand(createListCommand3());
|
|
13599
14187
|
command.addCommand(createRunCommand3());
|
|
13600
14188
|
command.addCommand(createValidateCommand2());
|
|
@@ -13607,7 +14195,7 @@ function createSkillCommand() {
|
|
|
13607
14195
|
|
|
13608
14196
|
// src/commands/snapshot.ts
|
|
13609
14197
|
init_dist3();
|
|
13610
|
-
import { Command as
|
|
14198
|
+
import { Command as Command110 } from "commander";
|
|
13611
14199
|
import { execSync as execSync5 } from "child_process";
|
|
13612
14200
|
import chalk17 from "chalk";
|
|
13613
14201
|
function getCommitHash3(cwd) {
|
|
@@ -13789,7 +14377,7 @@ function registerListCommand2(parent) {
|
|
|
13789
14377
|
});
|
|
13790
14378
|
}
|
|
13791
14379
|
function createSnapshotCommand() {
|
|
13792
|
-
const command = new
|
|
14380
|
+
const command = new Command110("snapshot").description("Architecture timeline snapshot commands");
|
|
13793
14381
|
registerCaptureCommand(command);
|
|
13794
14382
|
registerTrendsCommand(command);
|
|
13795
14383
|
registerListCommand2(command);
|
|
@@ -13797,9 +14385,9 @@ function createSnapshotCommand() {
|
|
|
13797
14385
|
}
|
|
13798
14386
|
|
|
13799
14387
|
// src/commands/spec-craft.ts
|
|
13800
|
-
import { Command as
|
|
14388
|
+
import { Command as Command111 } from "commander";
|
|
13801
14389
|
function createSpecCraftCommand() {
|
|
13802
|
-
return new
|
|
14390
|
+
return new Command111("spec-craft").description(
|
|
13803
14391
|
"LLM-judgment critique of spec quality (proposals + ADRs). Second craft-pipeline ceiling skill; 7 seed rubrics from the spec-quality canon. Per-section critique."
|
|
13804
14392
|
).option("-f, --files <files...>", "Optional spec file/glob scope").option("-k, --kinds <kinds...>", "Restrict to proposal / adr (default: both)").option("-s, --sections <names...>", "Restrict to specific canonical section names").option("--max-files <n>", "Cap doc count (default: 50)").option("--max-sections-per-file <n>", "Cap per-doc section critique (default: 10)").action(async (opts, cmd) => {
|
|
13805
14393
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -13867,7 +14455,7 @@ ${file}`);
|
|
|
13867
14455
|
|
|
13868
14456
|
// src/commands/stale-constraints.ts
|
|
13869
14457
|
init_dist3();
|
|
13870
|
-
import { Command as
|
|
14458
|
+
import { Command as Command112 } from "commander";
|
|
13871
14459
|
import chalk18 from "chalk";
|
|
13872
14460
|
var CATEGORIES = [
|
|
13873
14461
|
"circular-deps",
|
|
@@ -13954,7 +14542,7 @@ async function runStaleConstraintsCommand(options) {
|
|
|
13954
14542
|
);
|
|
13955
14543
|
}
|
|
13956
14544
|
function createStaleConstraintsCommand() {
|
|
13957
|
-
return new
|
|
14545
|
+
return new Command112("stale-constraints").description(
|
|
13958
14546
|
"Detect architectural constraints not violated within a window (candidates for removal)"
|
|
13959
14547
|
).option(
|
|
13960
14548
|
"--window <days>",
|
|
@@ -13972,10 +14560,10 @@ function createStaleConstraintsCommand() {
|
|
|
13972
14560
|
}
|
|
13973
14561
|
|
|
13974
14562
|
// src/commands/state/index.ts
|
|
13975
|
-
import { Command as
|
|
14563
|
+
import { Command as Command117 } from "commander";
|
|
13976
14564
|
|
|
13977
14565
|
// src/commands/state/show.ts
|
|
13978
|
-
import { Command as
|
|
14566
|
+
import { Command as Command113 } from "commander";
|
|
13979
14567
|
import * as path71 from "path";
|
|
13980
14568
|
function printStateText(state, stream) {
|
|
13981
14569
|
if (stream) console.log(`Stream: ${stream}`);
|
|
@@ -14000,7 +14588,7 @@ function printStateProgress(progress) {
|
|
|
14000
14588
|
}
|
|
14001
14589
|
}
|
|
14002
14590
|
function createShowCommand() {
|
|
14003
|
-
return new
|
|
14591
|
+
return new Command113("show").description("Show current project state").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (opts, cmd) => {
|
|
14004
14592
|
const globalOpts = cmd.optsWithGlobals();
|
|
14005
14593
|
const result = await readHarnessState(path71.resolve(opts.path), { stream: opts.stream });
|
|
14006
14594
|
if (!result.ok) {
|
|
@@ -14018,13 +14606,13 @@ function createShowCommand() {
|
|
|
14018
14606
|
|
|
14019
14607
|
// src/commands/state/reset.ts
|
|
14020
14608
|
init_dist3();
|
|
14021
|
-
import { Command as
|
|
14609
|
+
import { Command as Command114 } from "commander";
|
|
14022
14610
|
import * as path72 from "path";
|
|
14023
14611
|
import * as readline3 from "readline";
|
|
14024
14612
|
async function confirmReset() {
|
|
14025
14613
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
14026
|
-
const answer = await new Promise((
|
|
14027
|
-
rl.question("Reset project state? This cannot be undone. [y/N] ",
|
|
14614
|
+
const answer = await new Promise((resolve49) => {
|
|
14615
|
+
rl.question("Reset project state? This cannot be undone. [y/N] ", resolve49);
|
|
14028
14616
|
});
|
|
14029
14617
|
rl.close();
|
|
14030
14618
|
return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
@@ -14044,15 +14632,15 @@ async function runReset(opts) {
|
|
|
14044
14632
|
process.exit(ExitCode.SUCCESS);
|
|
14045
14633
|
}
|
|
14046
14634
|
function createResetCommand() {
|
|
14047
|
-
return new
|
|
14635
|
+
return new Command114("reset").description("Reset project state (truncates the event log to a fresh default)").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").option("--yes", "Skip confirmation prompt").action(async (opts) => runReset(opts));
|
|
14048
14636
|
}
|
|
14049
14637
|
|
|
14050
14638
|
// src/commands/state/learn.ts
|
|
14051
14639
|
init_dist3();
|
|
14052
|
-
import { Command as
|
|
14640
|
+
import { Command as Command115 } from "commander";
|
|
14053
14641
|
import * as path73 from "path";
|
|
14054
14642
|
function createLearnCommand() {
|
|
14055
|
-
return new
|
|
14643
|
+
return new Command115("learn").description("Append a learning to .harness/learnings.md").argument("<message>", "The learning to record").option("--path <path>", "Project root path", ".").option("--stream <name>", "Target a specific stream").action(async (message, opts, _cmd) => {
|
|
14056
14644
|
const projectPath = path73.resolve(opts.path);
|
|
14057
14645
|
const result = await appendLearning(projectPath, message, void 0, void 0, opts.stream);
|
|
14058
14646
|
if (!result.ok) {
|
|
@@ -14067,7 +14655,7 @@ function createLearnCommand() {
|
|
|
14067
14655
|
|
|
14068
14656
|
// src/commands/state/streams.ts
|
|
14069
14657
|
init_dist3();
|
|
14070
|
-
import { Command as
|
|
14658
|
+
import { Command as Command116 } from "commander";
|
|
14071
14659
|
import * as path74 from "path";
|
|
14072
14660
|
async function runListStreams(opts, globalOpts) {
|
|
14073
14661
|
const projectPath = path74.resolve(opts.path);
|
|
@@ -14118,7 +14706,7 @@ async function runActivateStream(name, opts) {
|
|
|
14118
14706
|
process.exit(ExitCode.SUCCESS);
|
|
14119
14707
|
}
|
|
14120
14708
|
function createStreamsCommand() {
|
|
14121
|
-
const command = new
|
|
14709
|
+
const command = new Command116("streams").description("Manage state streams");
|
|
14122
14710
|
command.command("list").description("List all known streams").option("--path <path>", "Project root path", ".").action(async (opts, cmd) => runListStreams(opts, cmd.optsWithGlobals()));
|
|
14123
14711
|
command.command("create <name>").description("Create a new stream").option("--path <path>", "Project root path", ".").option("--branch <branch>", "Associate with a git branch").action(async (name, opts) => runCreateStream(name, opts));
|
|
14124
14712
|
command.command("archive <name>").description("Archive a stream").option("--path <path>", "Project root path", ".").action(async (name, opts) => runArchiveStream(name, opts));
|
|
@@ -14128,7 +14716,7 @@ function createStreamsCommand() {
|
|
|
14128
14716
|
|
|
14129
14717
|
// src/commands/state/index.ts
|
|
14130
14718
|
function createStateCommand() {
|
|
14131
|
-
const command = new
|
|
14719
|
+
const command = new Command117("state").description("Project state management commands");
|
|
14132
14720
|
command.addCommand(createShowCommand());
|
|
14133
14721
|
command.addCommand(createResetCommand());
|
|
14134
14722
|
command.addCommand(createLearnCommand());
|
|
@@ -14139,7 +14727,7 @@ function createStateCommand() {
|
|
|
14139
14727
|
// src/commands/sync-analyses.ts
|
|
14140
14728
|
import * as fs47 from "fs";
|
|
14141
14729
|
import * as path75 from "path";
|
|
14142
|
-
import { Command as
|
|
14730
|
+
import { Command as Command118 } from "commander";
|
|
14143
14731
|
init_dist3();
|
|
14144
14732
|
function isValidRecord(record) {
|
|
14145
14733
|
return typeof record.issueId === "string" && !!record.issueId && typeof record.identifier === "string" && !!record.identifier && typeof record.analyzedAt === "string" && !/[/\\]/.test(record.issueId);
|
|
@@ -14264,7 +14852,7 @@ async function runSyncAnalyses(opts) {
|
|
|
14264
14852
|
return;
|
|
14265
14853
|
}
|
|
14266
14854
|
const { AnalysisArchive, loadPublishedIndex: loadPublishedIndex2, savePublishedIndex: savePublishedIndex2 } = await import("@harness-engineering/orchestrator");
|
|
14267
|
-
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-
|
|
14855
|
+
const { GitHubIssuesSyncAdapter: GitHubIssuesSyncAdapter2 } = await import("./dist-4CZLCE33.js");
|
|
14268
14856
|
const adapter = new GitHubIssuesSyncAdapter2({ token, config: trackerConfig });
|
|
14269
14857
|
const archive = new AnalysisArchive(path75.join(projectPath, ".harness", "analyses"));
|
|
14270
14858
|
const publishedIndex = loadPublishedIndex2(projectPath);
|
|
@@ -14286,7 +14874,7 @@ async function runSyncAnalyses(opts) {
|
|
|
14286
14874
|
}
|
|
14287
14875
|
}
|
|
14288
14876
|
function createSyncAnalysesCommand() {
|
|
14289
|
-
const command = new
|
|
14877
|
+
const command = new Command118("sync-analyses").description(
|
|
14290
14878
|
"Pull published intelligence analyses from the external issue tracker into the local .harness/analyses/ directory"
|
|
14291
14879
|
).option("-d, --dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
|
|
14292
14880
|
try {
|
|
@@ -14300,7 +14888,7 @@ function createSyncAnalysesCommand() {
|
|
|
14300
14888
|
}
|
|
14301
14889
|
|
|
14302
14890
|
// src/commands/sync-main.ts
|
|
14303
|
-
import { Command as
|
|
14891
|
+
import { Command as Command119 } from "commander";
|
|
14304
14892
|
import * as path76 from "path";
|
|
14305
14893
|
import {
|
|
14306
14894
|
syncMain as defaultSyncMain
|
|
@@ -14331,7 +14919,7 @@ function formatHuman2(r) {
|
|
|
14331
14919
|
}
|
|
14332
14920
|
}
|
|
14333
14921
|
function createSyncMainCommand() {
|
|
14334
|
-
return new
|
|
14922
|
+
return new Command119("sync-main").description("Fast-forward the local default branch from origin (no-op on conflict)").option("--json", "Emit a SyncMainResult JSON object", false).option("--path <path>", "Project root path", ".").action(async (opts) => {
|
|
14335
14923
|
const cwd = path76.resolve(opts.path ?? ".");
|
|
14336
14924
|
const exitCode = await runSyncMain({ cwd, json: Boolean(opts.json) });
|
|
14337
14925
|
process.exit(exitCode);
|
|
@@ -14340,7 +14928,7 @@ function createSyncMainCommand() {
|
|
|
14340
14928
|
|
|
14341
14929
|
// src/commands/taint.ts
|
|
14342
14930
|
init_dist3();
|
|
14343
|
-
import { Command as
|
|
14931
|
+
import { Command as Command120 } from "commander";
|
|
14344
14932
|
function getProjectRoot() {
|
|
14345
14933
|
return process.cwd();
|
|
14346
14934
|
}
|
|
@@ -14412,18 +15000,18 @@ function registerStatusCommand(taint) {
|
|
|
14412
15000
|
});
|
|
14413
15001
|
}
|
|
14414
15002
|
function createTaintCommand() {
|
|
14415
|
-
const taint = new
|
|
15003
|
+
const taint = new Command120("taint").description("Manage sentinel session taint state");
|
|
14416
15004
|
registerClearCommand(taint);
|
|
14417
15005
|
registerStatusCommand(taint);
|
|
14418
15006
|
return taint;
|
|
14419
15007
|
}
|
|
14420
15008
|
|
|
14421
15009
|
// src/commands/telemetry/index.ts
|
|
14422
|
-
import { Command as
|
|
15010
|
+
import { Command as Command124 } from "commander";
|
|
14423
15011
|
|
|
14424
15012
|
// src/commands/telemetry/identify.ts
|
|
14425
15013
|
init_dist3();
|
|
14426
|
-
import { Command as
|
|
15014
|
+
import { Command as Command121 } from "commander";
|
|
14427
15015
|
import * as fs48 from "fs";
|
|
14428
15016
|
import * as path77 from "path";
|
|
14429
15017
|
function telemetryFilePath(cwd) {
|
|
@@ -14447,7 +15035,7 @@ function printIdentity(identity) {
|
|
|
14447
15035
|
}
|
|
14448
15036
|
}
|
|
14449
15037
|
function createIdentifyCommand() {
|
|
14450
|
-
const cmd = new
|
|
15038
|
+
const cmd = new Command121("identify").description("Set or clear telemetry identity fields in .harness/telemetry.json").option("--project <name>", "Project name").option("--team <name>", "Team name").option("--alias <name>", "User alias").option("--clear", "Remove all identity fields").action((opts) => {
|
|
14451
15039
|
const cwd = process.cwd();
|
|
14452
15040
|
if (opts.clear) {
|
|
14453
15041
|
writeTelemetryFile(cwd, { identity: {} });
|
|
@@ -14472,7 +15060,7 @@ function createIdentifyCommand() {
|
|
|
14472
15060
|
|
|
14473
15061
|
// src/commands/telemetry/status.ts
|
|
14474
15062
|
init_dist3();
|
|
14475
|
-
import { Command as
|
|
15063
|
+
import { Command as Command122 } from "commander";
|
|
14476
15064
|
function gatherEnvOverrides() {
|
|
14477
15065
|
const overrides = {};
|
|
14478
15066
|
if (process.env.DO_NOT_TRACK) overrides.DO_NOT_TRACK = process.env.DO_NOT_TRACK;
|
|
@@ -14513,8 +15101,8 @@ function printHumanStatus(result) {
|
|
|
14513
15101
|
printIdentity2(result.identity);
|
|
14514
15102
|
printEnvOverrides(result.envOverrides);
|
|
14515
15103
|
}
|
|
14516
|
-
function
|
|
14517
|
-
const cmd = new
|
|
15104
|
+
function createStatusCommand2() {
|
|
15105
|
+
const cmd = new Command122("status").description("Show current telemetry consent state, install ID, and identity").option("--json", "Output as JSON").action((opts) => {
|
|
14518
15106
|
const cwd = process.cwd();
|
|
14519
15107
|
const envOverrides = gatherEnvOverrides();
|
|
14520
15108
|
const consent = resolveConsent(cwd, void 0);
|
|
@@ -14547,20 +15135,20 @@ function createStatusCommand() {
|
|
|
14547
15135
|
|
|
14548
15136
|
// src/commands/telemetry/test.ts
|
|
14549
15137
|
init_dist3();
|
|
14550
|
-
import { Command as
|
|
15138
|
+
import { Command as Command123 } from "commander";
|
|
14551
15139
|
|
|
14552
15140
|
// src/bin/command-telemetry.ts
|
|
14553
|
-
import { existsSync as existsSync44, readFileSync as readFileSync32, mkdirSync as
|
|
14554
|
-
import { join as
|
|
15141
|
+
import { existsSync as existsSync44, readFileSync as readFileSync32, mkdirSync as mkdirSync24, appendFileSync as appendFileSync2, writeFileSync as writeFileSync29 } from "fs";
|
|
15142
|
+
import { join as join65, parse as parsePath, resolve as resolve46 } from "path";
|
|
14555
15143
|
import { spawn as spawn2 } from "child_process";
|
|
14556
15144
|
var POSTHOG_API_KEY = "phc_wNTdCMcfJXZPgdNeDociZW6vwoGGo4nb7vqEfWThFfsG";
|
|
14557
15145
|
var EXCLUDED_COMMANDS = /* @__PURE__ */ new Set(["help", "completion"]);
|
|
14558
15146
|
function findProjectRoot(cwd) {
|
|
14559
|
-
let dir =
|
|
15147
|
+
let dir = resolve46(cwd);
|
|
14560
15148
|
const { root } = parsePath(dir);
|
|
14561
15149
|
while (dir !== root) {
|
|
14562
|
-
if (existsSync44(
|
|
14563
|
-
dir =
|
|
15150
|
+
if (existsSync44(join65(dir, "harness.config.json"))) return dir;
|
|
15151
|
+
dir = resolve46(dir, "..");
|
|
14564
15152
|
}
|
|
14565
15153
|
return cwd;
|
|
14566
15154
|
}
|
|
@@ -14597,8 +15185,8 @@ function resolveCommandName(cmd) {
|
|
|
14597
15185
|
}
|
|
14598
15186
|
function writeCommandRecordSync(cwd, command, duration, outcome) {
|
|
14599
15187
|
try {
|
|
14600
|
-
const metricsDir =
|
|
14601
|
-
|
|
15188
|
+
const metricsDir = join65(cwd, ".harness", "metrics");
|
|
15189
|
+
mkdirSync24(metricsDir, { recursive: true });
|
|
14602
15190
|
const record = {
|
|
14603
15191
|
skill: command,
|
|
14604
15192
|
session: `cli-${Date.now()}`,
|
|
@@ -14607,13 +15195,13 @@ function writeCommandRecordSync(cwd, command, duration, outcome) {
|
|
|
14607
15195
|
outcome,
|
|
14608
15196
|
phasesReached: []
|
|
14609
15197
|
};
|
|
14610
|
-
const adoptionFile =
|
|
14611
|
-
|
|
15198
|
+
const adoptionFile = join65(metricsDir, "adoption.jsonl");
|
|
15199
|
+
appendFileSync2(adoptionFile, JSON.stringify(record) + "\n");
|
|
14612
15200
|
} catch {
|
|
14613
15201
|
}
|
|
14614
15202
|
}
|
|
14615
15203
|
function isTelemetryDisabledByConfig(cwd) {
|
|
14616
|
-
const configPath =
|
|
15204
|
+
const configPath = join65(cwd, "harness.config.json");
|
|
14617
15205
|
if (!existsSync44(configPath)) return false;
|
|
14618
15206
|
try {
|
|
14619
15207
|
const config = JSON.parse(readFileSync32(configPath, "utf-8"));
|
|
@@ -14628,10 +15216,10 @@ function isTelemetryOptedOut(cwd) {
|
|
|
14628
15216
|
}
|
|
14629
15217
|
function flushTelemetryBackground(cwd) {
|
|
14630
15218
|
try {
|
|
14631
|
-
const adoptionFile =
|
|
15219
|
+
const adoptionFile = join65(cwd, ".harness", "metrics", "adoption.jsonl");
|
|
14632
15220
|
if (!existsSync44(adoptionFile)) return;
|
|
14633
15221
|
if (isTelemetryOptedOut(cwd)) return;
|
|
14634
|
-
const reporterPath =
|
|
15222
|
+
const reporterPath = join65(cwd, ".harness", "hooks", "telemetry-reporter.js");
|
|
14635
15223
|
if (!existsSync44(reporterPath)) return;
|
|
14636
15224
|
const child = spawn2(process.execPath, [reporterPath], {
|
|
14637
15225
|
cwd,
|
|
@@ -14669,7 +15257,7 @@ function reportTestSuccess(status, distinctId, identity) {
|
|
|
14669
15257
|
if (identity.team) logger.info(` team: ${identity.team}`);
|
|
14670
15258
|
}
|
|
14671
15259
|
function createTestCommand() {
|
|
14672
|
-
return new
|
|
15260
|
+
return new Command123("test").description("Send a test event to PostHog and verify connectivity").action(async () => {
|
|
14673
15261
|
const cwd = process.cwd();
|
|
14674
15262
|
const consent = resolveConsent(cwd, void 0);
|
|
14675
15263
|
if (!consent.allowed) {
|
|
@@ -14705,18 +15293,18 @@ function createTestCommand() {
|
|
|
14705
15293
|
}
|
|
14706
15294
|
|
|
14707
15295
|
// src/commands/telemetry/index.ts
|
|
14708
|
-
function
|
|
14709
|
-
const command = new
|
|
15296
|
+
function createTelemetryCommand2() {
|
|
15297
|
+
const command = new Command124("telemetry").description("Telemetry identity and status management");
|
|
14710
15298
|
command.addCommand(createIdentifyCommand());
|
|
14711
|
-
command.addCommand(
|
|
15299
|
+
command.addCommand(createStatusCommand2());
|
|
14712
15300
|
command.addCommand(createTestCommand());
|
|
14713
15301
|
return command;
|
|
14714
15302
|
}
|
|
14715
15303
|
|
|
14716
15304
|
// src/commands/test-craft.ts
|
|
14717
|
-
import { Command as
|
|
15305
|
+
import { Command as Command125 } from "commander";
|
|
14718
15306
|
function createTestCraftCommand() {
|
|
14719
|
-
return new
|
|
15307
|
+
return new Command125("test-craft").description(
|
|
14720
15308
|
"LLM-judgment critique of test quality across vitest/jest/mocha/playwright. Fourth craft-pipeline ceiling skill. Per-test critique with best-effort source pairing."
|
|
14721
15309
|
).option("-f, --files <files...>", "Optional test file/glob scope").option("--frameworks <names...>", "Restrict to: vitest / jest / mocha / playwright").option("--max-files <n>", "Cap test file count (default: 100)").option("--max-tests-per-file <n>", "Cap per-file test critique (default: 20)").option("--no-source-pair", "Skip source-pairing resolution").action(async (opts, cmd) => {
|
|
14722
15310
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -14786,7 +15374,7 @@ ${file}`);
|
|
|
14786
15374
|
}
|
|
14787
15375
|
|
|
14788
15376
|
// src/commands/traceability.ts
|
|
14789
|
-
import { Command as
|
|
15377
|
+
import { Command as Command126 } from "commander";
|
|
14790
15378
|
import chalk19 from "chalk";
|
|
14791
15379
|
function confidenceLabel(maxConfidence) {
|
|
14792
15380
|
if (maxConfidence >= 0.8) return "explicit";
|
|
@@ -14926,7 +15514,7 @@ async function runTraceability(options) {
|
|
|
14926
15514
|
process.exit(ExitCode.SUCCESS);
|
|
14927
15515
|
}
|
|
14928
15516
|
function createTraceabilityCommand() {
|
|
14929
|
-
return new
|
|
15517
|
+
return new Command126("traceability").description("Show spec-to-implementation traceability from the knowledge graph").option("--spec <path>", "Filter by spec file path").option("--feature <name>", "Filter by feature name").action(async (opts, cmd) => {
|
|
14930
15518
|
const globalOpts = cmd.optsWithGlobals();
|
|
14931
15519
|
await runTraceability({
|
|
14932
15520
|
spec: opts.spec,
|
|
@@ -14940,7 +15528,7 @@ function createTraceabilityCommand() {
|
|
|
14940
15528
|
|
|
14941
15529
|
// src/commands/uninstall.ts
|
|
14942
15530
|
import * as path78 from "path";
|
|
14943
|
-
import { Command as
|
|
15531
|
+
import { Command as Command127 } from "commander";
|
|
14944
15532
|
async function runUninstall(skillName, options) {
|
|
14945
15533
|
const packageName = resolvePackageName(skillName);
|
|
14946
15534
|
const shortName = extractSkillName(packageName);
|
|
@@ -14977,7 +15565,7 @@ async function runUninstall(skillName, options) {
|
|
|
14977
15565
|
return result;
|
|
14978
15566
|
}
|
|
14979
15567
|
function createUninstallCommand() {
|
|
14980
|
-
const cmd = new
|
|
15568
|
+
const cmd = new Command127("uninstall");
|
|
14981
15569
|
cmd.description("Uninstall a community skill").argument("<skill>", "Skill name or @harness-skills/scoped package name").option("--force", "Remove even if other skills depend on this one").action(async (skill, opts) => {
|
|
14982
15570
|
try {
|
|
14983
15571
|
const result = await runUninstall(skill, opts);
|
|
@@ -14999,7 +15587,7 @@ function createUninstallCommand() {
|
|
|
14999
15587
|
init_dist3();
|
|
15000
15588
|
import * as fs49 from "fs/promises";
|
|
15001
15589
|
import * as path79 from "path";
|
|
15002
|
-
import { Command as
|
|
15590
|
+
import { Command as Command128 } from "commander";
|
|
15003
15591
|
async function runUninstallConstraints(options) {
|
|
15004
15592
|
const { packageName, configPath, lockfilePath } = options;
|
|
15005
15593
|
const lockfileResult = await readLockfile(lockfilePath);
|
|
@@ -15056,7 +15644,7 @@ async function runUninstallConstraints(options) {
|
|
|
15056
15644
|
};
|
|
15057
15645
|
}
|
|
15058
15646
|
function createUninstallConstraintsCommand() {
|
|
15059
|
-
const cmd = new
|
|
15647
|
+
const cmd = new Command128("uninstall-constraints");
|
|
15060
15648
|
cmd.description("Remove a previously installed constraints package").argument("<name>", "Name of the constraint package to uninstall").option("-c, --config <path>", "Path to harness.config.json").action(async (name, opts) => {
|
|
15061
15649
|
let configPath;
|
|
15062
15650
|
if (opts.config) {
|
|
@@ -15096,10 +15684,10 @@ function createUninstallConstraintsCommand() {
|
|
|
15096
15684
|
|
|
15097
15685
|
// src/commands/update.ts
|
|
15098
15686
|
init_dist3();
|
|
15099
|
-
import { Command as
|
|
15100
|
-
import { execFile as execFile2, execFileSync as
|
|
15687
|
+
import { Command as Command129 } from "commander";
|
|
15688
|
+
import { execFile as execFile2, execFileSync as execFileSync13 } from "child_process";
|
|
15101
15689
|
import { realpathSync, existsSync as existsSync45, readFileSync as readFileSync33 } from "fs";
|
|
15102
|
-
import { dirname as dirname25, join as
|
|
15690
|
+
import { dirname as dirname25, join as join68 } from "path";
|
|
15103
15691
|
import { promisify as promisify2 } from "util";
|
|
15104
15692
|
import readline4 from "readline";
|
|
15105
15693
|
import chalk20 from "chalk";
|
|
@@ -15139,7 +15727,7 @@ async function getLatestVersionAsync(pkg) {
|
|
|
15139
15727
|
function getInstalledVersions(pm, packages) {
|
|
15140
15728
|
const versions = {};
|
|
15141
15729
|
try {
|
|
15142
|
-
const output =
|
|
15730
|
+
const output = execFileSync13(pm, ["list", "-g", "--json"], {
|
|
15143
15731
|
encoding: "utf-8",
|
|
15144
15732
|
timeout: 15e3
|
|
15145
15733
|
});
|
|
@@ -15160,7 +15748,7 @@ function getInstalledVersions(pm, packages) {
|
|
|
15160
15748
|
}
|
|
15161
15749
|
function getInstalledPackages(pm) {
|
|
15162
15750
|
try {
|
|
15163
|
-
const output =
|
|
15751
|
+
const output = execFileSync13(pm, ["list", "-g", "--json"], {
|
|
15164
15752
|
encoding: "utf-8",
|
|
15165
15753
|
timeout: 15e3
|
|
15166
15754
|
});
|
|
@@ -15180,19 +15768,19 @@ function prompt3(question) {
|
|
|
15180
15768
|
input: process.stdin,
|
|
15181
15769
|
output: process.stdout
|
|
15182
15770
|
});
|
|
15183
|
-
return new Promise((
|
|
15771
|
+
return new Promise((resolve49) => {
|
|
15184
15772
|
rl.question(question, (answer) => {
|
|
15185
15773
|
rl.close();
|
|
15186
|
-
|
|
15774
|
+
resolve49(answer.trim().toLowerCase());
|
|
15187
15775
|
});
|
|
15188
15776
|
});
|
|
15189
15777
|
}
|
|
15190
15778
|
function findPackageDir(resolvedBin) {
|
|
15191
15779
|
let dir = dirname25(resolvedBin);
|
|
15192
15780
|
for (let i = 0; i < 6; i++) {
|
|
15193
|
-
if (existsSync45(
|
|
15781
|
+
if (existsSync45(join68(dir, "package.json"))) {
|
|
15194
15782
|
try {
|
|
15195
|
-
const pkg = JSON.parse(readFileSync33(
|
|
15783
|
+
const pkg = JSON.parse(readFileSync33(join68(dir, "package.json"), "utf-8"));
|
|
15196
15784
|
if (pkg?.name === CLI_PACKAGE) return dir;
|
|
15197
15785
|
} catch {
|
|
15198
15786
|
}
|
|
@@ -15215,7 +15803,7 @@ function findAllInstalls() {
|
|
|
15215
15803
|
const args = isWindows ? ["harness"] : ["-a", "harness"];
|
|
15216
15804
|
let output;
|
|
15217
15805
|
try {
|
|
15218
|
-
const raw =
|
|
15806
|
+
const raw = execFileSync13(cmd, args, { encoding: "utf-8", timeout: 5e3 });
|
|
15219
15807
|
if (typeof raw !== "string") return [];
|
|
15220
15808
|
output = raw;
|
|
15221
15809
|
} catch {
|
|
@@ -15237,7 +15825,7 @@ function findAllInstalls() {
|
|
|
15237
15825
|
if (!packageDir) continue;
|
|
15238
15826
|
let version = null;
|
|
15239
15827
|
try {
|
|
15240
|
-
const pkg = JSON.parse(readFileSync33(
|
|
15828
|
+
const pkg = JSON.parse(readFileSync33(join68(packageDir, "package.json"), "utf-8"));
|
|
15241
15829
|
if (typeof pkg?.version === "string") version = pkg.version;
|
|
15242
15830
|
} catch {
|
|
15243
15831
|
}
|
|
@@ -15292,7 +15880,7 @@ async function offerCleanupOfOtherInstalls(activeDir) {
|
|
|
15292
15880
|
}
|
|
15293
15881
|
try {
|
|
15294
15882
|
logger.info(`Uninstalling: ${cmd.display}`);
|
|
15295
|
-
|
|
15883
|
+
execFileSync13(cmd.bin, cmd.args, { stdio: "inherit", timeout: 12e4 });
|
|
15296
15884
|
} catch {
|
|
15297
15885
|
logger.warn(`Uninstall failed for ${cmd.install.binPath}.`);
|
|
15298
15886
|
console.log(` Run manually: ${chalk20.cyan(cmd.display)}`);
|
|
@@ -15330,10 +15918,10 @@ async function ensureTelemetryIfNeeded() {
|
|
|
15330
15918
|
}
|
|
15331
15919
|
function refreshHooks() {
|
|
15332
15920
|
const cwd = process.cwd();
|
|
15333
|
-
const configPath =
|
|
15921
|
+
const configPath = join68(cwd, "harness.config.json");
|
|
15334
15922
|
if (!existsSync45(configPath)) return;
|
|
15335
15923
|
let profile = "standard";
|
|
15336
|
-
const profilePath =
|
|
15924
|
+
const profilePath = join68(cwd, ".harness", "hooks", "profile.json");
|
|
15337
15925
|
try {
|
|
15338
15926
|
const data = JSON.parse(readFileSync33(profilePath, "utf-8"));
|
|
15339
15927
|
if (data.profile && ["minimal", "standard", "strict"].includes(data.profile)) {
|
|
@@ -15352,7 +15940,7 @@ function refreshHooks() {
|
|
|
15352
15940
|
function runLocalGraphScan() {
|
|
15353
15941
|
try {
|
|
15354
15942
|
logger.info("Scanning codebase to rebuild knowledge graph...");
|
|
15355
|
-
|
|
15943
|
+
execFileSync13("harness", ["graph", "scan", "."], { stdio: "inherit" });
|
|
15356
15944
|
} catch {
|
|
15357
15945
|
logger.warn("Graph scan failed. Run manually:");
|
|
15358
15946
|
console.log(` ${chalk20.cyan("harness graph scan .")}`);
|
|
@@ -15367,7 +15955,7 @@ async function offerRegeneration() {
|
|
|
15367
15955
|
const scopeAnswer = await prompt3("Generate for (G)lobal or (l)ocal project? (G/l) ");
|
|
15368
15956
|
const isGlobal = scopeAnswer !== "l" && scopeAnswer !== "local";
|
|
15369
15957
|
try {
|
|
15370
|
-
|
|
15958
|
+
execFileSync13("harness", ["generate", ...isGlobal ? ["--global"] : []], {
|
|
15371
15959
|
stdio: "inherit"
|
|
15372
15960
|
});
|
|
15373
15961
|
} catch {
|
|
@@ -15447,7 +16035,7 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
15447
16035
|
}
|
|
15448
16036
|
try {
|
|
15449
16037
|
logger.info("Updating packages...");
|
|
15450
|
-
|
|
16038
|
+
execFileSync13(pm, ["install", "-g", ...installPkgs], { stdio: "inherit", timeout: 12e4 });
|
|
15451
16039
|
console.log("");
|
|
15452
16040
|
logger.success("Update complete");
|
|
15453
16041
|
invalidateCheckState();
|
|
@@ -15464,7 +16052,7 @@ async function runUpdateAction(opts, globalOpts) {
|
|
|
15464
16052
|
process.exit(ExitCode.SUCCESS);
|
|
15465
16053
|
}
|
|
15466
16054
|
function createUpdateCommand() {
|
|
15467
|
-
return new
|
|
16055
|
+
return new Command129("update").description("Update all @harness-engineering packages to the latest version").option("--version <semver>", "Pin @harness-engineering/cli to a specific version").option("--force", "Force update even if versions match").option(
|
|
15468
16056
|
"--regenerate",
|
|
15469
16057
|
"Only regenerate slash commands and agent definitions (skip package updates)"
|
|
15470
16058
|
).action(async (opts, cmd) => {
|
|
@@ -15474,9 +16062,9 @@ function createUpdateCommand() {
|
|
|
15474
16062
|
}
|
|
15475
16063
|
|
|
15476
16064
|
// src/commands/usage.ts
|
|
15477
|
-
import { Command as
|
|
16065
|
+
import { Command as Command130 } from "commander";
|
|
15478
16066
|
async function loadAndPriceRecords(cwd, includeClaudeSessions = false) {
|
|
15479
|
-
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-
|
|
16067
|
+
const { readCostRecords, loadPricingData, calculateCost, parseCCRecords } = await import("./dist-4CZLCE33.js");
|
|
15480
16068
|
const records = readCostRecords(cwd);
|
|
15481
16069
|
if (includeClaudeSessions) {
|
|
15482
16070
|
const ccRecords = parseCCRecords();
|
|
@@ -15569,7 +16157,7 @@ function registerDailyCommand(usage) {
|
|
|
15569
16157
|
else logger.info("No usage data found. Run some harness sessions first.");
|
|
15570
16158
|
return;
|
|
15571
16159
|
}
|
|
15572
|
-
const { aggregateByDay } = await import("./dist-
|
|
16160
|
+
const { aggregateByDay } = await import("./dist-4CZLCE33.js");
|
|
15573
16161
|
const limited = aggregateByDay(records).slice(0, days);
|
|
15574
16162
|
if (globalOpts.json) {
|
|
15575
16163
|
console.log(
|
|
@@ -15598,7 +16186,7 @@ function registerSessionsCommand(usage) {
|
|
|
15598
16186
|
}
|
|
15599
16187
|
return;
|
|
15600
16188
|
}
|
|
15601
|
-
const { aggregateBySession } = await import("./dist-
|
|
16189
|
+
const { aggregateBySession } = await import("./dist-4CZLCE33.js");
|
|
15602
16190
|
const sessionData = aggregateBySession(records);
|
|
15603
16191
|
const limited = sessionData.slice(0, limit);
|
|
15604
16192
|
if (globalOpts.json) {
|
|
@@ -15678,7 +16266,7 @@ function registerSessionCommand(usage) {
|
|
|
15678
16266
|
cwd,
|
|
15679
16267
|
globalOpts.includeClaudeSessions
|
|
15680
16268
|
);
|
|
15681
|
-
const { aggregateBySession } = await import("./dist-
|
|
16269
|
+
const { aggregateBySession } = await import("./dist-4CZLCE33.js");
|
|
15682
16270
|
const sessionData = aggregateBySession(records);
|
|
15683
16271
|
const match = sessionData.find((s) => s.sessionId === id);
|
|
15684
16272
|
if (!match) {
|
|
@@ -15713,7 +16301,7 @@ function registerLatestCommand(usage) {
|
|
|
15713
16301
|
}
|
|
15714
16302
|
return;
|
|
15715
16303
|
}
|
|
15716
|
-
const { aggregateBySession } = await import("./dist-
|
|
16304
|
+
const { aggregateBySession } = await import("./dist-4CZLCE33.js");
|
|
15717
16305
|
const sessionData = aggregateBySession(records);
|
|
15718
16306
|
const latest = sessionData[0];
|
|
15719
16307
|
if (!latest) {
|
|
@@ -15739,7 +16327,7 @@ function registerLatestCommand(usage) {
|
|
|
15739
16327
|
});
|
|
15740
16328
|
}
|
|
15741
16329
|
function createUsageCommand() {
|
|
15742
|
-
const usage = new
|
|
16330
|
+
const usage = new Command130("usage").description("Token usage and cost tracking");
|
|
15743
16331
|
usage.option(
|
|
15744
16332
|
"--include-claude-sessions",
|
|
15745
16333
|
"Include Claude Code session data from ~/.claude/projects/"
|
|
@@ -15754,10 +16342,10 @@ function createUsageCommand() {
|
|
|
15754
16342
|
// src/commands/validate.ts
|
|
15755
16343
|
init_dist3();
|
|
15756
16344
|
init_dist3();
|
|
15757
|
-
import { Command as
|
|
16345
|
+
import { Command as Command131 } from "commander";
|
|
15758
16346
|
import * as fs50 from "fs";
|
|
15759
16347
|
import * as path80 from "path";
|
|
15760
|
-
import { execFileSync as
|
|
16348
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
15761
16349
|
async function runValidate(options) {
|
|
15762
16350
|
const configResult = resolveConfig(options.configPath);
|
|
15763
16351
|
if (!configResult.ok) {
|
|
@@ -15876,7 +16464,7 @@ async function runValidate(options) {
|
|
|
15876
16464
|
const gitattributesContent = fs50.readFileSync(gitattributesPath, "utf-8");
|
|
15877
16465
|
let driverConfigured = false;
|
|
15878
16466
|
try {
|
|
15879
|
-
const out =
|
|
16467
|
+
const out = execFileSync14("git", ["config", "--get", "merge.ours.driver"], {
|
|
15880
16468
|
cwd,
|
|
15881
16469
|
encoding: "utf-8",
|
|
15882
16470
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -16062,7 +16650,7 @@ function resolveValidateMode(globalOpts) {
|
|
|
16062
16650
|
return OutputMode.TEXT;
|
|
16063
16651
|
}
|
|
16064
16652
|
async function printCrossCheckWarnings(mode) {
|
|
16065
|
-
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-
|
|
16653
|
+
const { runCrossCheck: runCrossCheck2 } = await import("./validate-cross-check-YYVYMSPA.js");
|
|
16066
16654
|
const cwd = process.cwd();
|
|
16067
16655
|
const crossResult = await runCrossCheck2({
|
|
16068
16656
|
specsDir: path80.join(cwd, "docs", "specs"),
|
|
@@ -16078,7 +16666,7 @@ async function printCrossCheckWarnings(mode) {
|
|
|
16078
16666
|
${crossResult.value.warnings} warnings`);
|
|
16079
16667
|
}
|
|
16080
16668
|
function createValidateCommand3() {
|
|
16081
|
-
const command = new
|
|
16669
|
+
const command = new Command131("validate").description("Run all validation checks").option("--cross-check", "Run cross-artifact consistency validation").option(
|
|
16082
16670
|
"--agent-configs",
|
|
16083
16671
|
"Validate agent configs (CLAUDE.md, hooks, skills) via agnix or built-in fallback rules"
|
|
16084
16672
|
).option("--strict", "Treat warnings as errors (applies to --agent-configs)").option("--agnix-bin <path>", "Override the agnix binary path discovered on PATH").action(async (opts, cmd) => runValidateAction(opts, cmd.optsWithGlobals()));
|
|
@@ -16127,7 +16715,7 @@ Agent configs checked via ${engineLabel}${note}`);
|
|
|
16127
16715
|
|
|
16128
16716
|
// src/commands/verify.ts
|
|
16129
16717
|
init_dist3();
|
|
16130
|
-
import { Command as
|
|
16718
|
+
import { Command as Command132 } from "commander";
|
|
16131
16719
|
import { execSync as execSync6 } from "child_process";
|
|
16132
16720
|
function loadBranchingConfig(configPath) {
|
|
16133
16721
|
const shouldLoad = configPath !== void 0 || findConfigFile().ok;
|
|
@@ -16190,7 +16778,7 @@ async function runVerify(options) {
|
|
|
16190
16778
|
process.exit(ExitCode.VALIDATION_FAILED);
|
|
16191
16779
|
}
|
|
16192
16780
|
function createVerifyCommand() {
|
|
16193
|
-
return new
|
|
16781
|
+
return new Command132("verify").description(
|
|
16194
16782
|
"Verify project conventions (currently: branch naming). Works with or without a harness.config.json."
|
|
16195
16783
|
).option(
|
|
16196
16784
|
"--branch <name>",
|
|
@@ -16268,6 +16856,7 @@ var commandCreators = [
|
|
|
16268
16856
|
createRecommendCommand,
|
|
16269
16857
|
createReviewCiCommand,
|
|
16270
16858
|
createRoadmapCommand,
|
|
16859
|
+
createRollbackCommand,
|
|
16271
16860
|
createRoutingCommand,
|
|
16272
16861
|
createScanConfigCommand,
|
|
16273
16862
|
createSearchCommand,
|
|
@@ -16283,7 +16872,7 @@ var commandCreators = [
|
|
|
16283
16872
|
createSyncAnalysesCommand,
|
|
16284
16873
|
createSyncMainCommand,
|
|
16285
16874
|
createTaintCommand,
|
|
16286
|
-
|
|
16875
|
+
createTelemetryCommand2,
|
|
16287
16876
|
createTestCraftCommand,
|
|
16288
16877
|
createTraceabilityCommand,
|
|
16289
16878
|
createUninstallCommand,
|
|
@@ -16317,7 +16906,7 @@ function registerDeprecatedGraphAliases(program) {
|
|
|
16317
16906
|
|
|
16318
16907
|
// src/index.ts
|
|
16319
16908
|
function createProgram() {
|
|
16320
|
-
const program = new
|
|
16909
|
+
const program = new Command133();
|
|
16321
16910
|
program.name("harness").description("CLI for Harness Engineering toolkit").version(CLI_VERSION).option("-c, --config <path>", "Path to config file").option("--json", "Output as JSON").option("--verbose", "Verbose output").option("--quiet", "Minimal output");
|
|
16322
16911
|
for (const creator of commandCreators) {
|
|
16323
16912
|
program.addCommand(creator());
|