@osfactory/har 1.2.0 → 1.3.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/index.js +1919 -528
- package/dist/templates/agent-skills/factory-line.md +22 -10
- package/dist/templates/agent-skills/skills.manifest.json +25 -9
- package/dist/templates/lines/example-line/.github/workflows/check-manifest.yml +24 -0
- package/dist/templates/lines/example-line/AGENTS.md +48 -0
- package/dist/templates/lines/example-line/README.md +72 -0
- package/dist/templates/lines/example-line/docs/AUTHORING.md +79 -0
- package/dist/templates/lines/example-line/line.json +72 -0
- package/dist/templates/lines/example-line/line.manifest.json +37 -0
- package/dist/templates/lines/example-line/scripts/check-manifest.mjs +103 -0
- package/dist/templates/lines/example-line/stages/example-gate.sh +59 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -593,8 +593,8 @@ var init_parseUtil = __esm({
|
|
|
593
593
|
init_errors();
|
|
594
594
|
init_en();
|
|
595
595
|
makeIssue = (params) => {
|
|
596
|
-
const { data, path:
|
|
597
|
-
const fullPath = [...
|
|
596
|
+
const { data, path: path97, errorMaps, issueData } = params;
|
|
597
|
+
const fullPath = [...path97, ...issueData.path || []];
|
|
598
598
|
const fullIssue = {
|
|
599
599
|
...issueData,
|
|
600
600
|
path: fullPath
|
|
@@ -902,11 +902,11 @@ var init_types = __esm({
|
|
|
902
902
|
init_parseUtil();
|
|
903
903
|
init_util();
|
|
904
904
|
ParseInputLazyPath = class {
|
|
905
|
-
constructor(parent, value,
|
|
905
|
+
constructor(parent, value, path97, key) {
|
|
906
906
|
this._cachedPath = [];
|
|
907
907
|
this.parent = parent;
|
|
908
908
|
this.data = value;
|
|
909
|
-
this._path =
|
|
909
|
+
this._path = path97;
|
|
910
910
|
this._key = key;
|
|
911
911
|
}
|
|
912
912
|
get path() {
|
|
@@ -28632,6 +28632,149 @@ var init_usage_pricing = __esm({
|
|
|
28632
28632
|
}
|
|
28633
28633
|
});
|
|
28634
28634
|
|
|
28635
|
+
// packages/schemas/src/line.ts
|
|
28636
|
+
var LINE_CONTRACT_VERSION, LINE_BUNDLE_KIND, LINE_MANIFEST_FILES, LineIdSchema, StationIdSchema, LineSkillSchema, LineMcpSchema, LineWorkSchema, LineWaveCellSchema, LineStationSchema, LineGateStageSchema, LineGateSchema, LineExtraStageSchema, LineHandoffSchema, LineTravelerSchema, LineProgramSchema, LineManifestFileSchema, LineManifestSchema, LineLedgerEntrySchema, LineLedgerSchema;
|
|
28637
|
+
var init_line = __esm({
|
|
28638
|
+
"packages/schemas/src/line.ts"() {
|
|
28639
|
+
"use strict";
|
|
28640
|
+
init_zod();
|
|
28641
|
+
init_schema();
|
|
28642
|
+
LINE_CONTRACT_VERSION = 1;
|
|
28643
|
+
LINE_BUNDLE_KIND = "line";
|
|
28644
|
+
LINE_MANIFEST_FILES = ["line.manifest.json", "template.manifest.json"];
|
|
28645
|
+
LineIdSchema = external_exports.string().min(1).regex(/^[a-z0-9][a-z0-9._-]*$/, "Line id must be a lowercase slug (letters, digits, ._-)");
|
|
28646
|
+
StationIdSchema = external_exports.string().min(1).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/, "Station id must be stable and shell-friendly");
|
|
28647
|
+
LineSkillSchema = external_exports.object({
|
|
28648
|
+
id: external_exports.string().min(1),
|
|
28649
|
+
role: external_exports.enum(["orchestrator", "station"]).default("station"),
|
|
28650
|
+
/** Install hint only — HAR never vendors third-party skill packs. */
|
|
28651
|
+
install: external_exports.string().min(1).optional()
|
|
28652
|
+
});
|
|
28653
|
+
LineMcpSchema = external_exports.object({
|
|
28654
|
+
name: external_exports.string().min(1),
|
|
28655
|
+
why: external_exports.string().min(1).optional(),
|
|
28656
|
+
required: external_exports.boolean().default(false)
|
|
28657
|
+
});
|
|
28658
|
+
LineWorkSchema = external_exports.object({
|
|
28659
|
+
/** `github`, `linear`, `none`, or a free string. */
|
|
28660
|
+
source: external_exports.string().min(1).default("none"),
|
|
28661
|
+
ids: external_exports.array(external_exports.string().min(1)).default([]),
|
|
28662
|
+
url: external_exports.string().min(1).optional(),
|
|
28663
|
+
optional: external_exports.boolean().default(false)
|
|
28664
|
+
});
|
|
28665
|
+
LineWaveCellSchema = external_exports.object({
|
|
28666
|
+
workId: external_exports.string().min(1).optional(),
|
|
28667
|
+
title: external_exports.string().min(1).optional()
|
|
28668
|
+
});
|
|
28669
|
+
LineStationSchema = external_exports.object({
|
|
28670
|
+
id: StationIdSchema,
|
|
28671
|
+
title: external_exports.string().min(1),
|
|
28672
|
+
description: external_exports.string().min(1).optional(),
|
|
28673
|
+
work: LineWorkSchema.optional(),
|
|
28674
|
+
/** Each inner array is one wave; cells inside a wave run in parallel slots. */
|
|
28675
|
+
waves: external_exports.array(external_exports.array(LineWaveCellSchema)).optional(),
|
|
28676
|
+
skills: external_exports.array(external_exports.string().min(1)).optional(),
|
|
28677
|
+
mcp: external_exports.array(external_exports.string().min(1)).optional()
|
|
28678
|
+
});
|
|
28679
|
+
LineGateStageSchema = external_exports.object({
|
|
28680
|
+
id: external_exports.string().min(1),
|
|
28681
|
+
/** Required from this station onward — this is the ratchet tag. */
|
|
28682
|
+
fromStation: StationIdSchema,
|
|
28683
|
+
tier: external_exports.enum(["quick", "full"]).default("full")
|
|
28684
|
+
});
|
|
28685
|
+
LineGateSchema = external_exports.object({
|
|
28686
|
+
/** Must be true: a factory line never drops an earlier station's stages. */
|
|
28687
|
+
cumulative: external_exports.literal(true),
|
|
28688
|
+
/** When set, the gate is skipped unless this env var is "1". */
|
|
28689
|
+
optInEnv: external_exports.string().min(1).nullable().default(null),
|
|
28690
|
+
stages: external_exports.array(LineGateStageSchema).default([])
|
|
28691
|
+
});
|
|
28692
|
+
LineExtraStageSchema = external_exports.object({
|
|
28693
|
+
id: external_exports.string().min(1),
|
|
28694
|
+
kind: HarnessStageKindSchema.default("test"),
|
|
28695
|
+
tier: external_exports.enum(["quick", "full"]).default("full"),
|
|
28696
|
+
description: external_exports.string().min(1).optional()
|
|
28697
|
+
});
|
|
28698
|
+
LineHandoffSchema = external_exports.object({
|
|
28699
|
+
/** Must be false: agents hand off, they do not merge or release. */
|
|
28700
|
+
autonomousShip: external_exports.literal(false),
|
|
28701
|
+
waitFor: external_exports.string().min(1).optional()
|
|
28702
|
+
});
|
|
28703
|
+
LineTravelerSchema = external_exports.object({
|
|
28704
|
+
kind: external_exports.string().min(1),
|
|
28705
|
+
ref: external_exports.string().min(1).optional(),
|
|
28706
|
+
note: external_exports.string().min(1).optional()
|
|
28707
|
+
});
|
|
28708
|
+
LineProgramSchema = external_exports.object({
|
|
28709
|
+
contractVersion: external_exports.literal(LINE_CONTRACT_VERSION),
|
|
28710
|
+
id: LineIdSchema,
|
|
28711
|
+
title: external_exports.string().min(1),
|
|
28712
|
+
description: external_exports.string().min(1).optional(),
|
|
28713
|
+
skills: external_exports.array(LineSkillSchema).default([]),
|
|
28714
|
+
mcp: external_exports.array(LineMcpSchema).default([]),
|
|
28715
|
+
plugins: external_exports.array(external_exports.string().min(1)).default([]),
|
|
28716
|
+
stations: external_exports.array(LineStationSchema).min(1),
|
|
28717
|
+
gate: LineGateSchema,
|
|
28718
|
+
extraStages: external_exports.array(LineExtraStageSchema).default([]),
|
|
28719
|
+
handoff: LineHandoffSchema,
|
|
28720
|
+
traveler: LineTravelerSchema.optional(),
|
|
28721
|
+
prototypeNotes: external_exports.array(external_exports.string().min(1)).default([])
|
|
28722
|
+
}).superRefine((data, ctx) => {
|
|
28723
|
+
const stationIds = new Set(data.stations.map((s) => s.id));
|
|
28724
|
+
if (stationIds.size !== data.stations.length) {
|
|
28725
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: "station ids must be unique" });
|
|
28726
|
+
}
|
|
28727
|
+
for (const stage of data.gate.stages) {
|
|
28728
|
+
if (!stationIds.has(stage.fromStation)) {
|
|
28729
|
+
ctx.addIssue({
|
|
28730
|
+
code: external_exports.ZodIssueCode.custom,
|
|
28731
|
+
message: `gate.stages[].fromStation "${stage.fromStation}" is not a station id`
|
|
28732
|
+
});
|
|
28733
|
+
}
|
|
28734
|
+
}
|
|
28735
|
+
});
|
|
28736
|
+
LineManifestFileSchema = external_exports.object({
|
|
28737
|
+
src: external_exports.string().min(1),
|
|
28738
|
+
dest: external_exports.string().min(1),
|
|
28739
|
+
executable: external_exports.boolean().optional()
|
|
28740
|
+
});
|
|
28741
|
+
LineManifestSchema = external_exports.object({
|
|
28742
|
+
kind: external_exports.literal(LINE_BUNDLE_KIND),
|
|
28743
|
+
id: LineIdSchema,
|
|
28744
|
+
title: external_exports.string().min(1).optional(),
|
|
28745
|
+
/** Bundle-relative path to the program JSON. */
|
|
28746
|
+
program: external_exports.string().min(1).default("line.json"),
|
|
28747
|
+
files: external_exports.array(LineManifestFileSchema).default([]),
|
|
28748
|
+
/** Stages to REGISTER in .har/stages.json — never added to verificationStages. */
|
|
28749
|
+
stages: external_exports.array(HarnessStageSchema).default([]),
|
|
28750
|
+
nextSteps: external_exports.array(external_exports.string().min(1)).default([]),
|
|
28751
|
+
docsPath: external_exports.string().min(1).optional()
|
|
28752
|
+
}).passthrough().superRefine((data, ctx) => {
|
|
28753
|
+
const raw = data;
|
|
28754
|
+
if (raw.verificationStages !== void 0) {
|
|
28755
|
+
ctx.addIssue({
|
|
28756
|
+
code: external_exports.ZodIssueCode.custom,
|
|
28757
|
+
message: "Line manifests must not declare verificationStages \u2014 line gate stages are opt-in and run via `har line gate`."
|
|
28758
|
+
});
|
|
28759
|
+
}
|
|
28760
|
+
});
|
|
28761
|
+
LineLedgerEntrySchema = external_exports.object({
|
|
28762
|
+
id: LineIdSchema,
|
|
28763
|
+
source: external_exports.enum(["bundled", "local", "path", "npm", "git"]),
|
|
28764
|
+
spec: external_exports.string().min(1),
|
|
28765
|
+
version: external_exports.string().optional(),
|
|
28766
|
+
/** Stages this line registered (registered only — not on verify). */
|
|
28767
|
+
stageIds: external_exports.array(external_exports.string().min(1)).default([]),
|
|
28768
|
+
programPath: external_exports.string().min(1),
|
|
28769
|
+
installedAt: external_exports.string()
|
|
28770
|
+
});
|
|
28771
|
+
LineLedgerSchema = external_exports.object({
|
|
28772
|
+
version: external_exports.literal("1"),
|
|
28773
|
+
lines: external_exports.array(LineLedgerEntrySchema).default([])
|
|
28774
|
+
});
|
|
28775
|
+
}
|
|
28776
|
+
});
|
|
28777
|
+
|
|
28635
28778
|
// src/harness/schema.ts
|
|
28636
28779
|
var init_schema2 = __esm({
|
|
28637
28780
|
"src/harness/schema.ts"() {
|
|
@@ -28640,6 +28783,7 @@ var init_schema2 = __esm({
|
|
|
28640
28783
|
init_harness_env();
|
|
28641
28784
|
init_usage_authority();
|
|
28642
28785
|
init_usage_pricing();
|
|
28786
|
+
init_line();
|
|
28643
28787
|
}
|
|
28644
28788
|
});
|
|
28645
28789
|
|
|
@@ -29043,7 +29187,7 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
|
29043
29187
|
const stream = options.stream ?? false;
|
|
29044
29188
|
const echoStdout = stream && (options.streamStdout ?? true);
|
|
29045
29189
|
const { stream: _stream, streamStdout: _streamStdout, ...spawnOptions } = options;
|
|
29046
|
-
return new Promise((
|
|
29190
|
+
return new Promise((resolve66) => {
|
|
29047
29191
|
const proc = (0, import_child_process.spawn)("bash", [scriptPath, ...args], {
|
|
29048
29192
|
...spawnOptions,
|
|
29049
29193
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -29058,14 +29202,14 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
|
29058
29202
|
stderr += d;
|
|
29059
29203
|
if (stream) process.stderr.write(d);
|
|
29060
29204
|
});
|
|
29061
|
-
proc.on("close", (code) =>
|
|
29205
|
+
proc.on("close", (code) => resolve66({ stdout, stderr, code: code ?? 0 }));
|
|
29062
29206
|
});
|
|
29063
29207
|
}
|
|
29064
29208
|
function runShellCommand(command2, options = {}) {
|
|
29065
29209
|
const stream = options.stream ?? false;
|
|
29066
29210
|
const echoStdout = stream && (options.streamStdout ?? true);
|
|
29067
29211
|
const { stream: _stream, streamStdout: _streamStdout, ...spawnOptions } = options;
|
|
29068
|
-
return new Promise((
|
|
29212
|
+
return new Promise((resolve66) => {
|
|
29069
29213
|
const proc = (0, import_child_process.spawn)("bash", ["-lc", command2], {
|
|
29070
29214
|
...spawnOptions,
|
|
29071
29215
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -29080,7 +29224,7 @@ function runShellCommand(command2, options = {}) {
|
|
|
29080
29224
|
stderr += d;
|
|
29081
29225
|
if (stream) process.stderr.write(d);
|
|
29082
29226
|
});
|
|
29083
|
-
proc.on("close", (code) =>
|
|
29227
|
+
proc.on("close", (code) => resolve66({ stdout, stderr, code: code ?? 0 }));
|
|
29084
29228
|
});
|
|
29085
29229
|
}
|
|
29086
29230
|
var import_child_process;
|
|
@@ -30071,7 +30215,7 @@ var init_slot_registry = __esm({
|
|
|
30071
30215
|
|
|
30072
30216
|
// src/runtime/exec.ts
|
|
30073
30217
|
function spawnResult(cmd, args, opts, shell) {
|
|
30074
|
-
return new Promise((
|
|
30218
|
+
return new Promise((resolve66) => {
|
|
30075
30219
|
const stream = opts.stream ?? false;
|
|
30076
30220
|
const proc = (0, import_child_process3.spawn)(cmd, args, {
|
|
30077
30221
|
cwd: opts.cwd,
|
|
@@ -30083,8 +30227,8 @@ function spawnResult(cmd, args, opts, shell) {
|
|
|
30083
30227
|
let stderr = "";
|
|
30084
30228
|
proc.stdout?.on("data", (c) => stdout += c.toString());
|
|
30085
30229
|
proc.stderr?.on("data", (c) => stderr += c.toString());
|
|
30086
|
-
proc.on("error", (err) =>
|
|
30087
|
-
proc.on("close", (code) =>
|
|
30230
|
+
proc.on("error", (err) => resolve66({ code: 127, stdout, stderr: stderr || String(err) }));
|
|
30231
|
+
proc.on("close", (code) => resolve66({ code: code ?? 1, stdout, stderr }));
|
|
30088
30232
|
});
|
|
30089
30233
|
}
|
|
30090
30234
|
var import_child_process3, fs13, path13, realSystemOps, defaultExec, stderrLog, realSleep;
|
|
@@ -30147,7 +30291,7 @@ var init_exec = __esm({
|
|
|
30147
30291
|
process.stderr.write(`==> ${message}
|
|
30148
30292
|
`);
|
|
30149
30293
|
};
|
|
30150
|
-
realSleep = (seconds) => new Promise((
|
|
30294
|
+
realSleep = (seconds) => new Promise((resolve66) => setTimeout(resolve66, seconds * 1e3));
|
|
30151
30295
|
}
|
|
30152
30296
|
});
|
|
30153
30297
|
|
|
@@ -34738,16 +34882,16 @@ var init_local_executor = __esm({
|
|
|
34738
34882
|
const walk = (dir, prefix) => {
|
|
34739
34883
|
for (const entry of fs35.readdirSync(dir, { withFileTypes: true })) {
|
|
34740
34884
|
const full = path36.join(dir, entry.name);
|
|
34741
|
-
const
|
|
34885
|
+
const relative6 = path36.join(prefix, entry.name);
|
|
34742
34886
|
if (entry.isDirectory()) {
|
|
34743
|
-
walk(full,
|
|
34887
|
+
walk(full, relative6);
|
|
34744
34888
|
continue;
|
|
34745
34889
|
}
|
|
34746
|
-
if (filter2?.stageId && !
|
|
34890
|
+
if (filter2?.stageId && !relative6.includes(filter2.stageId)) continue;
|
|
34747
34891
|
const stat = fs35.statSync(full);
|
|
34748
34892
|
entries.push({
|
|
34749
34893
|
path: full,
|
|
34750
|
-
relativePath:
|
|
34894
|
+
relativePath: relative6,
|
|
34751
34895
|
sizeBytes: stat.size,
|
|
34752
34896
|
modifiedAt: stat.mtime.toISOString()
|
|
34753
34897
|
});
|
|
@@ -36663,7 +36807,7 @@ async function attempt(url) {
|
|
|
36663
36807
|
async function readControlJson(url) {
|
|
36664
36808
|
const first = await attempt(url);
|
|
36665
36809
|
if (first.read.ok || !first.retryable) return first.read;
|
|
36666
|
-
await new Promise((
|
|
36810
|
+
await new Promise((resolve66) => setTimeout(resolve66, RETRY_DELAY_MS));
|
|
36667
36811
|
return (await attempt(url)).read;
|
|
36668
36812
|
}
|
|
36669
36813
|
async function readControlPages(options) {
|
|
@@ -37148,7 +37292,7 @@ async function postForResponse(url, headers, payload) {
|
|
|
37148
37292
|
} catch (err) {
|
|
37149
37293
|
lastErr = err;
|
|
37150
37294
|
if (attempt2 < MAX_FETCH_ATTEMPTS) {
|
|
37151
|
-
await new Promise((
|
|
37295
|
+
await new Promise((resolve66) => setTimeout(resolve66, attempt2 * 100));
|
|
37152
37296
|
}
|
|
37153
37297
|
}
|
|
37154
37298
|
}
|
|
@@ -37388,7 +37532,7 @@ async function waitForControlApi(apiUrl = getControlApiUrl(), timeoutMs = 6e4, i
|
|
|
37388
37532
|
const deadline = Date.now() + timeoutMs;
|
|
37389
37533
|
while (Date.now() < deadline) {
|
|
37390
37534
|
if (await isControlApiReachable(apiUrl)) return true;
|
|
37391
|
-
await new Promise((
|
|
37535
|
+
await new Promise((resolve66) => setTimeout(resolve66, intervalMs));
|
|
37392
37536
|
}
|
|
37393
37537
|
return false;
|
|
37394
37538
|
}
|
|
@@ -39037,15 +39181,15 @@ var require_route = __commonJS({
|
|
|
39037
39181
|
};
|
|
39038
39182
|
}
|
|
39039
39183
|
function wrapConversion(toModel, graph) {
|
|
39040
|
-
const
|
|
39184
|
+
const path97 = [graph[toModel].parent, toModel];
|
|
39041
39185
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
39042
39186
|
let cur = graph[toModel].parent;
|
|
39043
39187
|
while (graph[cur].parent) {
|
|
39044
|
-
|
|
39188
|
+
path97.unshift(graph[cur].parent);
|
|
39045
39189
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
39046
39190
|
cur = graph[cur].parent;
|
|
39047
39191
|
}
|
|
39048
|
-
fn.conversion =
|
|
39192
|
+
fn.conversion = path97;
|
|
39049
39193
|
return fn;
|
|
39050
39194
|
}
|
|
39051
39195
|
module2.exports = function(fromModel) {
|
|
@@ -45539,26 +45683,26 @@ var require_lib2 = __commonJS({
|
|
|
45539
45683
|
return matches;
|
|
45540
45684
|
};
|
|
45541
45685
|
exports2.analyse = analyse;
|
|
45542
|
-
var detectFile = (filepath, opts = {}) => new Promise((
|
|
45686
|
+
var detectFile = (filepath, opts = {}) => new Promise((resolve66, reject) => {
|
|
45543
45687
|
let fd;
|
|
45544
|
-
const
|
|
45688
|
+
const fs79 = (0, node_1.default)();
|
|
45545
45689
|
const handler = (err, buffer) => {
|
|
45546
45690
|
if (fd) {
|
|
45547
|
-
|
|
45691
|
+
fs79.closeSync(fd);
|
|
45548
45692
|
}
|
|
45549
45693
|
if (err) {
|
|
45550
45694
|
reject(err);
|
|
45551
45695
|
} else if (buffer) {
|
|
45552
|
-
|
|
45696
|
+
resolve66((0, exports2.detect)(buffer));
|
|
45553
45697
|
} else {
|
|
45554
45698
|
reject(new Error("No error and no buffer received"));
|
|
45555
45699
|
}
|
|
45556
45700
|
};
|
|
45557
45701
|
const sampleSize = (opts === null || opts === void 0 ? void 0 : opts.sampleSize) || 0;
|
|
45558
45702
|
if (sampleSize > 0) {
|
|
45559
|
-
fd =
|
|
45703
|
+
fd = fs79.openSync(filepath, "r");
|
|
45560
45704
|
let sample = Buffer.allocUnsafe(sampleSize);
|
|
45561
|
-
|
|
45705
|
+
fs79.read(fd, sample, 0, sampleSize, opts.offset, (err, bytesRead) => {
|
|
45562
45706
|
if (err) {
|
|
45563
45707
|
handler(err, null);
|
|
45564
45708
|
} else {
|
|
@@ -45570,22 +45714,22 @@ var require_lib2 = __commonJS({
|
|
|
45570
45714
|
});
|
|
45571
45715
|
return;
|
|
45572
45716
|
}
|
|
45573
|
-
|
|
45717
|
+
fs79.readFile(filepath, handler);
|
|
45574
45718
|
});
|
|
45575
45719
|
exports2.detectFile = detectFile;
|
|
45576
45720
|
var detectFileSync = (filepath, opts = {}) => {
|
|
45577
|
-
const
|
|
45721
|
+
const fs79 = (0, node_1.default)();
|
|
45578
45722
|
if (opts && opts.sampleSize) {
|
|
45579
|
-
const fd =
|
|
45723
|
+
const fd = fs79.openSync(filepath, "r");
|
|
45580
45724
|
let sample = Buffer.allocUnsafe(opts.sampleSize);
|
|
45581
|
-
const bytesRead =
|
|
45725
|
+
const bytesRead = fs79.readSync(fd, sample, 0, opts.sampleSize, opts.offset);
|
|
45582
45726
|
if (bytesRead < opts.sampleSize) {
|
|
45583
45727
|
sample = sample.subarray(0, bytesRead);
|
|
45584
45728
|
}
|
|
45585
|
-
|
|
45729
|
+
fs79.closeSync(fd);
|
|
45586
45730
|
return (0, exports2.detect)(sample);
|
|
45587
45731
|
}
|
|
45588
|
-
return (0, exports2.detect)(
|
|
45732
|
+
return (0, exports2.detect)(fs79.readFileSync(filepath));
|
|
45589
45733
|
};
|
|
45590
45734
|
exports2.detectFileSync = detectFileSync;
|
|
45591
45735
|
exports2.default = {
|
|
@@ -50098,7 +50242,7 @@ var require_Observable = __commonJS({
|
|
|
50098
50242
|
Observable2.prototype.forEach = function(next, promiseCtor) {
|
|
50099
50243
|
var _this = this;
|
|
50100
50244
|
promiseCtor = getPromiseCtor(promiseCtor);
|
|
50101
|
-
return new promiseCtor(function(
|
|
50245
|
+
return new promiseCtor(function(resolve66, reject) {
|
|
50102
50246
|
var subscriber = new Subscriber_1.SafeSubscriber({
|
|
50103
50247
|
next: function(value) {
|
|
50104
50248
|
try {
|
|
@@ -50109,7 +50253,7 @@ var require_Observable = __commonJS({
|
|
|
50109
50253
|
}
|
|
50110
50254
|
},
|
|
50111
50255
|
error: reject,
|
|
50112
|
-
complete:
|
|
50256
|
+
complete: resolve66
|
|
50113
50257
|
});
|
|
50114
50258
|
_this.subscribe(subscriber);
|
|
50115
50259
|
});
|
|
@@ -50131,14 +50275,14 @@ var require_Observable = __commonJS({
|
|
|
50131
50275
|
Observable2.prototype.toPromise = function(promiseCtor) {
|
|
50132
50276
|
var _this = this;
|
|
50133
50277
|
promiseCtor = getPromiseCtor(promiseCtor);
|
|
50134
|
-
return new promiseCtor(function(
|
|
50278
|
+
return new promiseCtor(function(resolve66, reject) {
|
|
50135
50279
|
var value;
|
|
50136
50280
|
_this.subscribe(function(x) {
|
|
50137
50281
|
return value = x;
|
|
50138
50282
|
}, function(err) {
|
|
50139
50283
|
return reject(err);
|
|
50140
50284
|
}, function() {
|
|
50141
|
-
return
|
|
50285
|
+
return resolve66(value);
|
|
50142
50286
|
});
|
|
50143
50287
|
});
|
|
50144
50288
|
};
|
|
@@ -52234,11 +52378,11 @@ var require_innerFrom = __commonJS({
|
|
|
52234
52378
|
"use strict";
|
|
52235
52379
|
var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P2, generator) {
|
|
52236
52380
|
function adopt(value) {
|
|
52237
|
-
return value instanceof P2 ? value : new P2(function(
|
|
52238
|
-
|
|
52381
|
+
return value instanceof P2 ? value : new P2(function(resolve66) {
|
|
52382
|
+
resolve66(value);
|
|
52239
52383
|
});
|
|
52240
52384
|
}
|
|
52241
|
-
return new (P2 || (P2 = Promise))(function(
|
|
52385
|
+
return new (P2 || (P2 = Promise))(function(resolve66, reject) {
|
|
52242
52386
|
function fulfilled(value) {
|
|
52243
52387
|
try {
|
|
52244
52388
|
step(generator.next(value));
|
|
@@ -52254,7 +52398,7 @@ var require_innerFrom = __commonJS({
|
|
|
52254
52398
|
}
|
|
52255
52399
|
}
|
|
52256
52400
|
function step(result) {
|
|
52257
|
-
result.done ?
|
|
52401
|
+
result.done ? resolve66(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
52258
52402
|
}
|
|
52259
52403
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
52260
52404
|
});
|
|
@@ -52336,14 +52480,14 @@ var require_innerFrom = __commonJS({
|
|
|
52336
52480
|
}, i);
|
|
52337
52481
|
function verb(n) {
|
|
52338
52482
|
i[n] = o[n] && function(v2) {
|
|
52339
|
-
return new Promise(function(
|
|
52340
|
-
v2 = o[n](v2), settle(
|
|
52483
|
+
return new Promise(function(resolve66, reject) {
|
|
52484
|
+
v2 = o[n](v2), settle(resolve66, reject, v2.done, v2.value);
|
|
52341
52485
|
});
|
|
52342
52486
|
};
|
|
52343
52487
|
}
|
|
52344
|
-
function settle(
|
|
52488
|
+
function settle(resolve66, reject, d, v2) {
|
|
52345
52489
|
Promise.resolve(v2).then(function(v3) {
|
|
52346
|
-
|
|
52490
|
+
resolve66({ value: v3, done: d });
|
|
52347
52491
|
}, reject);
|
|
52348
52492
|
}
|
|
52349
52493
|
};
|
|
@@ -52962,7 +53106,7 @@ var require_lastValueFrom = __commonJS({
|
|
|
52962
53106
|
var EmptyError_1 = require_EmptyError();
|
|
52963
53107
|
function lastValueFrom2(source, config2) {
|
|
52964
53108
|
var hasConfig = typeof config2 === "object";
|
|
52965
|
-
return new Promise(function(
|
|
53109
|
+
return new Promise(function(resolve66, reject) {
|
|
52966
53110
|
var _hasValue = false;
|
|
52967
53111
|
var _value;
|
|
52968
53112
|
source.subscribe({
|
|
@@ -52973,9 +53117,9 @@ var require_lastValueFrom = __commonJS({
|
|
|
52973
53117
|
error: reject,
|
|
52974
53118
|
complete: function() {
|
|
52975
53119
|
if (_hasValue) {
|
|
52976
|
-
|
|
53120
|
+
resolve66(_value);
|
|
52977
53121
|
} else if (hasConfig) {
|
|
52978
|
-
|
|
53122
|
+
resolve66(config2.defaultValue);
|
|
52979
53123
|
} else {
|
|
52980
53124
|
reject(new EmptyError_1.EmptyError());
|
|
52981
53125
|
}
|
|
@@ -52997,16 +53141,16 @@ var require_firstValueFrom = __commonJS({
|
|
|
52997
53141
|
var Subscriber_1 = require_Subscriber();
|
|
52998
53142
|
function firstValueFrom(source, config2) {
|
|
52999
53143
|
var hasConfig = typeof config2 === "object";
|
|
53000
|
-
return new Promise(function(
|
|
53144
|
+
return new Promise(function(resolve66, reject) {
|
|
53001
53145
|
var subscriber = new Subscriber_1.SafeSubscriber({
|
|
53002
53146
|
next: function(value) {
|
|
53003
|
-
|
|
53147
|
+
resolve66(value);
|
|
53004
53148
|
subscriber.unsubscribe();
|
|
53005
53149
|
},
|
|
53006
53150
|
error: reject,
|
|
53007
53151
|
complete: function() {
|
|
53008
53152
|
if (hasConfig) {
|
|
53009
|
-
|
|
53153
|
+
resolve66(config2.defaultValue);
|
|
53010
53154
|
} else {
|
|
53011
53155
|
reject(new EmptyError_1.EmptyError());
|
|
53012
53156
|
}
|
|
@@ -58798,14 +58942,14 @@ var require_run_async = __commonJS({
|
|
|
58798
58942
|
return function() {
|
|
58799
58943
|
var args = arguments;
|
|
58800
58944
|
var originalThis = this;
|
|
58801
|
-
var promise = new Promise(function(
|
|
58945
|
+
var promise = new Promise(function(resolve66, reject) {
|
|
58802
58946
|
var resolved = false;
|
|
58803
58947
|
const wrappedResolve = function(value) {
|
|
58804
58948
|
if (resolved) {
|
|
58805
58949
|
console.warn("Run-async promise already resolved.");
|
|
58806
58950
|
}
|
|
58807
58951
|
resolved = true;
|
|
58808
|
-
|
|
58952
|
+
resolve66(value);
|
|
58809
58953
|
};
|
|
58810
58954
|
var rejected = false;
|
|
58811
58955
|
const wrappedReject = function(value) {
|
|
@@ -58913,32 +59057,32 @@ __export(otel_hooks_exports, {
|
|
|
58913
59057
|
});
|
|
58914
59058
|
function getOtelHooksHome() {
|
|
58915
59059
|
if (process.env.HAR_OTEL_HOOKS_HOME) {
|
|
58916
|
-
return
|
|
59060
|
+
return path76.resolve(process.env.HAR_OTEL_HOOKS_HOME);
|
|
58917
59061
|
}
|
|
58918
|
-
return
|
|
59062
|
+
return path76.join(os22.homedir(), ".har", "otel-hooks");
|
|
58919
59063
|
}
|
|
58920
59064
|
function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
|
|
58921
|
-
return
|
|
59065
|
+
return path76.join(hooksHome, "otel_config.json");
|
|
58922
59066
|
}
|
|
58923
59067
|
function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
|
|
58924
|
-
return
|
|
59068
|
+
return path76.join(hooksHome, "run-otel-hook.sh");
|
|
58925
59069
|
}
|
|
58926
59070
|
function getOtelHooksStateDir(hooksHome = getOtelHooksHome()) {
|
|
58927
|
-
return
|
|
59071
|
+
return path76.join(hooksHome, "state");
|
|
58928
59072
|
}
|
|
58929
59073
|
function localOtelHookBin(hooksHome) {
|
|
58930
|
-
return
|
|
59074
|
+
return path76.join(hooksHome, "node_modules", ".bin", "otel-hook");
|
|
58931
59075
|
}
|
|
58932
59076
|
function installedPackageVersion(hooksHome) {
|
|
58933
59077
|
try {
|
|
58934
|
-
const pkgPath =
|
|
59078
|
+
const pkgPath = path76.join(
|
|
58935
59079
|
hooksHome,
|
|
58936
59080
|
"node_modules",
|
|
58937
59081
|
"@osfactory",
|
|
58938
59082
|
"otel-hook",
|
|
58939
59083
|
"package.json"
|
|
58940
59084
|
);
|
|
58941
|
-
const pkg = JSON.parse(
|
|
59085
|
+
const pkg = JSON.parse(fs68.readFileSync(pkgPath, "utf8"));
|
|
58942
59086
|
return typeof pkg.version === "string" ? pkg.version : null;
|
|
58943
59087
|
} catch {
|
|
58944
59088
|
return null;
|
|
@@ -58989,15 +59133,15 @@ function buildOtelHooksConfig(options) {
|
|
|
58989
59133
|
};
|
|
58990
59134
|
}
|
|
58991
59135
|
function writeOtelHooksConfig(config2, hooksHome = getOtelHooksHome()) {
|
|
58992
|
-
|
|
59136
|
+
fs68.mkdirSync(hooksHome, { recursive: true });
|
|
58993
59137
|
const configPath = getOtelHooksConfigPath(hooksHome);
|
|
58994
|
-
|
|
59138
|
+
fs68.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
|
|
58995
59139
|
`);
|
|
58996
59140
|
return configPath;
|
|
58997
59141
|
}
|
|
58998
59142
|
function writeOtelHooksWrapper(otelHookCommand, hooksHome = getOtelHooksHome()) {
|
|
58999
|
-
|
|
59000
|
-
|
|
59143
|
+
fs68.mkdirSync(hooksHome, { recursive: true });
|
|
59144
|
+
fs68.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
|
|
59001
59145
|
const wrapperPath = getOtelHooksWrapperPath(hooksHome);
|
|
59002
59146
|
const configPath = getOtelHooksConfigPath(hooksHome);
|
|
59003
59147
|
const stateDir = getOtelHooksStateDir(hooksHome);
|
|
@@ -59009,9 +59153,9 @@ exec "${otelHookCommand}" run \\
|
|
|
59009
59153
|
--state-dir "${stateDir}" \\
|
|
59010
59154
|
"$@"
|
|
59011
59155
|
`;
|
|
59012
|
-
|
|
59156
|
+
fs68.writeFileSync(wrapperPath, script, { mode: 493 });
|
|
59013
59157
|
try {
|
|
59014
|
-
|
|
59158
|
+
fs68.chmodSync(wrapperPath, 493);
|
|
59015
59159
|
} catch {
|
|
59016
59160
|
}
|
|
59017
59161
|
return wrapperPath;
|
|
@@ -59024,7 +59168,7 @@ function commandExists3(command2) {
|
|
|
59024
59168
|
}
|
|
59025
59169
|
function resolveOtelHookCommand(hooksHome) {
|
|
59026
59170
|
const local = localOtelHookBin(hooksHome);
|
|
59027
|
-
if (
|
|
59171
|
+
if (fs68.existsSync(local)) return local;
|
|
59028
59172
|
return null;
|
|
59029
59173
|
}
|
|
59030
59174
|
function resolveHooksInstaller(hooksHome) {
|
|
@@ -59039,7 +59183,7 @@ function resolveHooksInstaller(hooksHome) {
|
|
|
59039
59183
|
return candidates.find((candidate) => commandExists3(candidate.command)) ?? null;
|
|
59040
59184
|
}
|
|
59041
59185
|
function tryInstallPackage(hooksHome) {
|
|
59042
|
-
|
|
59186
|
+
fs68.mkdirSync(hooksHome, { recursive: true });
|
|
59043
59187
|
const installer = resolveHooksInstaller(hooksHome);
|
|
59044
59188
|
if (!installer) {
|
|
59045
59189
|
return {
|
|
@@ -59052,7 +59196,7 @@ function tryInstallPackage(hooksHome) {
|
|
|
59052
59196
|
encoding: "utf8",
|
|
59053
59197
|
timeout: 18e4
|
|
59054
59198
|
});
|
|
59055
|
-
if (result.status === 0 &&
|
|
59199
|
+
if (result.status === 0 && fs68.existsSync(localOtelHookBin(hooksHome))) {
|
|
59056
59200
|
return { ok: true, detail: described };
|
|
59057
59201
|
}
|
|
59058
59202
|
return {
|
|
@@ -59078,14 +59222,14 @@ function uninstallLegacyPythonHooks(hooksHome) {
|
|
|
59078
59222
|
}
|
|
59079
59223
|
function removeLegacyPythonArtifacts(hooksHome) {
|
|
59080
59224
|
const legacyPaths = [
|
|
59081
|
-
|
|
59082
|
-
|
|
59083
|
-
|
|
59225
|
+
path76.join(hooksHome, ".venv"),
|
|
59226
|
+
path76.join(hooksHome, "otel_config.yaml"),
|
|
59227
|
+
path76.join(hooksHome, "venv")
|
|
59084
59228
|
];
|
|
59085
59229
|
for (const target of legacyPaths) {
|
|
59086
59230
|
try {
|
|
59087
|
-
if (
|
|
59088
|
-
|
|
59231
|
+
if (fs68.existsSync(target)) {
|
|
59232
|
+
fs68.rmSync(target, { recursive: true, force: true });
|
|
59089
59233
|
}
|
|
59090
59234
|
} catch {
|
|
59091
59235
|
}
|
|
@@ -59126,10 +59270,10 @@ function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
|
|
|
59126
59270
|
};
|
|
59127
59271
|
}
|
|
59128
59272
|
function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
|
|
59129
|
-
if (!
|
|
59273
|
+
if (!fs68.existsSync(filePath)) return false;
|
|
59130
59274
|
let raw;
|
|
59131
59275
|
try {
|
|
59132
|
-
raw =
|
|
59276
|
+
raw = fs68.readFileSync(filePath, "utf8");
|
|
59133
59277
|
} catch {
|
|
59134
59278
|
return false;
|
|
59135
59279
|
}
|
|
@@ -59176,15 +59320,15 @@ function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
|
|
|
59176
59320
|
return changed;
|
|
59177
59321
|
};
|
|
59178
59322
|
if (!walk(parsed)) return false;
|
|
59179
|
-
|
|
59323
|
+
fs68.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
59180
59324
|
`);
|
|
59181
59325
|
return true;
|
|
59182
59326
|
}
|
|
59183
59327
|
function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
59184
|
-
if (!
|
|
59328
|
+
if (!fs68.existsSync(filePath)) return false;
|
|
59185
59329
|
let raw;
|
|
59186
59330
|
try {
|
|
59187
|
-
raw =
|
|
59331
|
+
raw = fs68.readFileSync(filePath, "utf8");
|
|
59188
59332
|
} catch {
|
|
59189
59333
|
return false;
|
|
59190
59334
|
}
|
|
@@ -59219,21 +59363,21 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
|
59219
59363
|
}
|
|
59220
59364
|
}
|
|
59221
59365
|
if (!changed) return false;
|
|
59222
|
-
|
|
59366
|
+
fs68.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
59223
59367
|
`);
|
|
59224
59368
|
return true;
|
|
59225
59369
|
}
|
|
59226
59370
|
function rewriteKnownHookRegistrations(wrapperPath) {
|
|
59227
59371
|
const home = os22.homedir();
|
|
59228
59372
|
const candidates = [
|
|
59229
|
-
|
|
59230
|
-
|
|
59231
|
-
|
|
59373
|
+
path76.join(home, ".cursor", "hooks.json"),
|
|
59374
|
+
path76.join(home, ".claude", "settings.json"),
|
|
59375
|
+
path76.join(home, ".codex", "hooks.json")
|
|
59232
59376
|
];
|
|
59233
59377
|
for (const filePath of candidates) {
|
|
59234
59378
|
try {
|
|
59235
59379
|
rewriteHookCommandsToWrapper(filePath, wrapperPath);
|
|
59236
|
-
if (filePath.endsWith(`${
|
|
59380
|
+
if (filePath.endsWith(`${path76.sep}.cursor${path76.sep}hooks.json`)) {
|
|
59237
59381
|
pruneLegacyCursorHookEvents(filePath, wrapperPath);
|
|
59238
59382
|
}
|
|
59239
59383
|
} catch {
|
|
@@ -59249,7 +59393,7 @@ function ensureOtelHooks(options) {
|
|
|
59249
59393
|
const hooksHome = getOtelHooksHome();
|
|
59250
59394
|
const errors = [];
|
|
59251
59395
|
const providersSetup = [];
|
|
59252
|
-
|
|
59396
|
+
fs68.mkdirSync(hooksHome, { recursive: true });
|
|
59253
59397
|
let otelHookCommand = resolveOtelHookCommand(hooksHome);
|
|
59254
59398
|
const needsInstall = !otelHookCommand || installedPackageVersion(hooksHome) !== pinnedVersion();
|
|
59255
59399
|
if (needsInstall) {
|
|
@@ -59343,14 +59487,14 @@ function ensureOtelHooks(options) {
|
|
|
59343
59487
|
function disableOtelHooksExport() {
|
|
59344
59488
|
return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
|
|
59345
59489
|
}
|
|
59346
|
-
var import_child_process19,
|
|
59490
|
+
var import_child_process19, fs68, os22, path76, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
|
|
59347
59491
|
var init_otel_hooks = __esm({
|
|
59348
59492
|
"src/core/otel-hooks.ts"() {
|
|
59349
59493
|
"use strict";
|
|
59350
59494
|
import_child_process19 = require("child_process");
|
|
59351
|
-
|
|
59495
|
+
fs68 = __toESM(require("fs"));
|
|
59352
59496
|
os22 = __toESM(require("os"));
|
|
59353
|
-
|
|
59497
|
+
path76 = __toESM(require("path"));
|
|
59354
59498
|
init_control_config();
|
|
59355
59499
|
init_telemetry_config();
|
|
59356
59500
|
OTEL_HOOKS_PACKAGE = "@osfactory/otel-hook@0.2.0";
|
|
@@ -62325,7 +62469,7 @@ var require_compile = __commonJS({
|
|
|
62325
62469
|
const schOrFunc = root.refs[ref];
|
|
62326
62470
|
if (schOrFunc)
|
|
62327
62471
|
return schOrFunc;
|
|
62328
|
-
let _sch =
|
|
62472
|
+
let _sch = resolve66.call(this, root, ref);
|
|
62329
62473
|
if (_sch === void 0) {
|
|
62330
62474
|
const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
|
|
62331
62475
|
const { schemaId } = this.opts;
|
|
@@ -62352,7 +62496,7 @@ var require_compile = __commonJS({
|
|
|
62352
62496
|
function sameSchemaEnv(s1, s2) {
|
|
62353
62497
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
62354
62498
|
}
|
|
62355
|
-
function
|
|
62499
|
+
function resolve66(root, ref) {
|
|
62356
62500
|
let sch;
|
|
62357
62501
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
62358
62502
|
ref = sch;
|
|
@@ -62570,8 +62714,8 @@ var require_utils2 = __commonJS({
|
|
|
62570
62714
|
}
|
|
62571
62715
|
return ind;
|
|
62572
62716
|
}
|
|
62573
|
-
function removeDotSegments(
|
|
62574
|
-
let input =
|
|
62717
|
+
function removeDotSegments(path97) {
|
|
62718
|
+
let input = path97;
|
|
62575
62719
|
const output = [];
|
|
62576
62720
|
let nextSlash = -1;
|
|
62577
62721
|
let len = 0;
|
|
@@ -62823,8 +62967,8 @@ var require_schemes = __commonJS({
|
|
|
62823
62967
|
wsComponent.secure = void 0;
|
|
62824
62968
|
}
|
|
62825
62969
|
if (wsComponent.resourceName) {
|
|
62826
|
-
const [
|
|
62827
|
-
wsComponent.path =
|
|
62970
|
+
const [path97, query] = wsComponent.resourceName.split("?");
|
|
62971
|
+
wsComponent.path = path97 && path97 !== "/" ? path97 : void 0;
|
|
62828
62972
|
wsComponent.query = query;
|
|
62829
62973
|
wsComponent.resourceName = void 0;
|
|
62830
62974
|
}
|
|
@@ -62983,55 +63127,55 @@ var require_fast_uri = __commonJS({
|
|
|
62983
63127
|
}
|
|
62984
63128
|
return uri;
|
|
62985
63129
|
}
|
|
62986
|
-
function
|
|
63130
|
+
function resolve66(baseURI, relativeURI, options) {
|
|
62987
63131
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
62988
63132
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
62989
63133
|
schemelessOptions.skipEscape = true;
|
|
62990
63134
|
return serialize(resolved, schemelessOptions);
|
|
62991
63135
|
}
|
|
62992
|
-
function resolveComponent(base,
|
|
63136
|
+
function resolveComponent(base, relative6, options, skipNormalization) {
|
|
62993
63137
|
const target = {};
|
|
62994
63138
|
if (!skipNormalization) {
|
|
62995
63139
|
base = parse4(serialize(base, options), options);
|
|
62996
|
-
|
|
63140
|
+
relative6 = parse4(serialize(relative6, options), options);
|
|
62997
63141
|
}
|
|
62998
63142
|
options = options || {};
|
|
62999
|
-
if (!options.tolerant &&
|
|
63000
|
-
target.scheme =
|
|
63001
|
-
target.userinfo =
|
|
63002
|
-
target.host =
|
|
63003
|
-
target.port =
|
|
63004
|
-
target.path = removeDotSegments(
|
|
63005
|
-
target.query =
|
|
63143
|
+
if (!options.tolerant && relative6.scheme) {
|
|
63144
|
+
target.scheme = relative6.scheme;
|
|
63145
|
+
target.userinfo = relative6.userinfo;
|
|
63146
|
+
target.host = relative6.host;
|
|
63147
|
+
target.port = relative6.port;
|
|
63148
|
+
target.path = removeDotSegments(relative6.path || "");
|
|
63149
|
+
target.query = relative6.query;
|
|
63006
63150
|
} else {
|
|
63007
|
-
if (
|
|
63008
|
-
target.userinfo =
|
|
63009
|
-
target.host =
|
|
63010
|
-
target.port =
|
|
63011
|
-
target.path = removeDotSegments(
|
|
63012
|
-
target.query =
|
|
63151
|
+
if (relative6.userinfo !== void 0 || relative6.host !== void 0 || relative6.port !== void 0) {
|
|
63152
|
+
target.userinfo = relative6.userinfo;
|
|
63153
|
+
target.host = relative6.host;
|
|
63154
|
+
target.port = relative6.port;
|
|
63155
|
+
target.path = removeDotSegments(relative6.path || "");
|
|
63156
|
+
target.query = relative6.query;
|
|
63013
63157
|
} else {
|
|
63014
|
-
if (!
|
|
63158
|
+
if (!relative6.path) {
|
|
63015
63159
|
target.path = base.path;
|
|
63016
|
-
if (
|
|
63017
|
-
target.query =
|
|
63160
|
+
if (relative6.query !== void 0) {
|
|
63161
|
+
target.query = relative6.query;
|
|
63018
63162
|
} else {
|
|
63019
63163
|
target.query = base.query;
|
|
63020
63164
|
}
|
|
63021
63165
|
} else {
|
|
63022
|
-
if (
|
|
63023
|
-
target.path = removeDotSegments(
|
|
63166
|
+
if (relative6.path[0] === "/") {
|
|
63167
|
+
target.path = removeDotSegments(relative6.path);
|
|
63024
63168
|
} else {
|
|
63025
63169
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
63026
|
-
target.path = "/" +
|
|
63170
|
+
target.path = "/" + relative6.path;
|
|
63027
63171
|
} else if (!base.path) {
|
|
63028
|
-
target.path =
|
|
63172
|
+
target.path = relative6.path;
|
|
63029
63173
|
} else {
|
|
63030
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
63174
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative6.path;
|
|
63031
63175
|
}
|
|
63032
63176
|
target.path = removeDotSegments(target.path);
|
|
63033
63177
|
}
|
|
63034
|
-
target.query =
|
|
63178
|
+
target.query = relative6.query;
|
|
63035
63179
|
}
|
|
63036
63180
|
target.userinfo = base.userinfo;
|
|
63037
63181
|
target.host = base.host;
|
|
@@ -63039,7 +63183,7 @@ var require_fast_uri = __commonJS({
|
|
|
63039
63183
|
}
|
|
63040
63184
|
target.scheme = base.scheme;
|
|
63041
63185
|
}
|
|
63042
|
-
target.fragment =
|
|
63186
|
+
target.fragment = relative6.fragment;
|
|
63043
63187
|
return target;
|
|
63044
63188
|
}
|
|
63045
63189
|
function equal(uriA, uriB, options) {
|
|
@@ -63241,7 +63385,7 @@ var require_fast_uri = __commonJS({
|
|
|
63241
63385
|
var fastUri = {
|
|
63242
63386
|
SCHEMES,
|
|
63243
63387
|
normalize: normalize3,
|
|
63244
|
-
resolve:
|
|
63388
|
+
resolve: resolve66,
|
|
63245
63389
|
resolveComponent,
|
|
63246
63390
|
equal,
|
|
63247
63391
|
serialize,
|
|
@@ -66217,12 +66361,12 @@ var require_dist = __commonJS({
|
|
|
66217
66361
|
throw new Error(`Unknown format "${name}"`);
|
|
66218
66362
|
return f;
|
|
66219
66363
|
};
|
|
66220
|
-
function addFormats(ajv, list,
|
|
66364
|
+
function addFormats(ajv, list, fs79, exportName) {
|
|
66221
66365
|
var _a2;
|
|
66222
66366
|
var _b2;
|
|
66223
66367
|
(_a2 = (_b2 = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
66224
66368
|
for (const f of list)
|
|
66225
|
-
ajv.addFormat(f,
|
|
66369
|
+
ajv.addFormat(f, fs79[f]);
|
|
66226
66370
|
}
|
|
66227
66371
|
module2.exports = exports2 = formatsPlugin;
|
|
66228
66372
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -67506,11 +67650,11 @@ var parser = new YargsParser({
|
|
|
67506
67650
|
resolve: import_path2.resolve,
|
|
67507
67651
|
// TODO: figure out a way to combine ESM and CJS coverage, such that
|
|
67508
67652
|
// we can exercise all the lines below:
|
|
67509
|
-
require: (
|
|
67653
|
+
require: (path97) => {
|
|
67510
67654
|
if (typeof require !== "undefined") {
|
|
67511
|
-
return require(
|
|
67512
|
-
} else if (
|
|
67513
|
-
return JSON.parse((0, import_fs2.readFileSync)(
|
|
67655
|
+
return require(path97);
|
|
67656
|
+
} else if (path97.match(/\.json$/)) {
|
|
67657
|
+
return JSON.parse((0, import_fs2.readFileSync)(path97, "utf8"));
|
|
67514
67658
|
} else {
|
|
67515
67659
|
throw Error("only .json config files are supported in ESM");
|
|
67516
67660
|
}
|
|
@@ -70036,12 +70180,12 @@ var YargsInstance = class {
|
|
|
70036
70180
|
async getCompletion(args, done) {
|
|
70037
70181
|
argsert("<array> [function]", [args, done], arguments.length);
|
|
70038
70182
|
if (!done) {
|
|
70039
|
-
return new Promise((
|
|
70183
|
+
return new Promise((resolve66, reject) => {
|
|
70040
70184
|
__classPrivateFieldGet(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
|
|
70041
70185
|
if (err)
|
|
70042
70186
|
reject(err);
|
|
70043
70187
|
else
|
|
70044
|
-
|
|
70188
|
+
resolve66(completions);
|
|
70045
70189
|
});
|
|
70046
70190
|
});
|
|
70047
70191
|
} else {
|
|
@@ -71291,16 +71435,16 @@ async function handleAgentSkills(options) {
|
|
|
71291
71435
|
}
|
|
71292
71436
|
async function askYesNo(question) {
|
|
71293
71437
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
71294
|
-
return new Promise((
|
|
71438
|
+
return new Promise((resolve66) => {
|
|
71295
71439
|
process.stderr.write(`${question} `);
|
|
71296
71440
|
rl.once("line", (answer) => {
|
|
71297
71441
|
rl.close();
|
|
71298
71442
|
const trimmed = answer.trim();
|
|
71299
71443
|
if (trimmed === "") {
|
|
71300
|
-
|
|
71444
|
+
resolve66(true);
|
|
71301
71445
|
return;
|
|
71302
71446
|
}
|
|
71303
|
-
|
|
71447
|
+
resolve66(/^y(es)?$/i.test(trimmed));
|
|
71304
71448
|
});
|
|
71305
71449
|
});
|
|
71306
71450
|
}
|
|
@@ -71380,8 +71524,8 @@ function handleRemove(argv) {
|
|
|
71380
71524
|
}
|
|
71381
71525
|
|
|
71382
71526
|
// src/cli/commands/env.ts
|
|
71383
|
-
var
|
|
71384
|
-
var
|
|
71527
|
+
var fs71 = __toESM(require("fs"));
|
|
71528
|
+
var path80 = __toESM(require("path"));
|
|
71385
71529
|
|
|
71386
71530
|
// src/cli/finish-command.ts
|
|
71387
71531
|
init_sync_context();
|
|
@@ -71391,8 +71535,8 @@ async function finishCommand(code) {
|
|
|
71391
71535
|
}
|
|
71392
71536
|
|
|
71393
71537
|
// src/core/harness.ts
|
|
71394
|
-
var
|
|
71395
|
-
var
|
|
71538
|
+
var fs65 = __toESM(require("fs"));
|
|
71539
|
+
var path72 = __toESM(require("path"));
|
|
71396
71540
|
|
|
71397
71541
|
// src/harness/generator.ts
|
|
71398
71542
|
var fs48 = __toESM(require("fs"));
|
|
@@ -72901,13 +73045,13 @@ var PromisePolyfill = class extends Promise {
|
|
|
72901
73045
|
// Available starting from Node 22
|
|
72902
73046
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
|
72903
73047
|
static withResolver() {
|
|
72904
|
-
let
|
|
73048
|
+
let resolve66;
|
|
72905
73049
|
let reject;
|
|
72906
73050
|
const promise = new Promise((res, rej) => {
|
|
72907
|
-
|
|
73051
|
+
resolve66 = res;
|
|
72908
73052
|
reject = rej;
|
|
72909
73053
|
});
|
|
72910
|
-
return { promise, resolve:
|
|
73054
|
+
return { promise, resolve: resolve66, reject };
|
|
72911
73055
|
}
|
|
72912
73056
|
};
|
|
72913
73057
|
|
|
@@ -72941,7 +73085,7 @@ function createPrompt(view) {
|
|
|
72941
73085
|
output
|
|
72942
73086
|
});
|
|
72943
73087
|
const screen = new ScreenManager(rl);
|
|
72944
|
-
const { promise, resolve:
|
|
73088
|
+
const { promise, resolve: resolve66, reject } = PromisePolyfill.withResolver();
|
|
72945
73089
|
const cancel = () => reject(new CancelPromptError());
|
|
72946
73090
|
if (signal) {
|
|
72947
73091
|
const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
|
|
@@ -72968,7 +73112,7 @@ function createPrompt(view) {
|
|
|
72968
73112
|
cycle(() => {
|
|
72969
73113
|
try {
|
|
72970
73114
|
const nextView = view(config2, (value) => {
|
|
72971
|
-
setImmediate(() =>
|
|
73115
|
+
setImmediate(() => resolve66(value));
|
|
72972
73116
|
});
|
|
72973
73117
|
if (nextView === void 0) {
|
|
72974
73118
|
const callerFilename = callSites[1]?.getFileName();
|
|
@@ -74277,9 +74421,9 @@ var import_rxjs = __toESM(require_cjs(), 1);
|
|
|
74277
74421
|
var import_run_async = __toESM(require_run_async(), 1);
|
|
74278
74422
|
var import_mute_stream2 = __toESM(require_lib(), 1);
|
|
74279
74423
|
var _ = {
|
|
74280
|
-
set: (obj,
|
|
74424
|
+
set: (obj, path97 = "", value) => {
|
|
74281
74425
|
let pointer = obj;
|
|
74282
|
-
|
|
74426
|
+
path97.split(".").forEach((key, index, arr) => {
|
|
74283
74427
|
if (key === "__proto__" || key === "constructor")
|
|
74284
74428
|
return;
|
|
74285
74429
|
if (index === arr.length - 1) {
|
|
@@ -74290,8 +74434,8 @@ var _ = {
|
|
|
74290
74434
|
pointer = pointer[key];
|
|
74291
74435
|
});
|
|
74292
74436
|
},
|
|
74293
|
-
get: (obj,
|
|
74294
|
-
const travel = (regexp) => String.prototype.split.call(
|
|
74437
|
+
get: (obj, path97 = "", defaultValue) => {
|
|
74438
|
+
const travel = (regexp) => String.prototype.split.call(path97, regexp).filter(Boolean).reduce(
|
|
74295
74439
|
// @ts-expect-error implicit any on res[key]
|
|
74296
74440
|
(res, key) => res == null ? res : res[key],
|
|
74297
74441
|
obj
|
|
@@ -74409,7 +74553,7 @@ var PromptsRunner = class {
|
|
|
74409
74553
|
throw new Error(`Prompt for type ${question.type} not found`);
|
|
74410
74554
|
}
|
|
74411
74555
|
let cleanupSignal;
|
|
74412
|
-
const promptFn = isPromptConstructor(prompt2) ? (q, opt) => new Promise((
|
|
74556
|
+
const promptFn = isPromptConstructor(prompt2) ? (q, opt) => new Promise((resolve66, reject) => {
|
|
74413
74557
|
const { signal: signal2 } = opt;
|
|
74414
74558
|
if (signal2.aborted) {
|
|
74415
74559
|
reject(new AbortPromptError({ cause: signal2.reason }));
|
|
@@ -74446,7 +74590,7 @@ var PromptsRunner = class {
|
|
|
74446
74590
|
signal2.removeEventListener("abort", abort);
|
|
74447
74591
|
cleanupSignal = void 0;
|
|
74448
74592
|
};
|
|
74449
|
-
activePrompt.run().then(
|
|
74593
|
+
activePrompt.run().then(resolve66, reject).finally(cleanup);
|
|
74450
74594
|
}) : prompt2;
|
|
74451
74595
|
let cleanupModuleSignal;
|
|
74452
74596
|
const { signal: moduleSignal } = this.opt;
|
|
@@ -75418,15 +75562,21 @@ function harnessExists(repoPath) {
|
|
|
75418
75562
|
return fs53.existsSync(`${repoPath}/.har/stages.json`);
|
|
75419
75563
|
}
|
|
75420
75564
|
|
|
75421
|
-
// src/harness/
|
|
75565
|
+
// src/harness/bundle-resolve.ts
|
|
75422
75566
|
var import_child_process16 = require("child_process");
|
|
75423
75567
|
var fs54 = __toESM(require("fs"));
|
|
75424
75568
|
var os20 = __toESM(require("os"));
|
|
75425
75569
|
var path60 = __toESM(require("path"));
|
|
75426
75570
|
init_paths();
|
|
75427
|
-
|
|
75428
|
-
|
|
75429
|
-
|
|
75571
|
+
function findManifestPath(dir, config2) {
|
|
75572
|
+
for (const name of config2.manifestFiles) {
|
|
75573
|
+
const candidate = path60.join(dir, name);
|
|
75574
|
+
if (fs54.existsSync(candidate)) return candidate;
|
|
75575
|
+
}
|
|
75576
|
+
return null;
|
|
75577
|
+
}
|
|
75578
|
+
function hasManifest(dir, config2) {
|
|
75579
|
+
return findManifestPath(dir, config2) !== null;
|
|
75430
75580
|
}
|
|
75431
75581
|
function readPackageVersion(dir) {
|
|
75432
75582
|
const pkgPath = path60.join(dir, "package.json");
|
|
@@ -75438,9 +75588,9 @@ function readPackageVersion(dir) {
|
|
|
75438
75588
|
return void 0;
|
|
75439
75589
|
}
|
|
75440
75590
|
}
|
|
75441
|
-
function readManifestId(dir) {
|
|
75442
|
-
const manifestPath =
|
|
75443
|
-
if (!
|
|
75591
|
+
function readManifestId(dir, config2) {
|
|
75592
|
+
const manifestPath = findManifestPath(dir, config2);
|
|
75593
|
+
if (!manifestPath) return void 0;
|
|
75444
75594
|
try {
|
|
75445
75595
|
const raw = JSON.parse(fs54.readFileSync(manifestPath, "utf8"));
|
|
75446
75596
|
return typeof raw.id === "string" ? raw.id : void 0;
|
|
@@ -75459,47 +75609,48 @@ function looksLikeNpm(spec) {
|
|
|
75459
75609
|
if (spec.includes("/") && !spec.startsWith("@")) return false;
|
|
75460
75610
|
return /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@.+)?$/i.test(spec);
|
|
75461
75611
|
}
|
|
75462
|
-
function resolveBundledDir(pluginId) {
|
|
75463
|
-
const dir = path60.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
75464
|
-
return hasManifest(dir) ? dir : null;
|
|
75465
|
-
}
|
|
75466
75612
|
function expandHome(p) {
|
|
75467
75613
|
if (p.startsWith("~/")) return path60.join(os20.homedir(), p.slice(2));
|
|
75468
75614
|
if (p === "~") return os20.homedir();
|
|
75469
75615
|
return p;
|
|
75470
75616
|
}
|
|
75471
|
-
function
|
|
75472
|
-
|
|
75473
|
-
|
|
75617
|
+
function makeTempDir(prefix) {
|
|
75618
|
+
return fs54.mkdtempSync(path60.join(os20.tmpdir(), prefix));
|
|
75619
|
+
}
|
|
75620
|
+
function manifestNames(config2) {
|
|
75621
|
+
return config2.manifestFiles.join(" or ");
|
|
75622
|
+
}
|
|
75623
|
+
function resolveTemplatesBundleDir(id, config2) {
|
|
75624
|
+
const dir = path60.join(resolveTemplatesDir(), config2.templatesSubdir, id);
|
|
75625
|
+
return hasManifest(dir, config2) ? dir : null;
|
|
75626
|
+
}
|
|
75627
|
+
function resolveLocalDir(id, repoPath, config2) {
|
|
75628
|
+
const dir = path60.resolve(repoPath, config2.localDir, id);
|
|
75629
|
+
return hasManifest(dir, config2) ? dir : null;
|
|
75474
75630
|
}
|
|
75475
|
-
function
|
|
75631
|
+
function isLocalBundleDir(dir, repoPath, config2) {
|
|
75632
|
+
return path60.dirname(dir) === path60.resolve(repoPath, config2.localDir);
|
|
75633
|
+
}
|
|
75634
|
+
function resolvePathSpec(spec, repoPath, config2) {
|
|
75476
75635
|
const raw = spec.startsWith("file:") ? spec.slice("file:".length) : spec;
|
|
75477
75636
|
const dir = path60.resolve(expandHome(raw));
|
|
75478
75637
|
if (!fs54.existsSync(dir) || !fs54.statSync(dir).isDirectory()) {
|
|
75479
|
-
throw new Error(
|
|
75638
|
+
throw new Error(`${config2.label} path not found: ${spec}`);
|
|
75480
75639
|
}
|
|
75481
|
-
if (!hasManifest(dir)) {
|
|
75482
|
-
throw new Error(`No
|
|
75640
|
+
if (!hasManifest(dir, config2)) {
|
|
75641
|
+
throw new Error(`No ${manifestNames(config2)} in ${dir}`);
|
|
75483
75642
|
}
|
|
75484
|
-
const id = readManifestId(dir) ?? path60.basename(dir);
|
|
75485
75643
|
return {
|
|
75486
|
-
id,
|
|
75487
|
-
kind:
|
|
75644
|
+
id: readManifestId(dir, config2) ?? path60.basename(dir),
|
|
75645
|
+
kind: isLocalBundleDir(dir, repoPath, config2) ? "local" : "path",
|
|
75488
75646
|
dir,
|
|
75489
75647
|
spec,
|
|
75490
75648
|
version: readPackageVersion(dir),
|
|
75491
75649
|
cleanupDirs: []
|
|
75492
75650
|
};
|
|
75493
75651
|
}
|
|
75494
|
-
function
|
|
75495
|
-
const
|
|
75496
|
-
return hasManifest(dir) ? dir : null;
|
|
75497
|
-
}
|
|
75498
|
-
function makeTempDir(prefix) {
|
|
75499
|
-
return fs54.mkdtempSync(path60.join(os20.tmpdir(), prefix));
|
|
75500
|
-
}
|
|
75501
|
-
function resolveNpmSpec(spec) {
|
|
75502
|
-
const tmp = makeTempDir("har-plugin-npm-");
|
|
75652
|
+
function resolveNpmSpec(spec, config2) {
|
|
75653
|
+
const tmp = makeTempDir(`har-${config2.label}-npm-`);
|
|
75503
75654
|
const cleanupDirs = [tmp];
|
|
75504
75655
|
try {
|
|
75505
75656
|
(0, import_child_process16.execFileSync)("npm", ["pack", spec, "--pack-destination", tmp], {
|
|
@@ -75517,20 +75668,18 @@ function resolveNpmSpec(spec) {
|
|
|
75517
75668
|
encoding: "utf8",
|
|
75518
75669
|
stdio: ["ignore", "pipe", "pipe"]
|
|
75519
75670
|
});
|
|
75520
|
-
|
|
75521
|
-
|
|
75522
|
-
|
|
75523
|
-
const nested = fs54.readdirSync(extractDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path60.join(extractDir, e.name)).find((d) => hasManifest(d));
|
|
75671
|
+
let dir = path60.join(extractDir, "package");
|
|
75672
|
+
if (!hasManifest(dir, config2)) {
|
|
75673
|
+
const nested = fs54.readdirSync(extractDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path60.join(extractDir, e.name)).find((d) => hasManifest(d, config2));
|
|
75524
75674
|
if (!nested) {
|
|
75525
75675
|
throw new Error(
|
|
75526
|
-
`npm package ${spec} has no
|
|
75676
|
+
`npm package ${spec} has no ${manifestNames(config2)} (not a HAR ${config2.label} bundle)`
|
|
75527
75677
|
);
|
|
75528
75678
|
}
|
|
75529
75679
|
dir = nested;
|
|
75530
75680
|
}
|
|
75531
|
-
const id = readManifestId(dir) ?? spec.replace(/^@/, "").replace(/[/:].*/g, "");
|
|
75532
75681
|
return {
|
|
75533
|
-
id,
|
|
75682
|
+
id: readManifestId(dir, config2) ?? spec.replace(/^@/, "").replace(/[/:].*/g, ""),
|
|
75534
75683
|
kind: "npm",
|
|
75535
75684
|
dir,
|
|
75536
75685
|
spec,
|
|
@@ -75542,11 +75691,11 @@ function resolveNpmSpec(spec) {
|
|
|
75542
75691
|
fs54.rmSync(d, { recursive: true, force: true });
|
|
75543
75692
|
}
|
|
75544
75693
|
const message = err instanceof Error ? err.message : String(err);
|
|
75545
|
-
throw new Error(`Failed to install
|
|
75694
|
+
throw new Error(`Failed to install ${config2.label} from npm (${spec}): ${message}`);
|
|
75546
75695
|
}
|
|
75547
75696
|
}
|
|
75548
|
-
function resolveGitSpec(spec) {
|
|
75549
|
-
const tmp = makeTempDir(
|
|
75697
|
+
function resolveGitSpec(spec, config2) {
|
|
75698
|
+
const tmp = makeTempDir(`har-${config2.label}-git-`);
|
|
75550
75699
|
const cleanupDirs = [tmp];
|
|
75551
75700
|
const cloneDir = path60.join(tmp, "repo");
|
|
75552
75701
|
try {
|
|
@@ -75566,19 +75715,20 @@ function resolveGitSpec(spec) {
|
|
|
75566
75715
|
timeout: 18e4
|
|
75567
75716
|
});
|
|
75568
75717
|
let dir = cloneDir;
|
|
75569
|
-
if (!hasManifest(dir)) {
|
|
75570
|
-
const
|
|
75571
|
-
if (fs54.existsSync(
|
|
75572
|
-
const child = fs54.readdirSync(
|
|
75718
|
+
if (!hasManifest(dir, config2)) {
|
|
75719
|
+
const nestedRoot = path60.join(cloneDir, config2.gitNestedDir);
|
|
75720
|
+
if (fs54.existsSync(nestedRoot)) {
|
|
75721
|
+
const child = fs54.readdirSync(nestedRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path60.join(nestedRoot, e.name)).find((d) => hasManifest(d, config2));
|
|
75573
75722
|
if (child) dir = child;
|
|
75574
75723
|
}
|
|
75575
75724
|
}
|
|
75576
|
-
if (!hasManifest(dir)) {
|
|
75577
|
-
throw new Error(
|
|
75725
|
+
if (!hasManifest(dir, config2)) {
|
|
75726
|
+
throw new Error(
|
|
75727
|
+
`Git repo ${spec} has no ${manifestNames(config2)} (not a HAR ${config2.label} bundle)`
|
|
75728
|
+
);
|
|
75578
75729
|
}
|
|
75579
|
-
const id = readManifestId(dir) ?? path60.basename(url.replace(/\.git$/, ""));
|
|
75580
75730
|
return {
|
|
75581
|
-
id,
|
|
75731
|
+
id: readManifestId(dir, config2) ?? path60.basename(url.replace(/\.git$/, "")),
|
|
75582
75732
|
kind: "git",
|
|
75583
75733
|
dir,
|
|
75584
75734
|
spec,
|
|
@@ -75590,21 +75740,21 @@ function resolveGitSpec(spec) {
|
|
|
75590
75740
|
fs54.rmSync(d, { recursive: true, force: true });
|
|
75591
75741
|
}
|
|
75592
75742
|
const message = err instanceof Error ? err.message : String(err);
|
|
75593
|
-
throw new Error(`Failed to install
|
|
75743
|
+
throw new Error(`Failed to install ${config2.label} from git (${spec}): ${message}`);
|
|
75594
75744
|
}
|
|
75595
75745
|
}
|
|
75596
|
-
function
|
|
75746
|
+
function resolveBundleSource(spec, repoPath, config2) {
|
|
75597
75747
|
const trimmed = spec.trim();
|
|
75598
75748
|
if (!trimmed) {
|
|
75599
|
-
throw new Error(
|
|
75749
|
+
throw new Error(`${config2.label} spec is empty`);
|
|
75600
75750
|
}
|
|
75601
75751
|
if (looksLikePath(trimmed)) {
|
|
75602
|
-
return resolvePathSpec(trimmed, repoPath);
|
|
75752
|
+
return resolvePathSpec(trimmed, repoPath, config2);
|
|
75603
75753
|
}
|
|
75604
75754
|
if (looksLikeGit(trimmed)) {
|
|
75605
|
-
return resolveGitSpec(trimmed);
|
|
75755
|
+
return resolveGitSpec(trimmed, config2);
|
|
75606
75756
|
}
|
|
75607
|
-
const bundled =
|
|
75757
|
+
const bundled = resolveTemplatesBundleDir(trimmed, config2);
|
|
75608
75758
|
if (bundled) {
|
|
75609
75759
|
return {
|
|
75610
75760
|
id: trimmed,
|
|
@@ -75615,10 +75765,10 @@ function resolvePluginSource(spec, repoPath = ".") {
|
|
|
75615
75765
|
cleanupDirs: []
|
|
75616
75766
|
};
|
|
75617
75767
|
}
|
|
75618
|
-
const local = resolveLocalDir(trimmed, repoPath);
|
|
75768
|
+
const local = resolveLocalDir(trimmed, repoPath, config2);
|
|
75619
75769
|
if (local) {
|
|
75620
75770
|
return {
|
|
75621
|
-
id: readManifestId(local) ?? trimmed,
|
|
75771
|
+
id: readManifestId(local, config2) ?? trimmed,
|
|
75622
75772
|
kind: "local",
|
|
75623
75773
|
dir: local,
|
|
75624
75774
|
spec: trimmed,
|
|
@@ -75626,23 +75776,54 @@ function resolvePluginSource(spec, repoPath = ".") {
|
|
|
75626
75776
|
cleanupDirs: []
|
|
75627
75777
|
};
|
|
75628
75778
|
}
|
|
75629
|
-
|
|
75630
|
-
return resolveNpmSpec(trimmed);
|
|
75631
|
-
}
|
|
75779
|
+
const hint = config2.unknownHint?.(repoPath) ?? "";
|
|
75632
75780
|
if (looksLikeNpm(trimmed)) {
|
|
75633
75781
|
try {
|
|
75634
|
-
return resolveNpmSpec(trimmed);
|
|
75782
|
+
return resolveNpmSpec(trimmed, config2);
|
|
75635
75783
|
} catch (npmErr) {
|
|
75784
|
+
if (trimmed.includes("@") || trimmed.includes("/")) throw npmErr;
|
|
75636
75785
|
const npmMessage = npmErr instanceof Error ? npmErr.message : String(npmErr);
|
|
75637
75786
|
throw new Error(
|
|
75638
|
-
`Unknown
|
|
75787
|
+
`Unknown ${config2.label}: ${trimmed}. ${hint} Or pass a path, npm package, or git URL. (${npmMessage})`
|
|
75639
75788
|
);
|
|
75640
75789
|
}
|
|
75641
75790
|
}
|
|
75642
75791
|
throw new Error(
|
|
75643
|
-
`Unknown
|
|
75792
|
+
`Unknown ${config2.label}: ${trimmed}. ${hint} Or pass a path (./bundle), npm package (@org/pkg), or git URL (github:org/repo).`
|
|
75644
75793
|
);
|
|
75645
75794
|
}
|
|
75795
|
+
function listTemplateBundleIds(config2) {
|
|
75796
|
+
const root = path60.join(resolveTemplatesDir(), config2.templatesSubdir);
|
|
75797
|
+
if (!fs54.existsSync(root)) return [];
|
|
75798
|
+
return fs54.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path60.join(root, name), config2)).sort();
|
|
75799
|
+
}
|
|
75800
|
+
function listLocalBundleIds(repoPath, config2) {
|
|
75801
|
+
const root = path60.resolve(repoPath, config2.localDir);
|
|
75802
|
+
if (!fs54.existsSync(root)) return [];
|
|
75803
|
+
return fs54.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path60.join(root, name), config2)).sort();
|
|
75804
|
+
}
|
|
75805
|
+
function cleanupResolvedBundle(source) {
|
|
75806
|
+
for (const dir of source.cleanupDirs) {
|
|
75807
|
+
fs54.rmSync(dir, { recursive: true, force: true });
|
|
75808
|
+
}
|
|
75809
|
+
}
|
|
75810
|
+
|
|
75811
|
+
// src/harness/plugin-resolve.ts
|
|
75812
|
+
var LOCAL_PLUGINS_DIR = ".har/plugins";
|
|
75813
|
+
var PLUGIN_BUNDLE_CONFIG = {
|
|
75814
|
+
// `line.manifest.json` is accepted here on purpose: resolving a line bundle
|
|
75815
|
+
// lets `readPluginManifestFromDir` refuse it with a pointer at `har line add`
|
|
75816
|
+
// instead of a bare "not a HAR plugin bundle".
|
|
75817
|
+
manifestFiles: ["template.manifest.json", "line.manifest.json"],
|
|
75818
|
+
templatesSubdir: "plugins",
|
|
75819
|
+
localDir: LOCAL_PLUGINS_DIR,
|
|
75820
|
+
gitNestedDir: "plugins",
|
|
75821
|
+
label: "plugin",
|
|
75822
|
+
unknownHint: (repoPath) => knownPluginsHint(repoPath)
|
|
75823
|
+
};
|
|
75824
|
+
function resolvePluginSource(spec, repoPath = ".") {
|
|
75825
|
+
return resolveBundleSource(spec, repoPath, PLUGIN_BUNDLE_CONFIG);
|
|
75826
|
+
}
|
|
75646
75827
|
function knownPluginsHint(repoPath) {
|
|
75647
75828
|
const bundled = listBundledPluginIds();
|
|
75648
75829
|
const local = listLocalPluginIds(repoPath);
|
|
@@ -75655,19 +75836,13 @@ function knownPluginsHint(repoPath) {
|
|
|
75655
75836
|
return parts.join(" ");
|
|
75656
75837
|
}
|
|
75657
75838
|
function listLocalPluginIds(repoPath = ".") {
|
|
75658
|
-
|
|
75659
|
-
if (!fs54.existsSync(root)) return [];
|
|
75660
|
-
return fs54.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path60.join(root, name))).sort();
|
|
75839
|
+
return listLocalBundleIds(repoPath, PLUGIN_BUNDLE_CONFIG);
|
|
75661
75840
|
}
|
|
75662
75841
|
function listBundledPluginIds() {
|
|
75663
|
-
|
|
75664
|
-
if (!fs54.existsSync(root)) return [];
|
|
75665
|
-
return fs54.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path60.join(root, name))).sort();
|
|
75842
|
+
return listTemplateBundleIds(PLUGIN_BUNDLE_CONFIG);
|
|
75666
75843
|
}
|
|
75667
75844
|
function cleanupResolvedPlugin(source) {
|
|
75668
|
-
|
|
75669
|
-
fs54.rmSync(dir, { recursive: true, force: true });
|
|
75670
|
-
}
|
|
75845
|
+
cleanupResolvedBundle(source);
|
|
75671
75846
|
}
|
|
75672
75847
|
|
|
75673
75848
|
// src/harness/plugin-prompt.ts
|
|
@@ -75774,13 +75949,17 @@ function resolveBundledPluginDir(pluginId) {
|
|
|
75774
75949
|
return dir;
|
|
75775
75950
|
}
|
|
75776
75951
|
function readPluginManifestFromDir(pluginDir, expectedId) {
|
|
75777
|
-
const manifestPath =
|
|
75778
|
-
if (!
|
|
75952
|
+
const manifestPath = findManifestPath(pluginDir, PLUGIN_BUNDLE_CONFIG);
|
|
75953
|
+
if (!manifestPath) {
|
|
75779
75954
|
throw new Error(`No template.manifest.json in ${pluginDir}`);
|
|
75780
75955
|
}
|
|
75781
|
-
const
|
|
75782
|
-
|
|
75783
|
-
|
|
75956
|
+
const raw = JSON.parse(fs56.readFileSync(manifestPath, "utf8"));
|
|
75957
|
+
if (raw.kind === LINE_BUNDLE_KIND || path62.basename(manifestPath) === "line.manifest.json") {
|
|
75958
|
+
throw new Error(
|
|
75959
|
+
`${path62.basename(manifestPath)} declares "kind": "line" \u2014 this is a factory line bundle, not a verification plugin. Install it with: har line add <spec>`
|
|
75960
|
+
);
|
|
75961
|
+
}
|
|
75962
|
+
const parsed = PluginManifestSchema.safeParse(raw);
|
|
75784
75963
|
if (!parsed.success) {
|
|
75785
75964
|
throw new Error(`Invalid plugin manifest: ${parsed.error.message}`);
|
|
75786
75965
|
}
|
|
@@ -76682,8 +76861,8 @@ init_manifest();
|
|
|
76682
76861
|
init_stages();
|
|
76683
76862
|
|
|
76684
76863
|
// src/harness/doctor.ts
|
|
76685
|
-
var
|
|
76686
|
-
var
|
|
76864
|
+
var fs63 = __toESM(require("fs"));
|
|
76865
|
+
var path70 = __toESM(require("path"));
|
|
76687
76866
|
init_slot_registry();
|
|
76688
76867
|
|
|
76689
76868
|
// src/harness/eject.ts
|
|
@@ -76787,20 +76966,408 @@ function adoptHarness(repoPath) {
|
|
|
76787
76966
|
// src/harness/doctor.ts
|
|
76788
76967
|
init_env();
|
|
76789
76968
|
init_manifest();
|
|
76969
|
+
|
|
76970
|
+
// src/harness/line-ledger.ts
|
|
76971
|
+
var fs60 = __toESM(require("fs"));
|
|
76972
|
+
var path66 = __toESM(require("path"));
|
|
76973
|
+
init_file_ops();
|
|
76974
|
+
init_manifest();
|
|
76975
|
+
init_schema2();
|
|
76976
|
+
function getLineLedgerPath(repoPath) {
|
|
76977
|
+
return path66.join(path66.resolve(repoPath), DEFAULT_HAR_DIR, "lines.json");
|
|
76978
|
+
}
|
|
76979
|
+
function readLineLedger(repoPath) {
|
|
76980
|
+
const ledgerPath = getLineLedgerPath(repoPath);
|
|
76981
|
+
if (!fs60.existsSync(ledgerPath)) return null;
|
|
76982
|
+
try {
|
|
76983
|
+
const parsed = LineLedgerSchema.safeParse(JSON.parse(fs60.readFileSync(ledgerPath, "utf8")));
|
|
76984
|
+
return parsed.success ? parsed.data : null;
|
|
76985
|
+
} catch {
|
|
76986
|
+
return null;
|
|
76987
|
+
}
|
|
76988
|
+
}
|
|
76989
|
+
function writeLineLedger(repoPath, ledger) {
|
|
76990
|
+
const ledgerPath = getLineLedgerPath(repoPath);
|
|
76991
|
+
const harnessDir = path66.dirname(ledgerPath);
|
|
76992
|
+
if (!fs60.existsSync(harnessDir)) {
|
|
76993
|
+
fs60.mkdirSync(harnessDir, { recursive: true });
|
|
76994
|
+
}
|
|
76995
|
+
writeFileSafe(ledgerPath, `${JSON.stringify(ledger, null, 2)}
|
|
76996
|
+
`);
|
|
76997
|
+
}
|
|
76998
|
+
function upsertLineLedgerEntry(repoPath, entry) {
|
|
76999
|
+
const existing = readLineLedger(repoPath) ?? { version: "1", lines: [] };
|
|
77000
|
+
const lines = existing.lines.filter((l) => l.id !== entry.id);
|
|
77001
|
+
lines.push(entry);
|
|
77002
|
+
lines.sort((a, b2) => a.id.localeCompare(b2.id));
|
|
77003
|
+
const ledger = { version: "1", lines };
|
|
77004
|
+
writeLineLedger(repoPath, ledger);
|
|
77005
|
+
return ledger;
|
|
77006
|
+
}
|
|
77007
|
+
|
|
77008
|
+
// src/harness/lines.ts
|
|
77009
|
+
var fs61 = __toESM(require("fs"));
|
|
77010
|
+
var path68 = __toESM(require("path"));
|
|
77011
|
+
init_logging();
|
|
77012
|
+
|
|
77013
|
+
// src/harness/line-prompt.ts
|
|
77014
|
+
var path67 = __toESM(require("path"));
|
|
77015
|
+
init_file_ops();
|
|
77016
|
+
init_manifest();
|
|
77017
|
+
function lineAdaptationPromptFile(lineId) {
|
|
77018
|
+
return `ADAPT-PROMPT-line-${lineId}.md`;
|
|
77019
|
+
}
|
|
77020
|
+
function buildLineAdaptationPrompt(repoPath, program, result) {
|
|
77021
|
+
const stations = program.stations.map((s, i) => `${i + 1}. \`${s.id}\` \u2014 ${s.title}${s.work?.ids?.length ? ` (work: ${s.work.ids.join(", ")})` : ""}`).join("\n");
|
|
77022
|
+
const gateRows = program.gate.stages.map((s) => `| \`${s.id}\` | \`${s.fromStation}\` | ${s.tier} |`).join("\n");
|
|
77023
|
+
const registered = result.stageIds.length > 0 ? result.stageIds.map((id) => `- \`${id}\` \u2014 registered, **not** in \`verificationStages\``).join("\n") : "- _(this line registered no extra stages)_";
|
|
77024
|
+
const declaredSkills = program.skills.length > 0 ? program.skills.map((s) => `- \`${s.id}\` (${s.role})${s.install ? ` \u2014 install: \`${s.install}\`` : ""}`).join("\n") : "- _(none declared)_";
|
|
77025
|
+
const declaredMcp = program.mcp.length > 0 ? program.mcp.map((m) => `- \`${m.name}\`${m.required ? " (required)" : " (optional)"}${m.why ? ` \u2014 ${m.why}` : ""}`).join("\n") : "- _(none declared)_";
|
|
77026
|
+
const warnings = result.warnings.length > 0 ? result.warnings.map((w2) => `- \u26A0 ${w2}`).join("\n") : "- _(none)_";
|
|
77027
|
+
const optIn = program.gate.optInEnv ? `This line's gate is opt-in: stages run only when \`${program.gate.optInEnv}=1\`.` : "This line has no opt-in env var \u2014 `har line gate` runs its stages on demand.";
|
|
77028
|
+
return `# Adapt the factory line: ${result.lineId}
|
|
77029
|
+
|
|
77030
|
+
Installed from \`${result.source}\` into \`${path67.basename(path67.resolve(repoPath))}\`.
|
|
77031
|
+
Program: \`${result.programPath}\`
|
|
77032
|
+
|
|
77033
|
+
## What just happened
|
|
77034
|
+
|
|
77035
|
+
A **factory line** was installed. A line is a *program* \u2014 an ordered set of
|
|
77036
|
+
stations plus a cumulative gate. It is not a verification plugin:
|
|
77037
|
+
|
|
77038
|
+
${registered}
|
|
77039
|
+
|
|
77040
|
+
\`verificationStages\` was **not** modified. Default \`har env verify --full\`
|
|
77041
|
+
takes exactly as long as it did before this install. ${optIn}
|
|
77042
|
+
|
|
77043
|
+
## Stations
|
|
77044
|
+
|
|
77045
|
+
${stations}
|
|
77046
|
+
|
|
77047
|
+
## Cumulative gate (the ratchet)
|
|
77048
|
+
|
|
77049
|
+
A gate stage tagged \`fromStation: X\` is required at X **and every later
|
|
77050
|
+
station**. Adding a station must never drop an earlier station's stages.
|
|
77051
|
+
|
|
77052
|
+
| Stage | From station | Tier |
|
|
77053
|
+
|---|---|---|
|
|
77054
|
+
${gateRows || "| _(none)_ | | |"}
|
|
77055
|
+
|
|
77056
|
+
Run it with:
|
|
77057
|
+
|
|
77058
|
+
\`\`\`bash
|
|
77059
|
+
har line gate <station> --line ${result.lineId}
|
|
77060
|
+
\`\`\`
|
|
77061
|
+
|
|
77062
|
+
Never with \`har env verify --full\` \u2014 that is the whole point of the split.
|
|
77063
|
+
|
|
77064
|
+
## Declared dependencies (declarations, not installs)
|
|
77065
|
+
|
|
77066
|
+
Skills:
|
|
77067
|
+
|
|
77068
|
+
${declaredSkills}
|
|
77069
|
+
|
|
77070
|
+
MCP servers:
|
|
77071
|
+
|
|
77072
|
+
${declaredMcp}
|
|
77073
|
+
|
|
77074
|
+
HAR does not vendor skill packs or MCP servers. Check they are present, install
|
|
77075
|
+
them the way your agent normally does, and skip tracker steps for any MCP marked
|
|
77076
|
+
optional that is missing.
|
|
77077
|
+
|
|
77078
|
+
## Warnings from install
|
|
77079
|
+
|
|
77080
|
+
${warnings}
|
|
77081
|
+
|
|
77082
|
+
## Your job now
|
|
77083
|
+
|
|
77084
|
+
1. Read \`${result.programPath}\` and make the stations describe *this* repo's
|
|
77085
|
+
work \u2014 station titles, \`work.source\`/\`work.ids\`, waves.
|
|
77086
|
+
2. Make each registered stage script real (replace TODO blocks). They live under
|
|
77087
|
+
\`.har/stages/\`.
|
|
77088
|
+
3. Leave \`gate.cumulative: true\` and \`handoff.autonomousShip: false\` alone \u2014
|
|
77089
|
+
both are contract, not preference.
|
|
77090
|
+
4. Do **not** add line stages to \`verificationStages\`. If a check should gate
|
|
77091
|
+
every verify, it belongs in a verification plugin instead
|
|
77092
|
+
(\`har env add-plugin\`), not on this line.
|
|
77093
|
+
5. Verify the harness still passes as before: \`har env verify <slot> --full\`.
|
|
77094
|
+
`;
|
|
77095
|
+
}
|
|
77096
|
+
function writeLineAdaptationPrompt(repoPath, lineId, content) {
|
|
77097
|
+
const filePath = path67.join(getHarnessDir(repoPath), lineAdaptationPromptFile(lineId));
|
|
77098
|
+
writeFileSafe(filePath, content);
|
|
77099
|
+
return filePath;
|
|
77100
|
+
}
|
|
77101
|
+
|
|
77102
|
+
// src/harness/line-resolve.ts
|
|
77103
|
+
init_schema2();
|
|
77104
|
+
var LOCAL_LINES_DIR = ".har/lines";
|
|
77105
|
+
var LINE_BUNDLE_CONFIG = {
|
|
77106
|
+
manifestFiles: LINE_MANIFEST_FILES,
|
|
77107
|
+
templatesSubdir: "lines",
|
|
77108
|
+
localDir: LOCAL_LINES_DIR,
|
|
77109
|
+
gitNestedDir: "lines",
|
|
77110
|
+
label: "line",
|
|
77111
|
+
unknownHint: (repoPath) => knownLinesHint(repoPath)
|
|
77112
|
+
};
|
|
77113
|
+
function resolveLineSource(spec, repoPath = ".") {
|
|
77114
|
+
return resolveBundleSource(spec, repoPath, LINE_BUNDLE_CONFIG);
|
|
77115
|
+
}
|
|
77116
|
+
function knownLinesHint(repoPath) {
|
|
77117
|
+
const bundled = listBundledLineIds();
|
|
77118
|
+
const local = listLocalLineIds(repoPath);
|
|
77119
|
+
const parts = [`Bundled: ${bundled.join(", ") || "(none)"}.`];
|
|
77120
|
+
if (local.length > 0) {
|
|
77121
|
+
parts.push(`Local (${LOCAL_LINES_DIR}/): ${local.join(", ")}.`);
|
|
77122
|
+
} else {
|
|
77123
|
+
parts.push("Scaffold a project-owned one with: har line create <id>.");
|
|
77124
|
+
}
|
|
77125
|
+
return parts.join(" ");
|
|
77126
|
+
}
|
|
77127
|
+
function listLocalLineIds(repoPath = ".") {
|
|
77128
|
+
return listLocalBundleIds(repoPath, LINE_BUNDLE_CONFIG);
|
|
77129
|
+
}
|
|
77130
|
+
function listBundledLineIds() {
|
|
77131
|
+
return listTemplateBundleIds(LINE_BUNDLE_CONFIG);
|
|
77132
|
+
}
|
|
77133
|
+
function cleanupResolvedLine(source) {
|
|
77134
|
+
cleanupResolvedBundle(source);
|
|
77135
|
+
}
|
|
77136
|
+
|
|
77137
|
+
// src/harness/lines.ts
|
|
77138
|
+
init_schema2();
|
|
77139
|
+
init_schema2();
|
|
77140
|
+
init_stages();
|
|
77141
|
+
function lineDirRel(lineId) {
|
|
77142
|
+
return `${LOCAL_LINES_DIR}/${lineId}`;
|
|
77143
|
+
}
|
|
77144
|
+
function lineProgramPathRel(lineId) {
|
|
77145
|
+
return `${lineDirRel(lineId)}/line.json`;
|
|
77146
|
+
}
|
|
77147
|
+
function readLineManifestFromDir(bundleDir, expectedId) {
|
|
77148
|
+
const manifestPath = findManifestPath(bundleDir, LINE_BUNDLE_CONFIG);
|
|
77149
|
+
if (!manifestPath) {
|
|
77150
|
+
throw new Error(`No ${LINE_MANIFEST_FILES.join(" or ")} in ${bundleDir}`);
|
|
77151
|
+
}
|
|
77152
|
+
const raw = JSON.parse(fs61.readFileSync(manifestPath, "utf8"));
|
|
77153
|
+
if (raw.kind !== LINE_BUNDLE_KIND) {
|
|
77154
|
+
throw new Error(
|
|
77155
|
+
`${path68.basename(manifestPath)} is not a factory line bundle (missing "kind": "line"). Verification plugins install with: har env add-plugin <spec>`
|
|
77156
|
+
);
|
|
77157
|
+
}
|
|
77158
|
+
const parsed = LineManifestSchema.safeParse(raw);
|
|
77159
|
+
if (!parsed.success) {
|
|
77160
|
+
throw new Error(`Invalid line manifest: ${parsed.error.message}`);
|
|
77161
|
+
}
|
|
77162
|
+
if (expectedId && parsed.data.id !== expectedId) {
|
|
77163
|
+
throw new Error(`Line manifest id mismatch: expected ${expectedId}, got ${parsed.data.id}`);
|
|
77164
|
+
}
|
|
77165
|
+
return parsed.data;
|
|
77166
|
+
}
|
|
77167
|
+
function readLineProgramFromDir(bundleDir, manifest) {
|
|
77168
|
+
const programPath = path68.join(bundleDir, manifest.program);
|
|
77169
|
+
if (!fs61.existsSync(programPath)) {
|
|
77170
|
+
throw new Error(`Line program missing: ${manifest.program} (referenced by line.manifest.json)`);
|
|
77171
|
+
}
|
|
77172
|
+
const parsed = LineProgramSchema.safeParse(JSON.parse(fs61.readFileSync(programPath, "utf8")));
|
|
77173
|
+
if (!parsed.success) {
|
|
77174
|
+
throw new Error(`Invalid line program (${manifest.program}): ${parsed.error.message}`);
|
|
77175
|
+
}
|
|
77176
|
+
if (parsed.data.id !== manifest.id) {
|
|
77177
|
+
throw new Error(
|
|
77178
|
+
`Line program id "${parsed.data.id}" does not match manifest id "${manifest.id}"`
|
|
77179
|
+
);
|
|
77180
|
+
}
|
|
77181
|
+
return parsed.data;
|
|
77182
|
+
}
|
|
77183
|
+
function readInstalledLineProgram(repoPath, lineId) {
|
|
77184
|
+
const programPath = path68.join(path68.resolve(repoPath), lineProgramPathRel(lineId));
|
|
77185
|
+
if (!fs61.existsSync(programPath)) return null;
|
|
77186
|
+
const parsed = LineProgramSchema.safeParse(JSON.parse(fs61.readFileSync(programPath, "utf8")));
|
|
77187
|
+
return parsed.success ? parsed.data : null;
|
|
77188
|
+
}
|
|
77189
|
+
function ensureParentDir3(filePath) {
|
|
77190
|
+
fs61.mkdirSync(path68.dirname(filePath), { recursive: true });
|
|
77191
|
+
}
|
|
77192
|
+
function copyBundleFile(bundleDir, file, repoPath, force) {
|
|
77193
|
+
const srcPath = path68.join(bundleDir, file.src);
|
|
77194
|
+
const destPath = path68.join(repoPath, file.dest);
|
|
77195
|
+
if (!fs61.existsSync(srcPath)) {
|
|
77196
|
+
throw new Error(`Line file missing: ${file.src}`);
|
|
77197
|
+
}
|
|
77198
|
+
if (path68.resolve(srcPath) === path68.resolve(destPath)) {
|
|
77199
|
+
return file.dest;
|
|
77200
|
+
}
|
|
77201
|
+
if (fs61.existsSync(destPath) && !force) {
|
|
77202
|
+
throw new Error(
|
|
77203
|
+
`File already exists: ${file.dest}. Use --force to overwrite or remove it first.`
|
|
77204
|
+
);
|
|
77205
|
+
}
|
|
77206
|
+
ensureParentDir3(destPath);
|
|
77207
|
+
fs61.copyFileSync(srcPath, destPath);
|
|
77208
|
+
if (file.executable) {
|
|
77209
|
+
fs61.chmodSync(destPath, 493);
|
|
77210
|
+
}
|
|
77211
|
+
return file.dest;
|
|
77212
|
+
}
|
|
77213
|
+
function registerStagesOnly(repoPath, stages, force) {
|
|
77214
|
+
if (stages.length === 0) return;
|
|
77215
|
+
const registry2 = readStageRegistry(repoPath);
|
|
77216
|
+
const before = JSON.stringify(registry2.verificationStages ?? null);
|
|
77217
|
+
let nextStages = [...registry2.stages];
|
|
77218
|
+
for (const stage of stages) {
|
|
77219
|
+
const existing = nextStages.find((s) => s.id === stage.id);
|
|
77220
|
+
if (existing && !force) {
|
|
77221
|
+
throw new Error(
|
|
77222
|
+
`Stage "${stage.id}" already registered in .har/stages.json. Use --force to replace.`
|
|
77223
|
+
);
|
|
77224
|
+
}
|
|
77225
|
+
nextStages = existing ? nextStages.map((s) => s.id === stage.id ? stage : s) : [...nextStages, stage];
|
|
77226
|
+
}
|
|
77227
|
+
const updated = { ...registry2, stages: nextStages };
|
|
77228
|
+
const after = JSON.stringify(updated.verificationStages ?? null);
|
|
77229
|
+
if (before !== after) {
|
|
77230
|
+
throw new Error(
|
|
77231
|
+
"Refusing to write: applying a line changed verificationStages. Line gate stages are opt-in and run via `har line gate`."
|
|
77232
|
+
);
|
|
77233
|
+
}
|
|
77234
|
+
writeStageRegistry(repoPath, updated);
|
|
77235
|
+
}
|
|
77236
|
+
function assertGateStagesResolvable(program, registeredIds, repoPath) {
|
|
77237
|
+
const warnings = [];
|
|
77238
|
+
const registry2 = readStageRegistry(repoPath);
|
|
77239
|
+
const known = /* @__PURE__ */ new Set([...registry2.stages.map((s) => s.id), ...registeredIds]);
|
|
77240
|
+
for (const stage of program.gate.stages) {
|
|
77241
|
+
if (!known.has(stage.id)) {
|
|
77242
|
+
warnings.push(
|
|
77243
|
+
`gate stage "${stage.id}" (from ${stage.fromStation}) is not registered in .har/stages.json \u2014 install the plugin that provides it, or add it to the line bundle.`
|
|
77244
|
+
);
|
|
77245
|
+
}
|
|
77246
|
+
}
|
|
77247
|
+
return warnings;
|
|
77248
|
+
}
|
|
77249
|
+
function applyLineFromDir(repoPath, bundleDir, options, meta) {
|
|
77250
|
+
const resolved = path68.resolve(repoPath);
|
|
77251
|
+
const force = options.force ?? false;
|
|
77252
|
+
const warnings = [];
|
|
77253
|
+
const filesWritten = [];
|
|
77254
|
+
if (!harnessExists(resolved)) {
|
|
77255
|
+
throw new Error('No .har/ harness found. Run "har onboard" first.');
|
|
77256
|
+
}
|
|
77257
|
+
const manifest = readLineManifestFromDir(bundleDir);
|
|
77258
|
+
const program = readLineProgramFromDir(bundleDir, manifest);
|
|
77259
|
+
const stages = manifest.stages;
|
|
77260
|
+
const stageIds = stages.map((s) => s.id);
|
|
77261
|
+
const verificationBefore = JSON.stringify(readStageRegistry(resolved).verificationStages ?? null);
|
|
77262
|
+
for (const file of manifest.files) {
|
|
77263
|
+
filesWritten.push(copyBundleFile(bundleDir, file, resolved, force));
|
|
77264
|
+
}
|
|
77265
|
+
const programDest = path68.join(resolved, lineProgramPathRel(manifest.id));
|
|
77266
|
+
const programSrc = path68.join(bundleDir, manifest.program);
|
|
77267
|
+
if (path68.resolve(programSrc) !== path68.resolve(programDest)) {
|
|
77268
|
+
if (fs61.existsSync(programDest) && !force) {
|
|
77269
|
+
throw new Error(
|
|
77270
|
+
`Line already installed: ${lineProgramPathRel(manifest.id)}. Use --force to replace.`
|
|
77271
|
+
);
|
|
77272
|
+
}
|
|
77273
|
+
ensureParentDir3(programDest);
|
|
77274
|
+
fs61.copyFileSync(programSrc, programDest);
|
|
77275
|
+
}
|
|
77276
|
+
filesWritten.push(lineProgramPathRel(manifest.id));
|
|
77277
|
+
const manifestDest = path68.join(resolved, lineDirRel(manifest.id), "line.manifest.json");
|
|
77278
|
+
const manifestSrc = findManifestPath(bundleDir, LINE_BUNDLE_CONFIG);
|
|
77279
|
+
if (path68.resolve(manifestSrc) !== path68.resolve(manifestDest)) {
|
|
77280
|
+
ensureParentDir3(manifestDest);
|
|
77281
|
+
fs61.copyFileSync(manifestSrc, manifestDest);
|
|
77282
|
+
filesWritten.push(`${lineDirRel(manifest.id)}/line.manifest.json`);
|
|
77283
|
+
}
|
|
77284
|
+
registerStagesOnly(resolved, stages, force);
|
|
77285
|
+
const verificationAfter = JSON.stringify(readStageRegistry(resolved).verificationStages ?? null);
|
|
77286
|
+
if (verificationBefore !== verificationAfter) {
|
|
77287
|
+
throw new Error(
|
|
77288
|
+
"Line apply changed verificationStages \u2014 this is a bug. Line gate stages must stay off `har env verify --full`."
|
|
77289
|
+
);
|
|
77290
|
+
}
|
|
77291
|
+
warnings.push(...assertGateStagesResolvable(program, stageIds, resolved));
|
|
77292
|
+
upsertLineLedgerEntry(resolved, {
|
|
77293
|
+
id: manifest.id,
|
|
77294
|
+
source: meta.source,
|
|
77295
|
+
spec: meta.spec,
|
|
77296
|
+
version: meta.version,
|
|
77297
|
+
stageIds,
|
|
77298
|
+
programPath: lineProgramPathRel(manifest.id),
|
|
77299
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
77300
|
+
});
|
|
77301
|
+
const firstGatedStation = program.stations.find(
|
|
77302
|
+
(station) => program.gate.stages.some((stage) => stage.fromStation === station.id)
|
|
77303
|
+
)?.id ?? program.stations[0].id;
|
|
77304
|
+
const nextSteps = manifest.nextSteps.length > 0 ? manifest.nextSteps : [
|
|
77305
|
+
`har line status ${manifest.id}`,
|
|
77306
|
+
`har line gate ${firstGatedStation} --line ${manifest.id}`,
|
|
77307
|
+
`Adapt the program: ${lineProgramPathRel(manifest.id)}`
|
|
77308
|
+
];
|
|
77309
|
+
const partial2 = {
|
|
77310
|
+
lineId: manifest.id,
|
|
77311
|
+
title: manifest.title ?? program.title,
|
|
77312
|
+
stageIds,
|
|
77313
|
+
filesWritten,
|
|
77314
|
+
warnings,
|
|
77315
|
+
nextSteps,
|
|
77316
|
+
programPath: lineProgramPathRel(manifest.id),
|
|
77317
|
+
docsPath: manifest.docsPath,
|
|
77318
|
+
source: meta.source,
|
|
77319
|
+
stationIds: program.stations.map((s) => s.id),
|
|
77320
|
+
firstGatedStationId: firstGatedStation
|
|
77321
|
+
};
|
|
77322
|
+
const promptAbsPath = writeLineAdaptationPrompt(
|
|
77323
|
+
resolved,
|
|
77324
|
+
manifest.id,
|
|
77325
|
+
buildLineAdaptationPrompt(resolved, program, { ...partial2, adaptPromptPath: "" })
|
|
77326
|
+
);
|
|
77327
|
+
const adaptPromptPath = path68.relative(resolved, promptAbsPath);
|
|
77328
|
+
success(`Applied line: ${manifest.id}`);
|
|
77329
|
+
info(`Stations: ${partial2.stationIds.join(" \u2192 ")}`);
|
|
77330
|
+
info(
|
|
77331
|
+
stageIds.length > 0 ? `Registered stage(s) (NOT on verify): ${stageIds.join(", ")}` : "No extra stages registered"
|
|
77332
|
+
);
|
|
77333
|
+
for (const file of filesWritten) {
|
|
77334
|
+
info(` + ${file}`);
|
|
77335
|
+
}
|
|
77336
|
+
info(` + ${adaptPromptPath} (adaptation prompt for your coding agent)`);
|
|
77337
|
+
for (const warning of warnings) {
|
|
77338
|
+
warn(` \u26A0 ${warning}`);
|
|
77339
|
+
}
|
|
77340
|
+
return { ...partial2, adaptPromptPath };
|
|
77341
|
+
}
|
|
77342
|
+
function applyLine(repoPath, lineSpec, options = {}) {
|
|
77343
|
+
const spec = options.spec ?? lineSpec;
|
|
77344
|
+
const source = resolveLineSource(spec, repoPath);
|
|
77345
|
+
try {
|
|
77346
|
+
return applyLineFromDir(repoPath, source.dir, options, {
|
|
77347
|
+
source: source.kind,
|
|
77348
|
+
spec: source.spec,
|
|
77349
|
+
version: source.version
|
|
77350
|
+
});
|
|
77351
|
+
} finally {
|
|
77352
|
+
cleanupResolvedLine(source);
|
|
77353
|
+
}
|
|
77354
|
+
}
|
|
77355
|
+
|
|
77356
|
+
// src/harness/doctor.ts
|
|
76790
77357
|
init_stages();
|
|
76791
77358
|
init_hooks2();
|
|
76792
77359
|
|
|
76793
77360
|
// src/harness/migrations.ts
|
|
76794
|
-
var
|
|
76795
|
-
var
|
|
77361
|
+
var fs62 = __toESM(require("fs"));
|
|
77362
|
+
var path69 = __toESM(require("path"));
|
|
76796
77363
|
init_schema2();
|
|
76797
77364
|
init_manifest();
|
|
76798
77365
|
init_profiles();
|
|
76799
77366
|
init_stages();
|
|
76800
77367
|
init_manifest();
|
|
76801
77368
|
var MIGRATE_DIR = "migrate";
|
|
76802
|
-
var MIGRATE_BACKUP_DIR =
|
|
76803
|
-
var MIGRATE_PLAN_FILE =
|
|
77369
|
+
var MIGRATE_BACKUP_DIR = path69.join(MIGRATE_DIR, "backup");
|
|
77370
|
+
var MIGRATE_PLAN_FILE = path69.join(MIGRATE_DIR, "plan.json");
|
|
76804
77371
|
var LEGACY_MACHINERY_FILES = [
|
|
76805
77372
|
"agent-slot.sh",
|
|
76806
77373
|
"provision-toolchain.sh",
|
|
@@ -76841,25 +77408,25 @@ function harnessEnvIsPre10(content) {
|
|
|
76841
77408
|
return /^\s*(har_infra_enabled|har_pg|har_node_[a-z_]+|har_pkg_exec)\s*\(\)/m.test(content) || /^export\s+HARNESS_[A-Z0-9_]+_PORT_(DEFAULT|SCAN_START|SCAN_END)=/m.test(content);
|
|
76842
77409
|
}
|
|
76843
77410
|
function scriptIsVendored(harnessDir, script) {
|
|
76844
|
-
const file =
|
|
76845
|
-
if (!
|
|
76846
|
-
const content =
|
|
77411
|
+
const file = path69.join(harnessDir, script);
|
|
77412
|
+
if (!fs62.existsSync(file)) return false;
|
|
77413
|
+
const content = fs62.readFileSync(file, "utf8");
|
|
76847
77414
|
return !content.includes("exec har env") && !content.includes("runtime/har.cjs");
|
|
76848
77415
|
}
|
|
76849
77416
|
function isPre10Harness(repoPath) {
|
|
76850
|
-
const resolved =
|
|
77417
|
+
const resolved = path69.resolve(repoPath);
|
|
76851
77418
|
const harnessDir = getHarnessDir(resolved);
|
|
76852
|
-
if (!
|
|
77419
|
+
if (!fs62.existsSync(harnessDir)) return false;
|
|
76853
77420
|
const manifest = readManifest(resolved);
|
|
76854
77421
|
if (manifest?.ejected) return false;
|
|
76855
77422
|
for (const file of LEGACY_MACHINERY_FILES) {
|
|
76856
|
-
if (
|
|
77423
|
+
if (fs62.existsSync(path69.join(harnessDir, file))) return true;
|
|
76857
77424
|
}
|
|
76858
77425
|
for (const script of MANAGED_SHIM_FILES) {
|
|
76859
77426
|
if (scriptIsVendored(harnessDir, script)) return true;
|
|
76860
77427
|
}
|
|
76861
|
-
const envPath =
|
|
76862
|
-
if (
|
|
77428
|
+
const envPath = path69.join(harnessDir, "harness.env");
|
|
77429
|
+
if (fs62.existsSync(envPath) && harnessEnvIsPre10(fs62.readFileSync(envPath, "utf8"))) {
|
|
76863
77430
|
return true;
|
|
76864
77431
|
}
|
|
76865
77432
|
return false;
|
|
@@ -76992,10 +77559,10 @@ var SCRIPT_RESIDUE_TARGET = {
|
|
|
76992
77559
|
"agent-cli.sh": "review"
|
|
76993
77560
|
};
|
|
76994
77561
|
function backupRel(file) {
|
|
76995
|
-
return
|
|
77562
|
+
return path69.join(MIGRATE_BACKUP_DIR, file);
|
|
76996
77563
|
}
|
|
76997
77564
|
function buildPre10Plan(repoPath) {
|
|
76998
|
-
const resolved =
|
|
77565
|
+
const resolved = path69.resolve(repoPath);
|
|
76999
77566
|
const harnessDir = getHarnessDir(resolved);
|
|
77000
77567
|
const manifest = readManifest(resolved);
|
|
77001
77568
|
const profile = manifest?.profile ?? "default";
|
|
@@ -77004,7 +77571,7 @@ function buildPre10Plan(repoPath) {
|
|
|
77004
77571
|
const deleteLifecycleScripts = [];
|
|
77005
77572
|
const residue = [];
|
|
77006
77573
|
for (const script of MANAGED_SHIM_FILES) {
|
|
77007
|
-
if (!
|
|
77574
|
+
if (!fs62.existsSync(path69.join(harnessDir, script))) continue;
|
|
77008
77575
|
deleteLifecycleScripts.push(script);
|
|
77009
77576
|
if (scriptIsVendored(harnessDir, script)) {
|
|
77010
77577
|
const target = SCRIPT_RESIDUE_TARGET[script] ?? "review";
|
|
@@ -77018,31 +77585,31 @@ function buildPre10Plan(repoPath) {
|
|
|
77018
77585
|
}
|
|
77019
77586
|
const survivingScripts = [];
|
|
77020
77587
|
for (const dir of ["stages", "hooks"]) {
|
|
77021
|
-
const full =
|
|
77022
|
-
if (!
|
|
77023
|
-
for (const entry of
|
|
77024
|
-
if (entry.endsWith(".sh") || entry.endsWith(".mjs")) survivingScripts.push(
|
|
77588
|
+
const full = path69.join(harnessDir, dir);
|
|
77589
|
+
if (!fs62.existsSync(full)) continue;
|
|
77590
|
+
for (const entry of fs62.readdirSync(full)) {
|
|
77591
|
+
if (entry.endsWith(".sh") || entry.endsWith(".mjs")) survivingScripts.push(path69.join(dir, entry));
|
|
77025
77592
|
}
|
|
77026
77593
|
}
|
|
77027
|
-
for (const entry of
|
|
77594
|
+
for (const entry of fs62.readdirSync(harnessDir)) {
|
|
77028
77595
|
if (!entry.endsWith(".sh")) continue;
|
|
77029
77596
|
if (MANAGED_SHIM_FILES.includes(entry)) continue;
|
|
77030
77597
|
if (LEGACY_MACHINERY_FILES.includes(entry)) continue;
|
|
77031
|
-
if (!
|
|
77598
|
+
if (!fs62.statSync(path69.join(harnessDir, entry)).isFile()) continue;
|
|
77032
77599
|
survivingScripts.push(entry);
|
|
77033
77600
|
}
|
|
77034
77601
|
const referencedBy = (machineryFile) => {
|
|
77035
|
-
const base =
|
|
77602
|
+
const base = path69.basename(machineryFile).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
77036
77603
|
const loadRe = new RegExp(
|
|
77037
77604
|
`(?:\\bsource\\b|\\bbash\\b|\\bexec\\b|(?:^|[;&|(])\\s*\\.\\s)[^\\n#]*${base}`
|
|
77038
77605
|
);
|
|
77039
77606
|
return survivingScripts.filter(
|
|
77040
|
-
(script) =>
|
|
77607
|
+
(script) => fs62.readFileSync(path69.join(harnessDir, script), "utf8").split("\n").some((line) => !/^\s*#/.test(line) && loadRe.test(line))
|
|
77041
77608
|
);
|
|
77042
77609
|
};
|
|
77043
77610
|
const retireDocs = [];
|
|
77044
77611
|
for (const doc of RETIRED_DOC_FILES) {
|
|
77045
|
-
if (!
|
|
77612
|
+
if (!fs62.existsSync(path69.join(harnessDir, doc))) continue;
|
|
77046
77613
|
retireDocs.push(doc);
|
|
77047
77614
|
residue.push({
|
|
77048
77615
|
source: doc,
|
|
@@ -77055,8 +77622,8 @@ function buildPre10Plan(repoPath) {
|
|
|
77055
77622
|
const editedMachinery = [];
|
|
77056
77623
|
const retainMachinery = [];
|
|
77057
77624
|
for (const file of LEGACY_MACHINERY_FILES) {
|
|
77058
|
-
const full =
|
|
77059
|
-
if (!
|
|
77625
|
+
const full = path69.join(harnessDir, file);
|
|
77626
|
+
if (!fs62.existsSync(full)) continue;
|
|
77060
77627
|
const refs = referencedBy(file);
|
|
77061
77628
|
if (refs.length > 0) {
|
|
77062
77629
|
retainMachinery.push(file);
|
|
@@ -77070,7 +77637,7 @@ function buildPre10Plan(repoPath) {
|
|
|
77070
77637
|
}
|
|
77071
77638
|
deleteMachinery.push(file);
|
|
77072
77639
|
const recorded = fileBaseline[file];
|
|
77073
|
-
const installed = computeFileChecksum(
|
|
77640
|
+
const installed = computeFileChecksum(fs62.readFileSync(full, "utf8"));
|
|
77074
77641
|
if (recorded !== void 0 && installed !== recorded) {
|
|
77075
77642
|
editedMachinery.push(file);
|
|
77076
77643
|
residue.push({
|
|
@@ -77082,9 +77649,9 @@ function buildPre10Plan(repoPath) {
|
|
|
77082
77649
|
}
|
|
77083
77650
|
}
|
|
77084
77651
|
let env3 = null;
|
|
77085
|
-
const envPath =
|
|
77086
|
-
if (
|
|
77087
|
-
const content =
|
|
77652
|
+
const envPath = path69.join(harnessDir, "harness.env");
|
|
77653
|
+
if (fs62.existsSync(envPath)) {
|
|
77654
|
+
const content = fs62.readFileSync(envPath, "utf8");
|
|
77088
77655
|
if (harnessEnvIsPre10(content) || migrateHarnessEnvContent(content).commentedKeys.length > 0) {
|
|
77089
77656
|
env3 = migrateHarnessEnvContent(content);
|
|
77090
77657
|
for (const fn of env3.customFunctions) {
|
|
@@ -77109,7 +77676,7 @@ function buildPre10Plan(repoPath) {
|
|
|
77109
77676
|
for (const file of composed.keys()) {
|
|
77110
77677
|
if (MANAGED_SHIM_FILES.includes(file)) continue;
|
|
77111
77678
|
if (file === "gitignore.template") continue;
|
|
77112
|
-
if (!
|
|
77679
|
+
if (!fs62.existsSync(path69.join(harnessDir, file))) installMissing.push(file);
|
|
77113
77680
|
}
|
|
77114
77681
|
let phantomVerificationIds = [];
|
|
77115
77682
|
try {
|
|
@@ -77140,25 +77707,25 @@ function buildPre10Plan(repoPath) {
|
|
|
77140
77707
|
};
|
|
77141
77708
|
}
|
|
77142
77709
|
function applyPre10Plan(repoPath, plan) {
|
|
77143
|
-
const resolved =
|
|
77710
|
+
const resolved = path69.resolve(repoPath);
|
|
77144
77711
|
const harnessDir = getHarnessDir(resolved);
|
|
77145
77712
|
const effective = plan ?? buildPre10Plan(resolved);
|
|
77146
|
-
const backupDir =
|
|
77147
|
-
|
|
77713
|
+
const backupDir = path69.join(harnessDir, MIGRATE_BACKUP_DIR);
|
|
77714
|
+
fs62.mkdirSync(backupDir, { recursive: true });
|
|
77148
77715
|
const backup = (file) => {
|
|
77149
|
-
const src =
|
|
77150
|
-
if (!
|
|
77151
|
-
const dest =
|
|
77152
|
-
|
|
77153
|
-
|
|
77716
|
+
const src = path69.join(harnessDir, file);
|
|
77717
|
+
if (!fs62.existsSync(src)) return;
|
|
77718
|
+
const dest = path69.join(backupDir, file);
|
|
77719
|
+
fs62.mkdirSync(path69.dirname(dest), { recursive: true });
|
|
77720
|
+
fs62.copyFileSync(src, dest);
|
|
77154
77721
|
};
|
|
77155
77722
|
const written = [];
|
|
77156
77723
|
const deleted = [];
|
|
77157
|
-
const projectName =
|
|
77724
|
+
const projectName = path69.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
77158
77725
|
const composed = composeProfileTemplateMap(effective.profile);
|
|
77159
77726
|
for (const script of effective.deleteLifecycleScripts) {
|
|
77160
77727
|
backup(script);
|
|
77161
|
-
|
|
77728
|
+
fs62.rmSync(path69.join(harnessDir, script), { force: true });
|
|
77162
77729
|
deleted.push(script);
|
|
77163
77730
|
}
|
|
77164
77731
|
if (stripLifecycleShimCommands(resolved)) {
|
|
@@ -77166,26 +77733,26 @@ function applyPre10Plan(repoPath, plan) {
|
|
|
77166
77733
|
}
|
|
77167
77734
|
for (const file of effective.deleteMachinery) {
|
|
77168
77735
|
backup(file);
|
|
77169
|
-
|
|
77736
|
+
fs62.rmSync(path69.join(harnessDir, file), { force: true });
|
|
77170
77737
|
deleted.push(file);
|
|
77171
77738
|
}
|
|
77172
77739
|
for (const doc of effective.retireDocs ?? []) {
|
|
77173
77740
|
backup(doc);
|
|
77174
77741
|
}
|
|
77175
|
-
const libDir =
|
|
77176
|
-
if (
|
|
77177
|
-
|
|
77742
|
+
const libDir = path69.join(harnessDir, "lib");
|
|
77743
|
+
if (fs62.existsSync(libDir) && fs62.readdirSync(libDir).length === 0) {
|
|
77744
|
+
fs62.rmdirSync(libDir);
|
|
77178
77745
|
deleted.push("lib/");
|
|
77179
77746
|
}
|
|
77180
77747
|
for (const file of effective.installMissing ?? []) {
|
|
77181
77748
|
const source = composed.get(file);
|
|
77182
77749
|
if (!source) continue;
|
|
77183
|
-
const dest =
|
|
77184
|
-
if (
|
|
77750
|
+
const dest = path69.join(harnessDir, file);
|
|
77751
|
+
if (fs62.existsSync(dest)) continue;
|
|
77185
77752
|
const rendered = substituteTemplateTokens(readComposedTemplateContent(source), projectName);
|
|
77186
|
-
|
|
77187
|
-
|
|
77188
|
-
if (/\.(sh|mjs)$/.test(file))
|
|
77753
|
+
fs62.mkdirSync(path69.dirname(dest), { recursive: true });
|
|
77754
|
+
fs62.writeFileSync(dest, rendered);
|
|
77755
|
+
if (/\.(sh|mjs)$/.test(file)) fs62.chmodSync(dest, 493);
|
|
77189
77756
|
written.push(file);
|
|
77190
77757
|
}
|
|
77191
77758
|
if (effective.phantomVerificationIds.length > 0) {
|
|
@@ -77200,7 +77767,7 @@ function applyPre10Plan(repoPath, plan) {
|
|
|
77200
77767
|
}
|
|
77201
77768
|
if (effective.env) {
|
|
77202
77769
|
backup("harness.env");
|
|
77203
|
-
|
|
77770
|
+
fs62.writeFileSync(path69.join(harnessDir, "harness.env"), effective.env.content);
|
|
77204
77771
|
written.push("harness.env");
|
|
77205
77772
|
}
|
|
77206
77773
|
const manifest = readManifest(resolved);
|
|
@@ -77215,8 +77782,8 @@ function applyPre10Plan(repoPath, plan) {
|
|
|
77215
77782
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
77216
77783
|
});
|
|
77217
77784
|
}
|
|
77218
|
-
|
|
77219
|
-
|
|
77785
|
+
fs62.writeFileSync(
|
|
77786
|
+
path69.join(harnessDir, MIGRATE_PLAN_FILE),
|
|
77220
77787
|
JSON.stringify({ ...effective, appliedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2) + "\n"
|
|
77221
77788
|
);
|
|
77222
77789
|
return { plan: effective, backupDir, written, deleted };
|
|
@@ -77236,33 +77803,33 @@ function pendingMigrations(repoPath) {
|
|
|
77236
77803
|
);
|
|
77237
77804
|
}
|
|
77238
77805
|
function writeMigrationPlan(repoPath, plan) {
|
|
77239
|
-
const harnessDir = getHarnessDir(
|
|
77240
|
-
const planPath =
|
|
77241
|
-
|
|
77242
|
-
|
|
77806
|
+
const harnessDir = getHarnessDir(path69.resolve(repoPath));
|
|
77807
|
+
const planPath = path69.join(harnessDir, MIGRATE_PLAN_FILE);
|
|
77808
|
+
fs62.mkdirSync(path69.dirname(planPath), { recursive: true });
|
|
77809
|
+
fs62.writeFileSync(planPath, JSON.stringify(plan, null, 2) + "\n");
|
|
77243
77810
|
return planPath;
|
|
77244
77811
|
}
|
|
77245
77812
|
function removeMigrationArtifacts(repoPath) {
|
|
77246
|
-
const harnessDir = getHarnessDir(
|
|
77247
|
-
|
|
77248
|
-
|
|
77813
|
+
const harnessDir = getHarnessDir(path69.resolve(repoPath));
|
|
77814
|
+
fs62.rmSync(path69.join(harnessDir, MIGRATE_DIR), { recursive: true, force: true });
|
|
77815
|
+
fs62.rmSync(path69.join(harnessDir, "MIGRATE-PROMPT.md"), { force: true });
|
|
77249
77816
|
}
|
|
77250
77817
|
|
|
77251
77818
|
// src/harness/doctor.ts
|
|
77252
77819
|
function listHarnessShellScripts(harnessDir) {
|
|
77253
77820
|
const out = [];
|
|
77254
77821
|
const push = (dir, prefix) => {
|
|
77255
|
-
if (!
|
|
77256
|
-
for (const entry of
|
|
77822
|
+
if (!fs63.existsSync(dir)) return;
|
|
77823
|
+
for (const entry of fs63.readdirSync(dir).sort()) {
|
|
77257
77824
|
if (!entry.endsWith(".sh")) continue;
|
|
77258
|
-
const full =
|
|
77259
|
-
if (!
|
|
77825
|
+
const full = path70.join(dir, entry);
|
|
77826
|
+
if (!fs63.statSync(full).isFile()) continue;
|
|
77260
77827
|
out.push(prefix ? `${prefix}/${entry}` : entry);
|
|
77261
77828
|
}
|
|
77262
77829
|
};
|
|
77263
77830
|
push(harnessDir, "");
|
|
77264
|
-
push(
|
|
77265
|
-
push(
|
|
77831
|
+
push(path70.join(harnessDir, "stages"), "stages");
|
|
77832
|
+
push(path70.join(harnessDir, "hooks"), "hooks");
|
|
77266
77833
|
return out;
|
|
77267
77834
|
}
|
|
77268
77835
|
var CHECK_LABELS = {
|
|
@@ -77275,14 +77842,15 @@ var CHECK_LABELS = {
|
|
|
77275
77842
|
"slot-registry": "slot registry worktrees",
|
|
77276
77843
|
hooks: "lifecycle hooks (.har/hooks)",
|
|
77277
77844
|
"retired-machinery": "no references to retired runtime machinery",
|
|
77278
|
-
"ejected-runtime": "ejected runtime (user-owned)"
|
|
77845
|
+
"ejected-runtime": "ejected runtime (user-owned)",
|
|
77846
|
+
"factory-lines": "factory lines stay off verify"
|
|
77279
77847
|
};
|
|
77280
77848
|
var PRE_1_0_FUNCTION_RE = /^\s*(har_infra_enabled|har_pg|har_node_[a-z_]+|har_pkg_exec)\s*\(\)/m;
|
|
77281
77849
|
var LEGACY_TRIPLET_RE = /^export\s+HARNESS_[A-Z0-9_]+_PORT_(DEFAULT|SCAN_START|SCAN_END)=/m;
|
|
77282
77850
|
function detectContract(harnessDir) {
|
|
77283
|
-
const envPath =
|
|
77284
|
-
if (!
|
|
77285
|
-
const content =
|
|
77851
|
+
const envPath = path70.join(harnessDir, "harness.env");
|
|
77852
|
+
if (!fs63.existsSync(envPath)) return "none";
|
|
77853
|
+
const content = fs63.readFileSync(envPath, "utf8");
|
|
77286
77854
|
if (PRE_1_0_FUNCTION_RE.test(content) || LEGACY_TRIPLET_RE.test(content)) {
|
|
77287
77855
|
return "pre-1.0";
|
|
77288
77856
|
}
|
|
@@ -77292,18 +77860,18 @@ function resolveStageFile(harnessDir, stage) {
|
|
|
77292
77860
|
if (PACKAGE_RUNTIME_KINDS.has(stage.kind) && (!stage.command && !stage.script || stagePointsAtLifecycleShim(stage))) {
|
|
77293
77861
|
return null;
|
|
77294
77862
|
}
|
|
77295
|
-
if (stage.script) return
|
|
77863
|
+
if (stage.script) return path70.join(harnessDir, stage.script);
|
|
77296
77864
|
if (stage.command) {
|
|
77297
77865
|
const first = stage.command.trim().split(/\s+/)[0];
|
|
77298
77866
|
if (first.startsWith("./.har/")) {
|
|
77299
|
-
return
|
|
77867
|
+
return path70.join(harnessDir, first.replace(/^\.\/\.har\//, ""));
|
|
77300
77868
|
}
|
|
77301
77869
|
if (first.startsWith(".har/")) {
|
|
77302
|
-
return
|
|
77870
|
+
return path70.join(harnessDir, first.replace(/^\.har\//, ""));
|
|
77303
77871
|
}
|
|
77304
77872
|
return null;
|
|
77305
77873
|
}
|
|
77306
|
-
return
|
|
77874
|
+
return path70.join(harnessDir, "stages", `${stage.id}.sh`);
|
|
77307
77875
|
}
|
|
77308
77876
|
function checkStatus(findings, id) {
|
|
77309
77877
|
const mine = findings.filter((f) => f.check === id);
|
|
@@ -77315,7 +77883,7 @@ function runDoctor(repoPath) {
|
|
|
77315
77883
|
const harnessDir = getHarnessDir(repoPath);
|
|
77316
77884
|
const findings = [];
|
|
77317
77885
|
const skipped = /* @__PURE__ */ new Set();
|
|
77318
|
-
if (!
|
|
77886
|
+
if (!fs63.existsSync(harnessDir)) {
|
|
77319
77887
|
return {
|
|
77320
77888
|
ok: false,
|
|
77321
77889
|
contract: "none",
|
|
@@ -77362,9 +77930,9 @@ function runDoctor(repoPath) {
|
|
|
77362
77930
|
}
|
|
77363
77931
|
let registry2 = null;
|
|
77364
77932
|
try {
|
|
77365
|
-
const stagesPath =
|
|
77366
|
-
if (
|
|
77367
|
-
const raw = JSON.parse(
|
|
77933
|
+
const stagesPath = path70.join(harnessDir, "stages.json");
|
|
77934
|
+
if (fs63.existsSync(stagesPath)) {
|
|
77935
|
+
const raw = JSON.parse(fs63.readFileSync(stagesPath, "utf8"));
|
|
77368
77936
|
if (typeof raw !== "object" || raw === null || !Array.isArray(raw.stages)) {
|
|
77369
77937
|
throw new Error("stages.json has no `stages` array \u2014 the registry is structurally invalid");
|
|
77370
77938
|
}
|
|
@@ -77395,8 +77963,8 @@ function runDoctor(repoPath) {
|
|
|
77395
77963
|
for (const stage of registry2.stages) {
|
|
77396
77964
|
const file = resolveStageFile(harnessDir, stage);
|
|
77397
77965
|
if (!file) continue;
|
|
77398
|
-
const rel =
|
|
77399
|
-
if (!
|
|
77966
|
+
const rel = path70.relative(harnessDir, file);
|
|
77967
|
+
if (!fs63.existsSync(file)) {
|
|
77400
77968
|
findings.push({
|
|
77401
77969
|
check: "stage-files",
|
|
77402
77970
|
severity: contractSeverity,
|
|
@@ -77406,7 +77974,7 @@ function runDoctor(repoPath) {
|
|
|
77406
77974
|
});
|
|
77407
77975
|
continue;
|
|
77408
77976
|
}
|
|
77409
|
-
if (rel.endsWith(".sh") && !(
|
|
77977
|
+
if (rel.endsWith(".sh") && !(fs63.statSync(file).mode & 73)) {
|
|
77410
77978
|
findings.push({
|
|
77411
77979
|
check: "stage-files",
|
|
77412
77980
|
severity: "warning",
|
|
@@ -77429,13 +77997,13 @@ function runDoctor(repoPath) {
|
|
|
77429
77997
|
continue;
|
|
77430
77998
|
}
|
|
77431
77999
|
const file = resolveStageFile(harnessDir, stage);
|
|
77432
|
-
if (file && !
|
|
78000
|
+
if (file && !fs63.existsSync(file)) {
|
|
77433
78001
|
findings.push({
|
|
77434
78002
|
check: "lifecycle-stages",
|
|
77435
78003
|
severity: contractSeverity,
|
|
77436
|
-
file:
|
|
78004
|
+
file: path70.relative(harnessDir, file),
|
|
77437
78005
|
message: `Lifecycle stage \`${stage.id}\` (${kind}) points at a missing file`,
|
|
77438
|
-
remedy: `Restore .har/${
|
|
78006
|
+
remedy: `Restore .har/${path70.relative(harnessDir, file)} or fix the \`${stage.id}\` entry in stages.json`
|
|
77439
78007
|
});
|
|
77440
78008
|
}
|
|
77441
78009
|
}
|
|
@@ -77480,9 +78048,9 @@ function runDoctor(repoPath) {
|
|
|
77480
78048
|
if (!manifest?.ejected) {
|
|
77481
78049
|
skipped.add("ejected-runtime");
|
|
77482
78050
|
} else {
|
|
77483
|
-
const runtimeRel =
|
|
77484
|
-
const runtimePath =
|
|
77485
|
-
if (!
|
|
78051
|
+
const runtimeRel = path70.join(EJECTED_RUNTIME_DIR, EJECTED_RUNTIME_BUNDLE);
|
|
78052
|
+
const runtimePath = path70.join(harnessDir, runtimeRel);
|
|
78053
|
+
if (!fs63.existsSync(runtimePath)) {
|
|
77486
78054
|
findings.push({
|
|
77487
78055
|
check: "ejected-runtime",
|
|
77488
78056
|
severity: "error",
|
|
@@ -77495,7 +78063,7 @@ function runDoctor(repoPath) {
|
|
|
77495
78063
|
for (const entry of listSlotRegistryEntries(repoPath)) {
|
|
77496
78064
|
if (entry.status === "completed") continue;
|
|
77497
78065
|
const dir = entry.worktreePath ?? entry.workDir;
|
|
77498
|
-
if (dir && !
|
|
78066
|
+
if (dir && !fs63.existsSync(dir)) {
|
|
77499
78067
|
findings.push({
|
|
77500
78068
|
check: "slot-registry",
|
|
77501
78069
|
severity: "warning",
|
|
@@ -77505,11 +78073,11 @@ function runDoctor(repoPath) {
|
|
|
77505
78073
|
});
|
|
77506
78074
|
}
|
|
77507
78075
|
}
|
|
77508
|
-
const hooksDir =
|
|
77509
|
-
if (
|
|
77510
|
-
for (const file of
|
|
77511
|
-
const full =
|
|
77512
|
-
if (!
|
|
78076
|
+
const hooksDir = path70.join(harnessDir, "hooks");
|
|
78077
|
+
if (fs63.existsSync(hooksDir)) {
|
|
78078
|
+
for (const file of fs63.readdirSync(hooksDir).sort()) {
|
|
78079
|
+
const full = path70.join(hooksDir, file);
|
|
78080
|
+
if (!fs63.statSync(full).isFile() || !file.endsWith(".sh")) continue;
|
|
77513
78081
|
if (!LIFECYCLE_HOOKS.includes(file.replace(/\.sh$/, ""))) {
|
|
77514
78082
|
findings.push({
|
|
77515
78083
|
check: "hooks",
|
|
@@ -77520,7 +78088,7 @@ function runDoctor(repoPath) {
|
|
|
77520
78088
|
});
|
|
77521
78089
|
continue;
|
|
77522
78090
|
}
|
|
77523
|
-
if (!(
|
|
78091
|
+
if (!(fs63.statSync(full).mode & 73)) {
|
|
77524
78092
|
findings.push({
|
|
77525
78093
|
check: "hooks",
|
|
77526
78094
|
severity: "warning",
|
|
@@ -77532,15 +78100,15 @@ function runDoctor(repoPath) {
|
|
|
77532
78100
|
}
|
|
77533
78101
|
}
|
|
77534
78102
|
for (const rel of listHarnessShellScripts(harnessDir)) {
|
|
77535
|
-
const full =
|
|
78103
|
+
const full = path70.join(harnessDir, rel);
|
|
77536
78104
|
let content;
|
|
77537
78105
|
try {
|
|
77538
|
-
content =
|
|
78106
|
+
content = fs63.readFileSync(full, "utf8");
|
|
77539
78107
|
} catch {
|
|
77540
78108
|
continue;
|
|
77541
78109
|
}
|
|
77542
78110
|
for (const machinery of LEGACY_MACHINERY_FILES) {
|
|
77543
|
-
if (
|
|
78111
|
+
if (fs63.existsSync(path70.join(harnessDir, machinery))) continue;
|
|
77544
78112
|
const base = machinery.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
77545
78113
|
const loadRe = new RegExp(
|
|
77546
78114
|
`(?:\\bsource\\b|\\bbash\\b|\\bexec\\b|(?:^|[;&|(])\\s*\\.\\s)[^\\n#]*${base}`
|
|
@@ -77559,6 +78127,46 @@ function runDoctor(repoPath) {
|
|
|
77559
78127
|
break;
|
|
77560
78128
|
}
|
|
77561
78129
|
}
|
|
78130
|
+
const lineLedger = readLineLedger(repoPath);
|
|
78131
|
+
if (lineLedger) {
|
|
78132
|
+
const verificationStages = registry2?.verificationStages ?? [];
|
|
78133
|
+
const registeredIds = new Set((registry2?.stages ?? []).map((stage) => stage.id));
|
|
78134
|
+
for (const line of lineLedger.lines) {
|
|
78135
|
+
for (const stageId of line.stageIds) {
|
|
78136
|
+
if (verificationStages.includes(stageId)) {
|
|
78137
|
+
findings.push({
|
|
78138
|
+
check: "factory-lines",
|
|
78139
|
+
severity: "error",
|
|
78140
|
+
file: "stages.json",
|
|
78141
|
+
message: `line "${line.id}" stage "${stageId}" is listed in verificationStages`,
|
|
78142
|
+
remedy: "Remove it from verificationStages \u2014 line gate stages run via `har line gate <station>`. If it must gate every verify, ship it as a verification plugin instead."
|
|
78143
|
+
});
|
|
78144
|
+
}
|
|
78145
|
+
}
|
|
78146
|
+
const program = readInstalledLineProgram(repoPath, line.id);
|
|
78147
|
+
if (!program) {
|
|
78148
|
+
findings.push({
|
|
78149
|
+
check: "factory-lines",
|
|
78150
|
+
severity: "warning",
|
|
78151
|
+
file: line.programPath,
|
|
78152
|
+
message: `line "${line.id}" is in .har/lines.json but its program is missing or invalid`,
|
|
78153
|
+
remedy: `Reinstall it (\`har line add ${line.id}\`) or drop the entry from .har/lines.json`
|
|
78154
|
+
});
|
|
78155
|
+
continue;
|
|
78156
|
+
}
|
|
78157
|
+
for (const gateStage of program.gate.stages) {
|
|
78158
|
+
if (!registeredIds.has(gateStage.id)) {
|
|
78159
|
+
findings.push({
|
|
78160
|
+
check: "factory-lines",
|
|
78161
|
+
severity: "warning",
|
|
78162
|
+
file: line.programPath,
|
|
78163
|
+
message: `line "${line.id}" gate stage "${gateStage.id}" (from ${gateStage.fromStation}) is not registered in stages.json`,
|
|
78164
|
+
remedy: "Install the plugin that provides it, add it to the line bundle, or drop the gate tag"
|
|
78165
|
+
});
|
|
78166
|
+
}
|
|
78167
|
+
}
|
|
78168
|
+
}
|
|
78169
|
+
}
|
|
77562
78170
|
const checks = Object.keys(CHECK_LABELS).map(
|
|
77563
78171
|
(id) => skipped.has(id) ? { id, label: CHECK_LABELS[id], status: "skip" } : checkStatus(findings, id)
|
|
77564
78172
|
);
|
|
@@ -77604,8 +78212,8 @@ function summarizeDoctorReport(report) {
|
|
|
77604
78212
|
}
|
|
77605
78213
|
|
|
77606
78214
|
// src/harness/migrate-prompt.ts
|
|
77607
|
-
var
|
|
77608
|
-
var
|
|
78215
|
+
var fs64 = __toESM(require("fs"));
|
|
78216
|
+
var path71 = __toESM(require("path"));
|
|
77609
78217
|
init_paths();
|
|
77610
78218
|
init_file_ops();
|
|
77611
78219
|
init_manifest();
|
|
@@ -77719,13 +78327,13 @@ function loadTemplate2() {
|
|
|
77719
78327
|
if (!filePath) {
|
|
77720
78328
|
throw new Error("Migration prompt template not found: migration-prompt.md. Run npm run build.");
|
|
77721
78329
|
}
|
|
77722
|
-
return
|
|
78330
|
+
return fs64.readFileSync(filePath, "utf8");
|
|
77723
78331
|
}
|
|
77724
78332
|
function buildMigrationPrompt(plan, applied) {
|
|
77725
78333
|
return loadTemplate2().replace("{{MIGRATION_SECTION}}", buildMigrationSection(plan, applied));
|
|
77726
78334
|
}
|
|
77727
78335
|
function writeMigrationPrompt(repoPath, content) {
|
|
77728
|
-
const filePath =
|
|
78336
|
+
const filePath = path71.join(getHarnessDir(repoPath), MIGRATE_PROMPT_FILE);
|
|
77729
78337
|
writeFileSafe(filePath, content);
|
|
77730
78338
|
return filePath;
|
|
77731
78339
|
}
|
|
@@ -77733,11 +78341,11 @@ function writeMigrationPrompt(repoPath, content) {
|
|
|
77733
78341
|
// src/core/harness.ts
|
|
77734
78342
|
function listHarnessScripts(repoPath) {
|
|
77735
78343
|
const harnessDir = getHarnessDir(repoPath);
|
|
77736
|
-
if (!
|
|
77737
|
-
return
|
|
78344
|
+
if (!fs65.existsSync(harnessDir)) return [];
|
|
78345
|
+
return fs65.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
|
|
77738
78346
|
}
|
|
77739
78347
|
function describeProject(repoPath) {
|
|
77740
|
-
const resolved =
|
|
78348
|
+
const resolved = path72.resolve(repoPath);
|
|
77741
78349
|
const manifest = readManifest(resolved);
|
|
77742
78350
|
const present = harnessExists(resolved);
|
|
77743
78351
|
return {
|
|
@@ -77757,8 +78365,8 @@ function describeProject(repoPath) {
|
|
|
77757
78365
|
};
|
|
77758
78366
|
}
|
|
77759
78367
|
async function initHarness(options) {
|
|
77760
|
-
const repoPath =
|
|
77761
|
-
if (!
|
|
78368
|
+
const repoPath = path72.resolve(options.repoPath);
|
|
78369
|
+
if (!fs65.existsSync(repoPath)) {
|
|
77762
78370
|
throw new Error(`Path not found: ${repoPath}`);
|
|
77763
78371
|
}
|
|
77764
78372
|
const scaffold = scaffoldHarnessBoilerplate(repoPath, {
|
|
@@ -77779,9 +78387,9 @@ async function initHarness(options) {
|
|
|
77779
78387
|
};
|
|
77780
78388
|
}
|
|
77781
78389
|
async function maintainHarness(options) {
|
|
77782
|
-
const repoPath =
|
|
78390
|
+
const repoPath = path72.resolve(options.repoPath);
|
|
77783
78391
|
const harnessDir = getHarnessDir(repoPath);
|
|
77784
|
-
if (!
|
|
78392
|
+
if (!fs65.existsSync(harnessDir)) {
|
|
77785
78393
|
throw new Error('No .har/ found. Run "har onboard" first.');
|
|
77786
78394
|
}
|
|
77787
78395
|
let migration;
|
|
@@ -77858,8 +78466,8 @@ function addPlugin(repoPath, pluginId, options = {}) {
|
|
|
77858
78466
|
}
|
|
77859
78467
|
|
|
77860
78468
|
// src/harness/adaptation-prompt.ts
|
|
77861
|
-
var
|
|
77862
|
-
var
|
|
78469
|
+
var fs66 = __toESM(require("fs"));
|
|
78470
|
+
var path73 = __toESM(require("path"));
|
|
77863
78471
|
var readline5 = __toESM(require("readline"));
|
|
77864
78472
|
|
|
77865
78473
|
// src/utils/clipboard.ts
|
|
@@ -77950,7 +78558,7 @@ function loadTemplate3(name) {
|
|
|
77950
78558
|
if (!filePath) {
|
|
77951
78559
|
throw new Error(`Adaptation prompt template not found: ${name}. Run npm run build.`);
|
|
77952
78560
|
}
|
|
77953
|
-
return
|
|
78561
|
+
return fs66.readFileSync(filePath, "utf8");
|
|
77954
78562
|
}
|
|
77955
78563
|
function applyProfilePlaceholders(content, profile) {
|
|
77956
78564
|
return content.replace(/\{\{PROFILE\}\}/g, profile).replace(/\{\{PROFILE_HINT\}\}/g, PROFILE_HINTS[profile]);
|
|
@@ -77972,7 +78580,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
|
|
|
77972
78580
|
}
|
|
77973
78581
|
function writeAdaptationPrompt(repoPath, content) {
|
|
77974
78582
|
const harnessDir = getHarnessDir(repoPath);
|
|
77975
|
-
const filePath =
|
|
78583
|
+
const filePath = path73.join(harnessDir, ADAPTATION_PROMPT_FILE);
|
|
77976
78584
|
writeFileSafe(filePath, content);
|
|
77977
78585
|
return filePath;
|
|
77978
78586
|
}
|
|
@@ -77991,12 +78599,12 @@ function printAdaptationPrompt(content) {
|
|
|
77991
78599
|
}
|
|
77992
78600
|
function askYesNo2(question) {
|
|
77993
78601
|
const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
|
|
77994
|
-
return new Promise((
|
|
78602
|
+
return new Promise((resolve66) => {
|
|
77995
78603
|
process.stderr.write(`${question} `);
|
|
77996
78604
|
rl.once("line", (answer) => {
|
|
77997
78605
|
rl.close();
|
|
77998
78606
|
const trimmed = answer.trim();
|
|
77999
|
-
|
|
78607
|
+
resolve66(trimmed === "" || /^y(es)?$/i.test(trimmed));
|
|
78000
78608
|
});
|
|
78001
78609
|
});
|
|
78002
78610
|
}
|
|
@@ -78028,28 +78636,28 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
|
|
|
78028
78636
|
}
|
|
78029
78637
|
|
|
78030
78638
|
// src/harness/cursor-rule.ts
|
|
78031
|
-
var
|
|
78032
|
-
var
|
|
78639
|
+
var fs67 = __toESM(require("fs"));
|
|
78640
|
+
var path74 = __toESM(require("path"));
|
|
78033
78641
|
var readline6 = __toESM(require("readline"));
|
|
78034
78642
|
init_file_ops();
|
|
78035
78643
|
init_logging();
|
|
78036
78644
|
init_paths();
|
|
78037
78645
|
var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
|
|
78038
78646
|
function getCursorRulePath(repoPath) {
|
|
78039
|
-
return
|
|
78647
|
+
return path74.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
|
|
78040
78648
|
}
|
|
78041
78649
|
function isCursorWorkspace(repoPath) {
|
|
78042
|
-
return
|
|
78650
|
+
return fs67.existsSync(path74.join(repoPath, ".cursor"));
|
|
78043
78651
|
}
|
|
78044
78652
|
function cursorRuleExists(repoPath) {
|
|
78045
|
-
return
|
|
78653
|
+
return fs67.existsSync(getCursorRulePath(repoPath));
|
|
78046
78654
|
}
|
|
78047
78655
|
function scaffoldCursorRule(repoPath) {
|
|
78048
78656
|
const templatePath = resolveTemplateFile("cursor-rule.mdc.template");
|
|
78049
78657
|
if (!templatePath) {
|
|
78050
78658
|
throw new Error("Cursor rule template not found (cursor-rule.mdc.template). Run npm run build.");
|
|
78051
78659
|
}
|
|
78052
|
-
const content =
|
|
78660
|
+
const content = fs67.readFileSync(templatePath, "utf8");
|
|
78053
78661
|
writeFileSafe(getCursorRulePath(repoPath), content);
|
|
78054
78662
|
}
|
|
78055
78663
|
async function handleCursorRule(options) {
|
|
@@ -78087,16 +78695,16 @@ async function promptScaffoldCursorRule(exists) {
|
|
|
78087
78695
|
}
|
|
78088
78696
|
async function askYesNo3(question) {
|
|
78089
78697
|
const rl = readline6.createInterface({ input: process.stdin, output: process.stderr });
|
|
78090
|
-
return new Promise((
|
|
78698
|
+
return new Promise((resolve66) => {
|
|
78091
78699
|
process.stderr.write(`${question} `);
|
|
78092
78700
|
rl.once("line", (answer) => {
|
|
78093
78701
|
rl.close();
|
|
78094
78702
|
const trimmed = answer.trim();
|
|
78095
78703
|
if (trimmed === "") {
|
|
78096
|
-
|
|
78704
|
+
resolve66(true);
|
|
78097
78705
|
return;
|
|
78098
78706
|
}
|
|
78099
|
-
|
|
78707
|
+
resolve66(/^y(es)?$/i.test(trimmed));
|
|
78100
78708
|
});
|
|
78101
78709
|
});
|
|
78102
78710
|
}
|
|
@@ -78140,7 +78748,7 @@ init_control_config();
|
|
|
78140
78748
|
|
|
78141
78749
|
// src/core/control-lifecycle.ts
|
|
78142
78750
|
var import_child_process18 = require("child_process");
|
|
78143
|
-
var
|
|
78751
|
+
var path75 = __toESM(require("path"));
|
|
78144
78752
|
|
|
78145
78753
|
// src/core/control-image.ts
|
|
78146
78754
|
init_package_version();
|
|
@@ -78167,10 +78775,10 @@ var CONTROL_DATA_VOLUME = "har_control_data";
|
|
|
78167
78775
|
var CONTROL_CONTAINER_PORT = 3847;
|
|
78168
78776
|
var CONTROL_DATA_DB_URL = "file:/data/har_control.db";
|
|
78169
78777
|
function resolveControlDir() {
|
|
78170
|
-
return
|
|
78778
|
+
return path75.resolve(__dirname, "..", "control");
|
|
78171
78779
|
}
|
|
78172
78780
|
function resolveControlBuildContext() {
|
|
78173
|
-
return
|
|
78781
|
+
return path75.resolve(resolveControlDir(), "..");
|
|
78174
78782
|
}
|
|
78175
78783
|
function buildDockerRunArgs(options) {
|
|
78176
78784
|
const name = options.containerName ?? CONTROL_CONTAINER_NAME;
|
|
@@ -78226,7 +78834,7 @@ async function startMissionControl(options) {
|
|
|
78226
78834
|
"-t",
|
|
78227
78835
|
imageRef,
|
|
78228
78836
|
"-f",
|
|
78229
|
-
|
|
78837
|
+
path75.join(resolveControlDir(), "Dockerfile"),
|
|
78230
78838
|
resolveControlBuildContext()
|
|
78231
78839
|
]);
|
|
78232
78840
|
if (buildCode !== 0) {
|
|
@@ -78373,7 +78981,7 @@ async function ensureTelemetryInfrastructure(options) {
|
|
|
78373
78981
|
// src/core/run-service.ts
|
|
78374
78982
|
init_telemetry_config();
|
|
78375
78983
|
init_telemetry_env();
|
|
78376
|
-
var
|
|
78984
|
+
var path77 = __toESM(require("path"));
|
|
78377
78985
|
init_local_executor();
|
|
78378
78986
|
function extractShellOutput(result) {
|
|
78379
78987
|
const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
|
|
@@ -78596,12 +79204,12 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
|
|
|
78596
79204
|
suffix: session.suffix,
|
|
78597
79205
|
createdAt: session.createdAt
|
|
78598
79206
|
});
|
|
78599
|
-
const envFile =
|
|
79207
|
+
const envFile = path77.join(session.workDir, `.env.agent.${options.agentId}`);
|
|
78600
79208
|
try {
|
|
78601
79209
|
appendTelemetryEnvToFile(envFile, {
|
|
78602
79210
|
sessionKey,
|
|
78603
79211
|
agentId: options.agentId,
|
|
78604
|
-
repoPath:
|
|
79212
|
+
repoPath: path77.resolve(options.repoPath),
|
|
78605
79213
|
workDir: session.workDir,
|
|
78606
79214
|
branch: session.branch,
|
|
78607
79215
|
suffix: session.suffix,
|
|
@@ -78843,9 +79451,9 @@ init_work_units();
|
|
|
78843
79451
|
init_manifest();
|
|
78844
79452
|
|
|
78845
79453
|
// src/core/cleanup-service.ts
|
|
78846
|
-
var
|
|
79454
|
+
var fs69 = __toESM(require("fs"));
|
|
78847
79455
|
var os23 = __toESM(require("os"));
|
|
78848
|
-
var
|
|
79456
|
+
var path78 = __toESM(require("path"));
|
|
78849
79457
|
var import_child_process20 = require("child_process");
|
|
78850
79458
|
init_control_sync();
|
|
78851
79459
|
init_control_repo_path();
|
|
@@ -78854,9 +79462,9 @@ init_manifest();
|
|
|
78854
79462
|
var DEFAULT_STALE_DAYS = 7;
|
|
78855
79463
|
function getWorktreesRoot() {
|
|
78856
79464
|
if (process.env.HAR_WORKTREES_ROOT) {
|
|
78857
|
-
return
|
|
79465
|
+
return path78.resolve(process.env.HAR_WORKTREES_ROOT);
|
|
78858
79466
|
}
|
|
78859
|
-
return
|
|
79467
|
+
return path78.join(process.env.HOME || os23.homedir(), "worktrees");
|
|
78860
79468
|
}
|
|
78861
79469
|
function runGit3(cwd, args) {
|
|
78862
79470
|
try {
|
|
@@ -78870,7 +79478,7 @@ function runGit3(cwd, args) {
|
|
|
78870
79478
|
}
|
|
78871
79479
|
}
|
|
78872
79480
|
function basenameRepo(repoPath) {
|
|
78873
|
-
return
|
|
79481
|
+
return path78.basename(canonicalizeControlRepoPath(repoPath));
|
|
78874
79482
|
}
|
|
78875
79483
|
function ageDaysFrom(iso) {
|
|
78876
79484
|
if (!iso) return void 0;
|
|
@@ -78882,12 +79490,12 @@ function matchesKeep(candidate, keep) {
|
|
|
78882
79490
|
if (!keep?.length) return false;
|
|
78883
79491
|
for (const pin of keep) {
|
|
78884
79492
|
if (pin.worktreePath && candidate.worktreePath) {
|
|
78885
|
-
if (
|
|
79493
|
+
if (path78.resolve(pin.worktreePath) === path78.resolve(candidate.worktreePath)) return true;
|
|
78886
79494
|
}
|
|
78887
79495
|
if (pin.repoPath && pin.agentId !== void 0 && candidate.agentId !== void 0) {
|
|
78888
79496
|
const repo = canonicalizeControlRepoPath(pin.repoPath);
|
|
78889
|
-
const candidateRepo =
|
|
78890
|
-
if ((repo === candidateRepo ||
|
|
79497
|
+
const candidateRepo = path78.resolve(candidate.repoPath);
|
|
79498
|
+
if ((repo === candidateRepo || path78.resolve(pin.repoPath) === candidateRepo) && pin.agentId === candidate.agentId) {
|
|
78891
79499
|
return true;
|
|
78892
79500
|
}
|
|
78893
79501
|
}
|
|
@@ -78942,20 +79550,20 @@ function classifySlotCandidate(repoPath, projectName, slot, options) {
|
|
|
78942
79550
|
return candidate;
|
|
78943
79551
|
}
|
|
78944
79552
|
function resolveRepoForWorktree(worktreePath) {
|
|
78945
|
-
if (!
|
|
79553
|
+
if (!fs69.existsSync(worktreePath)) return void 0;
|
|
78946
79554
|
const commonDir = runGit3(worktreePath, "rev-parse --git-common-dir");
|
|
78947
79555
|
if (!commonDir) return void 0;
|
|
78948
|
-
const gitRoot =
|
|
79556
|
+
const gitRoot = path78.resolve(worktreePath, commonDir, "..");
|
|
78949
79557
|
if (!readManifest(gitRoot)) return void 0;
|
|
78950
79558
|
return canonicalizeControlRepoPath(gitRoot);
|
|
78951
79559
|
}
|
|
78952
79560
|
function discoverOrphanWorktrees(knownPaths) {
|
|
78953
79561
|
const worktreesRoot = getWorktreesRoot();
|
|
78954
|
-
if (!
|
|
79562
|
+
if (!fs69.existsSync(worktreesRoot)) return [];
|
|
78955
79563
|
const orphans = [];
|
|
78956
|
-
for (const entry of
|
|
79564
|
+
for (const entry of fs69.readdirSync(worktreesRoot, { withFileTypes: true })) {
|
|
78957
79565
|
if (!entry.isDirectory() || !entry.name.includes("-har-agent-")) continue;
|
|
78958
|
-
const worktreePath =
|
|
79566
|
+
const worktreePath = path78.resolve(path78.join(worktreesRoot, entry.name));
|
|
78959
79567
|
if (knownPaths.has(worktreePath)) continue;
|
|
78960
79568
|
const repoPath = resolveRepoForWorktree(worktreePath) ?? worktreesRoot;
|
|
78961
79569
|
const porcelain = runGit3(worktreePath, "status --porcelain");
|
|
@@ -78980,14 +79588,14 @@ async function discoverCleanupCandidates(options = {}) {
|
|
|
78980
79588
|
const candidates = [];
|
|
78981
79589
|
const knownWorktreePaths = /* @__PURE__ */ new Set();
|
|
78982
79590
|
for (const repoPath of repoPaths) {
|
|
78983
|
-
if (!
|
|
79591
|
+
if (!fs69.existsSync(repoPath) || !readManifest(repoPath)) continue;
|
|
78984
79592
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
78985
79593
|
const canonicalRepo = canonicalizeControlRepoPath(harnessRoot);
|
|
78986
79594
|
const status = collectEnvironmentStatus(harnessRoot);
|
|
78987
79595
|
const projectName = basenameRepo(harnessRoot);
|
|
78988
79596
|
for (const slot of status.slots) {
|
|
78989
|
-
if (slot.worktreePath) knownWorktreePaths.add(
|
|
78990
|
-
if (slot.workDir) knownWorktreePaths.add(
|
|
79597
|
+
if (slot.worktreePath) knownWorktreePaths.add(path78.resolve(slot.worktreePath));
|
|
79598
|
+
if (slot.workDir) knownWorktreePaths.add(path78.resolve(slot.workDir));
|
|
78991
79599
|
const candidate = classifySlotCandidate(canonicalRepo, projectName, slot, {
|
|
78992
79600
|
staleDays: options.staleDays,
|
|
78993
79601
|
keep: options.keep
|
|
@@ -79047,8 +79655,8 @@ async function askYesNo4(question) {
|
|
|
79047
79655
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
79048
79656
|
const readline8 = await import("readline");
|
|
79049
79657
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
79050
|
-
const answer = await new Promise((
|
|
79051
|
-
rl.question(question,
|
|
79658
|
+
const answer = await new Promise((resolve66) => {
|
|
79659
|
+
rl.question(question, resolve66);
|
|
79052
79660
|
});
|
|
79053
79661
|
rl.close();
|
|
79054
79662
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -79093,7 +79701,7 @@ async function executeCleanupCandidates(candidates, options = {}) {
|
|
|
79093
79701
|
continue;
|
|
79094
79702
|
}
|
|
79095
79703
|
if (candidate.kind === "orphan_worktree" && candidate.worktreePath) {
|
|
79096
|
-
if (
|
|
79704
|
+
if (fs69.existsSync(candidate.worktreePath)) {
|
|
79097
79705
|
const repoRoot = candidate.repoPath !== getWorktreesRoot() ? candidate.repoPath : resolveRepoForWorktree(candidate.worktreePath);
|
|
79098
79706
|
if (repoRoot) {
|
|
79099
79707
|
try {
|
|
@@ -79104,8 +79712,8 @@ async function executeCleanupCandidates(candidates, options = {}) {
|
|
|
79104
79712
|
} catch {
|
|
79105
79713
|
}
|
|
79106
79714
|
}
|
|
79107
|
-
if (
|
|
79108
|
-
|
|
79715
|
+
if (fs69.existsSync(candidate.worktreePath)) {
|
|
79716
|
+
fs69.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
79109
79717
|
}
|
|
79110
79718
|
}
|
|
79111
79719
|
outcomes.push({ candidate, ok: true });
|
|
@@ -79131,7 +79739,7 @@ function parseCleanupKeepPins(values) {
|
|
|
79131
79739
|
}
|
|
79132
79740
|
if (raw.startsWith("/") || raw.startsWith("~")) {
|
|
79133
79741
|
return {
|
|
79134
|
-
worktreePath: raw.startsWith("~") ?
|
|
79742
|
+
worktreePath: raw.startsWith("~") ? path78.join(process.env.HOME || os23.homedir(), raw.slice(2)) : path78.resolve(raw)
|
|
79135
79743
|
};
|
|
79136
79744
|
}
|
|
79137
79745
|
return { repoPath: raw };
|
|
@@ -79145,12 +79753,12 @@ init_stages();
|
|
|
79145
79753
|
init_logging();
|
|
79146
79754
|
function askYesNo5(question) {
|
|
79147
79755
|
const rl = readline7.createInterface({ input: process.stdin, output: process.stderr });
|
|
79148
|
-
return new Promise((
|
|
79756
|
+
return new Promise((resolve66) => {
|
|
79149
79757
|
process.stderr.write(`${question} `);
|
|
79150
79758
|
rl.once("line", (answer) => {
|
|
79151
79759
|
rl.close();
|
|
79152
79760
|
const trimmed = answer.trim();
|
|
79153
|
-
|
|
79761
|
+
resolve66(trimmed === "" || /^y(es)?$/i.test(trimmed));
|
|
79154
79762
|
});
|
|
79155
79763
|
});
|
|
79156
79764
|
}
|
|
@@ -79251,21 +79859,21 @@ function warnIfDockerUnavailable(status = detectDockerStatus()) {
|
|
|
79251
79859
|
}
|
|
79252
79860
|
|
|
79253
79861
|
// src/core/onboarding-preferences.ts
|
|
79254
|
-
var
|
|
79862
|
+
var fs70 = __toESM(require("fs"));
|
|
79255
79863
|
var os24 = __toESM(require("os"));
|
|
79256
|
-
var
|
|
79864
|
+
var path79 = __toESM(require("path"));
|
|
79257
79865
|
init_schema2();
|
|
79258
79866
|
function getOnboardingPreferencesPath() {
|
|
79259
79867
|
if (process.env.HAR_PREFERENCES_PATH) {
|
|
79260
|
-
return
|
|
79868
|
+
return path79.resolve(process.env.HAR_PREFERENCES_PATH);
|
|
79261
79869
|
}
|
|
79262
|
-
return
|
|
79870
|
+
return path79.join(os24.homedir(), ".har", "preferences.json");
|
|
79263
79871
|
}
|
|
79264
79872
|
function readOnboardingPreferences() {
|
|
79265
79873
|
const preferencePath = getOnboardingPreferencesPath();
|
|
79266
79874
|
try {
|
|
79267
|
-
if (!
|
|
79268
|
-
return OnboardingPreferencesSchema.parse(JSON.parse(
|
|
79875
|
+
if (!fs70.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
|
|
79876
|
+
return OnboardingPreferencesSchema.parse(JSON.parse(fs70.readFileSync(preferencePath, "utf8")));
|
|
79269
79877
|
} catch {
|
|
79270
79878
|
return OnboardingPreferencesSchema.parse({});
|
|
79271
79879
|
}
|
|
@@ -79290,8 +79898,8 @@ function writeOnboardingPreferences(overrides) {
|
|
|
79290
79898
|
};
|
|
79291
79899
|
const parsed = OnboardingPreferencesSchema.parse(preference);
|
|
79292
79900
|
const preferencePath = getOnboardingPreferencesPath();
|
|
79293
|
-
|
|
79294
|
-
|
|
79901
|
+
fs70.mkdirSync(path79.dirname(preferencePath), { recursive: true });
|
|
79902
|
+
fs70.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
|
|
79295
79903
|
`);
|
|
79296
79904
|
return parsed;
|
|
79297
79905
|
}
|
|
@@ -79677,7 +80285,7 @@ var envCommand = {
|
|
|
79677
80285
|
}
|
|
79678
80286
|
};
|
|
79679
80287
|
async function handleInit(argv) {
|
|
79680
|
-
const repoPath =
|
|
80288
|
+
const repoPath = path80.resolve(argv.repo);
|
|
79681
80289
|
const onboarding = resolveOnboardingOptions(argv);
|
|
79682
80290
|
header("har env init");
|
|
79683
80291
|
info(`Repository: ${repoPath}`);
|
|
@@ -79724,7 +80332,7 @@ async function handleInit(argv) {
|
|
|
79724
80332
|
}
|
|
79725
80333
|
}
|
|
79726
80334
|
async function handleMaintain(argv) {
|
|
79727
|
-
const repoPath =
|
|
80335
|
+
const repoPath = path80.resolve(argv.repo);
|
|
79728
80336
|
const onboarding = resolveOnboardingOptions(argv);
|
|
79729
80337
|
header("har env maintain");
|
|
79730
80338
|
info(`Repository: ${repoPath}`);
|
|
@@ -79879,7 +80487,7 @@ async function applyAgentIntegrations(options) {
|
|
|
79879
80487
|
}
|
|
79880
80488
|
}
|
|
79881
80489
|
async function handleAddPlugin(argv) {
|
|
79882
|
-
const repoPath =
|
|
80490
|
+
const repoPath = path80.resolve(argv.repo);
|
|
79883
80491
|
const available = listPluginIds();
|
|
79884
80492
|
if (argv.list) {
|
|
79885
80493
|
for (const id of available) {
|
|
@@ -79915,7 +80523,7 @@ async function handleAddPlugin(argv) {
|
|
|
79915
80523
|
console.error(` Docs: ${result.docsPath}`);
|
|
79916
80524
|
console.error("");
|
|
79917
80525
|
info(`Adaptation prompt saved to ${result.adaptPromptPath}`);
|
|
79918
|
-
const promptContent =
|
|
80526
|
+
const promptContent = fs71.readFileSync(path80.join(repoPath, result.adaptPromptPath), "utf8");
|
|
79919
80527
|
await offerAdaptationPromptClipboard(promptContent, { fileLabel: result.adaptPromptPath });
|
|
79920
80528
|
} catch (err) {
|
|
79921
80529
|
error(err.message);
|
|
@@ -79957,7 +80565,7 @@ async function handleAddStage(argv) {
|
|
|
79957
80565
|
});
|
|
79958
80566
|
}
|
|
79959
80567
|
async function handlePreflight(argv) {
|
|
79960
|
-
const repo =
|
|
80568
|
+
const repo = path80.resolve(argv.repo);
|
|
79961
80569
|
const agentId = validateAgentId(argv.id, repo);
|
|
79962
80570
|
const result = await preflightEnvironment({
|
|
79963
80571
|
repoPath: repo,
|
|
@@ -79973,7 +80581,7 @@ async function handlePreflight(argv) {
|
|
|
79973
80581
|
return finishCommand(result.code);
|
|
79974
80582
|
}
|
|
79975
80583
|
async function handleLaunch(argv) {
|
|
79976
|
-
const repo =
|
|
80584
|
+
const repo = path80.resolve(argv.repo);
|
|
79977
80585
|
const agentId = validateAgentId(argv.id, repo);
|
|
79978
80586
|
const result = await launchEnvironment({
|
|
79979
80587
|
repoPath: repo,
|
|
@@ -80015,7 +80623,7 @@ async function handleWorkLink(argv) {
|
|
|
80015
80623
|
error("Provide --link or both --source and --url");
|
|
80016
80624
|
return finishCommand(1);
|
|
80017
80625
|
}
|
|
80018
|
-
const harnessRoot = resolveHarnessRoot(
|
|
80626
|
+
const harnessRoot = resolveHarnessRoot(path80.resolve(argv.repo));
|
|
80019
80627
|
const links = argv.link ? [parseWorkLinkSpec(argv.link)] : [{ source: argv.source, url: argv.url, label: argv.label }];
|
|
80020
80628
|
try {
|
|
80021
80629
|
const record2 = addWorkUnitLinks(harnessRoot, argv.workId, links);
|
|
@@ -80041,7 +80649,7 @@ async function handleRecover(argv) {
|
|
|
80041
80649
|
});
|
|
80042
80650
|
}
|
|
80043
80651
|
async function handleVerify(argv) {
|
|
80044
|
-
const repo =
|
|
80652
|
+
const repo = path80.resolve(argv.repo);
|
|
80045
80653
|
const agentId = validateAgentId(argv.id, repo);
|
|
80046
80654
|
const result = await runVerification({
|
|
80047
80655
|
repoPath: repo,
|
|
@@ -80070,7 +80678,7 @@ async function handleVerify(argv) {
|
|
|
80070
80678
|
return finishCommand(result.code);
|
|
80071
80679
|
}
|
|
80072
80680
|
async function handleTeardown(argv) {
|
|
80073
|
-
const repo =
|
|
80681
|
+
const repo = path80.resolve(argv.repo);
|
|
80074
80682
|
const agentId = validateAgentId(argv.id, repo);
|
|
80075
80683
|
const result = await teardownEnvironment({
|
|
80076
80684
|
repoPath: repo,
|
|
@@ -80081,7 +80689,7 @@ async function handleTeardown(argv) {
|
|
|
80081
80689
|
return finishCommand(result.code);
|
|
80082
80690
|
}
|
|
80083
80691
|
async function handleComplete(argv) {
|
|
80084
|
-
const repo =
|
|
80692
|
+
const repo = path80.resolve(argv.repo);
|
|
80085
80693
|
const agentId = validateAgentId(argv.id, repo);
|
|
80086
80694
|
const result = await completeEnvironment({
|
|
80087
80695
|
repoPath: repo,
|
|
@@ -80102,7 +80710,7 @@ async function handleComplete(argv) {
|
|
|
80102
80710
|
return finishCommand(result.code);
|
|
80103
80711
|
}
|
|
80104
80712
|
async function handleSetupInfra(argv) {
|
|
80105
|
-
const repo =
|
|
80713
|
+
const repo = path80.resolve(argv.repo);
|
|
80106
80714
|
const result = await runStage({
|
|
80107
80715
|
repoPath: repo,
|
|
80108
80716
|
kind: "setup",
|
|
@@ -80112,7 +80720,7 @@ async function handleSetupInfra(argv) {
|
|
|
80112
80720
|
return finishCommand(result.code ?? (result.status === "pass" ? 0 : 1));
|
|
80113
80721
|
}
|
|
80114
80722
|
async function handleAgent(argv) {
|
|
80115
|
-
const repo =
|
|
80723
|
+
const repo = path80.resolve(argv.repo);
|
|
80116
80724
|
const agentId = validateAgentId(argv.id, repo);
|
|
80117
80725
|
const result = await runAgentOp({
|
|
80118
80726
|
repoPath: repo,
|
|
@@ -80123,7 +80731,7 @@ async function handleAgent(argv) {
|
|
|
80123
80731
|
return finishCommand(result.code);
|
|
80124
80732
|
}
|
|
80125
80733
|
async function handleDoctor(argv) {
|
|
80126
|
-
const repoPath =
|
|
80734
|
+
const repoPath = path80.resolve(argv.repo);
|
|
80127
80735
|
const report = runDoctor(repoPath);
|
|
80128
80736
|
if (argv.json) {
|
|
80129
80737
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -80147,12 +80755,12 @@ async function confirm(question) {
|
|
|
80147
80755
|
if (!process.stdin.isTTY) return false;
|
|
80148
80756
|
const readline8 = await import("readline");
|
|
80149
80757
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
80150
|
-
const answer = await new Promise((
|
|
80758
|
+
const answer = await new Promise((resolve66) => rl.question(question, resolve66));
|
|
80151
80759
|
rl.close();
|
|
80152
80760
|
return /^y(es)?$/i.test(answer.trim());
|
|
80153
80761
|
}
|
|
80154
80762
|
async function handleEject(argv) {
|
|
80155
|
-
const repoPath = resolveHarnessRoot(
|
|
80763
|
+
const repoPath = resolveHarnessRoot(path80.resolve(argv.repo));
|
|
80156
80764
|
header("har env eject");
|
|
80157
80765
|
warn("This vendors the complete HAR runtime into .har/runtime/ \u2014 from then on");
|
|
80158
80766
|
warn("YOU OWN that directory:");
|
|
@@ -80183,7 +80791,7 @@ async function handleEject(argv) {
|
|
|
80183
80791
|
return finishCommand(0);
|
|
80184
80792
|
}
|
|
80185
80793
|
async function handleAdopt(argv) {
|
|
80186
|
-
const repoPath = resolveHarnessRoot(
|
|
80794
|
+
const repoPath = resolveHarnessRoot(path80.resolve(argv.repo));
|
|
80187
80795
|
try {
|
|
80188
80796
|
const result = adoptHarness(repoPath);
|
|
80189
80797
|
success("Returned to the packaged runtime \u2014 .har/runtime/ removed, eject flag cleared.");
|
|
@@ -80198,7 +80806,7 @@ async function handleAdopt(argv) {
|
|
|
80198
80806
|
return finishCommand(0);
|
|
80199
80807
|
}
|
|
80200
80808
|
async function handleStatus(argv) {
|
|
80201
|
-
const repoPath =
|
|
80809
|
+
const repoPath = path80.resolve(argv.repo);
|
|
80202
80810
|
const result = await getEnvironmentStatus({
|
|
80203
80811
|
repoPath,
|
|
80204
80812
|
capture: false
|
|
@@ -80211,7 +80819,7 @@ async function handleStatus(argv) {
|
|
|
80211
80819
|
if (result.stdout) process.stdout.write(result.stdout);
|
|
80212
80820
|
}
|
|
80213
80821
|
async function handleLogs(argv) {
|
|
80214
|
-
const repo =
|
|
80822
|
+
const repo = path80.resolve(argv.repo);
|
|
80215
80823
|
const agentId = validateAgentId(argv.id, repo);
|
|
80216
80824
|
const result = await getEnvironmentLogs({
|
|
80217
80825
|
repoPath: repo,
|
|
@@ -80223,7 +80831,7 @@ async function handleLogs(argv) {
|
|
|
80223
80831
|
return finishCommand(result.code);
|
|
80224
80832
|
}
|
|
80225
80833
|
async function handleRunStage(argv) {
|
|
80226
|
-
const repo =
|
|
80834
|
+
const repo = path80.resolve(argv.repo);
|
|
80227
80835
|
const agentId = validateAgentId(argv.id, repo);
|
|
80228
80836
|
if (!argv.stage) {
|
|
80229
80837
|
error("Missing stage id. Usage: har env run-stage <id> <stage> [args..]");
|
|
@@ -80249,7 +80857,7 @@ async function handleRunStage(argv) {
|
|
|
80249
80857
|
}
|
|
80250
80858
|
async function handleArtifacts(argv) {
|
|
80251
80859
|
const artifacts = listArtifacts({
|
|
80252
|
-
repoPath:
|
|
80860
|
+
repoPath: path80.resolve(argv.repo),
|
|
80253
80861
|
stageId: argv.stage
|
|
80254
80862
|
});
|
|
80255
80863
|
if (argv.json) {
|
|
@@ -80268,7 +80876,7 @@ async function handleArtifacts(argv) {
|
|
|
80268
80876
|
async function handleCleanup(argv) {
|
|
80269
80877
|
const keepValues = argv.keep?.split(",").map((value) => value.trim()).filter(Boolean);
|
|
80270
80878
|
const keep = parseCleanupKeepPins(keepValues);
|
|
80271
|
-
const repoPaths = argv.repo ? [
|
|
80879
|
+
const repoPaths = argv.repo ? [path80.resolve(argv.repo)] : void 0;
|
|
80272
80880
|
const plan = await discoverCleanupCandidates({
|
|
80273
80881
|
cwd: process.cwd(),
|
|
80274
80882
|
repoPaths,
|
|
@@ -80317,7 +80925,7 @@ async function handleCleanup(argv) {
|
|
|
80317
80925
|
return finishCommand(failed > 0 ? 1 : 0);
|
|
80318
80926
|
}
|
|
80319
80927
|
async function handleRunsList(argv) {
|
|
80320
|
-
const repoPath =
|
|
80928
|
+
const repoPath = path80.resolve(argv.repo);
|
|
80321
80929
|
const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
|
|
80322
80930
|
if (argv.json) {
|
|
80323
80931
|
process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
|
|
@@ -80334,7 +80942,7 @@ async function handleRunsList(argv) {
|
|
|
80334
80942
|
}
|
|
80335
80943
|
}
|
|
80336
80944
|
async function handleRunsGet(argv) {
|
|
80337
|
-
const run2 = getRun(
|
|
80945
|
+
const run2 = getRun(path80.resolve(argv.repo), argv.runId);
|
|
80338
80946
|
if (!run2) {
|
|
80339
80947
|
error(`Run not found: ${argv.runId}`);
|
|
80340
80948
|
return finishCommand(1);
|
|
@@ -80451,7 +81059,7 @@ function printNextSteps() {
|
|
|
80451
81059
|
}
|
|
80452
81060
|
|
|
80453
81061
|
// src/cli/commands/control.ts
|
|
80454
|
-
var
|
|
81062
|
+
var path85 = __toESM(require("path"));
|
|
80455
81063
|
init_control_config();
|
|
80456
81064
|
init_portal_targets();
|
|
80457
81065
|
|
|
@@ -80459,8 +81067,8 @@ init_portal_targets();
|
|
|
80459
81067
|
init_control_config();
|
|
80460
81068
|
|
|
80461
81069
|
// src/core/portal-connect.ts
|
|
80462
|
-
var
|
|
80463
|
-
var
|
|
81070
|
+
var fs72 = __toESM(require("fs"));
|
|
81071
|
+
var path81 = __toESM(require("path"));
|
|
80464
81072
|
var import_crypto2 = require("crypto");
|
|
80465
81073
|
init_control_repo_path();
|
|
80466
81074
|
init_control_registry();
|
|
@@ -80506,7 +81114,7 @@ async function loginViaBrowser(portalUrl, openUrlOrOptions = openBrowser) {
|
|
|
80506
81114
|
const options = typeof openUrlOrOptions === "function" ? { openUrl: openUrlOrOptions } : openUrlOrOptions;
|
|
80507
81115
|
const openUrl = options.openUrl ?? openBrowser;
|
|
80508
81116
|
const state = (0, import_crypto.randomUUID)();
|
|
80509
|
-
return new Promise((
|
|
81117
|
+
return new Promise((resolve66, reject) => {
|
|
80510
81118
|
let timer;
|
|
80511
81119
|
const server = http.createServer((req, res) => {
|
|
80512
81120
|
const requestUrl = new URL(req.url ?? "", "http://127.0.0.1");
|
|
@@ -80534,7 +81142,7 @@ async function loginViaBrowser(portalUrl, openUrlOrOptions = openBrowser) {
|
|
|
80534
81142
|
res.end("<h1>Logged in</h1><p>You can close this tab and return to the terminal.</p>");
|
|
80535
81143
|
cleanup();
|
|
80536
81144
|
const targets = parseCliTargetsParam(requestUrl.searchParams.get("targets"));
|
|
80537
|
-
|
|
81145
|
+
resolve66({
|
|
80538
81146
|
portalUrl,
|
|
80539
81147
|
token,
|
|
80540
81148
|
workspace: workspaceSlug ?? workspace,
|
|
@@ -80629,8 +81237,8 @@ function remainingConnections(connections, usedAliases) {
|
|
|
80629
81237
|
// src/core/portal-connect.ts
|
|
80630
81238
|
init_portal_targets();
|
|
80631
81239
|
function attachRepoIfPresent(alias, repoPath) {
|
|
80632
|
-
const resolved =
|
|
80633
|
-
if (!
|
|
81240
|
+
const resolved = path81.resolve(repoPath ?? ".");
|
|
81241
|
+
if (!fs72.existsSync(resolved)) return null;
|
|
80634
81242
|
const canonical = canonicalizeControlRepoPath(resolved);
|
|
80635
81243
|
attachRepoPortalTarget(canonical, alias);
|
|
80636
81244
|
recordRepoForControlSync(canonical);
|
|
@@ -80697,8 +81305,8 @@ async function runPortalConnect(input) {
|
|
|
80697
81305
|
return { record: record2, attachedRepo, extraAttached, mappedInBrowser: true };
|
|
80698
81306
|
}
|
|
80699
81307
|
function listRegisteredReposForConnect(repoPath) {
|
|
80700
|
-
const resolved = repoPath ?
|
|
80701
|
-
const current = resolved &&
|
|
81308
|
+
const resolved = repoPath ? path81.resolve(repoPath) : null;
|
|
81309
|
+
const current = resolved && fs72.existsSync(resolved) ? canonicalizeControlRepoPath(resolved) : null;
|
|
80702
81310
|
return [.../* @__PURE__ */ new Set([...current ? [current] : [], ...listRegisteredRepos()])];
|
|
80703
81311
|
}
|
|
80704
81312
|
|
|
@@ -81014,21 +81622,21 @@ init_control_port();
|
|
|
81014
81622
|
init_control_sync();
|
|
81015
81623
|
|
|
81016
81624
|
// src/core/control-sync-selection.ts
|
|
81017
|
-
var
|
|
81625
|
+
var fs73 = __toESM(require("fs"));
|
|
81018
81626
|
var os25 = __toESM(require("os"));
|
|
81019
|
-
var
|
|
81627
|
+
var path82 = __toESM(require("path"));
|
|
81020
81628
|
init_control_repo_path();
|
|
81021
81629
|
function getSelectionPath() {
|
|
81022
81630
|
if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
|
|
81023
|
-
return
|
|
81631
|
+
return path82.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
|
|
81024
81632
|
}
|
|
81025
|
-
return
|
|
81633
|
+
return path82.join(os25.homedir(), ".har", "sync-selection.json");
|
|
81026
81634
|
}
|
|
81027
81635
|
function readSyncSelection() {
|
|
81028
81636
|
const selectionPath = getSelectionPath();
|
|
81029
81637
|
try {
|
|
81030
|
-
if (!
|
|
81031
|
-
const parsed = JSON.parse(
|
|
81638
|
+
if (!fs73.existsSync(selectionPath)) return null;
|
|
81639
|
+
const parsed = JSON.parse(fs73.readFileSync(selectionPath, "utf8"));
|
|
81032
81640
|
if (!Array.isArray(parsed.repos)) return null;
|
|
81033
81641
|
return parsed.repos.map((repoPath) => canonicalizeControlRepoPath(repoPath));
|
|
81034
81642
|
} catch {
|
|
@@ -81038,8 +81646,8 @@ function readSyncSelection() {
|
|
|
81038
81646
|
function writeSyncSelection(repos) {
|
|
81039
81647
|
const selectionPath = getSelectionPath();
|
|
81040
81648
|
const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
|
|
81041
|
-
|
|
81042
|
-
|
|
81649
|
+
fs73.mkdirSync(path82.dirname(selectionPath), { recursive: true });
|
|
81650
|
+
fs73.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
|
|
81043
81651
|
}
|
|
81044
81652
|
function resolveSyncSelection(input) {
|
|
81045
81653
|
const { discovered, stored, forceSelect, isTTY } = input;
|
|
@@ -81066,8 +81674,8 @@ function resolveSyncSelection(input) {
|
|
|
81066
81674
|
}
|
|
81067
81675
|
|
|
81068
81676
|
// src/core/control-unregister.ts
|
|
81069
|
-
var
|
|
81070
|
-
var
|
|
81677
|
+
var fs74 = __toESM(require("fs"));
|
|
81678
|
+
var path83 = __toESM(require("path"));
|
|
81071
81679
|
init_control_repo_path();
|
|
81072
81680
|
init_control_registry();
|
|
81073
81681
|
init_control_config();
|
|
@@ -81077,9 +81685,9 @@ function listUnregisterWorktreeCandidates(repoPath) {
|
|
|
81077
81685
|
const harnessRoot = canonicalizeControlRepoPath(repoPath);
|
|
81078
81686
|
const byPath = /* @__PURE__ */ new Map();
|
|
81079
81687
|
const add = (partial2) => {
|
|
81080
|
-
const resolved =
|
|
81688
|
+
const resolved = path83.resolve(partial2.worktreePath);
|
|
81081
81689
|
if (!resolved || resolved === harnessRoot) return;
|
|
81082
|
-
const exists = partial2.exists ??
|
|
81690
|
+
const exists = partial2.exists ?? fs74.existsSync(resolved);
|
|
81083
81691
|
const prev = byPath.get(resolved);
|
|
81084
81692
|
if (prev) {
|
|
81085
81693
|
byPath.set(resolved, {
|
|
@@ -81130,8 +81738,8 @@ async function askYesNo6(question) {
|
|
|
81130
81738
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
81131
81739
|
const readline8 = await import("readline");
|
|
81132
81740
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
81133
|
-
const answer = await new Promise((
|
|
81134
|
-
rl.question(question,
|
|
81741
|
+
const answer = await new Promise((resolve66) => {
|
|
81742
|
+
rl.question(question, resolve66);
|
|
81135
81743
|
});
|
|
81136
81744
|
rl.close();
|
|
81137
81745
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -81193,28 +81801,28 @@ async function teardownWorktrees(repoPath, candidates, dryRun) {
|
|
|
81193
81801
|
trigger: "cli"
|
|
81194
81802
|
});
|
|
81195
81803
|
if (result.code !== 0) {
|
|
81196
|
-
if (
|
|
81197
|
-
|
|
81804
|
+
if (fs74.existsSync(candidate.worktreePath)) {
|
|
81805
|
+
fs74.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
81198
81806
|
}
|
|
81199
81807
|
}
|
|
81200
81808
|
outcomes.push({
|
|
81201
81809
|
path: candidate.worktreePath,
|
|
81202
81810
|
agentId: candidate.agentId,
|
|
81203
|
-
deleted: !
|
|
81204
|
-
error: result.code !== 0 &&
|
|
81811
|
+
deleted: !fs74.existsSync(candidate.worktreePath),
|
|
81812
|
+
error: result.code !== 0 && fs74.existsSync(candidate.worktreePath) ? result.stderr : void 0
|
|
81205
81813
|
});
|
|
81206
81814
|
} catch (err) {
|
|
81207
81815
|
const message = err instanceof Error ? err.message : String(err);
|
|
81208
81816
|
try {
|
|
81209
|
-
if (
|
|
81210
|
-
|
|
81817
|
+
if (fs74.existsSync(candidate.worktreePath)) {
|
|
81818
|
+
fs74.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
81211
81819
|
}
|
|
81212
81820
|
} catch {
|
|
81213
81821
|
}
|
|
81214
81822
|
outcomes.push({
|
|
81215
81823
|
path: candidate.worktreePath,
|
|
81216
81824
|
agentId: candidate.agentId,
|
|
81217
|
-
deleted: !
|
|
81825
|
+
deleted: !fs74.existsSync(candidate.worktreePath),
|
|
81218
81826
|
error: message
|
|
81219
81827
|
});
|
|
81220
81828
|
}
|
|
@@ -81277,16 +81885,16 @@ init_control_config();
|
|
|
81277
81885
|
init_control_registry();
|
|
81278
81886
|
|
|
81279
81887
|
// src/core/harness-scrub.ts
|
|
81280
|
-
var
|
|
81281
|
-
var
|
|
81888
|
+
var fs75 = __toESM(require("fs"));
|
|
81889
|
+
var path84 = __toESM(require("path"));
|
|
81282
81890
|
var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
|
|
81283
81891
|
function scrubLocalHarnessDirs(repoPath) {
|
|
81284
81892
|
const results = [];
|
|
81285
|
-
const resolved =
|
|
81286
|
-
if (!
|
|
81893
|
+
const resolved = path84.resolve(repoPath);
|
|
81894
|
+
if (!fs75.existsSync(resolved)) {
|
|
81287
81895
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
81288
81896
|
results.push({
|
|
81289
|
-
path:
|
|
81897
|
+
path: path84.join(resolved, ".har", directory),
|
|
81290
81898
|
directory,
|
|
81291
81899
|
deleted: false,
|
|
81292
81900
|
error: "repository path does not exist"
|
|
@@ -81295,24 +81903,24 @@ function scrubLocalHarnessDirs(repoPath) {
|
|
|
81295
81903
|
return results;
|
|
81296
81904
|
}
|
|
81297
81905
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
81298
|
-
const target =
|
|
81299
|
-
if (!
|
|
81906
|
+
const target = path84.join(resolved, ".har", directory);
|
|
81907
|
+
if (!fs75.existsSync(target)) {
|
|
81300
81908
|
results.push({ path: target, directory, deleted: true });
|
|
81301
81909
|
continue;
|
|
81302
81910
|
}
|
|
81303
81911
|
try {
|
|
81304
|
-
|
|
81912
|
+
fs75.rmSync(target, { recursive: true, force: true });
|
|
81305
81913
|
results.push({
|
|
81306
81914
|
path: target,
|
|
81307
81915
|
directory,
|
|
81308
|
-
deleted: !
|
|
81309
|
-
error:
|
|
81916
|
+
deleted: !fs75.existsSync(target),
|
|
81917
|
+
error: fs75.existsSync(target) ? "failed to remove directory" : void 0
|
|
81310
81918
|
});
|
|
81311
81919
|
} catch (err) {
|
|
81312
81920
|
results.push({
|
|
81313
81921
|
path: target,
|
|
81314
81922
|
directory,
|
|
81315
|
-
deleted: !
|
|
81923
|
+
deleted: !fs75.existsSync(target),
|
|
81316
81924
|
error: err instanceof Error ? err.message : String(err)
|
|
81317
81925
|
});
|
|
81318
81926
|
}
|
|
@@ -81323,7 +81931,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
|
|
|
81323
81931
|
const results = [];
|
|
81324
81932
|
const seen = /* @__PURE__ */ new Set();
|
|
81325
81933
|
for (const repoPath of repoPaths) {
|
|
81326
|
-
const key =
|
|
81934
|
+
const key = path84.resolve(repoPath);
|
|
81327
81935
|
if (seen.has(key)) continue;
|
|
81328
81936
|
seen.add(key);
|
|
81329
81937
|
results.push(...scrubLocalHarnessDirs(key));
|
|
@@ -81336,8 +81944,8 @@ async function askYesNo7(question) {
|
|
|
81336
81944
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
81337
81945
|
const readline8 = await import("readline");
|
|
81338
81946
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
81339
|
-
const answer = await new Promise((
|
|
81340
|
-
rl.question(question,
|
|
81947
|
+
const answer = await new Promise((resolve66) => {
|
|
81948
|
+
rl.question(question, resolve66);
|
|
81341
81949
|
});
|
|
81342
81950
|
rl.close();
|
|
81343
81951
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -81616,7 +82224,7 @@ async function handleDown() {
|
|
|
81616
82224
|
return finishCommand(code);
|
|
81617
82225
|
}
|
|
81618
82226
|
async function handleRegister(argv) {
|
|
81619
|
-
const repoPath =
|
|
82227
|
+
const repoPath = path85.resolve(argv.repo);
|
|
81620
82228
|
header("har control register");
|
|
81621
82229
|
info(`Repository: ${repoPath}`);
|
|
81622
82230
|
try {
|
|
@@ -81714,7 +82322,7 @@ async function handleReset(argv) {
|
|
|
81714
82322
|
}
|
|
81715
82323
|
}
|
|
81716
82324
|
async function handleUnregister(argv) {
|
|
81717
|
-
const repoPath =
|
|
82325
|
+
const repoPath = path85.resolve(argv.repo);
|
|
81718
82326
|
const worktrees = listUnregisterWorktreeCandidates(repoPath);
|
|
81719
82327
|
try {
|
|
81720
82328
|
let deleteWorktrees = argv.deleteWorktrees;
|
|
@@ -81995,12 +82603,12 @@ async function handleTrajectory(argv) {
|
|
|
81995
82603
|
}
|
|
81996
82604
|
|
|
81997
82605
|
// src/cli/commands/hooks.ts
|
|
81998
|
-
var
|
|
82606
|
+
var path87 = __toESM(require("path"));
|
|
81999
82607
|
init_hooks();
|
|
82000
82608
|
|
|
82001
82609
|
// src/core/claude-hooks.ts
|
|
82002
|
-
var
|
|
82003
|
-
var
|
|
82610
|
+
var fs76 = __toESM(require("fs"));
|
|
82611
|
+
var path86 = __toESM(require("path"));
|
|
82004
82612
|
init_paths();
|
|
82005
82613
|
var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
|
|
82006
82614
|
var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
|
|
@@ -82012,8 +82620,8 @@ function isHarGuardEntry(entry) {
|
|
|
82012
82620
|
);
|
|
82013
82621
|
}
|
|
82014
82622
|
function readSettings(settingsPath) {
|
|
82015
|
-
if (!
|
|
82016
|
-
const raw =
|
|
82623
|
+
if (!fs76.existsSync(settingsPath)) return {};
|
|
82624
|
+
const raw = fs76.readFileSync(settingsPath, "utf8").trim();
|
|
82017
82625
|
if (raw === "") return {};
|
|
82018
82626
|
const parsed = JSON.parse(raw);
|
|
82019
82627
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -82022,19 +82630,19 @@ function readSettings(settingsPath) {
|
|
|
82022
82630
|
return parsed;
|
|
82023
82631
|
}
|
|
82024
82632
|
function writeSettings(settingsPath, settings) {
|
|
82025
|
-
|
|
82026
|
-
|
|
82633
|
+
fs76.mkdirSync(path86.dirname(settingsPath), { recursive: true });
|
|
82634
|
+
fs76.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
82027
82635
|
}
|
|
82028
82636
|
function installClaudeGuard(repoPath) {
|
|
82029
82637
|
const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
|
|
82030
82638
|
if (!templatePath) {
|
|
82031
82639
|
throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
|
|
82032
82640
|
}
|
|
82033
|
-
const guardScript =
|
|
82034
|
-
|
|
82035
|
-
|
|
82036
|
-
|
|
82037
|
-
const settingsPath =
|
|
82641
|
+
const guardScript = path86.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
82642
|
+
fs76.mkdirSync(path86.dirname(guardScript), { recursive: true });
|
|
82643
|
+
fs76.copyFileSync(templatePath, guardScript);
|
|
82644
|
+
fs76.chmodSync(guardScript, 493);
|
|
82645
|
+
const settingsPath = path86.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
82038
82646
|
const settings = readSettings(settingsPath);
|
|
82039
82647
|
const hooks = settings.hooks ?? {};
|
|
82040
82648
|
const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
|
|
@@ -82048,15 +82656,15 @@ function installClaudeGuard(repoPath) {
|
|
|
82048
82656
|
}
|
|
82049
82657
|
function uninstallClaudeGuard(repoPath) {
|
|
82050
82658
|
let removed = false;
|
|
82051
|
-
const guardScript =
|
|
82052
|
-
if (
|
|
82053
|
-
|
|
82659
|
+
const guardScript = path86.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
82660
|
+
if (fs76.existsSync(guardScript)) {
|
|
82661
|
+
fs76.rmSync(guardScript);
|
|
82054
82662
|
removed = true;
|
|
82055
|
-
const parent =
|
|
82056
|
-
if (
|
|
82663
|
+
const parent = path86.dirname(guardScript);
|
|
82664
|
+
if (fs76.existsSync(parent) && fs76.readdirSync(parent).length === 0) fs76.rmdirSync(parent);
|
|
82057
82665
|
}
|
|
82058
|
-
const settingsPath =
|
|
82059
|
-
if (
|
|
82666
|
+
const settingsPath = path86.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
82667
|
+
if (fs76.existsSync(settingsPath)) {
|
|
82060
82668
|
const settings = readSettings(settingsPath);
|
|
82061
82669
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
82062
82670
|
if (preToolUse) {
|
|
@@ -82081,8 +82689,8 @@ function uninstallClaudeGuard(repoPath) {
|
|
|
82081
82689
|
return { removed };
|
|
82082
82690
|
}
|
|
82083
82691
|
function claudeGuardInstalled(repoPath) {
|
|
82084
|
-
const settingsPath =
|
|
82085
|
-
if (!
|
|
82692
|
+
const settingsPath = path86.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
82693
|
+
if (!fs76.existsSync(settingsPath)) return false;
|
|
82086
82694
|
try {
|
|
82087
82695
|
const settings = readSettings(settingsPath);
|
|
82088
82696
|
return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
|
|
@@ -82099,7 +82707,7 @@ function repoOption(y) {
|
|
|
82099
82707
|
function handleInstall2(argv) {
|
|
82100
82708
|
try {
|
|
82101
82709
|
if (argv.claude) {
|
|
82102
|
-
const result2 = installClaudeGuard(
|
|
82710
|
+
const result2 = installClaudeGuard(path87.resolve(argv.repo));
|
|
82103
82711
|
success("Claude Code worktree guard installed.");
|
|
82104
82712
|
info(`Guard script: ${result2.guardScript}`);
|
|
82105
82713
|
info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
|
|
@@ -82107,7 +82715,7 @@ function handleInstall2(argv) {
|
|
|
82107
82715
|
info("Commit both files so the guard travels with the repo.");
|
|
82108
82716
|
return;
|
|
82109
82717
|
}
|
|
82110
|
-
const result = installHooks({ repoPath:
|
|
82718
|
+
const result = installHooks({ repoPath: path87.resolve(argv.repo), force: argv.force });
|
|
82111
82719
|
success(`Commit gate installed in ${result.hooksDir}`);
|
|
82112
82720
|
info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
|
|
82113
82721
|
info("Commits of unverified change batches will be blocked in agent worktrees.");
|
|
@@ -82120,7 +82728,7 @@ function handleInstall2(argv) {
|
|
|
82120
82728
|
function handleUninstall(argv) {
|
|
82121
82729
|
try {
|
|
82122
82730
|
if (argv.claude) {
|
|
82123
|
-
const result2 = uninstallClaudeGuard(
|
|
82731
|
+
const result2 = uninstallClaudeGuard(path87.resolve(argv.repo));
|
|
82124
82732
|
if (result2.removed) {
|
|
82125
82733
|
success("Claude Code worktree guard removed.");
|
|
82126
82734
|
} else {
|
|
@@ -82128,7 +82736,7 @@ function handleUninstall(argv) {
|
|
|
82128
82736
|
}
|
|
82129
82737
|
return;
|
|
82130
82738
|
}
|
|
82131
|
-
const result = uninstallHooks(
|
|
82739
|
+
const result = uninstallHooks(path87.resolve(argv.repo));
|
|
82132
82740
|
if (result.removed) {
|
|
82133
82741
|
success(`Commit gate removed from ${result.hooksDir}`);
|
|
82134
82742
|
} else {
|
|
@@ -82141,7 +82749,7 @@ function handleUninstall(argv) {
|
|
|
82141
82749
|
}
|
|
82142
82750
|
function handleStatus2(argv) {
|
|
82143
82751
|
try {
|
|
82144
|
-
const status = getHooksStatus(
|
|
82752
|
+
const status = getHooksStatus(path87.resolve(argv.repo));
|
|
82145
82753
|
if (argv.json) {
|
|
82146
82754
|
process.stdout.write(`${JSON.stringify(status, null, 2)}
|
|
82147
82755
|
`);
|
|
@@ -82159,7 +82767,7 @@ function handleStatus2(argv) {
|
|
|
82159
82767
|
);
|
|
82160
82768
|
info(`Effective: ${status.effectiveMode} (in this checkout)`);
|
|
82161
82769
|
info(
|
|
82162
|
-
`Claude guard: ${claudeGuardInstalled(
|
|
82770
|
+
`Claude guard: ${claudeGuardInstalled(path87.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
|
|
82163
82771
|
);
|
|
82164
82772
|
} catch (err) {
|
|
82165
82773
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -82420,10 +83028,10 @@ function assignProp(target, prop, value) {
|
|
|
82420
83028
|
configurable: true
|
|
82421
83029
|
});
|
|
82422
83030
|
}
|
|
82423
|
-
function getElementAtPath(obj,
|
|
82424
|
-
if (!
|
|
83031
|
+
function getElementAtPath(obj, path97) {
|
|
83032
|
+
if (!path97)
|
|
82425
83033
|
return obj;
|
|
82426
|
-
return
|
|
83034
|
+
return path97.reduce((acc, key) => acc?.[key], obj);
|
|
82427
83035
|
}
|
|
82428
83036
|
function promiseAllObject(promisesObj) {
|
|
82429
83037
|
const keys = Object.keys(promisesObj);
|
|
@@ -82743,11 +83351,11 @@ function aborted(x, startIndex = 0) {
|
|
|
82743
83351
|
}
|
|
82744
83352
|
return false;
|
|
82745
83353
|
}
|
|
82746
|
-
function prefixIssues(
|
|
83354
|
+
function prefixIssues(path97, issues) {
|
|
82747
83355
|
return issues.map((iss) => {
|
|
82748
83356
|
var _a2;
|
|
82749
83357
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
82750
|
-
iss.path.unshift(
|
|
83358
|
+
iss.path.unshift(path97);
|
|
82751
83359
|
return iss;
|
|
82752
83360
|
});
|
|
82753
83361
|
}
|
|
@@ -88070,7 +88678,7 @@ var Protocol = class {
|
|
|
88070
88678
|
return;
|
|
88071
88679
|
}
|
|
88072
88680
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
88073
|
-
await new Promise((
|
|
88681
|
+
await new Promise((resolve66) => setTimeout(resolve66, pollInterval));
|
|
88074
88682
|
options?.signal?.throwIfAborted();
|
|
88075
88683
|
}
|
|
88076
88684
|
} catch (error3) {
|
|
@@ -88087,7 +88695,7 @@ var Protocol = class {
|
|
|
88087
88695
|
*/
|
|
88088
88696
|
request(request, resultSchema, options) {
|
|
88089
88697
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
88090
|
-
return new Promise((
|
|
88698
|
+
return new Promise((resolve66, reject) => {
|
|
88091
88699
|
const earlyReject = (error3) => {
|
|
88092
88700
|
reject(error3);
|
|
88093
88701
|
};
|
|
@@ -88165,7 +88773,7 @@ var Protocol = class {
|
|
|
88165
88773
|
if (!parseResult.success) {
|
|
88166
88774
|
reject(parseResult.error);
|
|
88167
88775
|
} else {
|
|
88168
|
-
|
|
88776
|
+
resolve66(parseResult.data);
|
|
88169
88777
|
}
|
|
88170
88778
|
} catch (error3) {
|
|
88171
88779
|
reject(error3);
|
|
@@ -88426,12 +89034,12 @@ var Protocol = class {
|
|
|
88426
89034
|
}
|
|
88427
89035
|
} catch {
|
|
88428
89036
|
}
|
|
88429
|
-
return new Promise((
|
|
89037
|
+
return new Promise((resolve66, reject) => {
|
|
88430
89038
|
if (signal.aborted) {
|
|
88431
89039
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
88432
89040
|
return;
|
|
88433
89041
|
}
|
|
88434
|
-
const timeoutId = setTimeout(
|
|
89042
|
+
const timeoutId = setTimeout(resolve66, interval);
|
|
88435
89043
|
signal.addEventListener("abort", () => {
|
|
88436
89044
|
clearTimeout(timeoutId);
|
|
88437
89045
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -89221,7 +89829,7 @@ var Server = class extends Protocol {
|
|
|
89221
89829
|
};
|
|
89222
89830
|
|
|
89223
89831
|
// src/mcp/server.ts
|
|
89224
|
-
var
|
|
89832
|
+
var path90 = __toESM(require("path"));
|
|
89225
89833
|
|
|
89226
89834
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
89227
89835
|
var import_node_process3 = __toESM(require("node:process"), 1);
|
|
@@ -89304,12 +89912,12 @@ var StdioServerTransport = class {
|
|
|
89304
89912
|
this.onclose?.();
|
|
89305
89913
|
}
|
|
89306
89914
|
send(message) {
|
|
89307
|
-
return new Promise((
|
|
89915
|
+
return new Promise((resolve66) => {
|
|
89308
89916
|
const json = serializeMessage(message);
|
|
89309
89917
|
if (this._stdout.write(json)) {
|
|
89310
|
-
|
|
89918
|
+
resolve66();
|
|
89311
89919
|
} else {
|
|
89312
|
-
this._stdout.once("drain",
|
|
89920
|
+
this._stdout.once("drain", resolve66);
|
|
89313
89921
|
}
|
|
89314
89922
|
});
|
|
89315
89923
|
}
|
|
@@ -89319,6 +89927,379 @@ var StdioServerTransport = class {
|
|
|
89319
89927
|
init_package_version();
|
|
89320
89928
|
init_telemetry_config();
|
|
89321
89929
|
init_runs();
|
|
89930
|
+
|
|
89931
|
+
// src/core/lines.ts
|
|
89932
|
+
var path89 = __toESM(require("path"));
|
|
89933
|
+
|
|
89934
|
+
// src/harness/line-create.ts
|
|
89935
|
+
var fs77 = __toESM(require("fs"));
|
|
89936
|
+
var path88 = __toESM(require("path"));
|
|
89937
|
+
init_paths();
|
|
89938
|
+
init_schema2();
|
|
89939
|
+
var LINE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
89940
|
+
function renderSkeleton(templatePath, tokens) {
|
|
89941
|
+
let content = fs77.readFileSync(templatePath, "utf8");
|
|
89942
|
+
for (const [token, value] of Object.entries(tokens)) {
|
|
89943
|
+
content = content.replace(new RegExp(token, "g"), value);
|
|
89944
|
+
}
|
|
89945
|
+
return content;
|
|
89946
|
+
}
|
|
89947
|
+
function createLine(repoPath, options) {
|
|
89948
|
+
const resolved = path88.resolve(repoPath);
|
|
89949
|
+
if (!harnessExists(resolved)) {
|
|
89950
|
+
throw new Error('No .har/ harness found. Run "har onboard" first.');
|
|
89951
|
+
}
|
|
89952
|
+
const id = options.id.trim();
|
|
89953
|
+
if (!LINE_ID_PATTERN.test(id)) {
|
|
89954
|
+
throw new Error(
|
|
89955
|
+
`Invalid line id "${id}". Use lowercase letters, digits, dots, dashes (e.g. "onboarding-line").`
|
|
89956
|
+
);
|
|
89957
|
+
}
|
|
89958
|
+
const lineDir = path88.join(resolved, LOCAL_LINES_DIR, id);
|
|
89959
|
+
const lineDirRel2 = `${LOCAL_LINES_DIR}/${id}`;
|
|
89960
|
+
if (fs77.existsSync(lineDir) && !options.force) {
|
|
89961
|
+
throw new Error(`Line already exists: ${lineDirRel2}/. Use --force to overwrite.`);
|
|
89962
|
+
}
|
|
89963
|
+
const stationIds = options.stations?.length ? options.stations : ["S1", "S2"];
|
|
89964
|
+
const title = options.title ?? `${id} factory line`;
|
|
89965
|
+
const gateStageId = `${id}-gate`;
|
|
89966
|
+
const withGateStage = options.gateStage ?? true;
|
|
89967
|
+
const program = LineProgramSchema.parse({
|
|
89968
|
+
contractVersion: LINE_CONTRACT_VERSION,
|
|
89969
|
+
id,
|
|
89970
|
+
title,
|
|
89971
|
+
description: options.description ?? 'Describe the program: what it produces, and what "done" means at the last station.',
|
|
89972
|
+
skills: [{ id: "factory-line", role: "orchestrator", install: "repo:.claude/skills/factory-line" }],
|
|
89973
|
+
mcp: [],
|
|
89974
|
+
plugins: [],
|
|
89975
|
+
stations: stationIds.map((stationId, i) => ({
|
|
89976
|
+
id: stationId,
|
|
89977
|
+
title: `Station ${i + 1}`,
|
|
89978
|
+
description: "What this station produces.",
|
|
89979
|
+
work: { source: "none", ids: [], optional: true }
|
|
89980
|
+
})),
|
|
89981
|
+
gate: {
|
|
89982
|
+
cumulative: true,
|
|
89983
|
+
optInEnv: options.optInEnv ?? null,
|
|
89984
|
+
stages: withGateStage ? [{ id: gateStageId, fromStation: stationIds[0], tier: "full" }] : []
|
|
89985
|
+
},
|
|
89986
|
+
extraStages: withGateStage ? [
|
|
89987
|
+
{
|
|
89988
|
+
id: gateStageId,
|
|
89989
|
+
kind: "test",
|
|
89990
|
+
tier: "full",
|
|
89991
|
+
description: `Line-owned gate for ${id} \u2014 registered, never on verify`
|
|
89992
|
+
}
|
|
89993
|
+
] : [],
|
|
89994
|
+
handoff: {
|
|
89995
|
+
autonomousShip: false,
|
|
89996
|
+
waitFor: "human review before merge or release"
|
|
89997
|
+
},
|
|
89998
|
+
prototypeNotes: []
|
|
89999
|
+
});
|
|
90000
|
+
const manifest = LineManifestSchema.parse({
|
|
90001
|
+
kind: LINE_BUNDLE_KIND,
|
|
90002
|
+
id,
|
|
90003
|
+
title,
|
|
90004
|
+
program: "line.json",
|
|
90005
|
+
files: withGateStage ? [{ src: `stages/${gateStageId}.sh`, dest: `.har/stages/${gateStageId}.sh`, executable: true }] : [],
|
|
90006
|
+
stages: withGateStage ? [
|
|
90007
|
+
{
|
|
90008
|
+
id: gateStageId,
|
|
90009
|
+
kind: "test",
|
|
90010
|
+
description: `Line-owned gate for ${id} \u2014 registered, never on verify`,
|
|
90011
|
+
script: `stages/${gateStageId}.sh`,
|
|
90012
|
+
requiresAgentId: true,
|
|
90013
|
+
artifacts: [
|
|
90014
|
+
{
|
|
90015
|
+
path: `.har/artifacts/${gateStageId}`,
|
|
90016
|
+
kind: "directory",
|
|
90017
|
+
description: `Artifacts for the ${gateStageId} stage`
|
|
90018
|
+
}
|
|
90019
|
+
],
|
|
90020
|
+
tier: "full"
|
|
90021
|
+
}
|
|
90022
|
+
] : [],
|
|
90023
|
+
nextSteps: [
|
|
90024
|
+
`Edit ${lineDirRel2}/line.json \u2014 name the stations and bind tracker work`,
|
|
90025
|
+
...withGateStage ? [`Edit ${lineDirRel2}/stages/${gateStageId}.sh \u2014 replace the TODO with the real gate`] : [],
|
|
90026
|
+
`har line status ${id}`,
|
|
90027
|
+
`har line gate ${stationIds[0]} --line ${id}`
|
|
90028
|
+
],
|
|
90029
|
+
docsPath: `${lineDirRel2}/README.md`
|
|
90030
|
+
});
|
|
90031
|
+
const filesWritten = [];
|
|
90032
|
+
const write = (rel, content, executable = false) => {
|
|
90033
|
+
const abs = path88.join(lineDir, rel);
|
|
90034
|
+
fs77.mkdirSync(path88.dirname(abs), { recursive: true });
|
|
90035
|
+
fs77.writeFileSync(abs, content);
|
|
90036
|
+
if (executable) fs77.chmodSync(abs, 493);
|
|
90037
|
+
filesWritten.push(`${lineDirRel2}/${rel}`);
|
|
90038
|
+
};
|
|
90039
|
+
write("line.manifest.json", `${JSON.stringify(manifest, null, 2)}
|
|
90040
|
+
`);
|
|
90041
|
+
write("line.json", `${JSON.stringify(program, null, 2)}
|
|
90042
|
+
`);
|
|
90043
|
+
if (withGateStage) {
|
|
90044
|
+
const stageScript = renderSkeleton(
|
|
90045
|
+
path88.join(resolveTemplatesDir(), "plugins", "custom-stage-skeleton.sh"),
|
|
90046
|
+
{
|
|
90047
|
+
__STAGE_ID__: gateStageId,
|
|
90048
|
+
__STAGE_KIND__: "test",
|
|
90049
|
+
__STAGE_DESCRIPTION__: `Line-owned gate for ${id} (not on verify)`
|
|
90050
|
+
}
|
|
90051
|
+
);
|
|
90052
|
+
write(`stages/${gateStageId}.sh`, stageScript, true);
|
|
90053
|
+
}
|
|
90054
|
+
write("README.md", renderLineReadme(id, title, stationIds, gateStageId, withGateStage));
|
|
90055
|
+
return {
|
|
90056
|
+
lineId: id,
|
|
90057
|
+
lineDir,
|
|
90058
|
+
filesWritten,
|
|
90059
|
+
nextSteps: [
|
|
90060
|
+
`Edit ${lineDirRel2}/line.json \u2014 stations, work binding, gate tags`,
|
|
90061
|
+
...withGateStage ? [`Edit ${lineDirRel2}/stages/${gateStageId}.sh \u2014 replace the TODO with the real gate`] : [],
|
|
90062
|
+
`Install it: har line add ${id} (re-run with --force after changes)`,
|
|
90063
|
+
`Installing writes .har/ADAPT-PROMPT-line-${id}.md \u2014 a ready adaptation prompt for your coding agent`,
|
|
90064
|
+
"Publishing later (npm/git) needs zero format changes \u2014 see the README"
|
|
90065
|
+
]
|
|
90066
|
+
};
|
|
90067
|
+
}
|
|
90068
|
+
function renderLineReadme(id, title, stationIds, gateStageId, withGateStage) {
|
|
90069
|
+
return `# ${title}
|
|
90070
|
+
|
|
90071
|
+
A HAR **factory line**: an ordered program of stations plus a cumulative gate.
|
|
90072
|
+
|
|
90073
|
+
A line is not a verification plugin. Installing it registers stages but never
|
|
90074
|
+
adds them to \`verificationStages\` \u2014 default \`har env verify --full\` stays
|
|
90075
|
+
exactly as fast as it was. Line gate stages run on demand:
|
|
90076
|
+
|
|
90077
|
+
\`\`\`bash
|
|
90078
|
+
har line gate ${stationIds[0]} --line ${id}
|
|
90079
|
+
\`\`\`
|
|
90080
|
+
|
|
90081
|
+
If a check should gate *every* verify, it belongs in a verification plugin
|
|
90082
|
+
(\`har plugin create\` / \`har env add-plugin\`), not here.
|
|
90083
|
+
|
|
90084
|
+
## Layout
|
|
90085
|
+
|
|
90086
|
+
\`\`\`text
|
|
90087
|
+
${id}/
|
|
90088
|
+
\u251C\u2500\u2500 line.manifest.json # kind: line \u2014 what \`har line add\` applies
|
|
90089
|
+
\u251C\u2500\u2500 line.json # the program: stations, gate, handoff
|
|
90090
|
+
${withGateStage ? `\u251C\u2500\u2500 stages/${gateStageId}.sh # extra gate stage \u2014 registered, NOT on verify
|
|
90091
|
+
` : ""}\u2514\u2500\u2500 README.md
|
|
90092
|
+
\`\`\`
|
|
90093
|
+
|
|
90094
|
+
## Stations
|
|
90095
|
+
|
|
90096
|
+
${stationIds.map((s, i) => `${i + 1}. \`${s}\``).join("\n")}
|
|
90097
|
+
|
|
90098
|
+
## The ratchet
|
|
90099
|
+
|
|
90100
|
+
\`gate.stages[].fromStation\` tags a stage as required at that station **and
|
|
90101
|
+
every later one**. Adding a station must never drop an earlier station's
|
|
90102
|
+
stages \u2014 that is what \`gate.cumulative: true\` means, and it is contract.
|
|
90103
|
+
|
|
90104
|
+
## Install channels
|
|
90105
|
+
|
|
90106
|
+
\`\`\`bash
|
|
90107
|
+
har line add ${id} # this repo (.har/lines/${id})
|
|
90108
|
+
har line add ./${id} # local path
|
|
90109
|
+
har line add github:acme/${id} # git
|
|
90110
|
+
har line add @acme/${id} # npm
|
|
90111
|
+
\`\`\`
|
|
90112
|
+
|
|
90113
|
+
Publishing needs no format change: add a \`package.json\` and push.
|
|
90114
|
+
`;
|
|
90115
|
+
}
|
|
90116
|
+
|
|
90117
|
+
// src/core/lines.ts
|
|
90118
|
+
init_stages();
|
|
90119
|
+
init_slot_registry();
|
|
90120
|
+
init_runs();
|
|
90121
|
+
function listInstalledLineIds(repoPath) {
|
|
90122
|
+
const ledger = readLineLedger(repoPath);
|
|
90123
|
+
const fromLedger = ledger?.lines.map((l) => l.id) ?? [];
|
|
90124
|
+
const onDisk = listLocalLineIds(repoPath).filter(
|
|
90125
|
+
(id) => readInstalledLineProgram(repoPath, id) !== null
|
|
90126
|
+
);
|
|
90127
|
+
return [.../* @__PURE__ */ new Set([...fromLedger, ...onDisk])].sort();
|
|
90128
|
+
}
|
|
90129
|
+
function cumulativeGateStages(program, stationId) {
|
|
90130
|
+
const stationIndex = program.stations.findIndex((s) => s.id === stationId);
|
|
90131
|
+
if (stationIndex < 0) {
|
|
90132
|
+
throw new Error(
|
|
90133
|
+
`Unknown station "${stationId}". Stations: ${program.stations.map((s) => s.id).join(", ")}`
|
|
90134
|
+
);
|
|
90135
|
+
}
|
|
90136
|
+
const indexOf = new Map(program.stations.map((s, i) => [s.id, i]));
|
|
90137
|
+
return program.gate.stages.filter((stage) => {
|
|
90138
|
+
const from2 = indexOf.get(stage.fromStation);
|
|
90139
|
+
return from2 !== void 0 && from2 <= stationIndex;
|
|
90140
|
+
});
|
|
90141
|
+
}
|
|
90142
|
+
function latestRunStatusByStage(repoPath, stageIds) {
|
|
90143
|
+
const statuses = /* @__PURE__ */ new Map();
|
|
90144
|
+
for (const stageId of stageIds) {
|
|
90145
|
+
const [latest] = listRuns(repoPath, { stageId, limit: 1 });
|
|
90146
|
+
if (latest) statuses.set(stageId, latest.status);
|
|
90147
|
+
}
|
|
90148
|
+
return statuses;
|
|
90149
|
+
}
|
|
90150
|
+
function getLineStatus(repoPath, lineId) {
|
|
90151
|
+
const resolved = path89.resolve(repoPath);
|
|
90152
|
+
const program = readInstalledLineProgram(resolved, lineId);
|
|
90153
|
+
if (!program) {
|
|
90154
|
+
throw new Error(
|
|
90155
|
+
`Line not installed: ${lineId}. Install one with "har line add <spec>" or scaffold with "har line create <id>".`
|
|
90156
|
+
);
|
|
90157
|
+
}
|
|
90158
|
+
const ledger = readLineLedger(resolved);
|
|
90159
|
+
const entry = ledger?.lines.find((l) => l.id === lineId);
|
|
90160
|
+
const registry2 = readStageRegistry(resolved);
|
|
90161
|
+
const registeredIds = new Set(registry2.stages.map((s) => s.id));
|
|
90162
|
+
const verificationStages = registry2.verificationStages ?? [];
|
|
90163
|
+
const allGateStageIds = [...new Set(program.gate.stages.map((s) => s.id))];
|
|
90164
|
+
const runStatuses = latestRunStatusByStage(resolved, allGateStageIds);
|
|
90165
|
+
const stations = program.stations.map((station, index) => {
|
|
90166
|
+
const required2 = cumulativeGateStages(program, station.id);
|
|
90167
|
+
const requiredStageIds = [...new Set(required2.map((s) => s.id))];
|
|
90168
|
+
const missingStageIds = requiredStageIds.filter((id) => !registeredIds.has(id));
|
|
90169
|
+
const passedStageIds = requiredStageIds.filter((id) => runStatuses.get(id) === "pass");
|
|
90170
|
+
const neverRunStageIds = requiredStageIds.filter((id) => !runStatuses.has(id));
|
|
90171
|
+
return {
|
|
90172
|
+
id: station.id,
|
|
90173
|
+
title: station.title,
|
|
90174
|
+
index,
|
|
90175
|
+
requiredStageIds,
|
|
90176
|
+
passedStageIds,
|
|
90177
|
+
neverRunStageIds,
|
|
90178
|
+
missingStageIds,
|
|
90179
|
+
green: missingStageIds.length === 0 && passedStageIds.length === requiredStageIds.length,
|
|
90180
|
+
work: station.work
|
|
90181
|
+
};
|
|
90182
|
+
});
|
|
90183
|
+
let currentStationId;
|
|
90184
|
+
for (const station of stations) {
|
|
90185
|
+
if (station.green) currentStationId = station.id;
|
|
90186
|
+
else break;
|
|
90187
|
+
}
|
|
90188
|
+
const nextStationId = stations.find((s) => !s.green)?.id;
|
|
90189
|
+
const lineStageIds = entry?.stageIds ?? [];
|
|
90190
|
+
const verifyLeaks = lineStageIds.filter((id) => verificationStages.includes(id));
|
|
90191
|
+
const warnings = [];
|
|
90192
|
+
if (verifyLeaks.length > 0) {
|
|
90193
|
+
warnings.push(
|
|
90194
|
+
`Line stage(s) ${verifyLeaks.join(", ")} are listed in verificationStages \u2014 line gate stages must stay off \`har env verify --full\`. Remove them from .har/stages.json.`
|
|
90195
|
+
);
|
|
90196
|
+
}
|
|
90197
|
+
for (const station of stations) {
|
|
90198
|
+
for (const missing of station.missingStageIds) {
|
|
90199
|
+
warnings.push(`Gate stage "${missing}" (station ${station.id}) is not registered in .har/stages.json`);
|
|
90200
|
+
}
|
|
90201
|
+
}
|
|
90202
|
+
const slotsInFlight = listSlotRegistryEntries(resolved).map((slot) => ({
|
|
90203
|
+
agentId: slot.agentId,
|
|
90204
|
+
branch: slot.branch,
|
|
90205
|
+
workUnitId: slot.workUnitId,
|
|
90206
|
+
workDir: slot.workDir
|
|
90207
|
+
}));
|
|
90208
|
+
return {
|
|
90209
|
+
lineId,
|
|
90210
|
+
title: program.title,
|
|
90211
|
+
programPath: entry?.programPath ?? `.har/lines/${lineId}/line.json`,
|
|
90212
|
+
installed: true,
|
|
90213
|
+
source: entry?.source,
|
|
90214
|
+
stations,
|
|
90215
|
+
currentStationId,
|
|
90216
|
+
nextStationId,
|
|
90217
|
+
optInEnv: program.gate.optInEnv,
|
|
90218
|
+
registeredStageIds: lineStageIds,
|
|
90219
|
+
verifyLeaks,
|
|
90220
|
+
slotsInFlight,
|
|
90221
|
+
handoffAutonomousShip: false,
|
|
90222
|
+
warnings: [...new Set(warnings)]
|
|
90223
|
+
};
|
|
90224
|
+
}
|
|
90225
|
+
function getAllLineStatuses(repoPath) {
|
|
90226
|
+
return listInstalledLineIds(repoPath).map((id) => getLineStatus(repoPath, id));
|
|
90227
|
+
}
|
|
90228
|
+
function resolveLineId(repoPath, lineId) {
|
|
90229
|
+
if (lineId) return lineId;
|
|
90230
|
+
const ids = listInstalledLineIds(repoPath);
|
|
90231
|
+
if (ids.length === 0) {
|
|
90232
|
+
throw new Error('No factory line installed. Run "har line create <id>" or "har line add <spec>".');
|
|
90233
|
+
}
|
|
90234
|
+
if (ids.length > 1) {
|
|
90235
|
+
throw new Error(`Multiple lines installed (${ids.join(", ")}). Pass --line <id>.`);
|
|
90236
|
+
}
|
|
90237
|
+
return ids[0];
|
|
90238
|
+
}
|
|
90239
|
+
async function runLineGate(options) {
|
|
90240
|
+
const repoPath = path89.resolve(options.repoPath);
|
|
90241
|
+
const lineId = resolveLineId(repoPath, options.lineId);
|
|
90242
|
+
const program = readInstalledLineProgram(repoPath, lineId);
|
|
90243
|
+
if (!program) {
|
|
90244
|
+
throw new Error(`Line not installed: ${lineId}`);
|
|
90245
|
+
}
|
|
90246
|
+
const required2 = cumulativeGateStages(program, options.station);
|
|
90247
|
+
if (program.gate.optInEnv && !options.force && process.env[program.gate.optInEnv] !== "1") {
|
|
90248
|
+
return {
|
|
90249
|
+
lineId,
|
|
90250
|
+
station: options.station,
|
|
90251
|
+
stages: required2.map((stage) => ({
|
|
90252
|
+
stageId: stage.id,
|
|
90253
|
+
fromStation: stage.fromStation,
|
|
90254
|
+
status: "skipped",
|
|
90255
|
+
reason: `${program.gate.optInEnv} is not "1"`
|
|
90256
|
+
})),
|
|
90257
|
+
pass: true,
|
|
90258
|
+
skipped: true,
|
|
90259
|
+
skipReason: `Gate is opt-in: set ${program.gate.optInEnv}=1 (or pass --force) to run it.`
|
|
90260
|
+
};
|
|
90261
|
+
}
|
|
90262
|
+
const registry2 = readStageRegistry(repoPath);
|
|
90263
|
+
const registeredIds = new Set(registry2.stages.map((s) => s.id));
|
|
90264
|
+
const results = [];
|
|
90265
|
+
let pass = true;
|
|
90266
|
+
for (const stage of required2) {
|
|
90267
|
+
if (!registeredIds.has(stage.id)) {
|
|
90268
|
+
results.push({
|
|
90269
|
+
stageId: stage.id,
|
|
90270
|
+
fromStation: stage.fromStation,
|
|
90271
|
+
status: "skipped",
|
|
90272
|
+
reason: "stage is not registered in .har/stages.json"
|
|
90273
|
+
});
|
|
90274
|
+
pass = false;
|
|
90275
|
+
continue;
|
|
90276
|
+
}
|
|
90277
|
+
const result = await runStage({
|
|
90278
|
+
repoPath,
|
|
90279
|
+
stageId: stage.id,
|
|
90280
|
+
agentId: options.agentId,
|
|
90281
|
+
trigger: "cli"
|
|
90282
|
+
});
|
|
90283
|
+
results.push({
|
|
90284
|
+
stageId: stage.id,
|
|
90285
|
+
fromStation: stage.fromStation,
|
|
90286
|
+
status: result.status,
|
|
90287
|
+
durationMs: result.durationMs
|
|
90288
|
+
});
|
|
90289
|
+
if (result.status !== "pass") {
|
|
90290
|
+
pass = false;
|
|
90291
|
+
}
|
|
90292
|
+
}
|
|
90293
|
+
return { lineId, station: options.station, stages: results, pass, skipped: false };
|
|
90294
|
+
}
|
|
90295
|
+
function createLineBundle(repoPath, options) {
|
|
90296
|
+
return createLine(repoPath, options);
|
|
90297
|
+
}
|
|
90298
|
+
function addLine(repoPath, spec, options = {}) {
|
|
90299
|
+
return applyLine(repoPath, spec, options);
|
|
90300
|
+
}
|
|
90301
|
+
|
|
90302
|
+
// src/mcp/server.ts
|
|
89322
90303
|
init_work_units();
|
|
89323
90304
|
init_manifest();
|
|
89324
90305
|
|
|
@@ -89532,6 +90513,32 @@ var ControlUpOutputSchema = external_exports.object({
|
|
|
89532
90513
|
failed: external_exports.number().int(),
|
|
89533
90514
|
apiReady: external_exports.boolean()
|
|
89534
90515
|
});
|
|
90516
|
+
var CreateLineInputSchema = external_exports.object({
|
|
90517
|
+
repo: external_exports.string().default("."),
|
|
90518
|
+
id: external_exports.string().min(1).describe("Line id (lowercase slug, e.g. onboarding-line)"),
|
|
90519
|
+
title: external_exports.string().min(1).optional().describe("Human-readable line title"),
|
|
90520
|
+
description: external_exports.string().min(1).max(2e3).optional(),
|
|
90521
|
+
stations: external_exports.array(external_exports.string().min(1)).optional().describe("Station ids in order (default: S1, S2)"),
|
|
90522
|
+
gateStage: external_exports.boolean().default(true).describe("Scaffold one registered-but-off-verify gate stage"),
|
|
90523
|
+
optInEnv: external_exports.string().min(1).optional().describe('Env var that must be "1" for the gate to run (e.g. HAR_FIXTURE_E2E)'),
|
|
90524
|
+
force: external_exports.boolean().default(false)
|
|
90525
|
+
});
|
|
90526
|
+
var AddLineInputSchema = external_exports.object({
|
|
90527
|
+
repo: external_exports.string().default("."),
|
|
90528
|
+
line: external_exports.string().min(1).describe("Line id, local path (./line), npm package (@org/pkg), or git URL (github:org/repo)"),
|
|
90529
|
+
force: external_exports.boolean().default(false).describe("Overwrite existing line files and stage entries")
|
|
90530
|
+
});
|
|
90531
|
+
var LineStatusInputSchema = external_exports.object({
|
|
90532
|
+
repo: external_exports.string().default("."),
|
|
90533
|
+
line: external_exports.string().min(1).optional().describe("Line id (default: every installed line)")
|
|
90534
|
+
});
|
|
90535
|
+
var RunLineGateInputSchema = external_exports.object({
|
|
90536
|
+
repo: external_exports.string().default("."),
|
|
90537
|
+
station: external_exports.string().min(1).describe("Station id whose cumulative gate should run"),
|
|
90538
|
+
line: external_exports.string().min(1).optional().describe("Line id when more than one is installed"),
|
|
90539
|
+
agentId: external_exports.number().int().optional().describe("Agent slot to run the stages in"),
|
|
90540
|
+
force: external_exports.boolean().default(false).describe("Run even when the program declares an opt-in env var that is not set")
|
|
90541
|
+
});
|
|
89535
90542
|
|
|
89536
90543
|
// src/mcp/server.ts
|
|
89537
90544
|
var HAR_MCP_TOOLS = [
|
|
@@ -89780,6 +90787,73 @@ var HAR_MCP_TOOLS = [
|
|
|
89780
90787
|
repo: repoJsonProperty,
|
|
89781
90788
|
detach: { type: "boolean", description: "Run the container in detached mode (default true)" }
|
|
89782
90789
|
})
|
|
90790
|
+
},
|
|
90791
|
+
{
|
|
90792
|
+
name: "har_line_create",
|
|
90793
|
+
description: "Scaffold a project-owned factory line at .har/lines/<id>/ (manifest, program, optional gate stage, README). A line is a multi-station program, not a verification plugin.",
|
|
90794
|
+
inputSchema: objectJsonSchema(
|
|
90795
|
+
{
|
|
90796
|
+
repo: repoJsonProperty,
|
|
90797
|
+
id: { type: "string", description: "Line id (lowercase slug, e.g. onboarding-line)" },
|
|
90798
|
+
title: { type: "string", description: "Human-readable line title" },
|
|
90799
|
+
description: { type: "string", description: "One-paragraph description of the program" },
|
|
90800
|
+
stations: {
|
|
90801
|
+
type: "array",
|
|
90802
|
+
items: { type: "string" },
|
|
90803
|
+
description: "Station ids in order (default: S1, S2)"
|
|
90804
|
+
},
|
|
90805
|
+
gateStage: {
|
|
90806
|
+
type: "boolean",
|
|
90807
|
+
description: "Scaffold one registered-but-off-verify gate stage (default true)"
|
|
90808
|
+
},
|
|
90809
|
+
optInEnv: {
|
|
90810
|
+
type: "string",
|
|
90811
|
+
description: 'Env var that must be "1" for the gate to run (e.g. HAR_FIXTURE_E2E)'
|
|
90812
|
+
},
|
|
90813
|
+
force: { type: "boolean", description: "Overwrite an existing line" }
|
|
90814
|
+
},
|
|
90815
|
+
["id"]
|
|
90816
|
+
)
|
|
90817
|
+
},
|
|
90818
|
+
{
|
|
90819
|
+
name: "har_add_line",
|
|
90820
|
+
description: "Install a factory line bundle (local id, path, npm package, or git URL). Registers the line's stages but NEVER adds them to verificationStages \u2014 default verify stays unchanged. Verification plugins use har_add_plugin instead.",
|
|
90821
|
+
inputSchema: objectJsonSchema(
|
|
90822
|
+
{
|
|
90823
|
+
repo: repoJsonProperty,
|
|
90824
|
+
line: {
|
|
90825
|
+
type: "string",
|
|
90826
|
+
description: "Line id, local path (./line), npm package (@org/pkg), or git URL"
|
|
90827
|
+
},
|
|
90828
|
+
force: { type: "boolean", description: "Overwrite existing line files and stage entries" }
|
|
90829
|
+
},
|
|
90830
|
+
["line"]
|
|
90831
|
+
)
|
|
90832
|
+
},
|
|
90833
|
+
{
|
|
90834
|
+
name: "har_line_status",
|
|
90835
|
+
description: "Stations, cumulative gate progress derived from .har/runs/ records, and slots in flight for installed factory lines. Pure read \u2014 writes no run records.",
|
|
90836
|
+
inputSchema: objectJsonSchema({
|
|
90837
|
+
repo: repoJsonProperty,
|
|
90838
|
+
line: { type: "string", description: "Line id (default: every installed line)" }
|
|
90839
|
+
})
|
|
90840
|
+
},
|
|
90841
|
+
{
|
|
90842
|
+
name: "har_run_line_gate",
|
|
90843
|
+
description: "Run one station's cumulative gate: every gate stage tagged at that station or earlier. Runs through the normal stage runner and writes run records; does not call verify and does not widen the verify plan.",
|
|
90844
|
+
inputSchema: objectJsonSchema(
|
|
90845
|
+
{
|
|
90846
|
+
repo: repoJsonProperty,
|
|
90847
|
+
station: { type: "string", description: "Station id whose cumulative gate should run" },
|
|
90848
|
+
line: { type: "string", description: "Line id when more than one is installed" },
|
|
90849
|
+
agentId: agentIdJsonProperty,
|
|
90850
|
+
force: {
|
|
90851
|
+
type: "boolean",
|
|
90852
|
+
description: "Run even when the program declares an opt-in env var that is not set"
|
|
90853
|
+
}
|
|
90854
|
+
},
|
|
90855
|
+
["station"]
|
|
90856
|
+
)
|
|
89783
90857
|
}
|
|
89784
90858
|
];
|
|
89785
90859
|
function jsonContent(data) {
|
|
@@ -90045,7 +91119,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
90045
91119
|
const input = ControlUpInputSchema.parse({ ...args, repo });
|
|
90046
91120
|
const result = await startControlAndSync({
|
|
90047
91121
|
detach: input.detach,
|
|
90048
|
-
cwd:
|
|
91122
|
+
cwd: path90.resolve(input.repo)
|
|
90049
91123
|
});
|
|
90050
91124
|
if (result.code !== 0) {
|
|
90051
91125
|
return {
|
|
@@ -90067,6 +91141,59 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
90067
91141
|
})
|
|
90068
91142
|
);
|
|
90069
91143
|
}
|
|
91144
|
+
case "har_line_create": {
|
|
91145
|
+
const input = CreateLineInputSchema.parse({ ...args, repo });
|
|
91146
|
+
const result = createLineBundle(repo, {
|
|
91147
|
+
id: input.id,
|
|
91148
|
+
title: input.title,
|
|
91149
|
+
description: input.description,
|
|
91150
|
+
stations: input.stations,
|
|
91151
|
+
gateStage: input.gateStage,
|
|
91152
|
+
optInEnv: input.optInEnv,
|
|
91153
|
+
force: input.force
|
|
91154
|
+
});
|
|
91155
|
+
return jsonContent({
|
|
91156
|
+
lineId: result.lineId,
|
|
91157
|
+
filesWritten: result.filesWritten,
|
|
91158
|
+
nextSteps: result.nextSteps
|
|
91159
|
+
});
|
|
91160
|
+
}
|
|
91161
|
+
case "har_add_line": {
|
|
91162
|
+
const input = AddLineInputSchema.parse({ ...args, repo });
|
|
91163
|
+
const result = addLine(repo, input.line, { force: input.force, spec: input.line });
|
|
91164
|
+
return jsonContent({
|
|
91165
|
+
lineId: result.lineId,
|
|
91166
|
+
title: result.title,
|
|
91167
|
+
stationIds: result.stationIds,
|
|
91168
|
+
firstGatedStationId: result.firstGatedStationId,
|
|
91169
|
+
stageIds: result.stageIds,
|
|
91170
|
+
filesWritten: result.filesWritten,
|
|
91171
|
+
warnings: result.warnings,
|
|
91172
|
+
nextSteps: result.nextSteps,
|
|
91173
|
+
programPath: result.programPath,
|
|
91174
|
+
docsPath: result.docsPath,
|
|
91175
|
+
source: result.source,
|
|
91176
|
+
adaptPromptPath: result.adaptPromptPath,
|
|
91177
|
+
verificationStagesUnchanged: true
|
|
91178
|
+
});
|
|
91179
|
+
}
|
|
91180
|
+
case "har_line_status": {
|
|
91181
|
+
const input = LineStatusInputSchema.parse({ ...args, repo });
|
|
91182
|
+
const statuses = input.line ? [getLineStatus(repo, input.line)] : getAllLineStatuses(repo);
|
|
91183
|
+
return jsonContent(input.line ? statuses[0] : { lines: statuses });
|
|
91184
|
+
}
|
|
91185
|
+
case "har_run_line_gate": {
|
|
91186
|
+
const input = RunLineGateInputSchema.parse({ ...args, repo });
|
|
91187
|
+
const agentId = input.agentId === void 0 ? void 0 : validateAgentId(input.agentId, repo);
|
|
91188
|
+
const result = await runLineGate({
|
|
91189
|
+
repoPath: repo,
|
|
91190
|
+
lineId: input.line,
|
|
91191
|
+
station: input.station,
|
|
91192
|
+
agentId,
|
|
91193
|
+
force: input.force
|
|
91194
|
+
});
|
|
91195
|
+
return jsonContent(result);
|
|
91196
|
+
}
|
|
90070
91197
|
default:
|
|
90071
91198
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
90072
91199
|
}
|
|
@@ -90109,11 +91236,11 @@ var mcpCommand = {
|
|
|
90109
91236
|
};
|
|
90110
91237
|
|
|
90111
91238
|
// src/cli/commands/onboard.ts
|
|
90112
|
-
var
|
|
91239
|
+
var path92 = __toESM(require("path"));
|
|
90113
91240
|
init_stages();
|
|
90114
91241
|
|
|
90115
91242
|
// src/core/onboarding.ts
|
|
90116
|
-
var
|
|
91243
|
+
var path91 = __toESM(require("path"));
|
|
90117
91244
|
init_control_config();
|
|
90118
91245
|
init_control_sync();
|
|
90119
91246
|
init_otel_hooks();
|
|
@@ -90257,7 +91384,7 @@ async function defaultEnsureControl(options) {
|
|
|
90257
91384
|
return { started: true, apiUrl: result.apiUrl };
|
|
90258
91385
|
}
|
|
90259
91386
|
async function runOnboarding(options, deps = {}) {
|
|
90260
|
-
const repoPath =
|
|
91387
|
+
const repoPath = path91.resolve(options.repoPath);
|
|
90261
91388
|
const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
|
|
90262
91389
|
const ensureControl = deps.ensureControl ?? defaultEnsureControl;
|
|
90263
91390
|
const init = deps.initHarness ?? initHarness;
|
|
@@ -90455,7 +91582,7 @@ async function promptChoices(args, docker) {
|
|
|
90455
91582
|
};
|
|
90456
91583
|
}
|
|
90457
91584
|
const pluginChoices = listPluginChoices();
|
|
90458
|
-
const repoPath =
|
|
91585
|
+
const repoPath = path92.resolve(args.repo);
|
|
90459
91586
|
const alreadyPresent = harnessExists(repoPath);
|
|
90460
91587
|
const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
|
|
90461
91588
|
const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
|
|
@@ -90576,7 +91703,7 @@ function printSummary(result) {
|
|
|
90576
91703
|
console.error("");
|
|
90577
91704
|
}
|
|
90578
91705
|
async function handleOnboard(argv) {
|
|
90579
|
-
const repoPath =
|
|
91706
|
+
const repoPath = path92.resolve(argv.repo);
|
|
90580
91707
|
header("har onboard");
|
|
90581
91708
|
info(`Repository: ${repoPath}`);
|
|
90582
91709
|
try {
|
|
@@ -90693,24 +91820,288 @@ var onboardCommand = {
|
|
|
90693
91820
|
handler: (argv) => handleOnboard(argv)
|
|
90694
91821
|
};
|
|
90695
91822
|
|
|
91823
|
+
// src/cli/commands/line.ts
|
|
91824
|
+
var path93 = __toESM(require("path"));
|
|
91825
|
+
init_logging();
|
|
91826
|
+
function handleLineCreate(argv) {
|
|
91827
|
+
if (!argv.id) {
|
|
91828
|
+
error('Missing line id. Usage: har line create <id> [--stations S1,S2] [--title "..."]');
|
|
91829
|
+
return finishCommand(1);
|
|
91830
|
+
}
|
|
91831
|
+
const repoPath = path93.resolve(argv.repo);
|
|
91832
|
+
header("har line create");
|
|
91833
|
+
info(`Repository: ${repoPath}`);
|
|
91834
|
+
info(`Line: ${argv.id}`);
|
|
91835
|
+
try {
|
|
91836
|
+
const result = createLineBundle(repoPath, {
|
|
91837
|
+
id: argv.id,
|
|
91838
|
+
title: argv.title,
|
|
91839
|
+
description: argv.description,
|
|
91840
|
+
stations: argv.stations,
|
|
91841
|
+
gateStage: argv.gateStage,
|
|
91842
|
+
optInEnv: argv.optInEnv,
|
|
91843
|
+
force: argv.force
|
|
91844
|
+
});
|
|
91845
|
+
divider();
|
|
91846
|
+
success(`Factory line scaffolded: .har/lines/${result.lineId}/`);
|
|
91847
|
+
for (const file of result.filesWritten) {
|
|
91848
|
+
info(` + ${file}`);
|
|
91849
|
+
}
|
|
91850
|
+
console.error("");
|
|
91851
|
+
console.error(" Next steps:");
|
|
91852
|
+
for (const step of result.nextSteps) {
|
|
91853
|
+
console.error(` ${step}`);
|
|
91854
|
+
}
|
|
91855
|
+
console.error("");
|
|
91856
|
+
console.error(` Docs: .har/lines/${result.lineId}/README.md`);
|
|
91857
|
+
console.error("");
|
|
91858
|
+
} catch (err) {
|
|
91859
|
+
error(err.message);
|
|
91860
|
+
return finishCommand(1);
|
|
91861
|
+
}
|
|
91862
|
+
}
|
|
91863
|
+
function handleLineAdd(argv) {
|
|
91864
|
+
if (!argv.spec) {
|
|
91865
|
+
error("Missing line spec. Usage: har line add <id|path|npm|git>");
|
|
91866
|
+
return finishCommand(1);
|
|
91867
|
+
}
|
|
91868
|
+
const repoPath = path93.resolve(argv.repo);
|
|
91869
|
+
header("har line add");
|
|
91870
|
+
info(`Repository: ${repoPath}`);
|
|
91871
|
+
info(`Line: ${argv.spec}`);
|
|
91872
|
+
try {
|
|
91873
|
+
const result = addLine(repoPath, argv.spec, { force: argv.force, spec: argv.spec });
|
|
91874
|
+
divider();
|
|
91875
|
+
console.error("");
|
|
91876
|
+
console.error(" verificationStages unchanged \u2014 line gate stages are opt-in.");
|
|
91877
|
+
console.error(
|
|
91878
|
+
` Run the gate with: har line gate ${result.firstGatedStationId} --line ${result.lineId}`
|
|
91879
|
+
);
|
|
91880
|
+
console.error("");
|
|
91881
|
+
console.error(" Next steps:");
|
|
91882
|
+
for (const step of result.nextSteps) {
|
|
91883
|
+
console.error(` ${step}`);
|
|
91884
|
+
}
|
|
91885
|
+
console.error("");
|
|
91886
|
+
} catch (err) {
|
|
91887
|
+
error(err.message);
|
|
91888
|
+
return finishCommand(1);
|
|
91889
|
+
}
|
|
91890
|
+
}
|
|
91891
|
+
function renderStatus(status) {
|
|
91892
|
+
header(`Line: ${status.lineId} \u2014 ${status.title}`);
|
|
91893
|
+
info(`Program: ${status.programPath}${status.source ? ` (source: ${status.source})` : ""}`);
|
|
91894
|
+
info(
|
|
91895
|
+
status.optInEnv ? `Gate: opt-in via ${status.optInEnv}=1` : "Gate: on demand (har line gate <station>)"
|
|
91896
|
+
);
|
|
91897
|
+
info(
|
|
91898
|
+
status.registeredStageIds.length > 0 ? `Registered stages (off verify): ${status.registeredStageIds.join(", ")}` : "Registered stages (off verify): none"
|
|
91899
|
+
);
|
|
91900
|
+
console.error("");
|
|
91901
|
+
for (const station of status.stations) {
|
|
91902
|
+
const marker = station.green ? "\u2713" : station.id === status.nextStationId ? "\u25B6" : "\xB7";
|
|
91903
|
+
const required2 = station.requiredStageIds.length > 0 ? `${station.passedStageIds.length}/${station.requiredStageIds.length} gate stages green` : "no gate stages";
|
|
91904
|
+
console.error(` ${marker} ${station.id} ${station.title} \u2014 ${required2}`);
|
|
91905
|
+
if (station.missingStageIds.length > 0) {
|
|
91906
|
+
console.error(` missing (not registered): ${station.missingStageIds.join(", ")}`);
|
|
91907
|
+
}
|
|
91908
|
+
const pending = station.requiredStageIds.filter((id) => !station.passedStageIds.includes(id));
|
|
91909
|
+
if (pending.length > 0 && station.missingStageIds.length === 0) {
|
|
91910
|
+
console.error(` pending: ${pending.join(", ")}`);
|
|
91911
|
+
}
|
|
91912
|
+
}
|
|
91913
|
+
console.error("");
|
|
91914
|
+
if (status.slotsInFlight.length > 0) {
|
|
91915
|
+
console.error(" Slots in flight:");
|
|
91916
|
+
for (const slot of status.slotsInFlight) {
|
|
91917
|
+
const work = slot.workUnitId ? ` work=${slot.workUnitId}` : "";
|
|
91918
|
+
console.error(` agent ${slot.agentId}: ${slot.branch ?? slot.workDir}${work}`);
|
|
91919
|
+
}
|
|
91920
|
+
console.error("");
|
|
91921
|
+
}
|
|
91922
|
+
for (const warning of status.warnings) {
|
|
91923
|
+
warn(` \u26A0 ${warning}`);
|
|
91924
|
+
}
|
|
91925
|
+
console.error(
|
|
91926
|
+
status.nextStationId ? ` Next station: ${status.nextStationId}` : " All stations green \u2014 hand off for human review (autonomousShip: false)."
|
|
91927
|
+
);
|
|
91928
|
+
console.error("");
|
|
91929
|
+
}
|
|
91930
|
+
function handleLineStatus(argv) {
|
|
91931
|
+
const repoPath = path93.resolve(argv.repo);
|
|
91932
|
+
try {
|
|
91933
|
+
const statuses = argv.id ? [getLineStatus(repoPath, argv.id)] : getAllLineStatuses(repoPath);
|
|
91934
|
+
if (argv.json) {
|
|
91935
|
+
console.log(JSON.stringify(argv.id ? statuses[0] : statuses, null, 2));
|
|
91936
|
+
return;
|
|
91937
|
+
}
|
|
91938
|
+
if (statuses.length === 0) {
|
|
91939
|
+
info("No factory line installed.");
|
|
91940
|
+
info("Scaffold one: har line create <id> \u2022 Install one: har line add <spec>");
|
|
91941
|
+
return;
|
|
91942
|
+
}
|
|
91943
|
+
for (const status of statuses) {
|
|
91944
|
+
renderStatus(status);
|
|
91945
|
+
}
|
|
91946
|
+
} catch (err) {
|
|
91947
|
+
error(err.message);
|
|
91948
|
+
return finishCommand(1);
|
|
91949
|
+
}
|
|
91950
|
+
}
|
|
91951
|
+
async function handleLineGate(argv) {
|
|
91952
|
+
if (!argv.station) {
|
|
91953
|
+
error("Missing station. Usage: har line gate <station> [--line <id>] [--agent <slot>]");
|
|
91954
|
+
return finishCommand(1);
|
|
91955
|
+
}
|
|
91956
|
+
const repoPath = path93.resolve(argv.repo);
|
|
91957
|
+
try {
|
|
91958
|
+
const result = await runLineGate({
|
|
91959
|
+
repoPath,
|
|
91960
|
+
lineId: argv.line,
|
|
91961
|
+
station: argv.station,
|
|
91962
|
+
agentId: argv.agent,
|
|
91963
|
+
force: argv.force
|
|
91964
|
+
});
|
|
91965
|
+
if (argv.json) {
|
|
91966
|
+
console.log(JSON.stringify(result, null, 2));
|
|
91967
|
+
return finishCommand(result.pass ? 0 : 1);
|
|
91968
|
+
}
|
|
91969
|
+
header(`har line gate ${result.station} (${result.lineId})`);
|
|
91970
|
+
if (result.skipped) {
|
|
91971
|
+
info(result.skipReason ?? "Gate skipped.");
|
|
91972
|
+
for (const stage of result.stages) {
|
|
91973
|
+
info(` \xB7 ${stage.stageId} (from ${stage.fromStation}) \u2014 skipped`);
|
|
91974
|
+
}
|
|
91975
|
+
return;
|
|
91976
|
+
}
|
|
91977
|
+
for (const stage of result.stages) {
|
|
91978
|
+
const mark = stage.status === "pass" ? "\u2713" : stage.status === "skipped" ? "\xB7" : "\u2717";
|
|
91979
|
+
const detail = stage.reason ? ` \u2014 ${stage.reason}` : "";
|
|
91980
|
+
const ms = stage.durationMs !== void 0 ? ` (${Math.round(stage.durationMs / 100) / 10}s)` : "";
|
|
91981
|
+
console.error(` ${mark} ${stage.stageId} from ${stage.fromStation} ${stage.status}${ms}${detail}`);
|
|
91982
|
+
}
|
|
91983
|
+
divider();
|
|
91984
|
+
if (result.pass) {
|
|
91985
|
+
success(`Gate passed for station ${result.station}`);
|
|
91986
|
+
} else {
|
|
91987
|
+
error(`Gate failed for station ${result.station}`);
|
|
91988
|
+
}
|
|
91989
|
+
return finishCommand(result.pass ? 0 : 1);
|
|
91990
|
+
} catch (err) {
|
|
91991
|
+
error(err.message);
|
|
91992
|
+
return finishCommand(1);
|
|
91993
|
+
}
|
|
91994
|
+
}
|
|
91995
|
+
function handleLineList(argv) {
|
|
91996
|
+
const repoPath = path93.resolve(argv.repo);
|
|
91997
|
+
const installed = new Set(listInstalledLineIds(repoPath));
|
|
91998
|
+
for (const id of listBundledLineIds()) {
|
|
91999
|
+
console.log(`${id} (bundled)`);
|
|
92000
|
+
}
|
|
92001
|
+
for (const id of listLocalLineIds(repoPath)) {
|
|
92002
|
+
console.log(`${id} (local: .har/lines/${id})${installed.has(id) ? " [installed]" : ""}`);
|
|
92003
|
+
}
|
|
92004
|
+
}
|
|
92005
|
+
function parseStations(value) {
|
|
92006
|
+
if (typeof value !== "string" || value.trim() === "") return void 0;
|
|
92007
|
+
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
92008
|
+
}
|
|
92009
|
+
var lineCommand = {
|
|
92010
|
+
command: "line <subcommand>",
|
|
92011
|
+
describe: "Factory lines: multi-station programs with a cumulative gate that never joins verificationStages",
|
|
92012
|
+
builder: (yargs) => yargs.command(
|
|
92013
|
+
"create [id]",
|
|
92014
|
+
"Scaffold a project-owned line at .har/lines/<id>/ (manifest, program, gate stage, README)",
|
|
92015
|
+
(y) => y.positional("id", { type: "string", describe: "Line id (lowercase slug, e.g. onboarding-line)" }).option("repo", { type: "string", default: ".", describe: "Path to the repository" }).option("title", { type: "string", describe: "Human-readable line title" }).option("description", { type: "string", describe: "One-paragraph description of the program" }).option("stations", {
|
|
92016
|
+
type: "string",
|
|
92017
|
+
describe: "Comma-separated station ids in order (default: S1,S2)"
|
|
92018
|
+
}).option("gate-stage", {
|
|
92019
|
+
type: "boolean",
|
|
92020
|
+
default: true,
|
|
92021
|
+
describe: "Scaffold one registered-but-off-verify gate stage"
|
|
92022
|
+
}).option("opt-in-env", {
|
|
92023
|
+
type: "string",
|
|
92024
|
+
describe: 'Env var that must be "1" for the gate to run (e.g. HAR_FIXTURE_E2E)'
|
|
92025
|
+
}).option("force", { type: "boolean", default: false, describe: "Overwrite an existing line" }),
|
|
92026
|
+
(argv) => handleLineCreate({
|
|
92027
|
+
id: argv.id,
|
|
92028
|
+
repo: argv.repo,
|
|
92029
|
+
title: argv.title,
|
|
92030
|
+
description: argv.description,
|
|
92031
|
+
stations: parseStations(argv.stations),
|
|
92032
|
+
gateStage: argv["gate-stage"],
|
|
92033
|
+
optInEnv: argv["opt-in-env"],
|
|
92034
|
+
force: argv.force
|
|
92035
|
+
})
|
|
92036
|
+
).command(
|
|
92037
|
+
"add [spec]",
|
|
92038
|
+
"Install a line bundle (local id, path, npm package, or git URL) \u2014 never touches verificationStages",
|
|
92039
|
+
(y) => y.positional("spec", {
|
|
92040
|
+
type: "string",
|
|
92041
|
+
describe: "Line id, path (./line), npm package (@org/pkg), or git URL (github:org/repo)"
|
|
92042
|
+
}).option("repo", { type: "string", default: ".", describe: "Path to the repository" }).option("force", {
|
|
92043
|
+
type: "boolean",
|
|
92044
|
+
default: false,
|
|
92045
|
+
describe: "Overwrite existing line files and stage entries"
|
|
92046
|
+
}),
|
|
92047
|
+
(argv) => handleLineAdd({
|
|
92048
|
+
spec: argv.spec,
|
|
92049
|
+
repo: argv.repo,
|
|
92050
|
+
force: argv.force
|
|
92051
|
+
})
|
|
92052
|
+
).command(
|
|
92053
|
+
"status [id]",
|
|
92054
|
+
"Show stations, cumulative gate progress from run records, and slots in flight",
|
|
92055
|
+
(y) => y.positional("id", { type: "string", describe: "Line id (default: all installed lines)" }).option("repo", { type: "string", default: ".", describe: "Path to the repository" }).option("json", { type: "boolean", default: false, describe: "Emit structured JSON" }),
|
|
92056
|
+
(argv) => handleLineStatus({
|
|
92057
|
+
id: argv.id,
|
|
92058
|
+
repo: argv.repo,
|
|
92059
|
+
json: argv.json
|
|
92060
|
+
})
|
|
92061
|
+
).command(
|
|
92062
|
+
"gate [station]",
|
|
92063
|
+
"Run the cumulative gate for a station (does NOT run verify and does not widen it)",
|
|
92064
|
+
(y) => y.positional("station", { type: "string", describe: "Station id (e.g. S1)" }).option("repo", { type: "string", default: ".", describe: "Path to the repository" }).option("line", { type: "string", describe: "Line id when more than one is installed" }).option("agent", { type: "number", describe: "Agent slot to run the stages in" }).option("force", {
|
|
92065
|
+
type: "boolean",
|
|
92066
|
+
default: false,
|
|
92067
|
+
describe: "Run even when the program declares an opt-in env var that is not set"
|
|
92068
|
+
}).option("json", { type: "boolean", default: false, describe: "Emit structured JSON" }),
|
|
92069
|
+
(argv) => handleLineGate({
|
|
92070
|
+
station: argv.station,
|
|
92071
|
+
repo: argv.repo,
|
|
92072
|
+
line: argv.line,
|
|
92073
|
+
agent: argv.agent,
|
|
92074
|
+
force: argv.force,
|
|
92075
|
+
json: argv.json
|
|
92076
|
+
})
|
|
92077
|
+
).command(
|
|
92078
|
+
"list",
|
|
92079
|
+
"List lines available to this repository (bundled and local)",
|
|
92080
|
+
(y) => y.option("repo", { type: "string", default: ".", describe: "Path to the repository" }),
|
|
92081
|
+
(argv) => handleLineList({ repo: argv.repo })
|
|
92082
|
+
).demandCommand(1, "Please specify a subcommand: create, add, status, gate, list"),
|
|
92083
|
+
handler: () => {
|
|
92084
|
+
}
|
|
92085
|
+
};
|
|
92086
|
+
|
|
90696
92087
|
// src/cli/commands/plugin.ts
|
|
90697
|
-
var
|
|
92088
|
+
var path95 = __toESM(require("path"));
|
|
90698
92089
|
|
|
90699
92090
|
// src/harness/plugin-create.ts
|
|
90700
|
-
var
|
|
90701
|
-
var
|
|
92091
|
+
var fs78 = __toESM(require("fs"));
|
|
92092
|
+
var path94 = __toESM(require("path"));
|
|
90702
92093
|
init_paths();
|
|
90703
92094
|
init_schema2();
|
|
90704
92095
|
var PLUGIN_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
90705
|
-
function
|
|
90706
|
-
let content =
|
|
92096
|
+
function renderSkeleton2(templatePath, tokens) {
|
|
92097
|
+
let content = fs78.readFileSync(templatePath, "utf8");
|
|
90707
92098
|
for (const [token, value] of Object.entries(tokens)) {
|
|
90708
92099
|
content = content.replace(new RegExp(token, "g"), value);
|
|
90709
92100
|
}
|
|
90710
92101
|
return content;
|
|
90711
92102
|
}
|
|
90712
92103
|
function createLocalPlugin(repoPath, options) {
|
|
90713
|
-
const resolved =
|
|
92104
|
+
const resolved = path94.resolve(repoPath);
|
|
90714
92105
|
if (!harnessExists(resolved)) {
|
|
90715
92106
|
throw new Error('No .har/ harness found. Run "har onboard" first.');
|
|
90716
92107
|
}
|
|
@@ -90726,9 +92117,9 @@ function createLocalPlugin(repoPath, options) {
|
|
|
90726
92117
|
`Invalid stage kind "${kind}". Available: ${HarnessStageKindSchema.options.join(", ")}`
|
|
90727
92118
|
);
|
|
90728
92119
|
}
|
|
90729
|
-
const pluginDir =
|
|
92120
|
+
const pluginDir = path94.join(resolved, LOCAL_PLUGINS_DIR, id);
|
|
90730
92121
|
const pluginDirRel = `${LOCAL_PLUGINS_DIR}/${id}`;
|
|
90731
|
-
if (
|
|
92122
|
+
if (fs78.existsSync(pluginDir) && !options.force) {
|
|
90732
92123
|
throw new Error(`Plugin already exists: ${pluginDirRel}/. Use --force to overwrite.`);
|
|
90733
92124
|
}
|
|
90734
92125
|
const description = options.description ?? `Custom ${kind} stage (local plugin: ${id})`;
|
|
@@ -90770,16 +92161,16 @@ function createLocalPlugin(repoPath, options) {
|
|
|
90770
92161
|
});
|
|
90771
92162
|
const filesWritten = [];
|
|
90772
92163
|
const write = (rel, content, executable = false) => {
|
|
90773
|
-
const abs =
|
|
90774
|
-
|
|
90775
|
-
|
|
90776
|
-
if (executable)
|
|
92164
|
+
const abs = path94.join(pluginDir, rel);
|
|
92165
|
+
fs78.mkdirSync(path94.dirname(abs), { recursive: true });
|
|
92166
|
+
fs78.writeFileSync(abs, content);
|
|
92167
|
+
if (executable) fs78.chmodSync(abs, 493);
|
|
90777
92168
|
filesWritten.push(`${pluginDirRel}/${rel}`);
|
|
90778
92169
|
};
|
|
90779
92170
|
write("template.manifest.json", `${JSON.stringify(manifest, null, 2)}
|
|
90780
92171
|
`);
|
|
90781
|
-
const stageScript =
|
|
90782
|
-
|
|
92172
|
+
const stageScript = renderSkeleton2(
|
|
92173
|
+
path94.join(resolveTemplatesDir(), "plugins", "custom-stage-skeleton.sh"),
|
|
90783
92174
|
{
|
|
90784
92175
|
__STAGE_ID__: id,
|
|
90785
92176
|
__STAGE_KIND__: kind,
|
|
@@ -90787,8 +92178,8 @@ function createLocalPlugin(repoPath, options) {
|
|
|
90787
92178
|
}
|
|
90788
92179
|
);
|
|
90789
92180
|
write(`stages/${id}.sh`, stageScript, true);
|
|
90790
|
-
const readme =
|
|
90791
|
-
|
|
92181
|
+
const readme = renderSkeleton2(
|
|
92182
|
+
path94.join(resolveTemplatesDir(), "plugins", "local-plugin-skeleton", "README.md"),
|
|
90792
92183
|
{ __PLUGIN_ID__: id }
|
|
90793
92184
|
);
|
|
90794
92185
|
write("README.md", readme);
|
|
@@ -90820,7 +92211,7 @@ async function handlePluginCreate(argv) {
|
|
|
90820
92211
|
error('Missing plugin id. Usage: har plugin create <id> [--kind test] [--description "..."]');
|
|
90821
92212
|
return finishCommand(1);
|
|
90822
92213
|
}
|
|
90823
|
-
const repoPath =
|
|
92214
|
+
const repoPath = path95.resolve(argv.repo);
|
|
90824
92215
|
header("har plugin create");
|
|
90825
92216
|
info(`Repository: ${repoPath}`);
|
|
90826
92217
|
info(`Plugin: ${argv.id}`);
|
|
@@ -90851,7 +92242,7 @@ async function handlePluginCreate(argv) {
|
|
|
90851
92242
|
}
|
|
90852
92243
|
}
|
|
90853
92244
|
function handlePluginList(argv) {
|
|
90854
|
-
const repoPath =
|
|
92245
|
+
const repoPath = path95.resolve(argv.repo);
|
|
90855
92246
|
for (const id of listPluginIds()) {
|
|
90856
92247
|
console.log(`${id} (bundled)`);
|
|
90857
92248
|
}
|
|
@@ -91018,7 +92409,7 @@ var preferencesCommand = {
|
|
|
91018
92409
|
};
|
|
91019
92410
|
|
|
91020
92411
|
// src/cli/commands/telemetry.ts
|
|
91021
|
-
var
|
|
92412
|
+
var path96 = __toESM(require("path"));
|
|
91022
92413
|
init_control_config();
|
|
91023
92414
|
init_control_sync();
|
|
91024
92415
|
init_manifest();
|
|
@@ -91111,7 +92502,7 @@ async function handleOff() {
|
|
|
91111
92502
|
info("Mission Control will not auto-start. Existing usage rows are kept.");
|
|
91112
92503
|
}
|
|
91113
92504
|
async function handleWriteEnv(argv) {
|
|
91114
|
-
const repoPath =
|
|
92505
|
+
const repoPath = path96.resolve(argv.repo);
|
|
91115
92506
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
91116
92507
|
const session = readSlotRegistry(harnessRoot, argv.agentId);
|
|
91117
92508
|
const workDir = argv.workDir ?? session?.workDir ?? repoPath;
|
|
@@ -91123,7 +92514,7 @@ async function handleWriteEnv(argv) {
|
|
|
91123
92514
|
suffix,
|
|
91124
92515
|
createdAt: session?.createdAt
|
|
91125
92516
|
});
|
|
91126
|
-
const envFile = argv.envFile ??
|
|
92517
|
+
const envFile = argv.envFile ?? path96.join(workDir, `.env.agent.${argv.agentId}`);
|
|
91127
92518
|
const attrs = {
|
|
91128
92519
|
sessionKey,
|
|
91129
92520
|
agentId: argv.agentId,
|
|
@@ -91139,7 +92530,7 @@ async function handleWriteEnv(argv) {
|
|
|
91139
92530
|
success(`Wrote session attribution to ${envFile}`);
|
|
91140
92531
|
}
|
|
91141
92532
|
function handlePrintEnv(argv) {
|
|
91142
|
-
const repoPath =
|
|
92533
|
+
const repoPath = path96.resolve(argv.repo);
|
|
91143
92534
|
const workDir = argv.workDir ?? repoPath;
|
|
91144
92535
|
const sessionKey = buildSessionKey({
|
|
91145
92536
|
branch: argv.branch,
|
|
@@ -91262,7 +92653,7 @@ var telemetryCommand = {
|
|
|
91262
92653
|
// src/cli/index.ts
|
|
91263
92654
|
async function runCli() {
|
|
91264
92655
|
ensureDefaultTelemetryPreference();
|
|
91265
|
-
await yargs_default(hideBin(process.argv)).scriptName("har").usage("$0 <command> [options]").command(onboardCommand).command(envCommand).command(agentsCommand).command(controlCommand).command(hqCommand).command(hooksCommand).command(mcpCommand).command(pluginCommand).command(preferencesCommand).command(telemetryCommand).demandCommand(1, "Please specify a command. Try: har onboard or har env --help").epilog(HAR_ROOT_EPILOG).strict().help().version(getHarPackageVersion()).parse();
|
|
92656
|
+
await yargs_default(hideBin(process.argv)).scriptName("har").usage("$0 <command> [options]").command(onboardCommand).command(envCommand).command(agentsCommand).command(controlCommand).command(hqCommand).command(hooksCommand).command(mcpCommand).command(pluginCommand).command(lineCommand).command(preferencesCommand).command(telemetryCommand).demandCommand(1, "Please specify a command. Try: har onboard or har env --help").epilog(HAR_ROOT_EPILOG).strict().help().version(getHarPackageVersion()).parse();
|
|
91266
92657
|
await syncDirtyRepos();
|
|
91267
92658
|
}
|
|
91268
92659
|
|