@osfactory/har 0.56.1 → 0.58.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 +1601 -593
- package/dist/templates/profiles/cli/profile.manifest.json +8 -0
- package/dist/templates/profiles/default/profile.manifest.json +9 -0
- package/dist/templates/profiles/ios/profile.manifest.json +9 -0
- package/dist/templates/runtime-bundles/pm2-runtime/README.md +4 -0
- package/dist/templates/runtime-bundles/pm2-runtime/attach.sh +22 -0
- package/dist/templates/runtime-bundles/pm2-runtime/ecosystem.agent.template.cjs +46 -0
- package/dist/templates/runtime-bundles/pm2-runtime/env.template +40 -0
- package/dist/templates/runtime-bundles/shared-kernel/README.md +3 -0
- package/dist/templates/runtime-bundles/shared-kernel/STAGES.md +99 -0
- package/dist/templates/runtime-bundles/shared-kernel/provision-toolchain.sh +407 -0
- package/dist/templates/runtime-bundles/shared-kernel/stages/README.sh +11 -0
- package/dist/templates/runtime-bundles/xcode-sim/README.md +4 -0
- package/dist/templates/runtime-bundles/xcode-sim/simulator.sh +492 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -553,8 +553,8 @@ var init_parseUtil = __esm({
|
|
|
553
553
|
init_errors();
|
|
554
554
|
init_en();
|
|
555
555
|
makeIssue = (params) => {
|
|
556
|
-
const { data, path:
|
|
557
|
-
const fullPath = [...
|
|
556
|
+
const { data, path: path66, errorMaps, issueData } = params;
|
|
557
|
+
const fullPath = [...path66, ...issueData.path || []];
|
|
558
558
|
const fullIssue = {
|
|
559
559
|
...issueData,
|
|
560
560
|
path: fullPath
|
|
@@ -862,11 +862,11 @@ var init_types = __esm({
|
|
|
862
862
|
init_parseUtil();
|
|
863
863
|
init_util();
|
|
864
864
|
ParseInputLazyPath = class {
|
|
865
|
-
constructor(parent, value,
|
|
865
|
+
constructor(parent, value, path66, key) {
|
|
866
866
|
this._cachedPath = [];
|
|
867
867
|
this.parent = parent;
|
|
868
868
|
this.data = value;
|
|
869
|
-
this._path =
|
|
869
|
+
this._path = path66;
|
|
870
870
|
this._key = key;
|
|
871
871
|
}
|
|
872
872
|
get path() {
|
|
@@ -4248,7 +4248,7 @@ var init_zod = __esm({
|
|
|
4248
4248
|
});
|
|
4249
4249
|
|
|
4250
4250
|
// packages/schemas/src/schema.ts
|
|
4251
|
-
var HAR_STAGE_KINDS, HAR_AGENT_SLOT_MIN, AgentSkillTargetSchema, ScaffoldedAgentFileSchema, HarnessManifestSchema, HarnessStageKindSchema, HarnessArtifactKindSchema, HarnessArtifactSchema, HarnessStageIdSchema, HarnessStageSchema, HarnessAgentSlotsSchema, CommitGateConfigSchema, OnboardingPreferencesSchema, HarnessStageRegistrySchema, HarnessVerificationStepSchema, ShellRunOutputSchema, HarnessVerificationResultSchema, HarnessStageRunStatusSchema, HarnessStageLogSchema, HarnessStageUrlSchema, HarnessStageRunResultSchema, StageKindSchema, VerificationResultSchema, StageResultSchema, RunRecordTriggerSchema, WorkUnitIdSchema, WorkAttemptIdSchema, WorkUnitMetadataSchema, WorkUnitOutcomeSchema, WorkUnitRecordSchema, WorkAttemptRecordSchema, RunRecordSchema, SlotRegistryEntrySchema, AgentSlotHarnessUsageSchema, PreflightBlockerSchema, SlotReadinessSchema, AgentSlotStatusSchema, EnvironmentStatusSchema, RegisterRepoInputSchema, UnregisterRepoInputSchema, UnregisterWorktreeResultSchema, UnregisterRepoResultSchema, ResetMissionControlInputSchema, HarnessScrubResultSchema, ResetMissionControlResultSchema, DeleteWorktreesInputSchema, DeleteWorktreeResultSchema, DeleteWorktreesResultSchema, SyncRunsInputSchema, SyncSlotsInputSchema, SyncWorkUnitsInputSchema, ChangedFileStatusSchema, ChangedFileSchema, ValidationRecordSchema, SyncValidationsInputSchema, ValidationBindingRecordSchema, SyncValidationBindingsInputSchema, AgentToolSchema, UsageSourceSchema, AgentTrajectorySourceSchema, AgentTrajectoryContentDisclosureSchema, AgentTrajectoryRecordV1Schema, AgentSessionUsageSchema, SyncUsageInputSchema, AgentSessionEventSchema, SyncSessionEventsInputSchema;
|
|
4251
|
+
var HAR_STAGE_KINDS, HAR_AGENT_SLOT_MIN, AgentSkillTargetSchema, ScaffoldedAgentFileSchema, HarnessManifestSchema, HarnessStageKindSchema, HarnessArtifactKindSchema, HarnessArtifactSchema, HarnessStageIdSchema, HarnessStageSchema, HarnessAgentSlotsSchema, CommitGateConfigSchema, OnboardingPreferencesSchema, HarnessStageRegistrySchema, HarnessVerificationStepSchema, ShellRunOutputSchema, HarnessVerificationResultSchema, HarnessStageRunStatusSchema, HarnessStageLogSchema, HarnessStageUrlSchema, HarnessStageRunResultSchema, StageKindSchema, VerificationResultSchema, StageResultSchema, RunRecordTriggerSchema, WorkUnitIdSchema, WorkAttemptIdSchema, WorkUnitRelatedLinkSchema, WorkUnitMetadataSchema, WorkUnitOutcomeSchema, WorkUnitRecordSchema, WorkAttemptRecordSchema, RunRecordSchema, SlotRegistryEntrySchema, AgentSlotHarnessUsageSchema, PreflightBlockerSchema, SlotReadinessSchema, AgentSlotStatusSchema, EnvironmentStatusSchema, RegisterRepoInputSchema, UnregisterRepoInputSchema, UnregisterWorktreeResultSchema, UnregisterRepoResultSchema, ResetMissionControlInputSchema, HarnessScrubResultSchema, ResetMissionControlResultSchema, DeleteWorktreesInputSchema, DeleteWorktreeResultSchema, DeleteWorktreesResultSchema, SyncRunsInputSchema, SyncSlotsInputSchema, SyncWorkUnitsInputSchema, ChangedFileStatusSchema, ChangedFileSchema, ValidationRecordSchema, SyncValidationsInputSchema, ValidationBindingRecordSchema, SyncValidationBindingsInputSchema, AgentToolSchema, UsageSourceSchema, AgentTrajectorySourceSchema, AgentTrajectoryContentDisclosureSchema, AgentTrajectoryRecordV1Schema, AgentSessionUsageSchema, SyncUsageInputSchema, AgentSessionEventSchema, SyncSessionEventsInputSchema;
|
|
4252
4252
|
var init_schema = __esm({
|
|
4253
4253
|
"packages/schemas/src/schema.ts"() {
|
|
4254
4254
|
"use strict";
|
|
@@ -4413,12 +4413,18 @@ var init_schema = __esm({
|
|
|
4413
4413
|
"work unit id must start with an alphanumeric character and contain only stable identifier characters"
|
|
4414
4414
|
);
|
|
4415
4415
|
WorkAttemptIdSchema = external_exports.string().uuid();
|
|
4416
|
+
WorkUnitRelatedLinkSchema = external_exports.object({
|
|
4417
|
+
source: external_exports.string().min(1).max(64),
|
|
4418
|
+
url: external_exports.string().url(),
|
|
4419
|
+
label: external_exports.string().min(1).max(128).optional()
|
|
4420
|
+
});
|
|
4416
4421
|
WorkUnitMetadataSchema = external_exports.object({
|
|
4417
4422
|
workUnitId: WorkUnitIdSchema,
|
|
4418
4423
|
source: external_exports.string().min(1).max(64).optional(),
|
|
4419
4424
|
sourceUrl: external_exports.string().url().optional(),
|
|
4420
4425
|
title: external_exports.string().min(1).max(256).optional(),
|
|
4421
|
-
parentWorkUnitId: WorkUnitIdSchema.optional()
|
|
4426
|
+
parentWorkUnitId: WorkUnitIdSchema.optional(),
|
|
4427
|
+
relatedLinks: external_exports.array(WorkUnitRelatedLinkSchema).optional()
|
|
4422
4428
|
});
|
|
4423
4429
|
WorkUnitOutcomeSchema = external_exports.object({
|
|
4424
4430
|
decision: external_exports.enum(["completed", "abandoned"]),
|
|
@@ -28353,6 +28359,7 @@ var init_manifest = __esm({
|
|
|
28353
28359
|
DEFAULT_HAR_DIR = ".har";
|
|
28354
28360
|
CHECKSUM_SKIP = /* @__PURE__ */ new Set([
|
|
28355
28361
|
"manifest.json",
|
|
28362
|
+
"plugins.json",
|
|
28356
28363
|
"AGENTS.md.proposed",
|
|
28357
28364
|
"AGENTS.md.proposed.meta.json",
|
|
28358
28365
|
"AGENT.md.proposed",
|
|
@@ -28757,7 +28764,7 @@ function runScript(scriptPath, args = [], options = {}) {
|
|
|
28757
28764
|
function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
28758
28765
|
const stream = options.stream ?? false;
|
|
28759
28766
|
const { stream: _stream, ...spawnOptions } = options;
|
|
28760
|
-
return new Promise((
|
|
28767
|
+
return new Promise((resolve50) => {
|
|
28761
28768
|
const proc = (0, import_child_process.spawn)("bash", [scriptPath, ...args], {
|
|
28762
28769
|
...spawnOptions,
|
|
28763
28770
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -28772,13 +28779,13 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
|
28772
28779
|
stderr += d;
|
|
28773
28780
|
if (stream) process.stderr.write(d);
|
|
28774
28781
|
});
|
|
28775
|
-
proc.on("close", (code) =>
|
|
28782
|
+
proc.on("close", (code) => resolve50({ stdout, stderr, code: code ?? 0 }));
|
|
28776
28783
|
});
|
|
28777
28784
|
}
|
|
28778
28785
|
function runShellCommand(command2, options = {}) {
|
|
28779
28786
|
const stream = options.stream ?? false;
|
|
28780
28787
|
const { stream: _stream, ...spawnOptions } = options;
|
|
28781
|
-
return new Promise((
|
|
28788
|
+
return new Promise((resolve50) => {
|
|
28782
28789
|
const proc = (0, import_child_process.spawn)("bash", ["-lc", command2], {
|
|
28783
28790
|
...spawnOptions,
|
|
28784
28791
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -28793,7 +28800,7 @@ function runShellCommand(command2, options = {}) {
|
|
|
28793
28800
|
stderr += d;
|
|
28794
28801
|
if (stream) process.stderr.write(d);
|
|
28795
28802
|
});
|
|
28796
|
-
proc.on("close", (code) =>
|
|
28803
|
+
proc.on("close", (code) => resolve50({ stdout, stderr, code: code ?? 0 }));
|
|
28797
28804
|
});
|
|
28798
28805
|
}
|
|
28799
28806
|
var import_child_process;
|
|
@@ -29495,6 +29502,22 @@ var init_runs = __esm({
|
|
|
29495
29502
|
}
|
|
29496
29503
|
});
|
|
29497
29504
|
|
|
29505
|
+
// src/harness/capabilities.ts
|
|
29506
|
+
function harnessUsesPm2(repoPath) {
|
|
29507
|
+
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
29508
|
+
return fs13.existsSync(path13.join(harnessRoot, ".har", "ecosystem.agent.template.cjs"));
|
|
29509
|
+
}
|
|
29510
|
+
var fs13, path13;
|
|
29511
|
+
var init_capabilities = __esm({
|
|
29512
|
+
"src/harness/capabilities.ts"() {
|
|
29513
|
+
"use strict";
|
|
29514
|
+
fs13 = __toESM(require("fs"));
|
|
29515
|
+
path13 = __toESM(require("path"));
|
|
29516
|
+
init_manifest();
|
|
29517
|
+
init_env();
|
|
29518
|
+
}
|
|
29519
|
+
});
|
|
29520
|
+
|
|
29498
29521
|
// src/core/slot-ports.ts
|
|
29499
29522
|
function portStep(env3) {
|
|
29500
29523
|
return Number(env3.HARNESS_PORT_STEP ?? 10);
|
|
@@ -29549,19 +29572,14 @@ function allocateAppPorts(repoPath, agentId) {
|
|
|
29549
29572
|
allocated: frontend !== feDefault || api !== apiDefault || debug !== debugDefault
|
|
29550
29573
|
};
|
|
29551
29574
|
}
|
|
29552
|
-
|
|
29553
|
-
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
29554
|
-
return fs13.existsSync(path13.join(harnessRoot, ".har", "ecosystem.agent.template.cjs"));
|
|
29555
|
-
}
|
|
29556
|
-
var import_child_process3, fs13, path13;
|
|
29575
|
+
var import_child_process3;
|
|
29557
29576
|
var init_slot_ports = __esm({
|
|
29558
29577
|
"src/core/slot-ports.ts"() {
|
|
29559
29578
|
"use strict";
|
|
29560
29579
|
import_child_process3 = require("child_process");
|
|
29561
|
-
fs13 = __toESM(require("fs"));
|
|
29562
|
-
path13 = __toESM(require("path"));
|
|
29563
29580
|
init_env();
|
|
29564
29581
|
init_manifest();
|
|
29582
|
+
init_capabilities();
|
|
29565
29583
|
}
|
|
29566
29584
|
});
|
|
29567
29585
|
|
|
@@ -30628,6 +30646,7 @@ var init_slot_preflight = __esm({
|
|
|
30628
30646
|
init_control_port();
|
|
30629
30647
|
init_slot_launch_guard_occupied();
|
|
30630
30648
|
init_slot_ports();
|
|
30649
|
+
init_capabilities();
|
|
30631
30650
|
init_slot_registry();
|
|
30632
30651
|
init_worktree_untracked();
|
|
30633
30652
|
import_child_process8 = require("child_process");
|
|
@@ -30891,6 +30910,29 @@ function listRecords(harnessRoot, dir, parse4) {
|
|
|
30891
30910
|
}
|
|
30892
30911
|
return records;
|
|
30893
30912
|
}
|
|
30913
|
+
function parseWorkLinkSpec(spec) {
|
|
30914
|
+
const parts = spec.split("|");
|
|
30915
|
+
if (parts.length < 2) {
|
|
30916
|
+
throw new Error(
|
|
30917
|
+
`Invalid work link "${spec}" \u2014 use source|url or source|url|label (example: github|https://github.com/org/repo/pull/42|PR #42)`
|
|
30918
|
+
);
|
|
30919
|
+
}
|
|
30920
|
+
const [source, url, ...labelParts] = parts;
|
|
30921
|
+
const label = labelParts.length > 0 ? labelParts.join("|") : void 0;
|
|
30922
|
+
return WorkUnitRelatedLinkSchema.parse({ source, url, label });
|
|
30923
|
+
}
|
|
30924
|
+
function mergeRelatedLinks(existing, incoming, primaryUrl) {
|
|
30925
|
+
if (!incoming?.length) return existing?.length ? existing : void 0;
|
|
30926
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30927
|
+
const merged = [];
|
|
30928
|
+
for (const link of [...existing ?? [], ...incoming]) {
|
|
30929
|
+
if (primaryUrl && link.url === primaryUrl) continue;
|
|
30930
|
+
if (seen.has(link.url)) continue;
|
|
30931
|
+
seen.add(link.url);
|
|
30932
|
+
merged.push(link);
|
|
30933
|
+
}
|
|
30934
|
+
return merged.length > 0 ? merged : void 0;
|
|
30935
|
+
}
|
|
30894
30936
|
function findWorkUnit(harnessRoot, workUnitId) {
|
|
30895
30937
|
const metadata = WorkUnitMetadataSchema.parse({ workUnitId });
|
|
30896
30938
|
const file = hashedRecordPath(harnessRoot, WORK_UNITS_DIR, metadata.workUnitId);
|
|
@@ -30920,13 +30962,19 @@ function upsertWorkUnit(harnessRoot, input) {
|
|
|
30920
30962
|
}
|
|
30921
30963
|
}
|
|
30922
30964
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
30965
|
+
const sourceUrl = existing?.sourceUrl ?? metadata.sourceUrl;
|
|
30923
30966
|
const record2 = WorkUnitRecordSchema.parse({
|
|
30924
30967
|
...existing,
|
|
30925
30968
|
workUnitId: metadata.workUnitId,
|
|
30926
30969
|
source: existing?.source ?? metadata.source,
|
|
30927
|
-
sourceUrl
|
|
30970
|
+
sourceUrl,
|
|
30928
30971
|
title: existing?.title ?? metadata.title,
|
|
30929
30972
|
parentWorkUnitId: existing?.parentWorkUnitId ?? metadata.parentWorkUnitId,
|
|
30973
|
+
relatedLinks: mergeRelatedLinks(
|
|
30974
|
+
existing?.relatedLinks,
|
|
30975
|
+
metadata.relatedLinks,
|
|
30976
|
+
sourceUrl
|
|
30977
|
+
),
|
|
30930
30978
|
version: 1,
|
|
30931
30979
|
createdAt: existing?.createdAt ?? now,
|
|
30932
30980
|
updatedAt: now,
|
|
@@ -30939,6 +30987,23 @@ function upsertWorkUnit(harnessRoot, input) {
|
|
|
30939
30987
|
markDirty(harnessRoot);
|
|
30940
30988
|
return record2;
|
|
30941
30989
|
}
|
|
30990
|
+
function addWorkUnitLinks(harnessRoot, workUnitId, links) {
|
|
30991
|
+
const existing = findWorkUnit(harnessRoot, workUnitId);
|
|
30992
|
+
if (!existing) throw new Error(`Unknown work unit: ${workUnitId}`);
|
|
30993
|
+
const parsed = links.map((link) => WorkUnitRelatedLinkSchema.parse(link));
|
|
30994
|
+
const relatedLinks = mergeRelatedLinks(existing.relatedLinks, parsed, existing.sourceUrl);
|
|
30995
|
+
const record2 = WorkUnitRecordSchema.parse({
|
|
30996
|
+
...existing,
|
|
30997
|
+
relatedLinks,
|
|
30998
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
30999
|
+
});
|
|
31000
|
+
writeRecord2(
|
|
31001
|
+
hashedRecordPath(harnessRoot, WORK_UNITS_DIR, workUnitId),
|
|
31002
|
+
record2
|
|
31003
|
+
);
|
|
31004
|
+
markDirty(harnessRoot);
|
|
31005
|
+
return record2;
|
|
31006
|
+
}
|
|
30942
31007
|
function listWorkUnits(harnessRoot) {
|
|
30943
31008
|
return listRecords(
|
|
30944
31009
|
harnessRoot,
|
|
@@ -32418,7 +32483,7 @@ async function postForResponse(url, headers, payload) {
|
|
|
32418
32483
|
} catch (err) {
|
|
32419
32484
|
lastErr = err;
|
|
32420
32485
|
if (attempt < MAX_FETCH_ATTEMPTS) {
|
|
32421
|
-
await new Promise((
|
|
32486
|
+
await new Promise((resolve50) => setTimeout(resolve50, attempt * 100));
|
|
32422
32487
|
}
|
|
32423
32488
|
}
|
|
32424
32489
|
}
|
|
@@ -32618,7 +32683,7 @@ async function waitForControlApi(apiUrl = getControlApiUrl(), timeoutMs = 6e4, i
|
|
|
32618
32683
|
const deadline = Date.now() + timeoutMs;
|
|
32619
32684
|
while (Date.now() < deadline) {
|
|
32620
32685
|
if (await isControlApiReachable(apiUrl)) return true;
|
|
32621
|
-
await new Promise((
|
|
32686
|
+
await new Promise((resolve50) => setTimeout(resolve50, intervalMs));
|
|
32622
32687
|
}
|
|
32623
32688
|
return false;
|
|
32624
32689
|
}
|
|
@@ -34115,15 +34180,15 @@ var require_route = __commonJS({
|
|
|
34115
34180
|
};
|
|
34116
34181
|
}
|
|
34117
34182
|
function wrapConversion(toModel, graph) {
|
|
34118
|
-
const
|
|
34183
|
+
const path66 = [graph[toModel].parent, toModel];
|
|
34119
34184
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
34120
34185
|
let cur = graph[toModel].parent;
|
|
34121
34186
|
while (graph[cur].parent) {
|
|
34122
|
-
|
|
34187
|
+
path66.unshift(graph[cur].parent);
|
|
34123
34188
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
34124
34189
|
cur = graph[cur].parent;
|
|
34125
34190
|
}
|
|
34126
|
-
fn.conversion =
|
|
34191
|
+
fn.conversion = path66;
|
|
34127
34192
|
return fn;
|
|
34128
34193
|
}
|
|
34129
34194
|
module2.exports = function(fromModel) {
|
|
@@ -40053,7 +40118,7 @@ var require_iso2022 = __commonJS({
|
|
|
40053
40118
|
// node_modules/chardet/index.js
|
|
40054
40119
|
var require_chardet = __commonJS({
|
|
40055
40120
|
"node_modules/chardet/index.js"(exports2, module2) {
|
|
40056
|
-
var
|
|
40121
|
+
var fs52 = require("fs");
|
|
40057
40122
|
var utf8 = require_utf8();
|
|
40058
40123
|
var unicode = require_unicode();
|
|
40059
40124
|
var mbcs = require_mbcs();
|
|
@@ -40127,28 +40192,28 @@ var require_chardet = __commonJS({
|
|
|
40127
40192
|
var fd;
|
|
40128
40193
|
var handler = function(err, buffer) {
|
|
40129
40194
|
if (fd) {
|
|
40130
|
-
|
|
40195
|
+
fs52.closeSync(fd);
|
|
40131
40196
|
}
|
|
40132
40197
|
if (err) return cb(err, null);
|
|
40133
40198
|
cb(null, self.detect(buffer, opts));
|
|
40134
40199
|
};
|
|
40135
40200
|
if (opts && opts.sampleSize) {
|
|
40136
|
-
fd =
|
|
40137
|
-
|
|
40201
|
+
fd = fs52.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
|
|
40202
|
+
fs52.read(fd, sample, 0, opts.sampleSize, null, function(err) {
|
|
40138
40203
|
handler(err, sample);
|
|
40139
40204
|
});
|
|
40140
40205
|
return;
|
|
40141
40206
|
}
|
|
40142
|
-
|
|
40207
|
+
fs52.readFile(filepath, handler);
|
|
40143
40208
|
};
|
|
40144
40209
|
module2.exports.detectFileSync = function(filepath, opts) {
|
|
40145
40210
|
if (opts && opts.sampleSize) {
|
|
40146
|
-
var fd =
|
|
40147
|
-
|
|
40148
|
-
|
|
40211
|
+
var fd = fs52.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
|
|
40212
|
+
fs52.readSync(fd, sample2, 0, opts.sampleSize);
|
|
40213
|
+
fs52.closeSync(fd);
|
|
40149
40214
|
return self.detect(sample2, opts);
|
|
40150
40215
|
}
|
|
40151
|
-
return self.detect(
|
|
40216
|
+
return self.detect(fs52.readFileSync(filepath), opts);
|
|
40152
40217
|
};
|
|
40153
40218
|
module2.exports.detectAll = function(buffer, opts) {
|
|
40154
40219
|
if (typeof opts !== "object") {
|
|
@@ -43613,16 +43678,16 @@ var require_os_tmpdir = __commonJS({
|
|
|
43613
43678
|
var isWindows = process.platform === "win32";
|
|
43614
43679
|
var trailingSlashRe = isWindows ? /[^:]\\$/ : /.\/$/;
|
|
43615
43680
|
module2.exports = function() {
|
|
43616
|
-
var
|
|
43681
|
+
var path66;
|
|
43617
43682
|
if (isWindows) {
|
|
43618
|
-
|
|
43683
|
+
path66 = process.env.TEMP || process.env.TMP || (process.env.SystemRoot || process.env.windir) + "\\temp";
|
|
43619
43684
|
} else {
|
|
43620
|
-
|
|
43685
|
+
path66 = process.env.TMPDIR || process.env.TMP || process.env.TEMP || "/tmp";
|
|
43621
43686
|
}
|
|
43622
|
-
if (trailingSlashRe.test(
|
|
43623
|
-
|
|
43687
|
+
if (trailingSlashRe.test(path66)) {
|
|
43688
|
+
path66 = path66.slice(0, -1);
|
|
43624
43689
|
}
|
|
43625
|
-
return
|
|
43690
|
+
return path66;
|
|
43626
43691
|
};
|
|
43627
43692
|
}
|
|
43628
43693
|
});
|
|
@@ -43630,8 +43695,8 @@ var require_os_tmpdir = __commonJS({
|
|
|
43630
43695
|
// node_modules/tmp/lib/tmp.js
|
|
43631
43696
|
var require_tmp = __commonJS({
|
|
43632
43697
|
"node_modules/tmp/lib/tmp.js"(exports2, module2) {
|
|
43633
|
-
var
|
|
43634
|
-
var
|
|
43698
|
+
var fs52 = require("fs");
|
|
43699
|
+
var path66 = require("path");
|
|
43635
43700
|
var crypto6 = require("crypto");
|
|
43636
43701
|
var osTmpDir = require_os_tmpdir();
|
|
43637
43702
|
var _c2 = process.binding("constants");
|
|
@@ -43673,7 +43738,7 @@ var require_tmp = __commonJS({
|
|
|
43673
43738
|
}
|
|
43674
43739
|
function _generateTmpName(opts) {
|
|
43675
43740
|
if (opts.name) {
|
|
43676
|
-
return
|
|
43741
|
+
return path66.join(opts.dir || tmpDir, opts.name);
|
|
43677
43742
|
}
|
|
43678
43743
|
if (opts.template) {
|
|
43679
43744
|
return opts.template.replace(TEMPLATE_PATTERN, _randomChars(6));
|
|
@@ -43684,7 +43749,7 @@ var require_tmp = __commonJS({
|
|
|
43684
43749
|
_randomChars(12),
|
|
43685
43750
|
opts.postfix || ""
|
|
43686
43751
|
].join("");
|
|
43687
|
-
return
|
|
43752
|
+
return path66.join(opts.dir || tmpDir, name);
|
|
43688
43753
|
}
|
|
43689
43754
|
function tmpName(options, callback) {
|
|
43690
43755
|
var args = _parseArguments(options, callback), opts = args[0], cb = args[1], tries = opts.name ? 1 : opts.tries || DEFAULT_TRIES;
|
|
@@ -43694,7 +43759,7 @@ var require_tmp = __commonJS({
|
|
|
43694
43759
|
return cb(new Error("Invalid template provided"));
|
|
43695
43760
|
(function _getUniqueName() {
|
|
43696
43761
|
const name = _generateTmpName(opts);
|
|
43697
|
-
|
|
43762
|
+
fs52.stat(name, function(err) {
|
|
43698
43763
|
if (!err) {
|
|
43699
43764
|
if (tries-- > 0) return _getUniqueName();
|
|
43700
43765
|
return cb(new Error("Could not get a unique tmp filename, max tries reached " + name));
|
|
@@ -43712,7 +43777,7 @@ var require_tmp = __commonJS({
|
|
|
43712
43777
|
do {
|
|
43713
43778
|
const name = _generateTmpName(opts);
|
|
43714
43779
|
try {
|
|
43715
|
-
|
|
43780
|
+
fs52.statSync(name);
|
|
43716
43781
|
} catch (e) {
|
|
43717
43782
|
return name;
|
|
43718
43783
|
}
|
|
@@ -43724,13 +43789,13 @@ var require_tmp = __commonJS({
|
|
|
43724
43789
|
opts.postfix = _isUndefined(opts.postfix) ? ".tmp" : opts.postfix;
|
|
43725
43790
|
tmpName(opts, function _tmpNameCreated(err, name) {
|
|
43726
43791
|
if (err) return cb(err);
|
|
43727
|
-
|
|
43792
|
+
fs52.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
|
|
43728
43793
|
if (err2) return cb(err2);
|
|
43729
43794
|
if (opts.discardDescriptor) {
|
|
43730
|
-
return
|
|
43795
|
+
return fs52.close(fd, function _discardCallback(err3) {
|
|
43731
43796
|
if (err3) {
|
|
43732
43797
|
try {
|
|
43733
|
-
|
|
43798
|
+
fs52.unlinkSync(name);
|
|
43734
43799
|
} catch (e) {
|
|
43735
43800
|
if (!isENOENT(e)) {
|
|
43736
43801
|
err3 = e;
|
|
@@ -43753,9 +43818,9 @@ var require_tmp = __commonJS({
|
|
|
43753
43818
|
opts.postfix = opts.postfix || ".tmp";
|
|
43754
43819
|
const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
|
|
43755
43820
|
const name = tmpNameSync(opts);
|
|
43756
|
-
var fd =
|
|
43821
|
+
var fd = fs52.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
|
|
43757
43822
|
if (opts.discardDescriptor) {
|
|
43758
|
-
|
|
43823
|
+
fs52.closeSync(fd);
|
|
43759
43824
|
fd = void 0;
|
|
43760
43825
|
}
|
|
43761
43826
|
return {
|
|
@@ -43767,9 +43832,9 @@ var require_tmp = __commonJS({
|
|
|
43767
43832
|
function _rmdirRecursiveSync(root) {
|
|
43768
43833
|
const dirs = [root];
|
|
43769
43834
|
do {
|
|
43770
|
-
var dir2 = dirs.pop(), deferred = false, files =
|
|
43835
|
+
var dir2 = dirs.pop(), deferred = false, files = fs52.readdirSync(dir2);
|
|
43771
43836
|
for (var i = 0, length = files.length; i < length; i++) {
|
|
43772
|
-
var file2 =
|
|
43837
|
+
var file2 = path66.join(dir2, files[i]), stat = fs52.lstatSync(file2);
|
|
43773
43838
|
if (stat.isDirectory()) {
|
|
43774
43839
|
if (!deferred) {
|
|
43775
43840
|
deferred = true;
|
|
@@ -43777,11 +43842,11 @@ var require_tmp = __commonJS({
|
|
|
43777
43842
|
}
|
|
43778
43843
|
dirs.push(file2);
|
|
43779
43844
|
} else {
|
|
43780
|
-
|
|
43845
|
+
fs52.unlinkSync(file2);
|
|
43781
43846
|
}
|
|
43782
43847
|
}
|
|
43783
43848
|
if (!deferred) {
|
|
43784
|
-
|
|
43849
|
+
fs52.rmdirSync(dir2);
|
|
43785
43850
|
}
|
|
43786
43851
|
} while (dirs.length !== 0);
|
|
43787
43852
|
}
|
|
@@ -43789,7 +43854,7 @@ var require_tmp = __commonJS({
|
|
|
43789
43854
|
var args = _parseArguments(options, callback), opts = args[0], cb = args[1];
|
|
43790
43855
|
tmpName(opts, function _tmpNameCreated(err, name) {
|
|
43791
43856
|
if (err) return cb(err);
|
|
43792
|
-
|
|
43857
|
+
fs52.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
|
|
43793
43858
|
if (err2) return cb(err2);
|
|
43794
43859
|
cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
|
|
43795
43860
|
});
|
|
@@ -43798,7 +43863,7 @@ var require_tmp = __commonJS({
|
|
|
43798
43863
|
function dirSync(options) {
|
|
43799
43864
|
var args = _parseArguments(options), opts = args[0];
|
|
43800
43865
|
const name = tmpNameSync(opts);
|
|
43801
|
-
|
|
43866
|
+
fs52.mkdirSync(name, opts.mode || DIR_MODE);
|
|
43802
43867
|
return {
|
|
43803
43868
|
name,
|
|
43804
43869
|
removeCallback: _prepareTmpDirRemoveCallback(name, opts)
|
|
@@ -43808,7 +43873,7 @@ var require_tmp = __commonJS({
|
|
|
43808
43873
|
const removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
|
|
43809
43874
|
try {
|
|
43810
43875
|
if (0 <= fdPath[0]) {
|
|
43811
|
-
|
|
43876
|
+
fs52.closeSync(fdPath[0]);
|
|
43812
43877
|
}
|
|
43813
43878
|
} catch (e) {
|
|
43814
43879
|
if (!isEBADF(e) && !isENOENT(e)) {
|
|
@@ -43816,7 +43881,7 @@ var require_tmp = __commonJS({
|
|
|
43816
43881
|
}
|
|
43817
43882
|
}
|
|
43818
43883
|
try {
|
|
43819
|
-
|
|
43884
|
+
fs52.unlinkSync(fdPath[1]);
|
|
43820
43885
|
} catch (e) {
|
|
43821
43886
|
if (!isENOENT(e)) {
|
|
43822
43887
|
throw e;
|
|
@@ -43829,7 +43894,7 @@ var require_tmp = __commonJS({
|
|
|
43829
43894
|
return removeCallback;
|
|
43830
43895
|
}
|
|
43831
43896
|
function _prepareTmpDirRemoveCallback(name, opts) {
|
|
43832
|
-
const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync :
|
|
43897
|
+
const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs52.rmdirSync.bind(fs52);
|
|
43833
43898
|
const removeCallback = _prepareRemoveCallback(removeFunction, name);
|
|
43834
43899
|
if (!opts.keep) {
|
|
43835
43900
|
_removeObjects.unshift(removeCallback);
|
|
@@ -44980,7 +45045,7 @@ var require_Observable = __commonJS({
|
|
|
44980
45045
|
Observable2.prototype.forEach = function(next, promiseCtor) {
|
|
44981
45046
|
var _this = this;
|
|
44982
45047
|
promiseCtor = getPromiseCtor(promiseCtor);
|
|
44983
|
-
return new promiseCtor(function(
|
|
45048
|
+
return new promiseCtor(function(resolve50, reject) {
|
|
44984
45049
|
var subscriber = new Subscriber_1.SafeSubscriber({
|
|
44985
45050
|
next: function(value) {
|
|
44986
45051
|
try {
|
|
@@ -44991,7 +45056,7 @@ var require_Observable = __commonJS({
|
|
|
44991
45056
|
}
|
|
44992
45057
|
},
|
|
44993
45058
|
error: reject,
|
|
44994
|
-
complete:
|
|
45059
|
+
complete: resolve50
|
|
44995
45060
|
});
|
|
44996
45061
|
_this.subscribe(subscriber);
|
|
44997
45062
|
});
|
|
@@ -45013,14 +45078,14 @@ var require_Observable = __commonJS({
|
|
|
45013
45078
|
Observable2.prototype.toPromise = function(promiseCtor) {
|
|
45014
45079
|
var _this = this;
|
|
45015
45080
|
promiseCtor = getPromiseCtor(promiseCtor);
|
|
45016
|
-
return new promiseCtor(function(
|
|
45081
|
+
return new promiseCtor(function(resolve50, reject) {
|
|
45017
45082
|
var value;
|
|
45018
45083
|
_this.subscribe(function(x) {
|
|
45019
45084
|
return value = x;
|
|
45020
45085
|
}, function(err) {
|
|
45021
45086
|
return reject(err);
|
|
45022
45087
|
}, function() {
|
|
45023
|
-
return
|
|
45088
|
+
return resolve50(value);
|
|
45024
45089
|
});
|
|
45025
45090
|
});
|
|
45026
45091
|
};
|
|
@@ -47116,11 +47181,11 @@ var require_innerFrom = __commonJS({
|
|
|
47116
47181
|
"use strict";
|
|
47117
47182
|
var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P2, generator) {
|
|
47118
47183
|
function adopt(value) {
|
|
47119
|
-
return value instanceof P2 ? value : new P2(function(
|
|
47120
|
-
|
|
47184
|
+
return value instanceof P2 ? value : new P2(function(resolve50) {
|
|
47185
|
+
resolve50(value);
|
|
47121
47186
|
});
|
|
47122
47187
|
}
|
|
47123
|
-
return new (P2 || (P2 = Promise))(function(
|
|
47188
|
+
return new (P2 || (P2 = Promise))(function(resolve50, reject) {
|
|
47124
47189
|
function fulfilled(value) {
|
|
47125
47190
|
try {
|
|
47126
47191
|
step(generator.next(value));
|
|
@@ -47136,7 +47201,7 @@ var require_innerFrom = __commonJS({
|
|
|
47136
47201
|
}
|
|
47137
47202
|
}
|
|
47138
47203
|
function step(result) {
|
|
47139
|
-
result.done ?
|
|
47204
|
+
result.done ? resolve50(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
47140
47205
|
}
|
|
47141
47206
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
47142
47207
|
});
|
|
@@ -47218,14 +47283,14 @@ var require_innerFrom = __commonJS({
|
|
|
47218
47283
|
}, i);
|
|
47219
47284
|
function verb(n) {
|
|
47220
47285
|
i[n] = o[n] && function(v2) {
|
|
47221
|
-
return new Promise(function(
|
|
47222
|
-
v2 = o[n](v2), settle(
|
|
47286
|
+
return new Promise(function(resolve50, reject) {
|
|
47287
|
+
v2 = o[n](v2), settle(resolve50, reject, v2.done, v2.value);
|
|
47223
47288
|
});
|
|
47224
47289
|
};
|
|
47225
47290
|
}
|
|
47226
|
-
function settle(
|
|
47291
|
+
function settle(resolve50, reject, d, v2) {
|
|
47227
47292
|
Promise.resolve(v2).then(function(v3) {
|
|
47228
|
-
|
|
47293
|
+
resolve50({ value: v3, done: d });
|
|
47229
47294
|
}, reject);
|
|
47230
47295
|
}
|
|
47231
47296
|
};
|
|
@@ -47844,7 +47909,7 @@ var require_lastValueFrom = __commonJS({
|
|
|
47844
47909
|
var EmptyError_1 = require_EmptyError();
|
|
47845
47910
|
function lastValueFrom2(source, config2) {
|
|
47846
47911
|
var hasConfig = typeof config2 === "object";
|
|
47847
|
-
return new Promise(function(
|
|
47912
|
+
return new Promise(function(resolve50, reject) {
|
|
47848
47913
|
var _hasValue = false;
|
|
47849
47914
|
var _value;
|
|
47850
47915
|
source.subscribe({
|
|
@@ -47855,9 +47920,9 @@ var require_lastValueFrom = __commonJS({
|
|
|
47855
47920
|
error: reject,
|
|
47856
47921
|
complete: function() {
|
|
47857
47922
|
if (_hasValue) {
|
|
47858
|
-
|
|
47923
|
+
resolve50(_value);
|
|
47859
47924
|
} else if (hasConfig) {
|
|
47860
|
-
|
|
47925
|
+
resolve50(config2.defaultValue);
|
|
47861
47926
|
} else {
|
|
47862
47927
|
reject(new EmptyError_1.EmptyError());
|
|
47863
47928
|
}
|
|
@@ -47879,16 +47944,16 @@ var require_firstValueFrom = __commonJS({
|
|
|
47879
47944
|
var Subscriber_1 = require_Subscriber();
|
|
47880
47945
|
function firstValueFrom(source, config2) {
|
|
47881
47946
|
var hasConfig = typeof config2 === "object";
|
|
47882
|
-
return new Promise(function(
|
|
47947
|
+
return new Promise(function(resolve50, reject) {
|
|
47883
47948
|
var subscriber = new Subscriber_1.SafeSubscriber({
|
|
47884
47949
|
next: function(value) {
|
|
47885
|
-
|
|
47950
|
+
resolve50(value);
|
|
47886
47951
|
subscriber.unsubscribe();
|
|
47887
47952
|
},
|
|
47888
47953
|
error: reject,
|
|
47889
47954
|
complete: function() {
|
|
47890
47955
|
if (hasConfig) {
|
|
47891
|
-
|
|
47956
|
+
resolve50(config2.defaultValue);
|
|
47892
47957
|
} else {
|
|
47893
47958
|
reject(new EmptyError_1.EmptyError());
|
|
47894
47959
|
}
|
|
@@ -53681,14 +53746,14 @@ var require_run_async = __commonJS({
|
|
|
53681
53746
|
return function() {
|
|
53682
53747
|
var args = arguments;
|
|
53683
53748
|
var originalThis = this;
|
|
53684
|
-
var promise = new Promise(function(
|
|
53749
|
+
var promise = new Promise(function(resolve50, reject) {
|
|
53685
53750
|
var resolved = false;
|
|
53686
53751
|
const wrappedResolve = function(value) {
|
|
53687
53752
|
if (resolved) {
|
|
53688
53753
|
console.warn("Run-async promise already resolved.");
|
|
53689
53754
|
}
|
|
53690
53755
|
resolved = true;
|
|
53691
|
-
|
|
53756
|
+
resolve50(value);
|
|
53692
53757
|
};
|
|
53693
53758
|
var rejected = false;
|
|
53694
53759
|
const wrappedReject = function(value) {
|
|
@@ -53788,32 +53853,32 @@ __export(otel_hooks_exports, {
|
|
|
53788
53853
|
});
|
|
53789
53854
|
function getOtelHooksHome() {
|
|
53790
53855
|
if (process.env.HAR_OTEL_HOOKS_HOME) {
|
|
53791
|
-
return
|
|
53856
|
+
return path51.resolve(process.env.HAR_OTEL_HOOKS_HOME);
|
|
53792
53857
|
}
|
|
53793
|
-
return
|
|
53858
|
+
return path51.join(os17.homedir(), ".har", "otel-hooks");
|
|
53794
53859
|
}
|
|
53795
53860
|
function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
|
|
53796
|
-
return
|
|
53861
|
+
return path51.join(hooksHome, "otel_config.json");
|
|
53797
53862
|
}
|
|
53798
53863
|
function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
|
|
53799
|
-
return
|
|
53864
|
+
return path51.join(hooksHome, "run-otel-hook.sh");
|
|
53800
53865
|
}
|
|
53801
53866
|
function getOtelHooksStateDir(hooksHome = getOtelHooksHome()) {
|
|
53802
|
-
return
|
|
53867
|
+
return path51.join(hooksHome, "state");
|
|
53803
53868
|
}
|
|
53804
53869
|
function localOtelHookBin(hooksHome) {
|
|
53805
|
-
return
|
|
53870
|
+
return path51.join(hooksHome, "node_modules", ".bin", "otel-hook");
|
|
53806
53871
|
}
|
|
53807
53872
|
function installedPackageVersion(hooksHome) {
|
|
53808
53873
|
try {
|
|
53809
|
-
const pkgPath =
|
|
53874
|
+
const pkgPath = path51.join(
|
|
53810
53875
|
hooksHome,
|
|
53811
53876
|
"node_modules",
|
|
53812
53877
|
"@osfactory",
|
|
53813
53878
|
"otel-hook",
|
|
53814
53879
|
"package.json"
|
|
53815
53880
|
);
|
|
53816
|
-
const pkg = JSON.parse(
|
|
53881
|
+
const pkg = JSON.parse(fs45.readFileSync(pkgPath, "utf8"));
|
|
53817
53882
|
return typeof pkg.version === "string" ? pkg.version : null;
|
|
53818
53883
|
} catch {
|
|
53819
53884
|
return null;
|
|
@@ -53864,15 +53929,15 @@ function buildOtelHooksConfig(options) {
|
|
|
53864
53929
|
};
|
|
53865
53930
|
}
|
|
53866
53931
|
function writeOtelHooksConfig(config2, hooksHome = getOtelHooksHome()) {
|
|
53867
|
-
|
|
53932
|
+
fs45.mkdirSync(hooksHome, { recursive: true });
|
|
53868
53933
|
const configPath = getOtelHooksConfigPath(hooksHome);
|
|
53869
|
-
|
|
53934
|
+
fs45.writeFileSync(configPath, `${JSON.stringify(config2, null, 2)}
|
|
53870
53935
|
`);
|
|
53871
53936
|
return configPath;
|
|
53872
53937
|
}
|
|
53873
53938
|
function writeOtelHooksWrapper(otelHookCommand, hooksHome = getOtelHooksHome()) {
|
|
53874
|
-
|
|
53875
|
-
|
|
53939
|
+
fs45.mkdirSync(hooksHome, { recursive: true });
|
|
53940
|
+
fs45.mkdirSync(getOtelHooksStateDir(hooksHome), { recursive: true });
|
|
53876
53941
|
const wrapperPath = getOtelHooksWrapperPath(hooksHome);
|
|
53877
53942
|
const configPath = getOtelHooksConfigPath(hooksHome);
|
|
53878
53943
|
const stateDir = getOtelHooksStateDir(hooksHome);
|
|
@@ -53884,22 +53949,22 @@ exec "${otelHookCommand}" run \\
|
|
|
53884
53949
|
--state-dir "${stateDir}" \\
|
|
53885
53950
|
"$@"
|
|
53886
53951
|
`;
|
|
53887
|
-
|
|
53952
|
+
fs45.writeFileSync(wrapperPath, script, { mode: 493 });
|
|
53888
53953
|
try {
|
|
53889
|
-
|
|
53954
|
+
fs45.chmodSync(wrapperPath, 493);
|
|
53890
53955
|
} catch {
|
|
53891
53956
|
}
|
|
53892
53957
|
return wrapperPath;
|
|
53893
53958
|
}
|
|
53894
53959
|
function commandExists3(command2) {
|
|
53895
|
-
const result = (0,
|
|
53960
|
+
const result = (0, import_child_process13.spawnSync)("sh", ["-c", `command -v ${JSON.stringify(command2)}`], {
|
|
53896
53961
|
encoding: "utf8"
|
|
53897
53962
|
});
|
|
53898
53963
|
return result.status === 0 && Boolean(result.stdout?.trim());
|
|
53899
53964
|
}
|
|
53900
53965
|
function resolveOtelHookCommand(hooksHome) {
|
|
53901
53966
|
const local = localOtelHookBin(hooksHome);
|
|
53902
|
-
if (
|
|
53967
|
+
if (fs45.existsSync(local)) return local;
|
|
53903
53968
|
return null;
|
|
53904
53969
|
}
|
|
53905
53970
|
function resolveHooksInstaller(hooksHome) {
|
|
@@ -53914,7 +53979,7 @@ function resolveHooksInstaller(hooksHome) {
|
|
|
53914
53979
|
return candidates.find((candidate) => commandExists3(candidate.command)) ?? null;
|
|
53915
53980
|
}
|
|
53916
53981
|
function tryInstallPackage(hooksHome) {
|
|
53917
|
-
|
|
53982
|
+
fs45.mkdirSync(hooksHome, { recursive: true });
|
|
53918
53983
|
const installer = resolveHooksInstaller(hooksHome);
|
|
53919
53984
|
if (!installer) {
|
|
53920
53985
|
return {
|
|
@@ -53923,11 +53988,11 @@ function tryInstallPackage(hooksHome) {
|
|
|
53923
53988
|
};
|
|
53924
53989
|
}
|
|
53925
53990
|
const described = `${installer.command} ${installer.args.join(" ")}`;
|
|
53926
|
-
const result = (0,
|
|
53991
|
+
const result = (0, import_child_process13.spawnSync)(installer.command, installer.args, {
|
|
53927
53992
|
encoding: "utf8",
|
|
53928
53993
|
timeout: 18e4
|
|
53929
53994
|
});
|
|
53930
|
-
if (result.status === 0 &&
|
|
53995
|
+
if (result.status === 0 && fs45.existsSync(localOtelHookBin(hooksHome))) {
|
|
53931
53996
|
return { ok: true, detail: described };
|
|
53932
53997
|
}
|
|
53933
53998
|
return {
|
|
@@ -53945,7 +54010,7 @@ function uninstallLegacyPythonHooks(hooksHome) {
|
|
|
53945
54010
|
for (const [cmd, args] of attempts) {
|
|
53946
54011
|
if (!commandExists3(cmd)) continue;
|
|
53947
54012
|
try {
|
|
53948
|
-
(0,
|
|
54013
|
+
(0, import_child_process13.spawnSync)(cmd, args, { encoding: "utf8", timeout: 6e4 });
|
|
53949
54014
|
} catch {
|
|
53950
54015
|
}
|
|
53951
54016
|
}
|
|
@@ -53953,14 +54018,14 @@ function uninstallLegacyPythonHooks(hooksHome) {
|
|
|
53953
54018
|
}
|
|
53954
54019
|
function removeLegacyPythonArtifacts(hooksHome) {
|
|
53955
54020
|
const legacyPaths = [
|
|
53956
|
-
|
|
53957
|
-
|
|
53958
|
-
|
|
54021
|
+
path51.join(hooksHome, ".venv"),
|
|
54022
|
+
path51.join(hooksHome, "otel_config.yaml"),
|
|
54023
|
+
path51.join(hooksHome, "venv")
|
|
53959
54024
|
];
|
|
53960
54025
|
for (const target of legacyPaths) {
|
|
53961
54026
|
try {
|
|
53962
|
-
if (
|
|
53963
|
-
|
|
54027
|
+
if (fs45.existsSync(target)) {
|
|
54028
|
+
fs45.rmSync(target, { recursive: true, force: true });
|
|
53964
54029
|
}
|
|
53965
54030
|
} catch {
|
|
53966
54031
|
}
|
|
@@ -53977,7 +54042,7 @@ function normalizeLegacyProviderFlagsInCommand(command2) {
|
|
|
53977
54042
|
}
|
|
53978
54043
|
function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
|
|
53979
54044
|
const hookCommand = `${wrapperPath} --provider ${providerId}`;
|
|
53980
|
-
const result = (0,
|
|
54045
|
+
const result = (0, import_child_process13.spawnSync)(
|
|
53981
54046
|
otelHookCommand,
|
|
53982
54047
|
[
|
|
53983
54048
|
"setup",
|
|
@@ -54001,10 +54066,10 @@ function runSetupProvider(providerId, otelHookCommand, wrapperPath) {
|
|
|
54001
54066
|
};
|
|
54002
54067
|
}
|
|
54003
54068
|
function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
|
|
54004
|
-
if (!
|
|
54069
|
+
if (!fs45.existsSync(filePath)) return false;
|
|
54005
54070
|
let raw;
|
|
54006
54071
|
try {
|
|
54007
|
-
raw =
|
|
54072
|
+
raw = fs45.readFileSync(filePath, "utf8");
|
|
54008
54073
|
} catch {
|
|
54009
54074
|
return false;
|
|
54010
54075
|
}
|
|
@@ -54051,15 +54116,15 @@ function rewriteHookCommandsToWrapper(filePath, wrapperPath) {
|
|
|
54051
54116
|
return changed;
|
|
54052
54117
|
};
|
|
54053
54118
|
if (!walk(parsed)) return false;
|
|
54054
|
-
|
|
54119
|
+
fs45.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
54055
54120
|
`);
|
|
54056
54121
|
return true;
|
|
54057
54122
|
}
|
|
54058
54123
|
function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
54059
|
-
if (!
|
|
54124
|
+
if (!fs45.existsSync(filePath)) return false;
|
|
54060
54125
|
let raw;
|
|
54061
54126
|
try {
|
|
54062
|
-
raw =
|
|
54127
|
+
raw = fs45.readFileSync(filePath, "utf8");
|
|
54063
54128
|
} catch {
|
|
54064
54129
|
return false;
|
|
54065
54130
|
}
|
|
@@ -54094,21 +54159,21 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
|
54094
54159
|
}
|
|
54095
54160
|
}
|
|
54096
54161
|
if (!changed) return false;
|
|
54097
|
-
|
|
54162
|
+
fs45.writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}
|
|
54098
54163
|
`);
|
|
54099
54164
|
return true;
|
|
54100
54165
|
}
|
|
54101
54166
|
function rewriteKnownHookRegistrations(wrapperPath) {
|
|
54102
|
-
const home =
|
|
54167
|
+
const home = os17.homedir();
|
|
54103
54168
|
const candidates = [
|
|
54104
|
-
|
|
54105
|
-
|
|
54106
|
-
|
|
54169
|
+
path51.join(home, ".cursor", "hooks.json"),
|
|
54170
|
+
path51.join(home, ".claude", "settings.json"),
|
|
54171
|
+
path51.join(home, ".codex", "hooks.json")
|
|
54107
54172
|
];
|
|
54108
54173
|
for (const filePath of candidates) {
|
|
54109
54174
|
try {
|
|
54110
54175
|
rewriteHookCommandsToWrapper(filePath, wrapperPath);
|
|
54111
|
-
if (filePath.endsWith(`${
|
|
54176
|
+
if (filePath.endsWith(`${path51.sep}.cursor${path51.sep}hooks.json`)) {
|
|
54112
54177
|
pruneLegacyCursorHookEvents(filePath, wrapperPath);
|
|
54113
54178
|
}
|
|
54114
54179
|
} catch {
|
|
@@ -54124,7 +54189,7 @@ function ensureOtelHooks(options) {
|
|
|
54124
54189
|
const hooksHome = getOtelHooksHome();
|
|
54125
54190
|
const errors = [];
|
|
54126
54191
|
const providersSetup = [];
|
|
54127
|
-
|
|
54192
|
+
fs45.mkdirSync(hooksHome, { recursive: true });
|
|
54128
54193
|
let otelHookCommand = resolveOtelHookCommand(hooksHome);
|
|
54129
54194
|
const needsInstall = !otelHookCommand || installedPackageVersion(hooksHome) !== pinnedVersion();
|
|
54130
54195
|
if (needsInstall) {
|
|
@@ -54218,14 +54283,14 @@ function ensureOtelHooks(options) {
|
|
|
54218
54283
|
function disableOtelHooksExport() {
|
|
54219
54284
|
return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
|
|
54220
54285
|
}
|
|
54221
|
-
var
|
|
54286
|
+
var import_child_process13, fs45, os17, path51, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
|
|
54222
54287
|
var init_otel_hooks = __esm({
|
|
54223
54288
|
"src/core/otel-hooks.ts"() {
|
|
54224
54289
|
"use strict";
|
|
54225
|
-
|
|
54226
|
-
|
|
54227
|
-
|
|
54228
|
-
|
|
54290
|
+
import_child_process13 = require("child_process");
|
|
54291
|
+
fs45 = __toESM(require("fs"));
|
|
54292
|
+
os17 = __toESM(require("os"));
|
|
54293
|
+
path51 = __toESM(require("path"));
|
|
54229
54294
|
init_control_config();
|
|
54230
54295
|
init_telemetry_config();
|
|
54231
54296
|
OTEL_HOOKS_PACKAGE = "@osfactory/otel-hook@0.2.0";
|
|
@@ -57200,7 +57265,7 @@ var require_compile = __commonJS({
|
|
|
57200
57265
|
const schOrFunc = root.refs[ref];
|
|
57201
57266
|
if (schOrFunc)
|
|
57202
57267
|
return schOrFunc;
|
|
57203
|
-
let _sch =
|
|
57268
|
+
let _sch = resolve50.call(this, root, ref);
|
|
57204
57269
|
if (_sch === void 0) {
|
|
57205
57270
|
const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
|
|
57206
57271
|
const { schemaId } = this.opts;
|
|
@@ -57227,7 +57292,7 @@ var require_compile = __commonJS({
|
|
|
57227
57292
|
function sameSchemaEnv(s1, s2) {
|
|
57228
57293
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
57229
57294
|
}
|
|
57230
|
-
function
|
|
57295
|
+
function resolve50(root, ref) {
|
|
57231
57296
|
let sch;
|
|
57232
57297
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
57233
57298
|
ref = sch;
|
|
@@ -57445,8 +57510,8 @@ var require_utils = __commonJS({
|
|
|
57445
57510
|
}
|
|
57446
57511
|
return ind;
|
|
57447
57512
|
}
|
|
57448
|
-
function removeDotSegments(
|
|
57449
|
-
let input =
|
|
57513
|
+
function removeDotSegments(path66) {
|
|
57514
|
+
let input = path66;
|
|
57450
57515
|
const output = [];
|
|
57451
57516
|
let nextSlash = -1;
|
|
57452
57517
|
let len = 0;
|
|
@@ -57698,8 +57763,8 @@ var require_schemes = __commonJS({
|
|
|
57698
57763
|
wsComponent.secure = void 0;
|
|
57699
57764
|
}
|
|
57700
57765
|
if (wsComponent.resourceName) {
|
|
57701
|
-
const [
|
|
57702
|
-
wsComponent.path =
|
|
57766
|
+
const [path66, query] = wsComponent.resourceName.split("?");
|
|
57767
|
+
wsComponent.path = path66 && path66 !== "/" ? path66 : void 0;
|
|
57703
57768
|
wsComponent.query = query;
|
|
57704
57769
|
wsComponent.resourceName = void 0;
|
|
57705
57770
|
}
|
|
@@ -57858,7 +57923,7 @@ var require_fast_uri = __commonJS({
|
|
|
57858
57923
|
}
|
|
57859
57924
|
return uri;
|
|
57860
57925
|
}
|
|
57861
|
-
function
|
|
57926
|
+
function resolve50(baseURI, relativeURI, options) {
|
|
57862
57927
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
57863
57928
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
57864
57929
|
schemelessOptions.skipEscape = true;
|
|
@@ -58116,7 +58181,7 @@ var require_fast_uri = __commonJS({
|
|
|
58116
58181
|
var fastUri = {
|
|
58117
58182
|
SCHEMES,
|
|
58118
58183
|
normalize: normalize3,
|
|
58119
|
-
resolve:
|
|
58184
|
+
resolve: resolve50,
|
|
58120
58185
|
resolveComponent,
|
|
58121
58186
|
equal,
|
|
58122
58187
|
serialize,
|
|
@@ -61092,12 +61157,12 @@ var require_dist = __commonJS({
|
|
|
61092
61157
|
throw new Error(`Unknown format "${name}"`);
|
|
61093
61158
|
return f;
|
|
61094
61159
|
};
|
|
61095
|
-
function addFormats(ajv, list,
|
|
61160
|
+
function addFormats(ajv, list, fs52, exportName) {
|
|
61096
61161
|
var _a2;
|
|
61097
61162
|
var _b2;
|
|
61098
61163
|
(_a2 = (_b2 = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
61099
61164
|
for (const f of list)
|
|
61100
|
-
ajv.addFormat(f,
|
|
61165
|
+
ajv.addFormat(f, fs52[f]);
|
|
61101
61166
|
}
|
|
61102
61167
|
module2.exports = exports2 = formatsPlugin;
|
|
61103
61168
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -62381,11 +62446,11 @@ var parser = new YargsParser({
|
|
|
62381
62446
|
resolve: import_path2.resolve,
|
|
62382
62447
|
// TODO: figure out a way to combine ESM and CJS coverage, such that
|
|
62383
62448
|
// we can exercise all the lines below:
|
|
62384
|
-
require: (
|
|
62449
|
+
require: (path66) => {
|
|
62385
62450
|
if (typeof require !== "undefined") {
|
|
62386
|
-
return require(
|
|
62387
|
-
} else if (
|
|
62388
|
-
return JSON.parse((0, import_fs2.readFileSync)(
|
|
62451
|
+
return require(path66);
|
|
62452
|
+
} else if (path66.match(/\.json$/)) {
|
|
62453
|
+
return JSON.parse((0, import_fs2.readFileSync)(path66, "utf8"));
|
|
62389
62454
|
} else {
|
|
62390
62455
|
throw Error("only .json config files are supported in ESM");
|
|
62391
62456
|
}
|
|
@@ -64911,12 +64976,12 @@ var YargsInstance = class {
|
|
|
64911
64976
|
async getCompletion(args, done) {
|
|
64912
64977
|
argsert("<array> [function]", [args, done], arguments.length);
|
|
64913
64978
|
if (!done) {
|
|
64914
|
-
return new Promise((
|
|
64979
|
+
return new Promise((resolve50, reject) => {
|
|
64915
64980
|
__classPrivateFieldGet(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
|
|
64916
64981
|
if (err)
|
|
64917
64982
|
reject(err);
|
|
64918
64983
|
else
|
|
64919
|
-
|
|
64984
|
+
resolve50(completions);
|
|
64920
64985
|
});
|
|
64921
64986
|
});
|
|
64922
64987
|
} else {
|
|
@@ -66205,16 +66270,16 @@ async function handleAgentSkills(options) {
|
|
|
66205
66270
|
}
|
|
66206
66271
|
async function askYesNo(question) {
|
|
66207
66272
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
66208
|
-
return new Promise((
|
|
66273
|
+
return new Promise((resolve50) => {
|
|
66209
66274
|
process.stderr.write(`${question} `);
|
|
66210
66275
|
rl.once("line", (answer) => {
|
|
66211
66276
|
rl.close();
|
|
66212
66277
|
const trimmed = answer.trim();
|
|
66213
66278
|
if (trimmed === "") {
|
|
66214
|
-
|
|
66279
|
+
resolve50(true);
|
|
66215
66280
|
return;
|
|
66216
66281
|
}
|
|
66217
|
-
|
|
66282
|
+
resolve50(/^y(es)?$/i.test(trimmed));
|
|
66218
66283
|
});
|
|
66219
66284
|
});
|
|
66220
66285
|
}
|
|
@@ -66294,7 +66359,7 @@ function handleRemove(argv) {
|
|
|
66294
66359
|
}
|
|
66295
66360
|
|
|
66296
66361
|
// src/cli/commands/env.ts
|
|
66297
|
-
var
|
|
66362
|
+
var path55 = __toESM(require("path"));
|
|
66298
66363
|
|
|
66299
66364
|
// src/cli/finish-command.ts
|
|
66300
66365
|
init_sync_context();
|
|
@@ -66304,12 +66369,12 @@ async function finishCommand(code) {
|
|
|
66304
66369
|
}
|
|
66305
66370
|
|
|
66306
66371
|
// src/core/harness.ts
|
|
66307
|
-
var
|
|
66308
|
-
var
|
|
66372
|
+
var fs41 = __toESM(require("fs"));
|
|
66373
|
+
var path46 = __toESM(require("path"));
|
|
66309
66374
|
|
|
66310
66375
|
// src/harness/generator.ts
|
|
66311
|
-
var
|
|
66312
|
-
var
|
|
66376
|
+
var fs31 = __toESM(require("fs"));
|
|
66377
|
+
var path37 = __toESM(require("path"));
|
|
66313
66378
|
init_file_ops();
|
|
66314
66379
|
init_logging();
|
|
66315
66380
|
|
|
@@ -66363,12 +66428,163 @@ function isExpectedHarnessOnlyFile(harnessFile, templateFiles) {
|
|
|
66363
66428
|
|
|
66364
66429
|
// src/harness/generator.ts
|
|
66365
66430
|
init_manifest();
|
|
66366
|
-
|
|
66431
|
+
|
|
66432
|
+
// src/harness/plugin-ledger.ts
|
|
66433
|
+
var fs29 = __toESM(require("fs"));
|
|
66434
|
+
var path35 = __toESM(require("path"));
|
|
66435
|
+
init_zod();
|
|
66436
|
+
init_file_ops();
|
|
66437
|
+
init_manifest();
|
|
66438
|
+
var PluginLedgerEntrySchema = external_exports.object({
|
|
66439
|
+
id: external_exports.string().min(1),
|
|
66440
|
+
source: external_exports.enum(["bundled", "path", "npm", "git"]),
|
|
66441
|
+
/** Original install spec (id, path, package, or git URL). */
|
|
66442
|
+
spec: external_exports.string().min(1),
|
|
66443
|
+
/** Package/plugin version when known. */
|
|
66444
|
+
version: external_exports.string().optional(),
|
|
66445
|
+
stageIds: external_exports.array(external_exports.string().min(1)).min(1),
|
|
66446
|
+
installedAt: external_exports.string()
|
|
66447
|
+
});
|
|
66448
|
+
var PluginLedgerSchema = external_exports.object({
|
|
66449
|
+
version: external_exports.literal("1"),
|
|
66450
|
+
/** Profile used at init, when known. */
|
|
66451
|
+
profile: external_exports.enum(["default", "cli", "ios"]).optional(),
|
|
66452
|
+
/** Ordered runtime bundles that composed the harness scaffold. */
|
|
66453
|
+
bundles: external_exports.array(external_exports.string().min(1)).optional(),
|
|
66454
|
+
plugins: external_exports.array(PluginLedgerEntrySchema).default([])
|
|
66455
|
+
});
|
|
66456
|
+
function getPluginLedgerPath(repoPath) {
|
|
66457
|
+
return path35.join(path35.resolve(repoPath), DEFAULT_HAR_DIR, "plugins.json");
|
|
66458
|
+
}
|
|
66459
|
+
function readPluginLedger(repoPath) {
|
|
66460
|
+
const ledgerPath = getPluginLedgerPath(repoPath);
|
|
66461
|
+
if (!fs29.existsSync(ledgerPath)) return null;
|
|
66462
|
+
try {
|
|
66463
|
+
const raw = JSON.parse(fs29.readFileSync(ledgerPath, "utf8"));
|
|
66464
|
+
const parsed = PluginLedgerSchema.safeParse(raw);
|
|
66465
|
+
return parsed.success ? parsed.data : null;
|
|
66466
|
+
} catch {
|
|
66467
|
+
return null;
|
|
66468
|
+
}
|
|
66469
|
+
}
|
|
66470
|
+
function writePluginLedger(repoPath, ledger) {
|
|
66471
|
+
const ledgerPath = getPluginLedgerPath(repoPath);
|
|
66472
|
+
const harnessDir = path35.dirname(ledgerPath);
|
|
66473
|
+
if (!fs29.existsSync(harnessDir)) {
|
|
66474
|
+
fs29.mkdirSync(harnessDir, { recursive: true });
|
|
66475
|
+
}
|
|
66476
|
+
writeFileSafe(ledgerPath, `${JSON.stringify(ledger, null, 2)}
|
|
66477
|
+
`);
|
|
66478
|
+
}
|
|
66479
|
+
function upsertPluginLedgerEntry(repoPath, entry, extras) {
|
|
66480
|
+
const existing = readPluginLedger(repoPath) ?? {
|
|
66481
|
+
version: "1",
|
|
66482
|
+
plugins: []
|
|
66483
|
+
};
|
|
66484
|
+
const plugins = existing.plugins.filter((p) => p.id !== entry.id);
|
|
66485
|
+
plugins.push(entry);
|
|
66486
|
+
plugins.sort((a, b2) => a.id.localeCompare(b2.id));
|
|
66487
|
+
const ledger = {
|
|
66488
|
+
version: "1",
|
|
66489
|
+
profile: extras?.profile ?? existing.profile,
|
|
66490
|
+
bundles: extras?.bundles ?? existing.bundles,
|
|
66491
|
+
plugins
|
|
66492
|
+
};
|
|
66493
|
+
writePluginLedger(repoPath, ledger);
|
|
66494
|
+
return ledger;
|
|
66495
|
+
}
|
|
66496
|
+
function ensurePluginLedgerScaffold(repoPath, options) {
|
|
66497
|
+
const existing = readPluginLedger(repoPath);
|
|
66498
|
+
const ledger = {
|
|
66499
|
+
version: "1",
|
|
66500
|
+
profile: options.profile ?? existing?.profile,
|
|
66501
|
+
bundles: options.bundles ?? existing?.bundles,
|
|
66502
|
+
plugins: existing?.plugins ?? []
|
|
66503
|
+
};
|
|
66504
|
+
writePluginLedger(repoPath, ledger);
|
|
66505
|
+
return ledger;
|
|
66506
|
+
}
|
|
66507
|
+
|
|
66508
|
+
// src/harness/profiles.ts
|
|
66509
|
+
var fs30 = __toESM(require("fs"));
|
|
66510
|
+
var path36 = __toESM(require("path"));
|
|
66511
|
+
init_zod();
|
|
66512
|
+
var HARNESS_PROFILES = ["default", "cli", "ios"];
|
|
66513
|
+
var ProfileBundleRefSchema = external_exports.object({
|
|
66514
|
+
/** Stable bundle id recorded in .har/plugins.json */
|
|
66515
|
+
id: external_exports.string().min(1),
|
|
66516
|
+
/**
|
|
66517
|
+
* Directory under src/templates/ (e.g. "runtime-bundles/shared-kernel"
|
|
66518
|
+
* or "har-boilerplate").
|
|
66519
|
+
*/
|
|
66520
|
+
path: external_exports.string().min(1)
|
|
66521
|
+
});
|
|
66522
|
+
var ProfileManifestSchema = external_exports.object({
|
|
66523
|
+
id: external_exports.enum(HARNESS_PROFILES),
|
|
66524
|
+
description: external_exports.string().min(1),
|
|
66525
|
+
/** Ordered runtime bundles — later bundles overwrite earlier files on conflict. */
|
|
66526
|
+
bundles: external_exports.array(ProfileBundleRefSchema).min(1)
|
|
66527
|
+
});
|
|
66528
|
+
var PROFILE_COMPOSITIONS = {
|
|
66529
|
+
default: {
|
|
66530
|
+
id: "default",
|
|
66531
|
+
description: "Web app \u2014 shared kernel + PM2 runtime + Docker infra",
|
|
66532
|
+
bundles: [
|
|
66533
|
+
{ id: "shared-kernel", path: "runtime-bundles/shared-kernel" },
|
|
66534
|
+
{ id: "pm2-runtime", path: "runtime-bundles/pm2-runtime" },
|
|
66535
|
+
{ id: "runtime-default", path: "har-boilerplate" }
|
|
66536
|
+
]
|
|
66537
|
+
},
|
|
66538
|
+
cli: {
|
|
66539
|
+
id: "cli",
|
|
66540
|
+
description: "CLI/library \u2014 shared kernel + CLI overlay (no PM2)",
|
|
66541
|
+
bundles: [
|
|
66542
|
+
{ id: "shared-kernel", path: "runtime-bundles/shared-kernel" },
|
|
66543
|
+
{ id: "runtime-cli", path: "har-boilerplate-cli" }
|
|
66544
|
+
]
|
|
66545
|
+
},
|
|
66546
|
+
ios: {
|
|
66547
|
+
id: "ios",
|
|
66548
|
+
description: "iOS \u2014 shared kernel + Xcode/Simulator overlay",
|
|
66549
|
+
bundles: [
|
|
66550
|
+
{ id: "shared-kernel", path: "runtime-bundles/shared-kernel" },
|
|
66551
|
+
{ id: "xcode-sim", path: "runtime-bundles/xcode-sim" },
|
|
66552
|
+
{ id: "runtime-ios", path: "har-boilerplate-ios" }
|
|
66553
|
+
]
|
|
66554
|
+
}
|
|
66555
|
+
};
|
|
66367
66556
|
var PROFILE_DIRS = {
|
|
66368
66557
|
default: "har-boilerplate",
|
|
66369
66558
|
cli: "har-boilerplate-cli",
|
|
66370
66559
|
ios: "har-boilerplate-ios"
|
|
66371
66560
|
};
|
|
66561
|
+
function readProfileManifest(profile) {
|
|
66562
|
+
const templates = resolveTemplatesDir();
|
|
66563
|
+
const manifestPath = path36.join(templates, "profiles", profile, "profile.manifest.json");
|
|
66564
|
+
if (fs30.existsSync(manifestPath)) {
|
|
66565
|
+
const parsed = ProfileManifestSchema.safeParse(
|
|
66566
|
+
JSON.parse(fs30.readFileSync(manifestPath, "utf8"))
|
|
66567
|
+
);
|
|
66568
|
+
if (!parsed.success) {
|
|
66569
|
+
throw new Error(`Invalid profile manifest for ${profile}: ${parsed.error.message}`);
|
|
66570
|
+
}
|
|
66571
|
+
if (parsed.data.id !== profile) {
|
|
66572
|
+
throw new Error(`Profile manifest id mismatch: expected ${profile}, got ${parsed.data.id}`);
|
|
66573
|
+
}
|
|
66574
|
+
return parsed.data;
|
|
66575
|
+
}
|
|
66576
|
+
return PROFILE_COMPOSITIONS[profile];
|
|
66577
|
+
}
|
|
66578
|
+
function resolveProfileBundleDir(bundle) {
|
|
66579
|
+
const dir = path36.join(resolveTemplatesDir(), bundle.path);
|
|
66580
|
+
if (!fs30.existsSync(dir)) {
|
|
66581
|
+
throw new Error(`Profile bundle not found: ${bundle.id} (${bundle.path}). Run npm run build.`);
|
|
66582
|
+
}
|
|
66583
|
+
return dir;
|
|
66584
|
+
}
|
|
66585
|
+
|
|
66586
|
+
// src/harness/generator.ts
|
|
66587
|
+
init_stages();
|
|
66372
66588
|
var CLI_PRUNE_FILES = [
|
|
66373
66589
|
"ecosystem.agent.template.cjs",
|
|
66374
66590
|
"env.template",
|
|
@@ -66376,39 +66592,46 @@ var CLI_PRUNE_FILES = [
|
|
|
66376
66592
|
];
|
|
66377
66593
|
function pruneCliProfile(harnessDir) {
|
|
66378
66594
|
for (const file of CLI_PRUNE_FILES) {
|
|
66379
|
-
const filePath =
|
|
66380
|
-
if (
|
|
66381
|
-
|
|
66595
|
+
const filePath = path37.join(harnessDir, file);
|
|
66596
|
+
if (fs31.existsSync(filePath)) {
|
|
66597
|
+
fs31.unlinkSync(filePath);
|
|
66382
66598
|
}
|
|
66383
66599
|
}
|
|
66384
66600
|
}
|
|
66385
66601
|
function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
66386
|
-
const harnessDir =
|
|
66387
|
-
const projectName =
|
|
66602
|
+
const harnessDir = path37.join(repoPath, DEFAULT_HAR_DIR);
|
|
66603
|
+
const projectName = path37.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
66388
66604
|
const profile = options.profile ?? "default";
|
|
66389
|
-
const
|
|
66390
|
-
|
|
66605
|
+
const profileManifest = readProfileManifest(profile);
|
|
66606
|
+
const bundleIds = profileManifest.bundles.map((b2) => b2.id);
|
|
66607
|
+
const primaryOverlay = PROFILE_DIRS[profile];
|
|
66608
|
+
const boilerplateDir = path37.join(resolveTemplatesDir(), primaryOverlay);
|
|
66609
|
+
if (fs31.existsSync(harnessDir) && !options.force) {
|
|
66391
66610
|
throw new Error(
|
|
66392
66611
|
'.har/ already exists. Use --force to overwrite or run "har env maintain" to update in place.'
|
|
66393
66612
|
);
|
|
66394
66613
|
}
|
|
66395
|
-
if (!
|
|
66614
|
+
if (!fs31.existsSync(boilerplateDir)) {
|
|
66396
66615
|
throw new Error(`Boilerplate template not found at ${boilerplateDir}`);
|
|
66397
66616
|
}
|
|
66398
|
-
if (options.force &&
|
|
66399
|
-
|
|
66617
|
+
if (options.force && fs31.existsSync(harnessDir)) {
|
|
66618
|
+
fs31.rmSync(harnessDir, { recursive: true, force: true });
|
|
66619
|
+
}
|
|
66620
|
+
fs31.mkdirSync(harnessDir, { recursive: true });
|
|
66621
|
+
for (const bundle of profileManifest.bundles) {
|
|
66622
|
+
const bundleDir = resolveProfileBundleDir(bundle);
|
|
66623
|
+
copyDirRecursive(bundleDir, harnessDir);
|
|
66400
66624
|
}
|
|
66401
|
-
copyDirRecursive(boilerplateDir, harnessDir);
|
|
66402
66625
|
writeHarnessGitignore(harnessDir, boilerplateDir);
|
|
66403
66626
|
if (profile === "cli") {
|
|
66404
66627
|
pruneCliProfile(harnessDir);
|
|
66405
66628
|
}
|
|
66406
66629
|
syncAgentSlotsToHarnessEnv(repoPath);
|
|
66407
|
-
const harnessEnvPath =
|
|
66408
|
-
if (
|
|
66409
|
-
let content =
|
|
66630
|
+
const harnessEnvPath = path37.join(harnessDir, "harness.env");
|
|
66631
|
+
if (fs31.existsSync(harnessEnvPath)) {
|
|
66632
|
+
let content = fs31.readFileSync(harnessEnvPath, "utf8");
|
|
66410
66633
|
content = content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
|
|
66411
|
-
|
|
66634
|
+
fs31.writeFileSync(harnessEnvPath, content);
|
|
66412
66635
|
}
|
|
66413
66636
|
const manifest = createManifest(
|
|
66414
66637
|
repoPath,
|
|
@@ -66417,10 +66640,12 @@ function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
|
66417
66640
|
profile
|
|
66418
66641
|
);
|
|
66419
66642
|
writeManifest(repoPath, manifest);
|
|
66643
|
+
ensurePluginLedgerScaffold(repoPath, { profile, bundles: bundleIds });
|
|
66420
66644
|
ensureRootGitignorePatterns(repoPath);
|
|
66421
66645
|
success(`Copied harness boilerplate to .har/ (profile: ${profile})`);
|
|
66422
66646
|
info(`Project name: ${projectName}`);
|
|
66423
|
-
|
|
66647
|
+
info(`Bundles: ${bundleIds.join(" \u2192 ")}`);
|
|
66648
|
+
return { harnessDir, projectName, bundles: bundleIds };
|
|
66424
66649
|
}
|
|
66425
66650
|
function finalizeHarness(repoPath, adaptationSummary, stack) {
|
|
66426
66651
|
const existing = readManifest(repoPath);
|
|
@@ -66430,16 +66655,16 @@ function finalizeHarness(repoPath, adaptationSummary, stack) {
|
|
|
66430
66655
|
}
|
|
66431
66656
|
|
|
66432
66657
|
// src/harness/agent-md.ts
|
|
66433
|
-
var
|
|
66434
|
-
var
|
|
66658
|
+
var fs33 = __toESM(require("fs"));
|
|
66659
|
+
var path39 = __toESM(require("path"));
|
|
66435
66660
|
init_file_ops();
|
|
66436
66661
|
init_logging();
|
|
66437
66662
|
init_manifest();
|
|
66438
66663
|
|
|
66439
66664
|
// src/harness/instruction-files.ts
|
|
66440
|
-
var
|
|
66665
|
+
var fs32 = __toESM(require("fs"));
|
|
66441
66666
|
var os14 = __toESM(require("os"));
|
|
66442
|
-
var
|
|
66667
|
+
var path38 = __toESM(require("path"));
|
|
66443
66668
|
|
|
66444
66669
|
// node_modules/@inquirer/core/dist/esm/lib/key.mjs
|
|
66445
66670
|
var isUpKey = (key) => (
|
|
@@ -67459,13 +67684,13 @@ var PromisePolyfill = class extends Promise {
|
|
|
67459
67684
|
// Available starting from Node 22
|
|
67460
67685
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
|
67461
67686
|
static withResolver() {
|
|
67462
|
-
let
|
|
67687
|
+
let resolve50;
|
|
67463
67688
|
let reject;
|
|
67464
67689
|
const promise = new Promise((res, rej) => {
|
|
67465
|
-
|
|
67690
|
+
resolve50 = res;
|
|
67466
67691
|
reject = rej;
|
|
67467
67692
|
});
|
|
67468
|
-
return { promise, resolve:
|
|
67693
|
+
return { promise, resolve: resolve50, reject };
|
|
67469
67694
|
}
|
|
67470
67695
|
};
|
|
67471
67696
|
|
|
@@ -67482,7 +67707,7 @@ function createPrompt(view) {
|
|
|
67482
67707
|
output
|
|
67483
67708
|
});
|
|
67484
67709
|
const screen = new ScreenManager(rl);
|
|
67485
|
-
const { promise, resolve:
|
|
67710
|
+
const { promise, resolve: resolve50, reject } = PromisePolyfill.withResolver();
|
|
67486
67711
|
const cancel = () => reject(new CancelPromptError());
|
|
67487
67712
|
if (signal) {
|
|
67488
67713
|
const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
|
|
@@ -67506,7 +67731,7 @@ function createPrompt(view) {
|
|
|
67506
67731
|
cycle(() => {
|
|
67507
67732
|
try {
|
|
67508
67733
|
const nextView = view(config2, (value) => {
|
|
67509
|
-
setImmediate(() =>
|
|
67734
|
+
setImmediate(() => resolve50(value));
|
|
67510
67735
|
});
|
|
67511
67736
|
const [content, bottomContent] = typeof nextView === "string" ? [nextView] : nextView;
|
|
67512
67737
|
screen.render(content, bottomContent);
|
|
@@ -68493,9 +68718,9 @@ var import_run_async = __toESM(require_run_async(), 1);
|
|
|
68493
68718
|
var import_mute_stream2 = __toESM(require_lib(), 1);
|
|
68494
68719
|
var import_ansi_escapes5 = __toESM(require_ansi_escapes(), 1);
|
|
68495
68720
|
var _ = {
|
|
68496
|
-
set: (obj,
|
|
68721
|
+
set: (obj, path66 = "", value) => {
|
|
68497
68722
|
let pointer = obj;
|
|
68498
|
-
|
|
68723
|
+
path66.split(".").forEach((key, index, arr) => {
|
|
68499
68724
|
if (key === "__proto__" || key === "constructor")
|
|
68500
68725
|
return;
|
|
68501
68726
|
if (index === arr.length - 1) {
|
|
@@ -68506,8 +68731,8 @@ var _ = {
|
|
|
68506
68731
|
pointer = pointer[key];
|
|
68507
68732
|
});
|
|
68508
68733
|
},
|
|
68509
|
-
get: (obj,
|
|
68510
|
-
const travel = (regexp) => String.prototype.split.call(
|
|
68734
|
+
get: (obj, path66 = "", defaultValue) => {
|
|
68735
|
+
const travel = (regexp) => String.prototype.split.call(path66, regexp).filter(Boolean).reduce(
|
|
68511
68736
|
// @ts-expect-error implicit any on res[key]
|
|
68512
68737
|
(res, key) => res !== null && res !== void 0 ? res[key] : res,
|
|
68513
68738
|
obj
|
|
@@ -68621,7 +68846,7 @@ var PromptsRunner = class {
|
|
|
68621
68846
|
throw new Error(`Prompt for type ${question.type} not found`);
|
|
68622
68847
|
}
|
|
68623
68848
|
let cleanupSignal;
|
|
68624
|
-
const promptFn = isPromptConstructor(prompt2) ? (q, { signal: signal2 } = {}) => new Promise((
|
|
68849
|
+
const promptFn = isPromptConstructor(prompt2) ? (q, { signal: signal2 } = {}) => new Promise((resolve50, reject) => {
|
|
68625
68850
|
const rl = import_node_readline.default.createInterface(setupReadlineOptions(this.opt));
|
|
68626
68851
|
rl.resume();
|
|
68627
68852
|
const onClose = () => {
|
|
@@ -68657,7 +68882,7 @@ var PromptsRunner = class {
|
|
|
68657
68882
|
cleanupSignal = void 0;
|
|
68658
68883
|
};
|
|
68659
68884
|
}
|
|
68660
|
-
activePrompt.run().then(
|
|
68885
|
+
activePrompt.run().then(resolve50, reject).finally(cleanup);
|
|
68661
68886
|
}) : prompt2;
|
|
68662
68887
|
const { signal: moduleSignal } = this.opt;
|
|
68663
68888
|
if (moduleSignal?.aborted) {
|
|
@@ -68833,12 +69058,12 @@ function outsideContentShrinkMessage(beforeLines, afterLines) {
|
|
|
68833
69058
|
}
|
|
68834
69059
|
function detectInstructionFiles(repoPath) {
|
|
68835
69060
|
return {
|
|
68836
|
-
agentsMd:
|
|
68837
|
-
agentMd:
|
|
68838
|
-
claudeMd:
|
|
68839
|
-
cursorDir:
|
|
68840
|
-
claudeDir:
|
|
68841
|
-
codexHome:
|
|
69061
|
+
agentsMd: fs32.existsSync(path38.join(repoPath, AGENTS_MD)),
|
|
69062
|
+
agentMd: fs32.existsSync(path38.join(repoPath, LEGACY_AGENT_MD)),
|
|
69063
|
+
claudeMd: fs32.existsSync(path38.join(repoPath, CLAUDE_MD)),
|
|
69064
|
+
cursorDir: fs32.existsSync(path38.join(repoPath, ".cursor")),
|
|
69065
|
+
claudeDir: fs32.existsSync(path38.join(repoPath, ".claude")),
|
|
69066
|
+
codexHome: fs32.existsSync(path38.join(os14.homedir(), ".codex"))
|
|
68842
69067
|
};
|
|
68843
69068
|
}
|
|
68844
69069
|
function formatDetectionReport(detection) {
|
|
@@ -68893,7 +69118,7 @@ function loadHarAgentsSectionFromTemplate() {
|
|
|
68893
69118
|
if (!templatePath) {
|
|
68894
69119
|
throw new Error("AGENTS.md.template not found. Run npm run build.");
|
|
68895
69120
|
}
|
|
68896
|
-
const content =
|
|
69121
|
+
const content = fs32.readFileSync(templatePath, "utf8");
|
|
68897
69122
|
const start = content.indexOf(HAR_SECTION_START);
|
|
68898
69123
|
const end = content.indexOf(HAR_SECTION_END);
|
|
68899
69124
|
if (start === -1 || end === -1 || end < start) {
|
|
@@ -68906,7 +69131,7 @@ function loadAgentsMdTemplate() {
|
|
|
68906
69131
|
if (!templatePath) {
|
|
68907
69132
|
throw new Error("AGENTS.md.template not found. Run npm run build.");
|
|
68908
69133
|
}
|
|
68909
|
-
return
|
|
69134
|
+
return fs32.readFileSync(templatePath, "utf8");
|
|
68910
69135
|
}
|
|
68911
69136
|
function upsertMarkedBlock2(content, block, startMarker, endMarker) {
|
|
68912
69137
|
const existingBlock = findLastCompleteMarkedBlock(content, startMarker, endMarker);
|
|
@@ -68939,13 +69164,13 @@ function mergeAgentsMdContent(existing, incoming) {
|
|
|
68939
69164
|
return content;
|
|
68940
69165
|
}
|
|
68941
69166
|
function upsertAgentsMdHarSection(repoPath, options = {}) {
|
|
68942
|
-
const dest =
|
|
69167
|
+
const dest = path38.join(repoPath, AGENTS_MD);
|
|
68943
69168
|
const section = loadHarAgentsSectionFromTemplate();
|
|
68944
|
-
if (!
|
|
69169
|
+
if (!fs32.existsSync(dest)) {
|
|
68945
69170
|
writeFileSafe(dest, loadAgentsMdTemplate());
|
|
68946
69171
|
return "created";
|
|
68947
69172
|
}
|
|
68948
|
-
const existing =
|
|
69173
|
+
const existing = fs32.readFileSync(dest, "utf8");
|
|
68949
69174
|
const sanitized = stripClaudePointerFromAgentsMd(existing);
|
|
68950
69175
|
const { content, action } = upsertMarkedBlock2(
|
|
68951
69176
|
sanitized,
|
|
@@ -68970,15 +69195,15 @@ function upsertAgentsMdHarSection(repoPath, options = {}) {
|
|
|
68970
69195
|
return action;
|
|
68971
69196
|
}
|
|
68972
69197
|
function migrateLegacyAgentMd(repoPath) {
|
|
68973
|
-
const legacyPath =
|
|
68974
|
-
const agentsPath =
|
|
68975
|
-
if (!
|
|
68976
|
-
const legacy =
|
|
68977
|
-
if (!
|
|
69198
|
+
const legacyPath = path38.join(repoPath, LEGACY_AGENT_MD);
|
|
69199
|
+
const agentsPath = path38.join(repoPath, AGENTS_MD);
|
|
69200
|
+
if (!fs32.existsSync(legacyPath)) return false;
|
|
69201
|
+
const legacy = fs32.readFileSync(legacyPath, "utf8");
|
|
69202
|
+
if (!fs32.existsSync(agentsPath)) {
|
|
68978
69203
|
writeFileSafe(agentsPath, legacy);
|
|
68979
69204
|
upsertAgentsMdHarSection(repoPath);
|
|
68980
69205
|
} else {
|
|
68981
|
-
const agents =
|
|
69206
|
+
const agents = fs32.readFileSync(agentsPath, "utf8");
|
|
68982
69207
|
const legacyTrimmed = legacy.trim();
|
|
68983
69208
|
if (legacyTrimmed.length > 0 && !agents.includes(legacyTrimmed)) {
|
|
68984
69209
|
const suffix = agents.endsWith("\n") ? "" : "\n";
|
|
@@ -68988,7 +69213,7 @@ ${legacyTrimmed}
|
|
|
68988
69213
|
}
|
|
68989
69214
|
upsertAgentsMdHarSection(repoPath);
|
|
68990
69215
|
}
|
|
68991
|
-
|
|
69216
|
+
fs32.unlinkSync(legacyPath);
|
|
68992
69217
|
info(`Migrated ${LEGACY_AGENT_MD} \u2192 ${AGENTS_MD} (removed legacy file)`);
|
|
68993
69218
|
return true;
|
|
68994
69219
|
}
|
|
@@ -68998,7 +69223,7 @@ function loadClaudeMdTemplate(projectName) {
|
|
|
68998
69223
|
throw new Error("CLAUDE.md.template not found. Run npm run build.");
|
|
68999
69224
|
}
|
|
69000
69225
|
const displayName = projectName.replace(/_/g, " ");
|
|
69001
|
-
return
|
|
69226
|
+
return fs32.readFileSync(templatePath, "utf8").replace(/__PROJECT_DISPLAY_NAME__/g, displayName);
|
|
69002
69227
|
}
|
|
69003
69228
|
function isThinClaudePointer(content) {
|
|
69004
69229
|
const trimmed = content.trim();
|
|
@@ -69012,14 +69237,14 @@ This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
|
|
|
69012
69237
|
[\`.har/README.md\`](./.har/README.md) before making changes.
|
|
69013
69238
|
${CLAUDE_HAR_SECTION_END}`;
|
|
69014
69239
|
function ensureClaudeMdPointer(repoPath, options = {}) {
|
|
69015
|
-
const dest =
|
|
69016
|
-
const projectName =
|
|
69240
|
+
const dest = path38.join(repoPath, CLAUDE_MD);
|
|
69241
|
+
const projectName = path38.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
69017
69242
|
const thin = loadClaudeMdTemplate(projectName);
|
|
69018
|
-
if (!
|
|
69243
|
+
if (!fs32.existsSync(dest)) {
|
|
69019
69244
|
writeFileSafe(dest, thin);
|
|
69020
69245
|
return "created";
|
|
69021
69246
|
}
|
|
69022
|
-
const existing =
|
|
69247
|
+
const existing = fs32.readFileSync(dest, "utf8");
|
|
69023
69248
|
if (isThinClaudePointer(existing) || options.force) {
|
|
69024
69249
|
writeFileSafe(dest, thin);
|
|
69025
69250
|
return "updated";
|
|
@@ -69168,19 +69393,19 @@ var AGENT_MD_PROPOSAL = "AGENT.md.proposed";
|
|
|
69168
69393
|
var AGENT_MD_PROPOSAL_META = "AGENT.md.proposed.meta.json";
|
|
69169
69394
|
function readAgentMdProposal(repoPath) {
|
|
69170
69395
|
const harnessDir = getHarnessDir(repoPath);
|
|
69171
|
-
const proposalPath =
|
|
69172
|
-
const metaPath =
|
|
69173
|
-
const legacyProposalPath =
|
|
69174
|
-
const legacyMetaPath =
|
|
69175
|
-
const resolvedProposal =
|
|
69396
|
+
const proposalPath = path39.join(harnessDir, AGENTS_MD_PROPOSAL);
|
|
69397
|
+
const metaPath = path39.join(harnessDir, AGENTS_MD_PROPOSAL_META);
|
|
69398
|
+
const legacyProposalPath = path39.join(harnessDir, AGENT_MD_PROPOSAL);
|
|
69399
|
+
const legacyMetaPath = path39.join(harnessDir, AGENT_MD_PROPOSAL_META);
|
|
69400
|
+
const resolvedProposal = fs33.existsSync(proposalPath) ? proposalPath : fs33.existsSync(legacyProposalPath) ? legacyProposalPath : null;
|
|
69176
69401
|
if (!resolvedProposal) return null;
|
|
69177
69402
|
const resolvedMeta = resolvedProposal === proposalPath ? metaPath : legacyMetaPath;
|
|
69178
|
-
const content =
|
|
69403
|
+
const content = fs33.readFileSync(resolvedProposal, "utf8");
|
|
69179
69404
|
let rationale = "";
|
|
69180
69405
|
let createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
69181
|
-
if (
|
|
69406
|
+
if (fs33.existsSync(resolvedMeta)) {
|
|
69182
69407
|
try {
|
|
69183
|
-
const meta = JSON.parse(
|
|
69408
|
+
const meta = JSON.parse(fs33.readFileSync(resolvedMeta, "utf8"));
|
|
69184
69409
|
rationale = meta.rationale ?? "";
|
|
69185
69410
|
createdAt = meta.createdAt ?? createdAt;
|
|
69186
69411
|
} catch {
|
|
@@ -69197,8 +69422,8 @@ function clearAgentMdProposal(repoPath) {
|
|
|
69197
69422
|
AGENT_MD_PROPOSAL,
|
|
69198
69423
|
AGENT_MD_PROPOSAL_META
|
|
69199
69424
|
]) {
|
|
69200
|
-
const p =
|
|
69201
|
-
if (
|
|
69425
|
+
const p = path39.join(harnessDir, file);
|
|
69426
|
+
if (fs33.existsSync(p)) fs33.unlinkSync(p);
|
|
69202
69427
|
}
|
|
69203
69428
|
}
|
|
69204
69429
|
function wouldProposalShrinkExisting(existing, proposal) {
|
|
@@ -69211,9 +69436,9 @@ function wouldProposalShrinkExisting(existing, proposal) {
|
|
|
69211
69436
|
function applyAgentMdProposalMerge(repoPath, options = {}) {
|
|
69212
69437
|
const proposal = readAgentMdProposal(repoPath);
|
|
69213
69438
|
if (!proposal) return false;
|
|
69214
|
-
const agentsMdPath =
|
|
69215
|
-
if (
|
|
69216
|
-
const existing =
|
|
69439
|
+
const agentsMdPath = path39.join(repoPath, AGENTS_MD);
|
|
69440
|
+
if (fs33.existsSync(agentsMdPath)) {
|
|
69441
|
+
const existing = fs33.readFileSync(agentsMdPath, "utf8");
|
|
69217
69442
|
if (wouldProposalShrinkExisting(existing, proposal.content)) {
|
|
69218
69443
|
const message = `${AGENTS_MD} proposal would drop project-specific content outside har:agent-environment markers \u2014 merge custom sections from .har/${AGENTS_MD_PROPOSAL} manually, then delete the proposal.`;
|
|
69219
69444
|
if (options.rejectSignificantShrink) {
|
|
@@ -69236,8 +69461,8 @@ function finalizeAgentsMdInstructionFiles(repoPath) {
|
|
|
69236
69461
|
}
|
|
69237
69462
|
|
|
69238
69463
|
// src/harness/validator.ts
|
|
69239
|
-
var
|
|
69240
|
-
var
|
|
69464
|
+
var fs34 = __toESM(require("fs"));
|
|
69465
|
+
var path40 = __toESM(require("path"));
|
|
69241
69466
|
init_shell();
|
|
69242
69467
|
init_manifest();
|
|
69243
69468
|
init_stages();
|
|
@@ -69292,22 +69517,22 @@ var SHELL_SCRIPTS = [
|
|
|
69292
69517
|
function validateHarness(repoPath) {
|
|
69293
69518
|
const harnessDir = getHarnessDir(repoPath);
|
|
69294
69519
|
const issues = [];
|
|
69295
|
-
if (!
|
|
69520
|
+
if (!fs34.existsSync(harnessDir)) {
|
|
69296
69521
|
return {
|
|
69297
69522
|
pass: false,
|
|
69298
69523
|
issues: [{ file: ".har", message: "Harness directory not found", severity: "error" }]
|
|
69299
69524
|
};
|
|
69300
69525
|
}
|
|
69301
69526
|
for (const file of getRequiredFiles(repoPath)) {
|
|
69302
|
-
const filePath =
|
|
69303
|
-
if (!
|
|
69527
|
+
const filePath = path40.join(harnessDir, file);
|
|
69528
|
+
if (!fs34.existsSync(filePath)) {
|
|
69304
69529
|
issues.push({ file, message: "Required file missing", severity: "error" });
|
|
69305
69530
|
}
|
|
69306
69531
|
}
|
|
69307
69532
|
for (const script of SHELL_SCRIPTS) {
|
|
69308
|
-
const scriptPath =
|
|
69309
|
-
if (!
|
|
69310
|
-
const stat =
|
|
69533
|
+
const scriptPath = path40.join(harnessDir, script);
|
|
69534
|
+
if (!fs34.existsSync(scriptPath)) continue;
|
|
69535
|
+
const stat = fs34.statSync(scriptPath);
|
|
69311
69536
|
if (!(stat.mode & 73)) {
|
|
69312
69537
|
issues.push({ file: script, message: "Script is not executable", severity: "warning" });
|
|
69313
69538
|
}
|
|
@@ -69322,9 +69547,9 @@ function validateHarness(repoPath) {
|
|
|
69322
69547
|
}
|
|
69323
69548
|
const manifest = readManifest(repoPath);
|
|
69324
69549
|
const profile = manifest?.profile ?? "default";
|
|
69325
|
-
const ecosystemPath =
|
|
69326
|
-
if (profile !== "cli" &&
|
|
69327
|
-
const content =
|
|
69550
|
+
const ecosystemPath = path40.join(harnessDir, "ecosystem.agent.template.cjs");
|
|
69551
|
+
if (profile !== "cli" && fs34.existsSync(ecosystemPath)) {
|
|
69552
|
+
const content = fs34.readFileSync(ecosystemPath, "utf8");
|
|
69328
69553
|
if (!content.includes("module.exports")) {
|
|
69329
69554
|
issues.push({
|
|
69330
69555
|
file: "ecosystem.agent.template.cjs",
|
|
@@ -69333,9 +69558,9 @@ function validateHarness(repoPath) {
|
|
|
69333
69558
|
});
|
|
69334
69559
|
}
|
|
69335
69560
|
}
|
|
69336
|
-
const harnessEnvPath =
|
|
69337
|
-
if (
|
|
69338
|
-
const content =
|
|
69561
|
+
const harnessEnvPath = path40.join(harnessDir, "harness.env");
|
|
69562
|
+
if (fs34.existsSync(harnessEnvPath)) {
|
|
69563
|
+
const content = fs34.readFileSync(harnessEnvPath, "utf8");
|
|
69339
69564
|
if (content.includes("TODO: set migrate command")) {
|
|
69340
69565
|
issues.push({ file: "harness.env", message: "Migrate command still has TODO", severity: "warning" });
|
|
69341
69566
|
}
|
|
@@ -69343,17 +69568,17 @@ function validateHarness(repoPath) {
|
|
|
69343
69568
|
issues.push({ file: "harness.env", message: "Seed command still has TODO", severity: "warning" });
|
|
69344
69569
|
}
|
|
69345
69570
|
}
|
|
69346
|
-
const verifyPath =
|
|
69347
|
-
if (
|
|
69348
|
-
const content =
|
|
69571
|
+
const verifyPath = path40.join(harnessDir, "verify.sh");
|
|
69572
|
+
if (fs34.existsSync(verifyPath)) {
|
|
69573
|
+
const content = fs34.readFileSync(verifyPath, "utf8");
|
|
69349
69574
|
if (content.includes("echo 'TODO:")) {
|
|
69350
69575
|
issues.push({ file: "verify.sh", message: "Verification steps still have TODO placeholders", severity: "warning" });
|
|
69351
69576
|
}
|
|
69352
69577
|
}
|
|
69353
|
-
const stagesPath =
|
|
69354
|
-
if (
|
|
69578
|
+
const stagesPath = path40.join(harnessDir, "stages.json");
|
|
69579
|
+
if (fs34.existsSync(stagesPath)) {
|
|
69355
69580
|
try {
|
|
69356
|
-
JSON.parse(
|
|
69581
|
+
JSON.parse(fs34.readFileSync(stagesPath, "utf8"));
|
|
69357
69582
|
const registry2 = readStageRegistry(repoPath);
|
|
69358
69583
|
if (registry2.stages.length === 0) {
|
|
69359
69584
|
issues.push({ file: "stages.json", message: "No harness stages declared", severity: "warning" });
|
|
@@ -69368,9 +69593,9 @@ function validateHarness(repoPath) {
|
|
|
69368
69593
|
} else {
|
|
69369
69594
|
issues.push({ file: "stages.json", message: "Stage registry missing", severity: "warning" });
|
|
69370
69595
|
}
|
|
69371
|
-
const readmePath =
|
|
69372
|
-
if (
|
|
69373
|
-
const content =
|
|
69596
|
+
const readmePath = path40.join(harnessDir, "README.md");
|
|
69597
|
+
if (fs34.existsSync(readmePath)) {
|
|
69598
|
+
const content = fs34.readFileSync(readmePath, "utf8");
|
|
69374
69599
|
if (!content.includes(".har")) {
|
|
69375
69600
|
issues.push({ file: "README.md", message: "README should document .har/ paths", severity: "warning" });
|
|
69376
69601
|
}
|
|
@@ -69384,8 +69609,8 @@ function validateHarness(repoPath) {
|
|
|
69384
69609
|
async function smokeTestHarness(repoPath) {
|
|
69385
69610
|
const harnessDir = getHarnessDir(repoPath);
|
|
69386
69611
|
const issues = [];
|
|
69387
|
-
const setupScript =
|
|
69388
|
-
if (
|
|
69612
|
+
const setupScript = path40.join(harnessDir, "setup-infra.sh");
|
|
69613
|
+
if (fs34.existsSync(setupScript)) {
|
|
69389
69614
|
const result = run(`bash "${setupScript}"`, { cwd: repoPath });
|
|
69390
69615
|
if (result.code !== 0) {
|
|
69391
69616
|
issues.push({
|
|
@@ -69400,16 +69625,11 @@ async function smokeTestHarness(repoPath) {
|
|
|
69400
69625
|
}
|
|
69401
69626
|
|
|
69402
69627
|
// src/harness/drift.ts
|
|
69403
|
-
var
|
|
69404
|
-
var
|
|
69628
|
+
var fs35 = __toESM(require("fs"));
|
|
69629
|
+
var path41 = __toESM(require("path"));
|
|
69405
69630
|
init_env();
|
|
69406
69631
|
init_manifest();
|
|
69407
69632
|
init_stages();
|
|
69408
|
-
var PROFILE_DIRS2 = {
|
|
69409
|
-
default: "har-boilerplate",
|
|
69410
|
-
cli: "har-boilerplate-cli",
|
|
69411
|
-
ios: "har-boilerplate-ios"
|
|
69412
|
-
};
|
|
69413
69633
|
var CLI_EXPECTED_ABSENT = /* @__PURE__ */ new Set([
|
|
69414
69634
|
"ecosystem.agent.template.cjs",
|
|
69415
69635
|
"env.template",
|
|
@@ -69472,16 +69692,16 @@ function substituteProjectName(content, projectName) {
|
|
|
69472
69692
|
return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
|
|
69473
69693
|
}
|
|
69474
69694
|
function listBoilerplateFiles(boilerplateDir) {
|
|
69475
|
-
if (!
|
|
69476
|
-
return
|
|
69695
|
+
if (!fs35.existsSync(boilerplateDir)) return [];
|
|
69696
|
+
return fs35.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
69477
69697
|
}
|
|
69478
69698
|
function compareHarnessToTemplate(repoPath) {
|
|
69479
|
-
const resolved =
|
|
69699
|
+
const resolved = path41.resolve(repoPath);
|
|
69480
69700
|
const manifest = readManifest(resolved);
|
|
69481
69701
|
const profile = manifest?.profile ?? "default";
|
|
69482
69702
|
const harnessDir = getHarnessDir(resolved);
|
|
69483
|
-
const projectName =
|
|
69484
|
-
const boilerplateDir =
|
|
69703
|
+
const projectName = path41.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
69704
|
+
const boilerplateDir = path41.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
|
|
69485
69705
|
const templateFiles = listBoilerplateFiles(boilerplateDir);
|
|
69486
69706
|
const missing = [];
|
|
69487
69707
|
const checksumMismatch = [];
|
|
@@ -69489,17 +69709,17 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
69489
69709
|
const unchanged = [];
|
|
69490
69710
|
for (const file of templateFiles) {
|
|
69491
69711
|
const harnessFile = harnessFileForTemplate(file);
|
|
69492
|
-
const templatePath =
|
|
69493
|
-
const harnessPath =
|
|
69494
|
-
let templateContent =
|
|
69712
|
+
const templatePath = path41.join(boilerplateDir, file);
|
|
69713
|
+
const harnessPath = path41.join(harnessDir, harnessFile);
|
|
69714
|
+
let templateContent = fs35.readFileSync(templatePath, "utf8");
|
|
69495
69715
|
if (file === "harness.env") {
|
|
69496
69716
|
templateContent = substituteProjectName(templateContent, projectName);
|
|
69497
69717
|
}
|
|
69498
|
-
if (!
|
|
69718
|
+
if (!fs35.existsSync(harnessPath)) {
|
|
69499
69719
|
missing.push(harnessFile);
|
|
69500
69720
|
continue;
|
|
69501
69721
|
}
|
|
69502
|
-
const harnessChecksum = computeFileChecksum(
|
|
69722
|
+
const harnessChecksum = computeFileChecksum(fs35.readFileSync(harnessPath, "utf8"));
|
|
69503
69723
|
const templateChecksum = computeFileChecksum(templateContent);
|
|
69504
69724
|
if (harnessChecksum === templateChecksum) {
|
|
69505
69725
|
unchanged.push(harnessFile);
|
|
@@ -69507,11 +69727,13 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
69507
69727
|
checksumMismatch.push(harnessFile);
|
|
69508
69728
|
}
|
|
69509
69729
|
}
|
|
69510
|
-
if (
|
|
69511
|
-
for (const file of
|
|
69512
|
-
const full =
|
|
69513
|
-
if (!
|
|
69514
|
-
if (file === "manifest.json" || file.startsWith("ADAPT-PROMPT"))
|
|
69730
|
+
if (fs35.existsSync(harnessDir)) {
|
|
69731
|
+
for (const file of fs35.readdirSync(harnessDir)) {
|
|
69732
|
+
const full = path41.join(harnessDir, file);
|
|
69733
|
+
if (!fs35.statSync(full).isFile()) continue;
|
|
69734
|
+
if (file === "manifest.json" || file === "plugins.json" || file.startsWith("ADAPT-PROMPT")) {
|
|
69735
|
+
continue;
|
|
69736
|
+
}
|
|
69515
69737
|
if (profile === "cli" && CLI_EXPECTED_ABSENT.has(file)) {
|
|
69516
69738
|
extra.push(file);
|
|
69517
69739
|
} else if (isExpectedHarnessOnlyFile(file, templateFiles)) {
|
|
@@ -69541,107 +69763,356 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
69541
69763
|
}
|
|
69542
69764
|
|
|
69543
69765
|
// src/harness/maintain-bundle.ts
|
|
69544
|
-
var
|
|
69545
|
-
var
|
|
69546
|
-
var
|
|
69766
|
+
var fs40 = __toESM(require("fs"));
|
|
69767
|
+
var os16 = __toESM(require("os"));
|
|
69768
|
+
var path45 = __toESM(require("path"));
|
|
69547
69769
|
init_file_ops();
|
|
69548
69770
|
init_shell();
|
|
69549
69771
|
init_manifest();
|
|
69550
69772
|
|
|
69551
69773
|
// src/harness/plugin-drift.ts
|
|
69552
|
-
var
|
|
69553
|
-
var
|
|
69774
|
+
var fs39 = __toESM(require("fs"));
|
|
69775
|
+
var path44 = __toESM(require("path"));
|
|
69554
69776
|
init_manifest();
|
|
69555
69777
|
|
|
69556
69778
|
// src/harness/plugins.ts
|
|
69557
|
-
var
|
|
69558
|
-
var
|
|
69779
|
+
var fs38 = __toESM(require("fs"));
|
|
69780
|
+
var path43 = __toESM(require("path"));
|
|
69559
69781
|
init_zod();
|
|
69560
69782
|
init_logging();
|
|
69561
69783
|
|
|
69562
69784
|
// src/harness/parser.ts
|
|
69563
|
-
var
|
|
69785
|
+
var fs36 = __toESM(require("fs"));
|
|
69564
69786
|
init_manifest();
|
|
69565
69787
|
function harnessExists(repoPath) {
|
|
69566
|
-
return
|
|
69788
|
+
return fs36.existsSync(`${repoPath}/.har/setup-infra.sh`);
|
|
69789
|
+
}
|
|
69790
|
+
|
|
69791
|
+
// src/harness/plugin-resolve.ts
|
|
69792
|
+
var import_child_process10 = require("child_process");
|
|
69793
|
+
var fs37 = __toESM(require("fs"));
|
|
69794
|
+
var os15 = __toESM(require("os"));
|
|
69795
|
+
var path42 = __toESM(require("path"));
|
|
69796
|
+
function hasManifest(dir) {
|
|
69797
|
+
return fs37.existsSync(path42.join(dir, "template.manifest.json"));
|
|
69798
|
+
}
|
|
69799
|
+
function readPackageVersion(dir) {
|
|
69800
|
+
const pkgPath = path42.join(dir, "package.json");
|
|
69801
|
+
if (!fs37.existsSync(pkgPath)) return void 0;
|
|
69802
|
+
try {
|
|
69803
|
+
const pkg = JSON.parse(fs37.readFileSync(pkgPath, "utf8"));
|
|
69804
|
+
return typeof pkg.version === "string" ? pkg.version : void 0;
|
|
69805
|
+
} catch {
|
|
69806
|
+
return void 0;
|
|
69807
|
+
}
|
|
69808
|
+
}
|
|
69809
|
+
function readManifestId(dir) {
|
|
69810
|
+
const manifestPath = path42.join(dir, "template.manifest.json");
|
|
69811
|
+
if (!fs37.existsSync(manifestPath)) return void 0;
|
|
69812
|
+
try {
|
|
69813
|
+
const raw = JSON.parse(fs37.readFileSync(manifestPath, "utf8"));
|
|
69814
|
+
return typeof raw.id === "string" ? raw.id : void 0;
|
|
69815
|
+
} catch {
|
|
69816
|
+
return void 0;
|
|
69817
|
+
}
|
|
69818
|
+
}
|
|
69819
|
+
function looksLikePath(spec) {
|
|
69820
|
+
return spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("~") || spec.startsWith("file:");
|
|
69821
|
+
}
|
|
69822
|
+
function looksLikeGit(spec) {
|
|
69823
|
+
return spec.startsWith("git+") || spec.startsWith("github:") || spec.startsWith("gitlab:") || spec.startsWith("bitbucket:") || /^https?:\/\/.+\.git$/i.test(spec) || /^git@/.test(spec);
|
|
69824
|
+
}
|
|
69825
|
+
function looksLikeNpm(spec) {
|
|
69826
|
+
if (looksLikePath(spec) || looksLikeGit(spec)) return false;
|
|
69827
|
+
if (spec.includes("/") && !spec.startsWith("@")) return false;
|
|
69828
|
+
return /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@.+)?$/i.test(spec);
|
|
69829
|
+
}
|
|
69830
|
+
function resolveBundledDir(pluginId) {
|
|
69831
|
+
const dir = path42.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
69832
|
+
return hasManifest(dir) ? dir : null;
|
|
69833
|
+
}
|
|
69834
|
+
function expandHome(p) {
|
|
69835
|
+
if (p.startsWith("~/")) return path42.join(os15.homedir(), p.slice(2));
|
|
69836
|
+
if (p === "~") return os15.homedir();
|
|
69837
|
+
return p;
|
|
69838
|
+
}
|
|
69839
|
+
function resolvePathSpec(spec) {
|
|
69840
|
+
const raw = spec.startsWith("file:") ? spec.slice("file:".length) : spec;
|
|
69841
|
+
const dir = path42.resolve(expandHome(raw));
|
|
69842
|
+
if (!fs37.existsSync(dir) || !fs37.statSync(dir).isDirectory()) {
|
|
69843
|
+
throw new Error(`Plugin path not found: ${spec}`);
|
|
69844
|
+
}
|
|
69845
|
+
if (!hasManifest(dir)) {
|
|
69846
|
+
throw new Error(`No template.manifest.json in ${dir}`);
|
|
69847
|
+
}
|
|
69848
|
+
const id = readManifestId(dir) ?? path42.basename(dir);
|
|
69849
|
+
return {
|
|
69850
|
+
id,
|
|
69851
|
+
kind: "path",
|
|
69852
|
+
dir,
|
|
69853
|
+
spec,
|
|
69854
|
+
version: readPackageVersion(dir),
|
|
69855
|
+
cleanupDirs: []
|
|
69856
|
+
};
|
|
69857
|
+
}
|
|
69858
|
+
function makeTempDir(prefix) {
|
|
69859
|
+
return fs37.mkdtempSync(path42.join(os15.tmpdir(), prefix));
|
|
69860
|
+
}
|
|
69861
|
+
function resolveNpmSpec(spec) {
|
|
69862
|
+
const tmp = makeTempDir("har-plugin-npm-");
|
|
69863
|
+
const cleanupDirs = [tmp];
|
|
69864
|
+
try {
|
|
69865
|
+
(0, import_child_process10.execFileSync)("npm", ["pack", spec, "--pack-destination", tmp], {
|
|
69866
|
+
encoding: "utf8",
|
|
69867
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
69868
|
+
timeout: 12e4
|
|
69869
|
+
});
|
|
69870
|
+
const tarballs = fs37.readdirSync(tmp).filter((f) => f.endsWith(".tgz"));
|
|
69871
|
+
if (tarballs.length === 0) {
|
|
69872
|
+
throw new Error(`npm pack produced no tarball for ${spec}`);
|
|
69873
|
+
}
|
|
69874
|
+
const extractDir = path42.join(tmp, "extract");
|
|
69875
|
+
fs37.mkdirSync(extractDir);
|
|
69876
|
+
(0, import_child_process10.execFileSync)("tar", ["-xzf", path42.join(tmp, tarballs[0]), "-C", extractDir], {
|
|
69877
|
+
encoding: "utf8",
|
|
69878
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
69879
|
+
});
|
|
69880
|
+
const packageDir = path42.join(extractDir, "package");
|
|
69881
|
+
let dir = packageDir;
|
|
69882
|
+
if (!hasManifest(dir)) {
|
|
69883
|
+
const nested = fs37.readdirSync(extractDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path42.join(extractDir, e.name)).find((d) => hasManifest(d));
|
|
69884
|
+
if (!nested) {
|
|
69885
|
+
throw new Error(
|
|
69886
|
+
`npm package ${spec} has no template.manifest.json (not a HAR plugin bundle)`
|
|
69887
|
+
);
|
|
69888
|
+
}
|
|
69889
|
+
dir = nested;
|
|
69890
|
+
}
|
|
69891
|
+
const id = readManifestId(dir) ?? spec.replace(/^@/, "").replace(/[/:].*/g, "");
|
|
69892
|
+
return {
|
|
69893
|
+
id,
|
|
69894
|
+
kind: "npm",
|
|
69895
|
+
dir,
|
|
69896
|
+
spec,
|
|
69897
|
+
version: readPackageVersion(dir),
|
|
69898
|
+
cleanupDirs
|
|
69899
|
+
};
|
|
69900
|
+
} catch (err) {
|
|
69901
|
+
for (const d of cleanupDirs) {
|
|
69902
|
+
fs37.rmSync(d, { recursive: true, force: true });
|
|
69903
|
+
}
|
|
69904
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
69905
|
+
throw new Error(`Failed to install plugin from npm (${spec}): ${message}`);
|
|
69906
|
+
}
|
|
69907
|
+
}
|
|
69908
|
+
function resolveGitSpec(spec) {
|
|
69909
|
+
const tmp = makeTempDir("har-plugin-git-");
|
|
69910
|
+
const cleanupDirs = [tmp];
|
|
69911
|
+
const cloneDir = path42.join(tmp, "repo");
|
|
69912
|
+
try {
|
|
69913
|
+
let url = spec;
|
|
69914
|
+
if (spec.startsWith("github:")) {
|
|
69915
|
+
url = `https://github.com/${spec.slice("github:".length)}.git`;
|
|
69916
|
+
} else if (spec.startsWith("gitlab:")) {
|
|
69917
|
+
url = `https://gitlab.com/${spec.slice("gitlab:".length)}.git`;
|
|
69918
|
+
} else if (spec.startsWith("bitbucket:")) {
|
|
69919
|
+
url = `https://bitbucket.org/${spec.slice("bitbucket:".length)}.git`;
|
|
69920
|
+
} else if (spec.startsWith("git+")) {
|
|
69921
|
+
url = spec.slice("git+".length);
|
|
69922
|
+
}
|
|
69923
|
+
(0, import_child_process10.execFileSync)("git", ["clone", "--depth", "1", url, cloneDir], {
|
|
69924
|
+
encoding: "utf8",
|
|
69925
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
69926
|
+
timeout: 18e4
|
|
69927
|
+
});
|
|
69928
|
+
let dir = cloneDir;
|
|
69929
|
+
if (!hasManifest(dir)) {
|
|
69930
|
+
const pluginsRoot = path42.join(cloneDir, "plugins");
|
|
69931
|
+
if (fs37.existsSync(pluginsRoot)) {
|
|
69932
|
+
const child = fs37.readdirSync(pluginsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path42.join(pluginsRoot, e.name)).find((d) => hasManifest(d));
|
|
69933
|
+
if (child) dir = child;
|
|
69934
|
+
}
|
|
69935
|
+
}
|
|
69936
|
+
if (!hasManifest(dir)) {
|
|
69937
|
+
throw new Error(`Git repo ${spec} has no template.manifest.json (not a HAR plugin bundle)`);
|
|
69938
|
+
}
|
|
69939
|
+
const id = readManifestId(dir) ?? path42.basename(url.replace(/\.git$/, ""));
|
|
69940
|
+
return {
|
|
69941
|
+
id,
|
|
69942
|
+
kind: "git",
|
|
69943
|
+
dir,
|
|
69944
|
+
spec,
|
|
69945
|
+
version: readPackageVersion(dir),
|
|
69946
|
+
cleanupDirs
|
|
69947
|
+
};
|
|
69948
|
+
} catch (err) {
|
|
69949
|
+
for (const d of cleanupDirs) {
|
|
69950
|
+
fs37.rmSync(d, { recursive: true, force: true });
|
|
69951
|
+
}
|
|
69952
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
69953
|
+
throw new Error(`Failed to install plugin from git (${spec}): ${message}`);
|
|
69954
|
+
}
|
|
69955
|
+
}
|
|
69956
|
+
function resolvePluginSource(spec) {
|
|
69957
|
+
const trimmed = spec.trim();
|
|
69958
|
+
if (!trimmed) {
|
|
69959
|
+
throw new Error("Plugin spec is empty");
|
|
69960
|
+
}
|
|
69961
|
+
if (looksLikePath(trimmed)) {
|
|
69962
|
+
return resolvePathSpec(trimmed);
|
|
69963
|
+
}
|
|
69964
|
+
if (looksLikeGit(trimmed)) {
|
|
69965
|
+
return resolveGitSpec(trimmed);
|
|
69966
|
+
}
|
|
69967
|
+
const bundled = resolveBundledDir(trimmed);
|
|
69968
|
+
if (bundled) {
|
|
69969
|
+
return {
|
|
69970
|
+
id: trimmed,
|
|
69971
|
+
kind: "bundled",
|
|
69972
|
+
dir: bundled,
|
|
69973
|
+
spec: trimmed,
|
|
69974
|
+
version: readPackageVersion(bundled),
|
|
69975
|
+
cleanupDirs: []
|
|
69976
|
+
};
|
|
69977
|
+
}
|
|
69978
|
+
if (looksLikeNpm(trimmed) && (trimmed.includes("@") || trimmed.includes("/"))) {
|
|
69979
|
+
return resolveNpmSpec(trimmed);
|
|
69980
|
+
}
|
|
69981
|
+
if (looksLikeNpm(trimmed)) {
|
|
69982
|
+
try {
|
|
69983
|
+
return resolveNpmSpec(trimmed);
|
|
69984
|
+
} catch (npmErr) {
|
|
69985
|
+
const available2 = listBundledPluginIds();
|
|
69986
|
+
const npmMessage = npmErr instanceof Error ? npmErr.message : String(npmErr);
|
|
69987
|
+
throw new Error(
|
|
69988
|
+
`Unknown plugin: ${trimmed}. Bundled: ${available2.join(", ") || "(none)"}. Or pass a path, npm package, or git URL. (${npmMessage})`
|
|
69989
|
+
);
|
|
69990
|
+
}
|
|
69991
|
+
}
|
|
69992
|
+
const available = listBundledPluginIds();
|
|
69993
|
+
throw new Error(
|
|
69994
|
+
`Unknown plugin: ${trimmed}. Bundled: ${available.join(", ") || "(none)"}. Or pass a path (./plugin), npm package (@org/pkg), or git URL (github:org/repo).`
|
|
69995
|
+
);
|
|
69996
|
+
}
|
|
69997
|
+
function listBundledPluginIds() {
|
|
69998
|
+
const root = path42.join(resolveTemplatesDir(), "plugins");
|
|
69999
|
+
if (!fs37.existsSync(root)) return [];
|
|
70000
|
+
return fs37.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path42.join(root, name))).sort();
|
|
70001
|
+
}
|
|
70002
|
+
function cleanupResolvedPlugin(source) {
|
|
70003
|
+
for (const dir of source.cleanupDirs) {
|
|
70004
|
+
fs37.rmSync(dir, { recursive: true, force: true });
|
|
70005
|
+
}
|
|
69567
70006
|
}
|
|
69568
70007
|
|
|
69569
70008
|
// src/harness/plugins.ts
|
|
69570
70009
|
init_schema2();
|
|
69571
70010
|
init_stages();
|
|
69572
|
-
var PLUGIN_IDS = ["playwright", "rocketsim", "kerno", "gitleaks", "trivy", "semgrep"];
|
|
69573
70011
|
var PluginManifestFileSchema = external_exports.object({
|
|
69574
70012
|
src: external_exports.string().min(1),
|
|
69575
70013
|
dest: external_exports.string().min(1),
|
|
69576
70014
|
executable: external_exports.boolean().optional(),
|
|
69577
70015
|
skipFlag: external_exports.string().optional()
|
|
69578
70016
|
});
|
|
70017
|
+
var PluginIdSchema = external_exports.string().min(1).regex(/^[a-z0-9][a-z0-9._-]*$/i, "Plugin id must be a slug (letters, digits, ._-)");
|
|
69579
70018
|
var PluginManifestSchema = external_exports.object({
|
|
69580
|
-
id:
|
|
69581
|
-
|
|
70019
|
+
id: PluginIdSchema,
|
|
70020
|
+
/** @deprecated Prefer `stages` — primary stage id for single-stage plugins. */
|
|
70021
|
+
stageId: external_exports.string().min(1).optional(),
|
|
69582
70022
|
verificationStages: external_exports.array(external_exports.string().min(1)).min(1),
|
|
69583
|
-
stage
|
|
70023
|
+
/** @deprecated Prefer `stages` — single stage object. */
|
|
70024
|
+
stage: external_exports.record(external_exports.unknown()).optional(),
|
|
70025
|
+
/** One or more stages registered by this plugin. */
|
|
70026
|
+
stages: external_exports.array(external_exports.record(external_exports.unknown())).optional(),
|
|
69584
70027
|
files: external_exports.array(PluginManifestFileSchema).min(1),
|
|
69585
70028
|
optionalFiles: external_exports.array(PluginManifestFileSchema).optional(),
|
|
69586
70029
|
merge: external_exports.record(external_exports.string()).optional(),
|
|
69587
70030
|
nextSteps: external_exports.array(external_exports.string().min(1)).min(1),
|
|
69588
70031
|
docsPath: external_exports.string().min(1)
|
|
70032
|
+
}).superRefine((data, ctx) => {
|
|
70033
|
+
const hasStages = Array.isArray(data.stages) && data.stages.length > 0;
|
|
70034
|
+
const hasLegacy = data.stage !== void 0 && data.stageId !== void 0;
|
|
70035
|
+
if (!hasStages && !hasLegacy) {
|
|
70036
|
+
ctx.addIssue({
|
|
70037
|
+
code: external_exports.ZodIssueCode.custom,
|
|
70038
|
+
message: "Plugin manifest requires `stages` (preferred) or legacy `stage` + `stageId`"
|
|
70039
|
+
});
|
|
70040
|
+
}
|
|
69589
70041
|
});
|
|
69590
|
-
function
|
|
69591
|
-
|
|
69592
|
-
|
|
70042
|
+
function normalizePluginStages(manifest) {
|
|
70043
|
+
if (manifest.stages && manifest.stages.length > 0) {
|
|
70044
|
+
return manifest.stages.map((s) => HarnessStageSchema.parse(s));
|
|
70045
|
+
}
|
|
70046
|
+
if (manifest.stage) {
|
|
70047
|
+
return [HarnessStageSchema.parse(manifest.stage)];
|
|
70048
|
+
}
|
|
70049
|
+
throw new Error(`Plugin ${manifest.id} has no stages`);
|
|
70050
|
+
}
|
|
70051
|
+
function primaryStageId(manifest) {
|
|
70052
|
+
const stages = normalizePluginStages(manifest);
|
|
70053
|
+
return manifest.stageId ?? stages[0].id;
|
|
70054
|
+
}
|
|
70055
|
+
function resolveBundledPluginDir(pluginId) {
|
|
70056
|
+
const dir = path43.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
70057
|
+
if (!fs38.existsSync(dir)) {
|
|
69593
70058
|
throw new Error(`Plugin not found: ${pluginId}. Run npm run build.`);
|
|
69594
70059
|
}
|
|
69595
70060
|
return dir;
|
|
69596
70061
|
}
|
|
69597
|
-
function
|
|
69598
|
-
const manifestPath =
|
|
70062
|
+
function readPluginManifestFromDir(pluginDir, expectedId) {
|
|
70063
|
+
const manifestPath = path43.join(pluginDir, "template.manifest.json");
|
|
70064
|
+
if (!fs38.existsSync(manifestPath)) {
|
|
70065
|
+
throw new Error(`No template.manifest.json in ${pluginDir}`);
|
|
70066
|
+
}
|
|
69599
70067
|
const parsed = PluginManifestSchema.safeParse(
|
|
69600
|
-
JSON.parse(
|
|
70068
|
+
JSON.parse(fs38.readFileSync(manifestPath, "utf8"))
|
|
69601
70069
|
);
|
|
69602
70070
|
if (!parsed.success) {
|
|
69603
|
-
throw new Error(`Invalid plugin manifest
|
|
70071
|
+
throw new Error(`Invalid plugin manifest: ${parsed.error.message}`);
|
|
69604
70072
|
}
|
|
69605
|
-
if (parsed.data.id !==
|
|
69606
|
-
throw new Error(`Plugin manifest id mismatch: expected ${
|
|
70073
|
+
if (expectedId && parsed.data.id !== expectedId) {
|
|
70074
|
+
throw new Error(`Plugin manifest id mismatch: expected ${expectedId}, got ${parsed.data.id}`);
|
|
69607
70075
|
}
|
|
69608
70076
|
return parsed.data;
|
|
69609
70077
|
}
|
|
70078
|
+
function readPluginManifest(pluginId) {
|
|
70079
|
+
return readPluginManifestFromDir(resolveBundledPluginDir(pluginId), pluginId);
|
|
70080
|
+
}
|
|
69610
70081
|
function ensureParentDir(filePath) {
|
|
69611
|
-
const parent =
|
|
69612
|
-
if (!
|
|
69613
|
-
|
|
70082
|
+
const parent = path43.dirname(filePath);
|
|
70083
|
+
if (!fs38.existsSync(parent)) {
|
|
70084
|
+
fs38.mkdirSync(parent, { recursive: true });
|
|
69614
70085
|
}
|
|
69615
70086
|
}
|
|
69616
70087
|
function copyPluginFile(pluginDir, file, repoPath, force) {
|
|
69617
|
-
const srcPath =
|
|
69618
|
-
const destPath =
|
|
69619
|
-
if (!
|
|
70088
|
+
const srcPath = path43.join(pluginDir, file.src);
|
|
70089
|
+
const destPath = path43.join(repoPath, file.dest);
|
|
70090
|
+
if (!fs38.existsSync(srcPath)) {
|
|
69620
70091
|
throw new Error(`Plugin file missing: ${file.src}`);
|
|
69621
70092
|
}
|
|
69622
|
-
if (
|
|
70093
|
+
if (fs38.existsSync(destPath) && !force) {
|
|
69623
70094
|
throw new Error(
|
|
69624
70095
|
`File already exists: ${file.dest}. Use --force to overwrite or remove it first.`
|
|
69625
70096
|
);
|
|
69626
70097
|
}
|
|
69627
70098
|
ensureParentDir(destPath);
|
|
69628
|
-
|
|
70099
|
+
fs38.copyFileSync(srcPath, destPath);
|
|
69629
70100
|
if (file.executable) {
|
|
69630
|
-
|
|
70101
|
+
fs38.chmodSync(destPath, 493);
|
|
69631
70102
|
}
|
|
69632
70103
|
return { written: true, path: file.dest };
|
|
69633
70104
|
}
|
|
69634
70105
|
function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
|
|
69635
|
-
const packagePath =
|
|
69636
|
-
if (!
|
|
70106
|
+
const packagePath = path43.join(repoPath, "package.json");
|
|
70107
|
+
if (!fs38.existsSync(packagePath)) {
|
|
69637
70108
|
throw new Error("No package.json in repo root. Add one before applying this plugin.");
|
|
69638
70109
|
}
|
|
69639
|
-
const fragmentPath =
|
|
69640
|
-
if (!
|
|
70110
|
+
const fragmentPath = path43.join(pluginDir, fragmentRelPath);
|
|
70111
|
+
if (!fs38.existsSync(fragmentPath)) {
|
|
69641
70112
|
throw new Error(`Package fragment missing: ${fragmentRelPath}`);
|
|
69642
70113
|
}
|
|
69643
|
-
const pkg = JSON.parse(
|
|
69644
|
-
const fragment = JSON.parse(
|
|
70114
|
+
const pkg = JSON.parse(fs38.readFileSync(packagePath, "utf8"));
|
|
70115
|
+
const fragment = JSON.parse(fs38.readFileSync(fragmentPath, "utf8"));
|
|
69645
70116
|
for (const section of ["scripts", "devDependencies"]) {
|
|
69646
70117
|
const existing = pkg[section] ?? {};
|
|
69647
70118
|
const incoming = fragment[section] ?? {};
|
|
@@ -69654,35 +70125,37 @@ function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
|
|
|
69654
70125
|
}
|
|
69655
70126
|
pkg[section] = existing;
|
|
69656
70127
|
}
|
|
69657
|
-
|
|
70128
|
+
fs38.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + "\n");
|
|
69658
70129
|
}
|
|
69659
|
-
function patchStageRegistry(repoPath,
|
|
70130
|
+
function patchStageRegistry(repoPath, stages, verificationStageIds, force) {
|
|
69660
70131
|
const registry2 = readStageRegistry(repoPath);
|
|
69661
|
-
|
|
69662
|
-
const
|
|
69663
|
-
|
|
69664
|
-
|
|
69665
|
-
|
|
69666
|
-
|
|
70132
|
+
let nextStages = [...registry2.stages];
|
|
70133
|
+
for (const stage of stages) {
|
|
70134
|
+
const existing = nextStages.find((s) => s.id === stage.id);
|
|
70135
|
+
if (existing && !force) {
|
|
70136
|
+
throw new Error(
|
|
70137
|
+
`Stage "${stage.id}" already registered in .har/stages.json. Use --force to replace.`
|
|
70138
|
+
);
|
|
70139
|
+
}
|
|
70140
|
+
nextStages = existing ? nextStages.map((s) => s.id === stage.id ? stage : s) : [...nextStages, stage];
|
|
69667
70141
|
}
|
|
69668
|
-
const stages = existing ? registry2.stages.map((s) => s.id === stage.id ? stage : s) : [...registry2.stages, stage];
|
|
69669
70142
|
const verificationStages = [...registry2.verificationStages ?? []];
|
|
69670
|
-
for (const id of
|
|
70143
|
+
for (const id of verificationStageIds) {
|
|
69671
70144
|
if (!verificationStages.includes(id)) {
|
|
69672
70145
|
verificationStages.push(id);
|
|
69673
70146
|
}
|
|
69674
70147
|
}
|
|
69675
|
-
const verifyIdx =
|
|
70148
|
+
const verifyIdx = nextStages.findIndex((s) => s.id === "verify");
|
|
69676
70149
|
if (verifyIdx >= 0) {
|
|
69677
|
-
|
|
69678
|
-
...
|
|
70150
|
+
nextStages[verifyIdx] = {
|
|
70151
|
+
...nextStages[verifyIdx],
|
|
69679
70152
|
description: `Verification pipeline (quick smoke by default; --full runs the registry's verificationStages: ${verificationStages.join(", ")})`,
|
|
69680
70153
|
acceptsArgs: ["--full"]
|
|
69681
70154
|
};
|
|
69682
70155
|
}
|
|
69683
70156
|
const updated = {
|
|
69684
70157
|
...registry2,
|
|
69685
|
-
stages,
|
|
70158
|
+
stages: nextStages,
|
|
69686
70159
|
verificationStages
|
|
69687
70160
|
};
|
|
69688
70161
|
writeStageRegistry(repoPath, updated);
|
|
@@ -69692,30 +70165,33 @@ function assertHarnessPresent(repoPath) {
|
|
|
69692
70165
|
throw new Error('No .har/ harness found. Run "har env init" first.');
|
|
69693
70166
|
}
|
|
69694
70167
|
}
|
|
69695
|
-
function
|
|
70168
|
+
function assertStagesNotPresent(repoPath, stageIds, force) {
|
|
69696
70169
|
if (force) return;
|
|
69697
|
-
const scriptPath = path40.join(repoPath, ".har", "stages", `${stageId}.sh`);
|
|
69698
|
-
if (fs35.existsSync(scriptPath)) {
|
|
69699
|
-
throw new Error(
|
|
69700
|
-
`Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
|
|
69701
|
-
);
|
|
69702
|
-
}
|
|
69703
70170
|
const registry2 = readStageRegistry(repoPath);
|
|
69704
|
-
|
|
69705
|
-
|
|
69706
|
-
|
|
69707
|
-
|
|
70171
|
+
for (const stageId of stageIds) {
|
|
70172
|
+
const scriptPath = path43.join(repoPath, ".har", "stages", `${stageId}.sh`);
|
|
70173
|
+
if (fs38.existsSync(scriptPath)) {
|
|
70174
|
+
throw new Error(
|
|
70175
|
+
`Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
|
|
70176
|
+
);
|
|
70177
|
+
}
|
|
70178
|
+
if (registry2.stages.some((s) => s.id === stageId)) {
|
|
70179
|
+
throw new Error(
|
|
70180
|
+
`Stage "${stageId}" already registered in .har/stages.json. Use --force to replace.`
|
|
70181
|
+
);
|
|
70182
|
+
}
|
|
69708
70183
|
}
|
|
69709
70184
|
}
|
|
69710
|
-
function
|
|
69711
|
-
const resolved =
|
|
70185
|
+
function applyPluginFromDir(repoPath, pluginDir, options, meta) {
|
|
70186
|
+
const resolved = path43.resolve(repoPath);
|
|
69712
70187
|
const force = options.force ?? false;
|
|
69713
70188
|
const warnings = [];
|
|
69714
70189
|
const filesWritten = [];
|
|
69715
70190
|
assertHarnessPresent(resolved);
|
|
69716
|
-
const manifest =
|
|
69717
|
-
|
|
69718
|
-
const
|
|
70191
|
+
const manifest = readPluginManifestFromDir(pluginDir);
|
|
70192
|
+
const stages = normalizePluginStages(manifest);
|
|
70193
|
+
const stageIds = stages.map((s) => s.id);
|
|
70194
|
+
assertStagesNotPresent(resolved, stageIds, force);
|
|
69719
70195
|
for (const file of manifest.files) {
|
|
69720
70196
|
const result = copyPluginFile(pluginDir, file, resolved, force);
|
|
69721
70197
|
if (result.written) {
|
|
@@ -69727,7 +70203,7 @@ function applyPlugin(repoPath, pluginId, options = {}) {
|
|
|
69727
70203
|
if (file.skipFlag === "skipCi" && options.skipCi) {
|
|
69728
70204
|
continue;
|
|
69729
70205
|
}
|
|
69730
|
-
if (
|
|
70206
|
+
if (fs38.existsSync(path43.join(resolved, file.dest)) && !force) {
|
|
69731
70207
|
warnings.push(`Skipped optional file (exists): ${file.dest}`);
|
|
69732
70208
|
continue;
|
|
69733
70209
|
}
|
|
@@ -69743,9 +70219,18 @@ function applyPlugin(repoPath, pluginId, options = {}) {
|
|
|
69743
70219
|
filesWritten.push("package.json");
|
|
69744
70220
|
}
|
|
69745
70221
|
}
|
|
69746
|
-
patchStageRegistry(resolved, manifest, force);
|
|
69747
|
-
|
|
69748
|
-
|
|
70222
|
+
patchStageRegistry(resolved, stages, manifest.verificationStages, force);
|
|
70223
|
+
upsertPluginLedgerEntry(resolved, {
|
|
70224
|
+
id: manifest.id,
|
|
70225
|
+
source: meta.source,
|
|
70226
|
+
spec: meta.spec,
|
|
70227
|
+
version: meta.version,
|
|
70228
|
+
stageIds,
|
|
70229
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
70230
|
+
});
|
|
70231
|
+
const primary = primaryStageId(manifest);
|
|
70232
|
+
success(`Applied plugin: ${manifest.id}`);
|
|
70233
|
+
info(`Registered stage(s): ${stageIds.join(", ")}`);
|
|
69749
70234
|
for (const file of filesWritten) {
|
|
69750
70235
|
info(` + ${file}`);
|
|
69751
70236
|
}
|
|
@@ -69753,50 +70238,88 @@ function applyPlugin(repoPath, pluginId, options = {}) {
|
|
|
69753
70238
|
warn(` \u26A0 ${warning}`);
|
|
69754
70239
|
}
|
|
69755
70240
|
return {
|
|
69756
|
-
pluginId,
|
|
69757
|
-
stageId:
|
|
70241
|
+
pluginId: manifest.id,
|
|
70242
|
+
stageId: primary,
|
|
70243
|
+
stageIds,
|
|
69758
70244
|
filesWritten,
|
|
69759
70245
|
warnings,
|
|
69760
70246
|
nextSteps: manifest.nextSteps,
|
|
69761
|
-
docsPath: manifest.docsPath
|
|
70247
|
+
docsPath: manifest.docsPath,
|
|
70248
|
+
source: meta.source
|
|
69762
70249
|
};
|
|
69763
70250
|
}
|
|
70251
|
+
function applyPlugin(repoPath, pluginSpec, options = {}) {
|
|
70252
|
+
const spec = options.spec ?? pluginSpec;
|
|
70253
|
+
const source = resolvePluginSource(spec);
|
|
70254
|
+
try {
|
|
70255
|
+
return applyPluginFromDir(repoPath, source.dir, options, {
|
|
70256
|
+
source: source.kind,
|
|
70257
|
+
spec: source.spec,
|
|
70258
|
+
version: source.version
|
|
70259
|
+
});
|
|
70260
|
+
} finally {
|
|
70261
|
+
cleanupResolvedPlugin(source);
|
|
70262
|
+
}
|
|
70263
|
+
}
|
|
69764
70264
|
function listPluginIds() {
|
|
69765
|
-
|
|
69766
|
-
if (!fs35.existsSync(root)) return [...PLUGIN_IDS];
|
|
69767
|
-
return fs35.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => PLUGIN_IDS.includes(name));
|
|
70265
|
+
return listBundledPluginIds();
|
|
69768
70266
|
}
|
|
69769
70267
|
|
|
69770
70268
|
// src/harness/plugin-drift.ts
|
|
69771
70269
|
init_stages();
|
|
69772
70270
|
var PACKAGE_SECTIONS = ["scripts", "devDependencies"];
|
|
69773
70271
|
function detectInstalledPlugins(repoPath) {
|
|
69774
|
-
const resolved =
|
|
69775
|
-
const
|
|
69776
|
-
if (
|
|
70272
|
+
const resolved = path44.resolve(repoPath);
|
|
70273
|
+
const ledger = readPluginLedger(resolved);
|
|
70274
|
+
if (ledger && ledger.plugins.length > 0) {
|
|
70275
|
+
return ledger.plugins.map((p) => p.id).sort();
|
|
70276
|
+
}
|
|
70277
|
+
const registryPath = path44.join(resolved, ".har", "stages.json");
|
|
70278
|
+
if (!fs39.existsSync(registryPath)) return [];
|
|
69777
70279
|
const registry2 = readStageRegistry(resolved);
|
|
69778
70280
|
const stageIds = new Set(registry2.stages.map((stage) => stage.id));
|
|
69779
70281
|
const installed = [];
|
|
69780
|
-
for (const pluginId of
|
|
69781
|
-
|
|
69782
|
-
|
|
69783
|
-
|
|
70282
|
+
for (const pluginId of listPluginIds()) {
|
|
70283
|
+
try {
|
|
70284
|
+
const manifest = readPluginManifest(pluginId);
|
|
70285
|
+
const primary = primaryStageId(manifest);
|
|
70286
|
+
if (stageIds.has(primary)) {
|
|
70287
|
+
installed.push(pluginId);
|
|
70288
|
+
}
|
|
70289
|
+
} catch {
|
|
69784
70290
|
}
|
|
69785
70291
|
}
|
|
69786
|
-
return installed;
|
|
70292
|
+
return installed.sort();
|
|
69787
70293
|
}
|
|
69788
70294
|
function pluginTemplatePath(pluginId, srcRel) {
|
|
69789
|
-
return
|
|
70295
|
+
return path44.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
|
|
70296
|
+
}
|
|
70297
|
+
function resolvePluginTemplateDir(repoPath, pluginId) {
|
|
70298
|
+
const ledger = readPluginLedger(repoPath);
|
|
70299
|
+
const entry = ledger?.plugins.find((p) => p.id === pluginId);
|
|
70300
|
+
if (entry && entry.source !== "bundled") {
|
|
70301
|
+
try {
|
|
70302
|
+
const source = resolvePluginSource(entry.spec);
|
|
70303
|
+
cleanupResolvedPlugin(source);
|
|
70304
|
+
} catch {
|
|
70305
|
+
}
|
|
70306
|
+
}
|
|
70307
|
+
const bundled = path44.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
70308
|
+
if (fs39.existsSync(path44.join(bundled, "template.manifest.json"))) {
|
|
70309
|
+
return bundled;
|
|
70310
|
+
}
|
|
70311
|
+
return null;
|
|
69790
70312
|
}
|
|
69791
70313
|
function readBundledPluginFile(pluginId, srcRel) {
|
|
69792
|
-
return
|
|
70314
|
+
return fs39.readFileSync(pluginTemplatePath(pluginId, srcRel), "utf8");
|
|
69793
70315
|
}
|
|
69794
70316
|
function listPluginDestPaths(pluginId, repoPath) {
|
|
69795
|
-
const
|
|
70317
|
+
const templateDir = resolvePluginTemplateDir(repoPath, pluginId);
|
|
70318
|
+
const manifest = templateDir ? readPluginManifestFromDir(templateDir) : readPluginManifest(pluginId);
|
|
69796
70319
|
const paths = manifest.files.map((file) => file.dest);
|
|
69797
70320
|
if (manifest.optionalFiles) {
|
|
69798
70321
|
for (const file of manifest.optionalFiles) {
|
|
69799
|
-
if (
|
|
70322
|
+
if (fs39.existsSync(path44.join(repoPath, file.dest))) {
|
|
69800
70323
|
paths.push(file.dest);
|
|
69801
70324
|
}
|
|
69802
70325
|
}
|
|
@@ -69855,9 +70378,9 @@ function readTemplatePluginFile(pluginId, dest) {
|
|
|
69855
70378
|
return null;
|
|
69856
70379
|
}
|
|
69857
70380
|
function readInstalledPluginFile(repoPath, pluginId, dest) {
|
|
69858
|
-
const installedPath =
|
|
69859
|
-
if (!
|
|
69860
|
-
const content =
|
|
70381
|
+
const installedPath = path44.join(path44.resolve(repoPath), dest);
|
|
70382
|
+
if (!fs39.existsSync(installedPath)) return null;
|
|
70383
|
+
const content = fs39.readFileSync(installedPath, "utf8");
|
|
69861
70384
|
const manifest = readPluginManifest(pluginId);
|
|
69862
70385
|
const fragmentRel = manifest.merge?.[dest];
|
|
69863
70386
|
if (fragmentRel) {
|
|
@@ -69876,7 +70399,7 @@ function pluginActionHint(pluginId, dest, kind) {
|
|
|
69876
70399
|
}
|
|
69877
70400
|
function comparePluginToTemplate(repoPath, pluginId) {
|
|
69878
70401
|
const manifest = readPluginManifest(pluginId);
|
|
69879
|
-
const resolved =
|
|
70402
|
+
const resolved = path44.resolve(repoPath);
|
|
69880
70403
|
const destPaths = listPluginDestPaths(pluginId, resolved);
|
|
69881
70404
|
const missing = [];
|
|
69882
70405
|
const checksumMismatch = [];
|
|
@@ -69891,8 +70414,8 @@ function comparePluginToTemplate(repoPath, pluginId) {
|
|
|
69891
70414
|
}
|
|
69892
70415
|
if (dest === "package.json") {
|
|
69893
70416
|
const fragmentRel = manifest.merge?.[dest];
|
|
69894
|
-
const installedPath =
|
|
69895
|
-
const installedRaw =
|
|
70417
|
+
const installedPath = path44.join(resolved, dest);
|
|
70418
|
+
const installedRaw = fs39.readFileSync(installedPath, "utf8");
|
|
69896
70419
|
if (fragmentRel && pluginKeysMatch(installedRaw, readBundledPluginFile(pluginId, fragmentRel))) {
|
|
69897
70420
|
unchanged.push(dest);
|
|
69898
70421
|
} else if (computeFileChecksum(installedContent) === computeFileChecksum(templateContent)) {
|
|
@@ -69910,16 +70433,17 @@ function comparePluginToTemplate(repoPath, pluginId) {
|
|
|
69910
70433
|
}
|
|
69911
70434
|
return {
|
|
69912
70435
|
pluginId,
|
|
69913
|
-
stageId: manifest
|
|
70436
|
+
stageId: primaryStageId(manifest),
|
|
69914
70437
|
missing,
|
|
69915
70438
|
checksumMismatch,
|
|
69916
70439
|
unchanged
|
|
69917
70440
|
};
|
|
69918
70441
|
}
|
|
69919
70442
|
function compareInstalledPluginsToTemplate(repoPath) {
|
|
69920
|
-
return detectInstalledPlugins(repoPath).
|
|
69921
|
-
(
|
|
69922
|
-
|
|
70443
|
+
return detectInstalledPlugins(repoPath).filter((pluginId) => {
|
|
70444
|
+
const bundled = path44.join(resolveTemplatesDir(), "plugins", pluginId, "template.manifest.json");
|
|
70445
|
+
return fs39.existsSync(bundled);
|
|
70446
|
+
}).map((pluginId) => comparePluginToTemplate(repoPath, pluginId));
|
|
69923
70447
|
}
|
|
69924
70448
|
function buildPluginDriftActions(repoPath, pluginDrift) {
|
|
69925
70449
|
const actions = [];
|
|
@@ -69952,23 +70476,18 @@ function buildPluginDriftActions(repoPath, pluginDrift) {
|
|
|
69952
70476
|
|
|
69953
70477
|
// src/harness/maintain-bundle.ts
|
|
69954
70478
|
var MAINTAIN_DIR = "maintain";
|
|
69955
|
-
var PROFILE_DIRS3 = {
|
|
69956
|
-
default: "har-boilerplate",
|
|
69957
|
-
cli: "har-boilerplate-cli",
|
|
69958
|
-
ios: "har-boilerplate-ios"
|
|
69959
|
-
};
|
|
69960
70479
|
function substituteProjectName2(content, projectName) {
|
|
69961
70480
|
return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
|
|
69962
70481
|
}
|
|
69963
70482
|
function projectNameFromRepo(repoPath) {
|
|
69964
|
-
return
|
|
70483
|
+
return path45.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
69965
70484
|
}
|
|
69966
70485
|
function boilerplateDirForProfile(profile) {
|
|
69967
|
-
return
|
|
70486
|
+
return path45.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
|
|
69968
70487
|
}
|
|
69969
70488
|
function readBundledTemplateContent(repoPath, profile, file) {
|
|
69970
|
-
const templatePath =
|
|
69971
|
-
let content =
|
|
70489
|
+
const templatePath = path45.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
|
|
70490
|
+
let content = fs40.readFileSync(templatePath, "utf8");
|
|
69972
70491
|
if (file === "harness.env") {
|
|
69973
70492
|
content = substituteProjectName2(content, projectNameFromRepo(repoPath));
|
|
69974
70493
|
}
|
|
@@ -69999,12 +70518,12 @@ function actionHint(file, kind) {
|
|
|
69999
70518
|
return `Read maintain/diffs/${file}.diff and merge into .har/${file}.`;
|
|
70000
70519
|
}
|
|
70001
70520
|
function createUnifiedDiff(installedContent, templateContent, installedLabel, templateLabel) {
|
|
70002
|
-
const tmpDir =
|
|
70521
|
+
const tmpDir = fs40.mkdtempSync(path45.join(os16.tmpdir(), "har-maintain-diff-"));
|
|
70003
70522
|
try {
|
|
70004
|
-
const installedPath =
|
|
70005
|
-
const templatePath =
|
|
70006
|
-
|
|
70007
|
-
|
|
70523
|
+
const installedPath = path45.join(tmpDir, "installed");
|
|
70524
|
+
const templatePath = path45.join(tmpDir, "template");
|
|
70525
|
+
fs40.writeFileSync(installedPath, installedContent);
|
|
70526
|
+
fs40.writeFileSync(templatePath, templateContent);
|
|
70008
70527
|
const result = run(`diff -u "${installedPath}" "${templatePath}"`);
|
|
70009
70528
|
const body = result.stdout.trim();
|
|
70010
70529
|
if (!body) return "";
|
|
@@ -70013,7 +70532,7 @@ function createUnifiedDiff(installedContent, templateContent, installedLabel, te
|
|
|
70013
70532
|
${body.split("\n").slice(2).join("\n")}
|
|
70014
70533
|
`;
|
|
70015
70534
|
} finally {
|
|
70016
|
-
|
|
70535
|
+
fs40.rmSync(tmpDir, { recursive: true, force: true });
|
|
70017
70536
|
}
|
|
70018
70537
|
}
|
|
70019
70538
|
function buildActions(repoPath, profile, drift) {
|
|
@@ -70028,7 +70547,7 @@ function buildActions(repoPath, profile, drift) {
|
|
|
70028
70547
|
});
|
|
70029
70548
|
}
|
|
70030
70549
|
for (const file of drift.checksumMismatch) {
|
|
70031
|
-
const installedPath =
|
|
70550
|
+
const installedPath = path45.join(harnessDir, file);
|
|
70032
70551
|
const installedRel = `maintain/installed/${file}`;
|
|
70033
70552
|
const templateRel = `maintain/templates/${file}`;
|
|
70034
70553
|
const diffRel = `maintain/diffs/${file}.diff`;
|
|
@@ -70036,7 +70555,7 @@ function buildActions(repoPath, profile, drift) {
|
|
|
70036
70555
|
file,
|
|
70037
70556
|
kind: "drift",
|
|
70038
70557
|
template: templateRel,
|
|
70039
|
-
installed:
|
|
70558
|
+
installed: fs40.existsSync(installedPath) ? installedRel : void 0,
|
|
70040
70559
|
diff: diffRel,
|
|
70041
70560
|
hint: actionHint(file, "drift")
|
|
70042
70561
|
});
|
|
@@ -70188,28 +70707,28 @@ function buildReadme(report) {
|
|
|
70188
70707
|
}
|
|
70189
70708
|
function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
70190
70709
|
const harnessDir = getHarnessDir(repoPath);
|
|
70191
|
-
const bundleDir =
|
|
70192
|
-
if (
|
|
70193
|
-
|
|
70710
|
+
const bundleDir = path45.join(harnessDir, MAINTAIN_DIR);
|
|
70711
|
+
if (fs40.existsSync(bundleDir)) {
|
|
70712
|
+
fs40.rmSync(bundleDir, { recursive: true, force: true });
|
|
70194
70713
|
}
|
|
70195
70714
|
const dirs = [
|
|
70196
70715
|
bundleDir,
|
|
70197
|
-
|
|
70198
|
-
|
|
70199
|
-
|
|
70200
|
-
|
|
70716
|
+
path45.join(bundleDir, "templates"),
|
|
70717
|
+
path45.join(bundleDir, "installed"),
|
|
70718
|
+
path45.join(bundleDir, "diffs"),
|
|
70719
|
+
path45.join(bundleDir, "stale")
|
|
70201
70720
|
];
|
|
70202
70721
|
for (const dir of dirs) {
|
|
70203
|
-
|
|
70722
|
+
fs40.mkdirSync(dir, { recursive: true });
|
|
70204
70723
|
}
|
|
70205
70724
|
const affectedFiles = [...drift.missing, ...drift.checksumMismatch];
|
|
70206
70725
|
for (const file of affectedFiles) {
|
|
70207
70726
|
const templateContent = readBundledTemplateContent(repoPath, profile, file);
|
|
70208
|
-
writeFileSafe(
|
|
70209
|
-
const harnessPath =
|
|
70210
|
-
if (
|
|
70211
|
-
const installedContent =
|
|
70212
|
-
writeFileSafe(
|
|
70727
|
+
writeFileSafe(path45.join(bundleDir, "templates", file), templateContent);
|
|
70728
|
+
const harnessPath = path45.join(harnessDir, file);
|
|
70729
|
+
if (fs40.existsSync(harnessPath)) {
|
|
70730
|
+
const installedContent = fs40.readFileSync(harnessPath, "utf8");
|
|
70731
|
+
writeFileSafe(path45.join(bundleDir, "installed", file), installedContent);
|
|
70213
70732
|
const diff = createUnifiedDiff(
|
|
70214
70733
|
installedContent,
|
|
70215
70734
|
templateContent,
|
|
@@ -70217,14 +70736,14 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
70217
70736
|
`templates/${file}`
|
|
70218
70737
|
);
|
|
70219
70738
|
if (diff) {
|
|
70220
|
-
writeFileSafe(
|
|
70739
|
+
writeFileSafe(path45.join(bundleDir, "diffs", `${file}.diff`), diff);
|
|
70221
70740
|
}
|
|
70222
70741
|
}
|
|
70223
70742
|
}
|
|
70224
|
-
writeFileSafe(
|
|
70225
|
-
writeFileSafe(
|
|
70743
|
+
writeFileSafe(path45.join(bundleDir, "README.md"), buildReadme(report));
|
|
70744
|
+
writeFileSafe(path45.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
|
|
70226
70745
|
writeFileSafe(
|
|
70227
|
-
|
|
70746
|
+
path45.join(bundleDir, "validation.json"),
|
|
70228
70747
|
JSON.stringify(report.validation, null, 2) + "\n"
|
|
70229
70748
|
);
|
|
70230
70749
|
if (report.stale.length > 0) {
|
|
@@ -70236,34 +70755,34 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
70236
70755
|
...report.stale.map((s) => `- **${s.file}** \u2014 ${s.hint}`),
|
|
70237
70756
|
""
|
|
70238
70757
|
];
|
|
70239
|
-
writeFileSafe(
|
|
70758
|
+
writeFileSafe(path45.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
|
|
70240
70759
|
}
|
|
70241
70760
|
return bundleDir;
|
|
70242
70761
|
}
|
|
70243
70762
|
function ensureParentDir2(filePath) {
|
|
70244
|
-
const parent =
|
|
70245
|
-
if (!
|
|
70246
|
-
|
|
70763
|
+
const parent = path45.dirname(filePath);
|
|
70764
|
+
if (!fs40.existsSync(parent)) {
|
|
70765
|
+
fs40.mkdirSync(parent, { recursive: true });
|
|
70247
70766
|
}
|
|
70248
70767
|
}
|
|
70249
70768
|
function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
70250
70769
|
if (report.pluginActions.length === 0) return;
|
|
70251
70770
|
for (const action of report.pluginActions) {
|
|
70252
|
-
const pluginRoot =
|
|
70253
|
-
const templatesDir =
|
|
70254
|
-
const installedDir =
|
|
70255
|
-
const diffsDir =
|
|
70771
|
+
const pluginRoot = path45.join(bundleDir, "plugins", action.pluginId);
|
|
70772
|
+
const templatesDir = path45.join(pluginRoot, "templates");
|
|
70773
|
+
const installedDir = path45.join(pluginRoot, "installed");
|
|
70774
|
+
const diffsDir = path45.join(pluginRoot, "diffs");
|
|
70256
70775
|
for (const dir of [templatesDir, installedDir, diffsDir]) {
|
|
70257
|
-
|
|
70776
|
+
fs40.mkdirSync(dir, { recursive: true });
|
|
70258
70777
|
}
|
|
70259
70778
|
const templateContent = readTemplatePluginFile(action.pluginId, action.file);
|
|
70260
70779
|
if (templateContent === null) continue;
|
|
70261
|
-
const templatePath =
|
|
70780
|
+
const templatePath = path45.join(templatesDir, action.file);
|
|
70262
70781
|
ensureParentDir2(templatePath);
|
|
70263
70782
|
writeFileSafe(templatePath, templateContent);
|
|
70264
70783
|
const installedContent = readInstalledPluginFile(repoPath, action.pluginId, action.file);
|
|
70265
70784
|
if (installedContent !== null) {
|
|
70266
|
-
const installedPath =
|
|
70785
|
+
const installedPath = path45.join(installedDir, action.file);
|
|
70267
70786
|
ensureParentDir2(installedPath);
|
|
70268
70787
|
writeFileSafe(installedPath, installedContent);
|
|
70269
70788
|
const diff = createUnifiedDiff(
|
|
@@ -70273,7 +70792,7 @@ function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
|
70273
70792
|
`templates/${action.file}`
|
|
70274
70793
|
);
|
|
70275
70794
|
if (diff) {
|
|
70276
|
-
const diffPath =
|
|
70795
|
+
const diffPath = path45.join(diffsDir, `${action.file}.diff`);
|
|
70277
70796
|
ensureParentDir2(diffPath);
|
|
70278
70797
|
writeFileSafe(diffPath, diff);
|
|
70279
70798
|
}
|
|
@@ -70309,9 +70828,9 @@ function buildMaintainBundle(repoPath, validation2, drift) {
|
|
|
70309
70828
|
return { bundleDir, report };
|
|
70310
70829
|
}
|
|
70311
70830
|
function removeMaintainBundle(repoPath) {
|
|
70312
|
-
const bundleDir =
|
|
70313
|
-
if (
|
|
70314
|
-
|
|
70831
|
+
const bundleDir = path45.join(getHarnessDir(repoPath), MAINTAIN_DIR);
|
|
70832
|
+
if (fs40.existsSync(bundleDir)) {
|
|
70833
|
+
fs40.rmSync(bundleDir, { recursive: true, force: true });
|
|
70315
70834
|
}
|
|
70316
70835
|
}
|
|
70317
70836
|
function formatMaintainBundlePromptSection(report) {
|
|
@@ -70400,11 +70919,11 @@ init_manifest();
|
|
|
70400
70919
|
init_stages();
|
|
70401
70920
|
function listHarnessScripts(repoPath) {
|
|
70402
70921
|
const harnessDir = getHarnessDir(repoPath);
|
|
70403
|
-
if (!
|
|
70404
|
-
return
|
|
70922
|
+
if (!fs41.existsSync(harnessDir)) return [];
|
|
70923
|
+
return fs41.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
|
|
70405
70924
|
}
|
|
70406
70925
|
function describeProject(repoPath) {
|
|
70407
|
-
const resolved =
|
|
70926
|
+
const resolved = path46.resolve(repoPath);
|
|
70408
70927
|
const manifest = readManifest(resolved);
|
|
70409
70928
|
const present = harnessExists(resolved);
|
|
70410
70929
|
return {
|
|
@@ -70424,8 +70943,8 @@ function describeProject(repoPath) {
|
|
|
70424
70943
|
};
|
|
70425
70944
|
}
|
|
70426
70945
|
async function initHarness(options) {
|
|
70427
|
-
const repoPath =
|
|
70428
|
-
if (!
|
|
70946
|
+
const repoPath = path46.resolve(options.repoPath);
|
|
70947
|
+
if (!fs41.existsSync(repoPath)) {
|
|
70429
70948
|
throw new Error(`Path not found: ${repoPath}`);
|
|
70430
70949
|
}
|
|
70431
70950
|
const scaffold = scaffoldHarnessBoilerplate(repoPath, {
|
|
@@ -70445,9 +70964,9 @@ async function initHarness(options) {
|
|
|
70445
70964
|
};
|
|
70446
70965
|
}
|
|
70447
70966
|
async function maintainHarness(options) {
|
|
70448
|
-
const repoPath =
|
|
70967
|
+
const repoPath = path46.resolve(options.repoPath);
|
|
70449
70968
|
const harnessDir = getHarnessDir(repoPath);
|
|
70450
|
-
if (!
|
|
70969
|
+
if (!fs41.existsSync(harnessDir)) {
|
|
70451
70970
|
throw new Error('No .har/ found. Run "har env init" first.');
|
|
70452
70971
|
}
|
|
70453
70972
|
const drift = compareHarnessToTemplate(repoPath);
|
|
@@ -70482,13 +71001,13 @@ function addPlugin(repoPath, pluginId, options = {}) {
|
|
|
70482
71001
|
}
|
|
70483
71002
|
|
|
70484
71003
|
// src/harness/custom-stage.ts
|
|
70485
|
-
var
|
|
70486
|
-
var
|
|
71004
|
+
var fs42 = __toESM(require("fs"));
|
|
71005
|
+
var path47 = __toESM(require("path"));
|
|
70487
71006
|
init_schema2();
|
|
70488
71007
|
init_stages();
|
|
70489
71008
|
var STAGE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
70490
71009
|
function addCustomStage(repoPath, options) {
|
|
70491
|
-
const resolved =
|
|
71010
|
+
const resolved = path47.resolve(repoPath);
|
|
70492
71011
|
if (!harnessExists(resolved)) {
|
|
70493
71012
|
throw new Error('No .har/ harness found. Run "har env init" first.');
|
|
70494
71013
|
}
|
|
@@ -70525,20 +71044,20 @@ function addCustomStage(repoPath, options) {
|
|
|
70525
71044
|
if (options.command) {
|
|
70526
71045
|
stage.command = options.command;
|
|
70527
71046
|
} else {
|
|
70528
|
-
const scriptRel =
|
|
70529
|
-
const scriptAbs =
|
|
70530
|
-
if (
|
|
71047
|
+
const scriptRel = path47.join("stages", `${id}.sh`);
|
|
71048
|
+
const scriptAbs = path47.join(resolved, ".har", scriptRel);
|
|
71049
|
+
if (fs42.existsSync(scriptAbs) && !options.force) {
|
|
70531
71050
|
throw new Error(`Stage script already exists: .har/${scriptRel}. Use --force to overwrite.`);
|
|
70532
71051
|
}
|
|
70533
|
-
const skeletonPath =
|
|
71052
|
+
const skeletonPath = path47.join(
|
|
70534
71053
|
resolveTemplatesDir(),
|
|
70535
71054
|
"plugins",
|
|
70536
71055
|
"custom-stage-skeleton.sh"
|
|
70537
71056
|
);
|
|
70538
|
-
const skeleton =
|
|
70539
|
-
|
|
70540
|
-
|
|
70541
|
-
|
|
71057
|
+
const skeleton = fs42.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
|
|
71058
|
+
fs42.mkdirSync(path47.dirname(scriptAbs), { recursive: true });
|
|
71059
|
+
fs42.writeFileSync(scriptAbs, skeleton);
|
|
71060
|
+
fs42.chmodSync(scriptAbs, 493);
|
|
70542
71061
|
filesWritten.push(`.har/${scriptRel}`);
|
|
70543
71062
|
stage.script = scriptRel;
|
|
70544
71063
|
stage.artifacts = [
|
|
@@ -70586,18 +71105,18 @@ function addCustomStage(repoPath, options) {
|
|
|
70586
71105
|
}
|
|
70587
71106
|
|
|
70588
71107
|
// src/harness/adaptation-prompt.ts
|
|
70589
|
-
var
|
|
70590
|
-
var
|
|
71108
|
+
var fs43 = __toESM(require("fs"));
|
|
71109
|
+
var path48 = __toESM(require("path"));
|
|
70591
71110
|
var readline5 = __toESM(require("readline"));
|
|
70592
71111
|
|
|
70593
71112
|
// src/utils/clipboard.ts
|
|
70594
|
-
var
|
|
71113
|
+
var import_child_process11 = require("child_process");
|
|
70595
71114
|
function commandExists2(command2) {
|
|
70596
|
-
const probe = process.platform === "win32" ? (0,
|
|
71115
|
+
const probe = process.platform === "win32" ? (0, import_child_process11.spawnSync)("where", [command2], { encoding: "utf8", stdio: ["ignore", "ignore", "ignore"] }) : (0, import_child_process11.spawnSync)("which", [command2], { encoding: "utf8", stdio: ["ignore", "ignore", "ignore"] });
|
|
70597
71116
|
return probe.status === 0;
|
|
70598
71117
|
}
|
|
70599
71118
|
function tryPipeCommand(command2, args, text) {
|
|
70600
|
-
const result = (0,
|
|
71119
|
+
const result = (0, import_child_process11.spawnSync)(command2, args, {
|
|
70601
71120
|
input: text,
|
|
70602
71121
|
encoding: "utf8",
|
|
70603
71122
|
stdio: ["pipe", "ignore", "ignore"]
|
|
@@ -70617,7 +71136,7 @@ function copyViaPlatformTools(text) {
|
|
|
70617
71136
|
}
|
|
70618
71137
|
if (process.platform === "win32") {
|
|
70619
71138
|
if (commandExists2("powershell")) {
|
|
70620
|
-
const result = (0,
|
|
71139
|
+
const result = (0, import_child_process11.spawnSync)(
|
|
70621
71140
|
"powershell",
|
|
70622
71141
|
[
|
|
70623
71142
|
"-NoProfile",
|
|
@@ -70677,7 +71196,7 @@ function loadTemplate(name) {
|
|
|
70677
71196
|
if (!filePath) {
|
|
70678
71197
|
throw new Error(`Adaptation prompt template not found: ${name}. Run npm run build.`);
|
|
70679
71198
|
}
|
|
70680
|
-
return
|
|
71199
|
+
return fs43.readFileSync(filePath, "utf8");
|
|
70681
71200
|
}
|
|
70682
71201
|
function applyProfilePlaceholders(content, profile) {
|
|
70683
71202
|
return content.replace(/\{\{PROFILE\}\}/g, profile).replace(/\{\{PROFILE_HINT\}\}/g, PROFILE_HINTS[profile]);
|
|
@@ -70699,7 +71218,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
|
|
|
70699
71218
|
}
|
|
70700
71219
|
function writeAdaptationPrompt(repoPath, content) {
|
|
70701
71220
|
const harnessDir = getHarnessDir(repoPath);
|
|
70702
|
-
const filePath =
|
|
71221
|
+
const filePath = path48.join(harnessDir, ADAPTATION_PROMPT_FILE);
|
|
70703
71222
|
writeFileSafe(filePath, content);
|
|
70704
71223
|
return filePath;
|
|
70705
71224
|
}
|
|
@@ -70718,12 +71237,12 @@ function printAdaptationPrompt(content) {
|
|
|
70718
71237
|
}
|
|
70719
71238
|
function askYesNo2(question) {
|
|
70720
71239
|
const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
|
|
70721
|
-
return new Promise((
|
|
71240
|
+
return new Promise((resolve50) => {
|
|
70722
71241
|
process.stderr.write(`${question} `);
|
|
70723
71242
|
rl.once("line", (answer) => {
|
|
70724
71243
|
rl.close();
|
|
70725
71244
|
const trimmed = answer.trim();
|
|
70726
|
-
|
|
71245
|
+
resolve50(trimmed === "" || /^y(es)?$/i.test(trimmed));
|
|
70727
71246
|
});
|
|
70728
71247
|
});
|
|
70729
71248
|
}
|
|
@@ -70754,27 +71273,27 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
|
|
|
70754
71273
|
}
|
|
70755
71274
|
|
|
70756
71275
|
// src/harness/cursor-rule.ts
|
|
70757
|
-
var
|
|
70758
|
-
var
|
|
71276
|
+
var fs44 = __toESM(require("fs"));
|
|
71277
|
+
var path49 = __toESM(require("path"));
|
|
70759
71278
|
var readline6 = __toESM(require("readline"));
|
|
70760
71279
|
init_file_ops();
|
|
70761
71280
|
init_logging();
|
|
70762
71281
|
var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
|
|
70763
71282
|
function getCursorRulePath(repoPath) {
|
|
70764
|
-
return
|
|
71283
|
+
return path49.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
|
|
70765
71284
|
}
|
|
70766
71285
|
function isCursorWorkspace(repoPath) {
|
|
70767
|
-
return
|
|
71286
|
+
return fs44.existsSync(path49.join(repoPath, ".cursor"));
|
|
70768
71287
|
}
|
|
70769
71288
|
function cursorRuleExists(repoPath) {
|
|
70770
|
-
return
|
|
71289
|
+
return fs44.existsSync(getCursorRulePath(repoPath));
|
|
70771
71290
|
}
|
|
70772
71291
|
function scaffoldCursorRule(repoPath) {
|
|
70773
71292
|
const templatePath = resolveTemplateFile("cursor-rule.mdc.template");
|
|
70774
71293
|
if (!templatePath) {
|
|
70775
71294
|
throw new Error("Cursor rule template not found (cursor-rule.mdc.template). Run npm run build.");
|
|
70776
71295
|
}
|
|
70777
|
-
const content =
|
|
71296
|
+
const content = fs44.readFileSync(templatePath, "utf8");
|
|
70778
71297
|
writeFileSafe(getCursorRulePath(repoPath), content);
|
|
70779
71298
|
}
|
|
70780
71299
|
async function handleCursorRule(options) {
|
|
@@ -70812,16 +71331,16 @@ async function promptScaffoldCursorRule(exists) {
|
|
|
70812
71331
|
}
|
|
70813
71332
|
async function askYesNo3(question) {
|
|
70814
71333
|
const rl = readline6.createInterface({ input: process.stdin, output: process.stderr });
|
|
70815
|
-
return new Promise((
|
|
71334
|
+
return new Promise((resolve50) => {
|
|
70816
71335
|
process.stderr.write(`${question} `);
|
|
70817
71336
|
rl.once("line", (answer) => {
|
|
70818
71337
|
rl.close();
|
|
70819
71338
|
const trimmed = answer.trim();
|
|
70820
71339
|
if (trimmed === "") {
|
|
70821
|
-
|
|
71340
|
+
resolve50(true);
|
|
70822
71341
|
return;
|
|
70823
71342
|
}
|
|
70824
|
-
|
|
71343
|
+
resolve50(/^y(es)?$/i.test(trimmed));
|
|
70825
71344
|
});
|
|
70826
71345
|
});
|
|
70827
71346
|
}
|
|
@@ -70863,8 +71382,8 @@ init_validation();
|
|
|
70863
71382
|
init_control_config();
|
|
70864
71383
|
|
|
70865
71384
|
// src/core/control-lifecycle.ts
|
|
70866
|
-
var
|
|
70867
|
-
var
|
|
71385
|
+
var import_child_process12 = require("child_process");
|
|
71386
|
+
var path50 = __toESM(require("path"));
|
|
70868
71387
|
|
|
70869
71388
|
// src/core/control-image.ts
|
|
70870
71389
|
var DEFAULT_CONTROL_IMAGE = "theosfactory/har-control";
|
|
@@ -70890,10 +71409,10 @@ var CONTROL_DATA_VOLUME = "har_control_data";
|
|
|
70890
71409
|
var CONTROL_CONTAINER_PORT = 3847;
|
|
70891
71410
|
var CONTROL_DATA_DB_URL = "file:/data/har_control.db";
|
|
70892
71411
|
function resolveControlDir() {
|
|
70893
|
-
return
|
|
71412
|
+
return path50.resolve(__dirname, "..", "control");
|
|
70894
71413
|
}
|
|
70895
71414
|
function resolveControlBuildContext() {
|
|
70896
|
-
return
|
|
71415
|
+
return path50.resolve(resolveControlDir(), "..");
|
|
70897
71416
|
}
|
|
70898
71417
|
function buildDockerRunArgs(options) {
|
|
70899
71418
|
const name = options.containerName ?? CONTROL_CONTAINER_NAME;
|
|
@@ -70916,7 +71435,7 @@ function buildDockerRunArgs(options) {
|
|
|
70916
71435
|
return args;
|
|
70917
71436
|
}
|
|
70918
71437
|
function runDocker(args) {
|
|
70919
|
-
const result = (0,
|
|
71438
|
+
const result = (0, import_child_process12.spawnSync)("docker", args, {
|
|
70920
71439
|
stdio: "inherit",
|
|
70921
71440
|
env: process.env
|
|
70922
71441
|
});
|
|
@@ -70926,7 +71445,7 @@ function runDocker(args) {
|
|
|
70926
71445
|
return result.status ?? 1;
|
|
70927
71446
|
}
|
|
70928
71447
|
function controlContainerExists(name = CONTROL_CONTAINER_NAME) {
|
|
70929
|
-
const result = (0,
|
|
71448
|
+
const result = (0, import_child_process12.spawnSync)("docker", ["ps", "-aq", "-f", `name=^${name}$`], {
|
|
70930
71449
|
encoding: "utf8",
|
|
70931
71450
|
stdio: ["pipe", "pipe", "ignore"]
|
|
70932
71451
|
});
|
|
@@ -70949,7 +71468,7 @@ async function startMissionControl(options) {
|
|
|
70949
71468
|
"-t",
|
|
70950
71469
|
imageRef,
|
|
70951
71470
|
"-f",
|
|
70952
|
-
|
|
71471
|
+
path50.join(resolveControlDir(), "Dockerfile"),
|
|
70953
71472
|
resolveControlBuildContext()
|
|
70954
71473
|
]);
|
|
70955
71474
|
if (buildCode !== 0) {
|
|
@@ -71096,7 +71615,7 @@ async function ensureTelemetryInfrastructure(options) {
|
|
|
71096
71615
|
// src/core/run-service.ts
|
|
71097
71616
|
init_telemetry_config();
|
|
71098
71617
|
init_telemetry_env();
|
|
71099
|
-
var
|
|
71618
|
+
var path52 = __toESM(require("path"));
|
|
71100
71619
|
init_local_executor();
|
|
71101
71620
|
function extractShellOutput(result) {
|
|
71102
71621
|
const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
|
|
@@ -71261,7 +71780,8 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
|
|
|
71261
71780
|
source: options.source,
|
|
71262
71781
|
sourceUrl: options.sourceUrl,
|
|
71263
71782
|
title: options.title,
|
|
71264
|
-
parentWorkUnitId: options.parentWorkUnitId
|
|
71783
|
+
parentWorkUnitId: options.parentWorkUnitId,
|
|
71784
|
+
relatedLinks: options.relatedLinks
|
|
71265
71785
|
});
|
|
71266
71786
|
createWorkAttempt(harnessRoot, {
|
|
71267
71787
|
attemptId,
|
|
@@ -71301,12 +71821,12 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
|
|
|
71301
71821
|
suffix: session.suffix,
|
|
71302
71822
|
createdAt: session.createdAt
|
|
71303
71823
|
});
|
|
71304
|
-
const envFile =
|
|
71824
|
+
const envFile = path52.join(session.workDir, `.env.agent.${options.agentId}`);
|
|
71305
71825
|
try {
|
|
71306
71826
|
appendTelemetryEnvToFile(envFile, {
|
|
71307
71827
|
sessionKey,
|
|
71308
71828
|
agentId: options.agentId,
|
|
71309
|
-
repoPath:
|
|
71829
|
+
repoPath: path52.resolve(options.repoPath),
|
|
71310
71830
|
workDir: session.workDir,
|
|
71311
71831
|
branch: session.branch,
|
|
71312
71832
|
suffix: session.suffix,
|
|
@@ -71538,21 +72058,319 @@ var getEnvironmentLogs = defaultRunService.getEnvironmentLogs.bind(defaultRunSer
|
|
|
71538
72058
|
|
|
71539
72059
|
// src/cli/commands/env.ts
|
|
71540
72060
|
init_runs();
|
|
72061
|
+
init_work_units();
|
|
72062
|
+
init_manifest();
|
|
71541
72063
|
init_slot_status();
|
|
71542
72064
|
|
|
72065
|
+
// src/core/cleanup-service.ts
|
|
72066
|
+
var fs46 = __toESM(require("fs"));
|
|
72067
|
+
var os18 = __toESM(require("os"));
|
|
72068
|
+
var path53 = __toESM(require("path"));
|
|
72069
|
+
var import_child_process14 = require("child_process");
|
|
72070
|
+
init_control_sync();
|
|
72071
|
+
init_control_repo_path();
|
|
72072
|
+
init_slot_status();
|
|
72073
|
+
init_manifest();
|
|
72074
|
+
var DEFAULT_STALE_DAYS = 7;
|
|
72075
|
+
function getWorktreesRoot() {
|
|
72076
|
+
if (process.env.HAR_WORKTREES_ROOT) {
|
|
72077
|
+
return path53.resolve(process.env.HAR_WORKTREES_ROOT);
|
|
72078
|
+
}
|
|
72079
|
+
return path53.join(process.env.HOME || os18.homedir(), "worktrees");
|
|
72080
|
+
}
|
|
72081
|
+
function runGit3(cwd, args) {
|
|
72082
|
+
try {
|
|
72083
|
+
return (0, import_child_process14.execSync)(`git ${args}`, {
|
|
72084
|
+
cwd,
|
|
72085
|
+
encoding: "utf8",
|
|
72086
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
72087
|
+
}).trim();
|
|
72088
|
+
} catch {
|
|
72089
|
+
return void 0;
|
|
72090
|
+
}
|
|
72091
|
+
}
|
|
72092
|
+
function basenameRepo(repoPath) {
|
|
72093
|
+
return path53.basename(canonicalizeControlRepoPath(repoPath));
|
|
72094
|
+
}
|
|
72095
|
+
function ageDaysFrom(iso) {
|
|
72096
|
+
if (!iso) return void 0;
|
|
72097
|
+
const created = Date.parse(iso);
|
|
72098
|
+
if (Number.isNaN(created)) return void 0;
|
|
72099
|
+
return Math.floor((Date.now() - created) / (24 * 60 * 60 * 1e3));
|
|
72100
|
+
}
|
|
72101
|
+
function matchesKeep(candidate, keep) {
|
|
72102
|
+
if (!keep?.length) return false;
|
|
72103
|
+
for (const pin of keep) {
|
|
72104
|
+
if (pin.worktreePath && candidate.worktreePath) {
|
|
72105
|
+
if (path53.resolve(pin.worktreePath) === path53.resolve(candidate.worktreePath)) return true;
|
|
72106
|
+
}
|
|
72107
|
+
if (pin.repoPath && pin.agentId !== void 0 && candidate.agentId !== void 0) {
|
|
72108
|
+
const repo = canonicalizeControlRepoPath(pin.repoPath);
|
|
72109
|
+
const candidateRepo = path53.resolve(candidate.repoPath);
|
|
72110
|
+
if ((repo === candidateRepo || path53.resolve(pin.repoPath) === candidateRepo) && pin.agentId === candidate.agentId) {
|
|
72111
|
+
return true;
|
|
72112
|
+
}
|
|
72113
|
+
}
|
|
72114
|
+
if (pin.repoPath && pin.agentId === void 0 && !pin.worktreePath) {
|
|
72115
|
+
if (canonicalizeControlRepoPath(pin.repoPath) === candidate.repoPath) return true;
|
|
72116
|
+
}
|
|
72117
|
+
}
|
|
72118
|
+
return false;
|
|
72119
|
+
}
|
|
72120
|
+
function classifySlotCandidate(repoPath, projectName, slot, options) {
|
|
72121
|
+
if (!slot.active && !slot.worktreePath) return void 0;
|
|
72122
|
+
const candidate = {
|
|
72123
|
+
kind: "active_slot",
|
|
72124
|
+
repoPath,
|
|
72125
|
+
projectName,
|
|
72126
|
+
agentId: slot.agentId,
|
|
72127
|
+
worktreePath: slot.worktreePath ?? slot.workDir,
|
|
72128
|
+
branch: slot.branch,
|
|
72129
|
+
active: slot.active,
|
|
72130
|
+
dirty: slot.dirty,
|
|
72131
|
+
ageDays: ageDaysFrom(slot.sessionCreatedAt),
|
|
72132
|
+
sessionCreatedAt: slot.sessionCreatedAt,
|
|
72133
|
+
recommendation: "review",
|
|
72134
|
+
reason: "active session"
|
|
72135
|
+
};
|
|
72136
|
+
if (matchesKeep(candidate, options?.keep)) {
|
|
72137
|
+
candidate.recommendation = "keep";
|
|
72138
|
+
candidate.reason = "pinned with --keep";
|
|
72139
|
+
return candidate;
|
|
72140
|
+
}
|
|
72141
|
+
if (slot.dirty) {
|
|
72142
|
+
candidate.recommendation = "review";
|
|
72143
|
+
candidate.reason = "uncommitted changes \u2014 review before teardown";
|
|
72144
|
+
return candidate;
|
|
72145
|
+
}
|
|
72146
|
+
if (slot.sessionStatus === "failed" || slot.sessionStatus === "starting") {
|
|
72147
|
+
candidate.recommendation = "review";
|
|
72148
|
+
candidate.reason = "failed or resumable session \u2014 recover or teardown manually";
|
|
72149
|
+
return candidate;
|
|
72150
|
+
}
|
|
72151
|
+
const staleDays = options?.staleDays ?? DEFAULT_STALE_DAYS;
|
|
72152
|
+
const age = candidate.ageDays;
|
|
72153
|
+
if (age !== void 0 && age >= staleDays) {
|
|
72154
|
+
candidate.recommendation = "teardown";
|
|
72155
|
+
candidate.reason = `idle ${age}d, clean`;
|
|
72156
|
+
return candidate;
|
|
72157
|
+
}
|
|
72158
|
+
if (slot.active) {
|
|
72159
|
+
candidate.recommendation = "review";
|
|
72160
|
+
candidate.reason = age !== void 0 ? `active session (${age}d) \u2014 keep unless finished` : "active session \u2014 keep unless finished";
|
|
72161
|
+
}
|
|
72162
|
+
return candidate;
|
|
72163
|
+
}
|
|
72164
|
+
function resolveRepoForWorktree(worktreePath) {
|
|
72165
|
+
if (!fs46.existsSync(worktreePath)) return void 0;
|
|
72166
|
+
const commonDir = runGit3(worktreePath, "rev-parse --git-common-dir");
|
|
72167
|
+
if (!commonDir) return void 0;
|
|
72168
|
+
const gitRoot = path53.resolve(worktreePath, commonDir, "..");
|
|
72169
|
+
if (!readManifest(gitRoot)) return void 0;
|
|
72170
|
+
return canonicalizeControlRepoPath(gitRoot);
|
|
72171
|
+
}
|
|
72172
|
+
function discoverOrphanWorktrees(knownPaths) {
|
|
72173
|
+
const worktreesRoot = getWorktreesRoot();
|
|
72174
|
+
if (!fs46.existsSync(worktreesRoot)) return [];
|
|
72175
|
+
const orphans = [];
|
|
72176
|
+
for (const entry of fs46.readdirSync(worktreesRoot, { withFileTypes: true })) {
|
|
72177
|
+
if (!entry.isDirectory() || !entry.name.includes("-har-agent-")) continue;
|
|
72178
|
+
const worktreePath = path53.resolve(path53.join(worktreesRoot, entry.name));
|
|
72179
|
+
if (knownPaths.has(worktreePath)) continue;
|
|
72180
|
+
const repoPath = resolveRepoForWorktree(worktreePath) ?? worktreesRoot;
|
|
72181
|
+
const porcelain = runGit3(worktreePath, "status --porcelain");
|
|
72182
|
+
const dirty = porcelain !== void 0 ? porcelain.length > 0 : void 0;
|
|
72183
|
+
const branch = runGit3(worktreePath, "rev-parse --abbrev-ref HEAD");
|
|
72184
|
+
orphans.push({
|
|
72185
|
+
kind: "orphan_worktree",
|
|
72186
|
+
repoPath,
|
|
72187
|
+
projectName: basenameRepo(repoPath),
|
|
72188
|
+
worktreePath,
|
|
72189
|
+
branch: branch && branch !== "HEAD" ? branch : void 0,
|
|
72190
|
+
active: false,
|
|
72191
|
+
dirty,
|
|
72192
|
+
recommendation: dirty ? "review" : "remove_orphan",
|
|
72193
|
+
reason: dirty ? "orphan worktree with uncommitted changes" : "orphan worktree \u2014 no slot registry"
|
|
72194
|
+
});
|
|
72195
|
+
}
|
|
72196
|
+
return orphans.sort((a, b2) => (a.worktreePath ?? "").localeCompare(b2.worktreePath ?? ""));
|
|
72197
|
+
}
|
|
72198
|
+
async function discoverCleanupCandidates(options = {}) {
|
|
72199
|
+
const repoPaths = options.repoPaths ?? await discoverHarRepos({ cwd: options.cwd ?? process.cwd() });
|
|
72200
|
+
const candidates = [];
|
|
72201
|
+
const knownWorktreePaths = /* @__PURE__ */ new Set();
|
|
72202
|
+
for (const repoPath of repoPaths) {
|
|
72203
|
+
if (!fs46.existsSync(repoPath) || !readManifest(repoPath)) continue;
|
|
72204
|
+
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
72205
|
+
const canonicalRepo = canonicalizeControlRepoPath(harnessRoot);
|
|
72206
|
+
const status = collectEnvironmentStatus(harnessRoot);
|
|
72207
|
+
const projectName = basenameRepo(harnessRoot);
|
|
72208
|
+
for (const slot of status.slots) {
|
|
72209
|
+
if (slot.worktreePath) knownWorktreePaths.add(path53.resolve(slot.worktreePath));
|
|
72210
|
+
if (slot.workDir) knownWorktreePaths.add(path53.resolve(slot.workDir));
|
|
72211
|
+
const candidate = classifySlotCandidate(canonicalRepo, projectName, slot, {
|
|
72212
|
+
staleDays: options.staleDays,
|
|
72213
|
+
keep: options.keep
|
|
72214
|
+
});
|
|
72215
|
+
if (!candidate) continue;
|
|
72216
|
+
if (candidate.recommendation === "review" && !options.includeReview) {
|
|
72217
|
+
}
|
|
72218
|
+
candidates.push(candidate);
|
|
72219
|
+
}
|
|
72220
|
+
}
|
|
72221
|
+
if (options.orphans !== false) {
|
|
72222
|
+
for (const orphan of discoverOrphanWorktrees(knownWorktreePaths)) {
|
|
72223
|
+
if (matchesKeep(orphan, options.keep)) {
|
|
72224
|
+
orphan.recommendation = "keep";
|
|
72225
|
+
orphan.reason = "pinned with --keep";
|
|
72226
|
+
}
|
|
72227
|
+
candidates.push(orphan);
|
|
72228
|
+
}
|
|
72229
|
+
}
|
|
72230
|
+
return {
|
|
72231
|
+
candidates: candidates.sort((a, b2) => {
|
|
72232
|
+
const repo = a.repoPath.localeCompare(b2.repoPath);
|
|
72233
|
+
if (repo !== 0) return repo;
|
|
72234
|
+
return (a.agentId ?? 0) - (b2.agentId ?? 0);
|
|
72235
|
+
}),
|
|
72236
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
72237
|
+
};
|
|
72238
|
+
}
|
|
72239
|
+
function selectAutoApprovedCandidates(plan, options) {
|
|
72240
|
+
return plan.candidates.filter((candidate) => {
|
|
72241
|
+
if (candidate.recommendation === "keep") return false;
|
|
72242
|
+
if (candidate.recommendation === "review") return options?.includeReview === true;
|
|
72243
|
+
return candidate.recommendation === "teardown" || candidate.recommendation === "remove_orphan";
|
|
72244
|
+
});
|
|
72245
|
+
}
|
|
72246
|
+
function formatCleanupPlan(plan) {
|
|
72247
|
+
if (plan.candidates.length === 0) {
|
|
72248
|
+
return "No session worktrees or orphans found.";
|
|
72249
|
+
}
|
|
72250
|
+
const lines2 = [];
|
|
72251
|
+
lines2.push(
|
|
72252
|
+
`${"REC".padEnd(8)} ${"REPO".padEnd(18)} ${"SLOT".padEnd(6)} ${"AGE".padEnd(5)} WORKTREE / REASON`
|
|
72253
|
+
);
|
|
72254
|
+
lines2.push("-".repeat(100));
|
|
72255
|
+
for (const candidate of plan.candidates) {
|
|
72256
|
+
const slot = candidate.agentId !== void 0 ? String(candidate.agentId) : "-";
|
|
72257
|
+
const age = candidate.ageDays !== void 0 ? `${candidate.ageDays}d` : "-";
|
|
72258
|
+
const target = candidate.worktreePath ?? candidate.repoPath;
|
|
72259
|
+
lines2.push(
|
|
72260
|
+
`${candidate.recommendation.padEnd(8)} ${candidate.projectName.padEnd(18)} ${slot.padEnd(6)} ${age.padEnd(5)} ${target}`
|
|
72261
|
+
);
|
|
72262
|
+
lines2.push(` ${candidate.reason}`);
|
|
72263
|
+
}
|
|
72264
|
+
return lines2.join("\n");
|
|
72265
|
+
}
|
|
72266
|
+
async function askYesNo4(question) {
|
|
72267
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
72268
|
+
const readline8 = await import("readline");
|
|
72269
|
+
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
72270
|
+
const answer = await new Promise((resolve50) => {
|
|
72271
|
+
rl.question(question, resolve50);
|
|
72272
|
+
});
|
|
72273
|
+
rl.close();
|
|
72274
|
+
return /^[Yy]$/.test(answer.trim());
|
|
72275
|
+
}
|
|
72276
|
+
async function confirmCleanupSelection(candidates) {
|
|
72277
|
+
if (candidates.length === 0) return [];
|
|
72278
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
72279
|
+
throw new Error("Non-interactive terminal \u2014 pass --yes (and optionally --include-review)");
|
|
72280
|
+
}
|
|
72281
|
+
const approved = [];
|
|
72282
|
+
for (const candidate of candidates) {
|
|
72283
|
+
if (candidate.recommendation === "keep") continue;
|
|
72284
|
+
const label = candidate.kind === "orphan_worktree" ? `orphan ${candidate.worktreePath}` : `${candidate.projectName} agent ${candidate.agentId}`;
|
|
72285
|
+
const action = candidate.recommendation === "remove_orphan" ? "remove" : "teardown";
|
|
72286
|
+
const ok = await askYesNo4(`${action} ${label}? [${candidate.recommendation === "teardown" || candidate.recommendation === "remove_orphan" ? "Y" : "y"}/n] `);
|
|
72287
|
+
if (ok) approved.push(candidate);
|
|
72288
|
+
}
|
|
72289
|
+
return approved;
|
|
72290
|
+
}
|
|
72291
|
+
async function executeCleanupCandidates(candidates, options = {}) {
|
|
72292
|
+
const service = createRunService();
|
|
72293
|
+
const outcomes = [];
|
|
72294
|
+
for (const candidate of candidates) {
|
|
72295
|
+
if (candidate.recommendation === "keep") continue;
|
|
72296
|
+
if (options.dryRun) {
|
|
72297
|
+
outcomes.push({ candidate, ok: true });
|
|
72298
|
+
continue;
|
|
72299
|
+
}
|
|
72300
|
+
try {
|
|
72301
|
+
if (candidate.kind === "active_slot" && candidate.agentId !== void 0) {
|
|
72302
|
+
const result = await service.teardownEnvironment({
|
|
72303
|
+
repoPath: candidate.repoPath,
|
|
72304
|
+
agentId: candidate.agentId,
|
|
72305
|
+
capture: false,
|
|
72306
|
+
trigger: "cli"
|
|
72307
|
+
});
|
|
72308
|
+
outcomes.push({
|
|
72309
|
+
candidate,
|
|
72310
|
+
ok: result.code === 0,
|
|
72311
|
+
error: result.code === 0 ? void 0 : result.stderr?.trim() || `exit ${result.code}`
|
|
72312
|
+
});
|
|
72313
|
+
continue;
|
|
72314
|
+
}
|
|
72315
|
+
if (candidate.kind === "orphan_worktree" && candidate.worktreePath) {
|
|
72316
|
+
if (fs46.existsSync(candidate.worktreePath)) {
|
|
72317
|
+
const repoRoot = candidate.repoPath !== getWorktreesRoot() ? candidate.repoPath : resolveRepoForWorktree(candidate.worktreePath);
|
|
72318
|
+
if (repoRoot) {
|
|
72319
|
+
try {
|
|
72320
|
+
(0, import_child_process14.execSync)(`git worktree remove --force ${JSON.stringify(candidate.worktreePath)}`, {
|
|
72321
|
+
cwd: repoRoot,
|
|
72322
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
72323
|
+
});
|
|
72324
|
+
} catch {
|
|
72325
|
+
}
|
|
72326
|
+
}
|
|
72327
|
+
if (fs46.existsSync(candidate.worktreePath)) {
|
|
72328
|
+
fs46.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
72329
|
+
}
|
|
72330
|
+
}
|
|
72331
|
+
outcomes.push({ candidate, ok: true });
|
|
72332
|
+
continue;
|
|
72333
|
+
}
|
|
72334
|
+
outcomes.push({ candidate, ok: false, error: "unsupported candidate" });
|
|
72335
|
+
} catch (err) {
|
|
72336
|
+
outcomes.push({
|
|
72337
|
+
candidate,
|
|
72338
|
+
ok: false,
|
|
72339
|
+
error: err instanceof Error ? err.message : String(err)
|
|
72340
|
+
});
|
|
72341
|
+
}
|
|
72342
|
+
}
|
|
72343
|
+
return outcomes;
|
|
72344
|
+
}
|
|
72345
|
+
function parseCleanupKeepPins(values) {
|
|
72346
|
+
if (!values?.length) return [];
|
|
72347
|
+
return values.map((raw) => {
|
|
72348
|
+
const agentMatch = raw.match(/^(.+):(\d+)$/);
|
|
72349
|
+
if (agentMatch) {
|
|
72350
|
+
return { repoPath: agentMatch[1], agentId: Number(agentMatch[2]) };
|
|
72351
|
+
}
|
|
72352
|
+
if (raw.startsWith("/") || raw.startsWith("~")) {
|
|
72353
|
+
return {
|
|
72354
|
+
worktreePath: raw.startsWith("~") ? path53.join(process.env.HOME || os18.homedir(), raw.slice(2)) : path53.resolve(raw)
|
|
72355
|
+
};
|
|
72356
|
+
}
|
|
72357
|
+
return { repoPath: raw };
|
|
72358
|
+
});
|
|
72359
|
+
}
|
|
72360
|
+
|
|
71543
72361
|
// src/core/commit-gate-onboarding.ts
|
|
71544
72362
|
var readline7 = __toESM(require("readline"));
|
|
71545
72363
|
init_hooks();
|
|
71546
72364
|
init_stages();
|
|
71547
72365
|
init_logging();
|
|
71548
|
-
function
|
|
72366
|
+
function askYesNo5(question) {
|
|
71549
72367
|
const rl = readline7.createInterface({ input: process.stdin, output: process.stderr });
|
|
71550
|
-
return new Promise((
|
|
72368
|
+
return new Promise((resolve50) => {
|
|
71551
72369
|
process.stderr.write(`${question} `);
|
|
71552
72370
|
rl.once("line", (answer) => {
|
|
71553
72371
|
rl.close();
|
|
71554
72372
|
const trimmed = answer.trim();
|
|
71555
|
-
|
|
72373
|
+
resolve50(trimmed === "" || /^y(es)?$/i.test(trimmed));
|
|
71556
72374
|
});
|
|
71557
72375
|
});
|
|
71558
72376
|
}
|
|
@@ -71577,7 +72395,7 @@ async function handleCommitGateOnboarding(options) {
|
|
|
71577
72395
|
const status = getHooksStatus(options.repoPath);
|
|
71578
72396
|
let shouldInstall = status.preCommitInstalled || status.postCommitInstalled || options.install === "always" || options.autoYes === true;
|
|
71579
72397
|
if (!shouldInstall && options.install === "prompt" && process.stdin.isTTY && process.stdout.isTTY) {
|
|
71580
|
-
shouldInstall = await
|
|
72398
|
+
shouldInstall = await askYesNo5("Install the HAR commit gate for this repository? [Y/n]");
|
|
71581
72399
|
}
|
|
71582
72400
|
if (!shouldInstall) {
|
|
71583
72401
|
info("Commit gate is not installed; run `har hooks install` when ready.");
|
|
@@ -71594,21 +72412,21 @@ async function handleCommitGateOnboarding(options) {
|
|
|
71594
72412
|
}
|
|
71595
72413
|
|
|
71596
72414
|
// src/core/onboarding-preferences.ts
|
|
71597
|
-
var
|
|
71598
|
-
var
|
|
71599
|
-
var
|
|
72415
|
+
var fs47 = __toESM(require("fs"));
|
|
72416
|
+
var os19 = __toESM(require("os"));
|
|
72417
|
+
var path54 = __toESM(require("path"));
|
|
71600
72418
|
init_schema2();
|
|
71601
72419
|
function getOnboardingPreferencesPath() {
|
|
71602
72420
|
if (process.env.HAR_PREFERENCES_PATH) {
|
|
71603
|
-
return
|
|
72421
|
+
return path54.resolve(process.env.HAR_PREFERENCES_PATH);
|
|
71604
72422
|
}
|
|
71605
|
-
return
|
|
72423
|
+
return path54.join(os19.homedir(), ".har", "preferences.json");
|
|
71606
72424
|
}
|
|
71607
72425
|
function readOnboardingPreferences() {
|
|
71608
72426
|
const preferencePath = getOnboardingPreferencesPath();
|
|
71609
72427
|
try {
|
|
71610
|
-
if (!
|
|
71611
|
-
return OnboardingPreferencesSchema.parse(JSON.parse(
|
|
72428
|
+
if (!fs47.existsSync(preferencePath)) return OnboardingPreferencesSchema.parse({});
|
|
72429
|
+
return OnboardingPreferencesSchema.parse(JSON.parse(fs47.readFileSync(preferencePath, "utf8")));
|
|
71612
72430
|
} catch {
|
|
71613
72431
|
return OnboardingPreferencesSchema.parse({});
|
|
71614
72432
|
}
|
|
@@ -71633,8 +72451,8 @@ function writeOnboardingPreferences(overrides) {
|
|
|
71633
72451
|
};
|
|
71634
72452
|
const parsed = OnboardingPreferencesSchema.parse(preference);
|
|
71635
72453
|
const preferencePath = getOnboardingPreferencesPath();
|
|
71636
|
-
|
|
71637
|
-
|
|
72454
|
+
fs47.mkdirSync(path54.dirname(preferencePath), { recursive: true });
|
|
72455
|
+
fs47.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
|
|
71638
72456
|
`);
|
|
71639
72457
|
return parsed;
|
|
71640
72458
|
}
|
|
@@ -71698,6 +72516,14 @@ feature branch.
|
|
|
71698
72516
|
Failed launch: har env recover 1 # or: har env launch 1 --resume`;
|
|
71699
72517
|
|
|
71700
72518
|
// src/cli/commands/env.ts
|
|
72519
|
+
var workLinkOptions = (y) => y.option("repo", { type: "string", default: ".", describe: "Path to the repository" }).option("work-id", {
|
|
72520
|
+
type: "string",
|
|
72521
|
+
demandOption: true,
|
|
72522
|
+
describe: "Repo-scoped work unit id (same as --work-id at launch)"
|
|
72523
|
+
}).option("link", {
|
|
72524
|
+
type: "string",
|
|
72525
|
+
describe: "Link as source|url or source|url|label"
|
|
72526
|
+
}).option("source", { type: "string", describe: "Tracker provider (e.g. github, jira)" }).option("url", { type: "string", describe: "Canonical URL for the link" }).option("label", { type: "string", describe: "Optional display label" });
|
|
71701
72527
|
var envCommand = {
|
|
71702
72528
|
command: "env <subcommand>",
|
|
71703
72529
|
describe: "Manage agent environments (launch \u2192 verify \u2192 complete)",
|
|
@@ -71768,14 +72594,14 @@ var envCommand = {
|
|
|
71768
72594
|
handleMaintain
|
|
71769
72595
|
).command(
|
|
71770
72596
|
"add-plugin [plugin]",
|
|
71771
|
-
|
|
72597
|
+
"Install a verification plugin (bundled id, path, npm package, or git URL) that registers stages",
|
|
71772
72598
|
(y) => y.positional("plugin", {
|
|
71773
72599
|
type: "string",
|
|
71774
|
-
describe:
|
|
72600
|
+
describe: "Bundled plugin id, local path (./plugin), npm package (@org/pkg), or git URL (github:org/repo)"
|
|
71775
72601
|
}).option("list", {
|
|
71776
72602
|
type: "boolean",
|
|
71777
72603
|
default: false,
|
|
71778
|
-
describe: "List
|
|
72604
|
+
describe: "List bundled plugins and exit"
|
|
71779
72605
|
}).option("repo", { type: "string", default: ".", describe: "Path to the repository" }).option("force", {
|
|
71780
72606
|
type: "boolean",
|
|
71781
72607
|
default: false,
|
|
@@ -71791,7 +72617,7 @@ var envCommand = {
|
|
|
71791
72617
|
`Register a custom stage (--custom), or install a plugin (deprecated alias for add-plugin)`,
|
|
71792
72618
|
(y) => y.positional("template", {
|
|
71793
72619
|
type: "string",
|
|
71794
|
-
describe:
|
|
72620
|
+
describe: "Custom stage id with --custom, or a plugin id / path / npm / git spec as a deprecated alias"
|
|
71795
72621
|
}).option("list", {
|
|
71796
72622
|
type: "boolean",
|
|
71797
72623
|
default: false,
|
|
@@ -71857,8 +72683,17 @@ var envCommand = {
|
|
|
71857
72683
|
}).option("parent-work-id", {
|
|
71858
72684
|
type: "string",
|
|
71859
72685
|
describe: "Optional parent work unit identifier"
|
|
72686
|
+
}).option("work-link", {
|
|
72687
|
+
type: "array",
|
|
72688
|
+
string: true,
|
|
72689
|
+
describe: "Additional tracker link: source|url or source|url|label (repeatable)"
|
|
71860
72690
|
}).epilog(LAUNCH_EPILOG),
|
|
71861
72691
|
handleLaunch
|
|
72692
|
+
).command(
|
|
72693
|
+
"work-link",
|
|
72694
|
+
"Append a related external link to an existing work unit",
|
|
72695
|
+
workLinkOptions,
|
|
72696
|
+
handleWorkLink
|
|
71862
72697
|
).command(
|
|
71863
72698
|
"recover <id>",
|
|
71864
72699
|
"Resume a failed or partial launch (alias for launch --resume)",
|
|
@@ -71897,6 +72732,38 @@ var envCommand = {
|
|
|
71897
72732
|
"Show status of all running agents",
|
|
71898
72733
|
(y) => y.option("repo", { type: "string", default: "." }).option("json", { type: "boolean", default: false, describe: "Structured JSON output" }),
|
|
71899
72734
|
handleStatus
|
|
72735
|
+
).command(
|
|
72736
|
+
"cleanup",
|
|
72737
|
+
"Discover stale session worktrees across registered repos and tear them down",
|
|
72738
|
+
(y) => y.option("repo", {
|
|
72739
|
+
type: "string",
|
|
72740
|
+
describe: "Limit cleanup scan to one repository path"
|
|
72741
|
+
}).option("dry-run", {
|
|
72742
|
+
type: "boolean",
|
|
72743
|
+
default: false,
|
|
72744
|
+
describe: "Show the cleanup plan without executing"
|
|
72745
|
+
}).option("yes", {
|
|
72746
|
+
alias: "y",
|
|
72747
|
+
type: "boolean",
|
|
72748
|
+
default: false,
|
|
72749
|
+
describe: "Approve teardown/remove for recommended rows without prompting"
|
|
72750
|
+
}).option("keep", {
|
|
72751
|
+
type: "string",
|
|
72752
|
+
describe: "Pin sessions to keep (comma-separated repoPath:agentId or worktree paths)"
|
|
72753
|
+
}).option("stale", {
|
|
72754
|
+
type: "number",
|
|
72755
|
+
default: 7,
|
|
72756
|
+
describe: "Age in days before a clean idle session is recommended for teardown"
|
|
72757
|
+
}).option("orphans", {
|
|
72758
|
+
type: "boolean",
|
|
72759
|
+
default: true,
|
|
72760
|
+
describe: "Include orphan worktree directories under ~/worktrees"
|
|
72761
|
+
}).option("include-review", {
|
|
72762
|
+
type: "boolean",
|
|
72763
|
+
default: false,
|
|
72764
|
+
describe: "With --yes, also teardown/remove rows marked review (dirty or recent active)"
|
|
72765
|
+
}).option("json", { type: "boolean", default: false, describe: "Structured JSON output" }),
|
|
72766
|
+
handleCleanup
|
|
71900
72767
|
).command(
|
|
71901
72768
|
"runs",
|
|
71902
72769
|
"Inspect harness run history",
|
|
@@ -71919,13 +72786,13 @@ var envCommand = {
|
|
|
71919
72786
|
}
|
|
71920
72787
|
).demandCommand(
|
|
71921
72788
|
1,
|
|
71922
|
-
"Please specify a subcommand: init, maintain, add-stage, launch, recover, verify, complete, teardown, status, runs"
|
|
72789
|
+
"Please specify a subcommand: init, maintain, add-stage, launch, recover, verify, complete, teardown, status, cleanup, runs"
|
|
71923
72790
|
).epilog(HAR_ENV_EPILOG),
|
|
71924
72791
|
handler: () => {
|
|
71925
72792
|
}
|
|
71926
72793
|
};
|
|
71927
72794
|
async function handleInit(argv) {
|
|
71928
|
-
const repoPath =
|
|
72795
|
+
const repoPath = path55.resolve(argv.repo);
|
|
71929
72796
|
const onboarding = resolveOnboardingOptions(argv);
|
|
71930
72797
|
header("har env init");
|
|
71931
72798
|
info(`Repository: ${repoPath}`);
|
|
@@ -71971,7 +72838,7 @@ async function handleInit(argv) {
|
|
|
71971
72838
|
}
|
|
71972
72839
|
}
|
|
71973
72840
|
async function handleMaintain(argv) {
|
|
71974
|
-
const repoPath =
|
|
72841
|
+
const repoPath = path55.resolve(argv.repo);
|
|
71975
72842
|
const onboarding = resolveOnboardingOptions(argv);
|
|
71976
72843
|
header("har env maintain");
|
|
71977
72844
|
info(`Repository: ${repoPath}`);
|
|
@@ -72102,7 +72969,7 @@ async function applyAgentIntegrations(options) {
|
|
|
72102
72969
|
}
|
|
72103
72970
|
}
|
|
72104
72971
|
async function handleAddPlugin(argv) {
|
|
72105
|
-
const repoPath =
|
|
72972
|
+
const repoPath = path55.resolve(argv.repo);
|
|
72106
72973
|
const available = listPluginIds();
|
|
72107
72974
|
if (argv.list) {
|
|
72108
72975
|
for (const id of available) {
|
|
@@ -72110,9 +72977,9 @@ async function handleAddPlugin(argv) {
|
|
|
72110
72977
|
}
|
|
72111
72978
|
return;
|
|
72112
72979
|
}
|
|
72113
|
-
if (!argv.plugin
|
|
72980
|
+
if (!argv.plugin) {
|
|
72114
72981
|
error(
|
|
72115
|
-
`
|
|
72982
|
+
`Missing plugin. Bundled: ${available.join(", ") || "(none)"}. Or pass a path, npm package, or git URL. For a project-specific stage, use: har env add-stage <id> --custom`
|
|
72116
72983
|
);
|
|
72117
72984
|
return finishCommand(1);
|
|
72118
72985
|
}
|
|
@@ -72122,10 +72989,12 @@ async function handleAddPlugin(argv) {
|
|
|
72122
72989
|
try {
|
|
72123
72990
|
const result = addPlugin(repoPath, argv.plugin, {
|
|
72124
72991
|
force: argv.force,
|
|
72125
|
-
skipCi: argv.skipCi
|
|
72992
|
+
skipCi: argv.skipCi,
|
|
72993
|
+
spec: argv.plugin
|
|
72126
72994
|
});
|
|
72127
72995
|
divider();
|
|
72128
|
-
|
|
72996
|
+
const stageLabel = result.stageIds.length > 1 ? `stages: ${result.stageIds.join(", ")}` : `stage: ${result.stageId}`;
|
|
72997
|
+
success(`Plugin applied \u2014 registered ${stageLabel} (source: ${result.source})`);
|
|
72129
72998
|
console.error("");
|
|
72130
72999
|
console.error(" Next steps:");
|
|
72131
73000
|
for (const step of result.nextSteps) {
|
|
@@ -72140,7 +73009,7 @@ async function handleAddPlugin(argv) {
|
|
|
72140
73009
|
}
|
|
72141
73010
|
}
|
|
72142
73011
|
async function handleAddStage(argv) {
|
|
72143
|
-
const repoPath =
|
|
73012
|
+
const repoPath = path55.resolve(argv.repo);
|
|
72144
73013
|
const available = listPluginIds();
|
|
72145
73014
|
if (argv.list) {
|
|
72146
73015
|
warn("har env add-stage --list is deprecated; prefer: har env add-plugin --list");
|
|
@@ -72188,9 +73057,9 @@ async function handleAddStage(argv) {
|
|
|
72188
73057
|
}
|
|
72189
73058
|
return;
|
|
72190
73059
|
}
|
|
72191
|
-
if (!argv.template
|
|
73060
|
+
if (!argv.template) {
|
|
72192
73061
|
error(
|
|
72193
|
-
`Unknown plugin:
|
|
73062
|
+
`Unknown plugin: (missing). Available: ${available.join(", ")}. Prefer: har env add-plugin <id>. For a project-specific stage, use: har env add-stage <id> --custom`
|
|
72194
73063
|
);
|
|
72195
73064
|
return finishCommand(1);
|
|
72196
73065
|
}
|
|
@@ -72206,7 +73075,7 @@ async function handleAddStage(argv) {
|
|
|
72206
73075
|
});
|
|
72207
73076
|
}
|
|
72208
73077
|
async function handlePreflight(argv) {
|
|
72209
|
-
const repo =
|
|
73078
|
+
const repo = path55.resolve(argv.repo);
|
|
72210
73079
|
const agentId = validateAgentId(argv.id, repo);
|
|
72211
73080
|
const result = await preflightEnvironment({
|
|
72212
73081
|
repoPath: repo,
|
|
@@ -72222,7 +73091,7 @@ async function handlePreflight(argv) {
|
|
|
72222
73091
|
return finishCommand(result.code);
|
|
72223
73092
|
}
|
|
72224
73093
|
async function handleLaunch(argv) {
|
|
72225
|
-
const repo =
|
|
73094
|
+
const repo = path55.resolve(argv.repo);
|
|
72226
73095
|
const agentId = validateAgentId(argv.id, repo);
|
|
72227
73096
|
if (!argv.resume) {
|
|
72228
73097
|
const guard = checkLaunchGuard2(repo, agentId, { worktree: argv.worktree });
|
|
@@ -72245,6 +73114,7 @@ async function handleLaunch(argv) {
|
|
|
72245
73114
|
sourceUrl: argv.workUrl,
|
|
72246
73115
|
title: argv.workTitle,
|
|
72247
73116
|
parentWorkUnitId: argv.parentWorkId,
|
|
73117
|
+
relatedLinks: argv.workLink?.map(parseWorkLinkSpec),
|
|
72248
73118
|
capture: false
|
|
72249
73119
|
});
|
|
72250
73120
|
if (result.blocked) {
|
|
@@ -72265,6 +73135,22 @@ async function handleLaunch(argv) {
|
|
|
72265
73135
|
}
|
|
72266
73136
|
return finishCommand(result.code);
|
|
72267
73137
|
}
|
|
73138
|
+
async function handleWorkLink(argv) {
|
|
73139
|
+
if (!argv.link && !(argv.source && argv.url)) {
|
|
73140
|
+
error("Provide --link or both --source and --url");
|
|
73141
|
+
return finishCommand(1);
|
|
73142
|
+
}
|
|
73143
|
+
const harnessRoot = resolveHarnessRoot(path55.resolve(argv.repo));
|
|
73144
|
+
const links = argv.link ? [parseWorkLinkSpec(argv.link)] : [{ source: argv.source, url: argv.url, label: argv.label }];
|
|
73145
|
+
try {
|
|
73146
|
+
const record2 = addWorkUnitLinks(harnessRoot, argv.workId, links);
|
|
73147
|
+
success(`Added link to work unit ${record2.workUnitId}`);
|
|
73148
|
+
return finishCommand(0);
|
|
73149
|
+
} catch (err) {
|
|
73150
|
+
error(err instanceof Error ? err.message : String(err));
|
|
73151
|
+
return finishCommand(1);
|
|
73152
|
+
}
|
|
73153
|
+
}
|
|
72268
73154
|
async function handleRecover(argv) {
|
|
72269
73155
|
return handleLaunch({
|
|
72270
73156
|
id: argv.id,
|
|
@@ -72280,7 +73166,7 @@ async function handleRecover(argv) {
|
|
|
72280
73166
|
});
|
|
72281
73167
|
}
|
|
72282
73168
|
async function handleVerify(argv) {
|
|
72283
|
-
const repo =
|
|
73169
|
+
const repo = path55.resolve(argv.repo);
|
|
72284
73170
|
const agentId = validateAgentId(argv.id, repo);
|
|
72285
73171
|
const result = await runVerification({
|
|
72286
73172
|
repoPath: repo,
|
|
@@ -72292,7 +73178,7 @@ async function handleVerify(argv) {
|
|
|
72292
73178
|
return finishCommand(result.code);
|
|
72293
73179
|
}
|
|
72294
73180
|
async function handleTeardown(argv) {
|
|
72295
|
-
const repo =
|
|
73181
|
+
const repo = path55.resolve(argv.repo);
|
|
72296
73182
|
const agentId = validateAgentId(argv.id, repo);
|
|
72297
73183
|
const result = await teardownEnvironment({
|
|
72298
73184
|
repoPath: repo,
|
|
@@ -72303,7 +73189,7 @@ async function handleTeardown(argv) {
|
|
|
72303
73189
|
return finishCommand(result.code);
|
|
72304
73190
|
}
|
|
72305
73191
|
async function handleComplete(argv) {
|
|
72306
|
-
const repo =
|
|
73192
|
+
const repo = path55.resolve(argv.repo);
|
|
72307
73193
|
const agentId = validateAgentId(argv.id, repo);
|
|
72308
73194
|
const result = await completeEnvironment({
|
|
72309
73195
|
repoPath: repo,
|
|
@@ -72324,7 +73210,7 @@ async function handleComplete(argv) {
|
|
|
72324
73210
|
return finishCommand(result.code);
|
|
72325
73211
|
}
|
|
72326
73212
|
async function handleStatus(argv) {
|
|
72327
|
-
const repoPath =
|
|
73213
|
+
const repoPath = path55.resolve(argv.repo);
|
|
72328
73214
|
if (argv.json) {
|
|
72329
73215
|
const status = collectEnvironmentStatus(repoPath);
|
|
72330
73216
|
const output = EnvironmentStatusSchema.parse(status);
|
|
@@ -72336,8 +73222,59 @@ async function handleStatus(argv) {
|
|
|
72336
73222
|
capture: false
|
|
72337
73223
|
});
|
|
72338
73224
|
}
|
|
73225
|
+
async function handleCleanup(argv) {
|
|
73226
|
+
const keepValues = argv.keep?.split(",").map((value) => value.trim()).filter(Boolean);
|
|
73227
|
+
const keep = parseCleanupKeepPins(keepValues);
|
|
73228
|
+
const repoPaths = argv.repo ? [path55.resolve(argv.repo)] : void 0;
|
|
73229
|
+
const plan = await discoverCleanupCandidates({
|
|
73230
|
+
cwd: process.cwd(),
|
|
73231
|
+
repoPaths,
|
|
73232
|
+
keep,
|
|
73233
|
+
staleDays: argv.stale,
|
|
73234
|
+
orphans: argv.orphans
|
|
73235
|
+
});
|
|
73236
|
+
if (argv.json) {
|
|
73237
|
+
process.stdout.write(JSON.stringify(plan, null, 2) + "\n");
|
|
73238
|
+
if (argv.dryRun) return;
|
|
73239
|
+
} else {
|
|
73240
|
+
header("har env cleanup");
|
|
73241
|
+
process.stdout.write(`${formatCleanupPlan(plan)}
|
|
73242
|
+
|
|
73243
|
+
`);
|
|
73244
|
+
if (argv.dryRun) {
|
|
73245
|
+
info("Dry run \u2014 no changes made.");
|
|
73246
|
+
return;
|
|
73247
|
+
}
|
|
73248
|
+
}
|
|
73249
|
+
let selected = selectAutoApprovedCandidates(plan, { includeReview: argv.includeReview });
|
|
73250
|
+
if (!argv.yes) {
|
|
73251
|
+
try {
|
|
73252
|
+
const interactive = await confirmCleanupSelection(plan.candidates);
|
|
73253
|
+
selected = interactive;
|
|
73254
|
+
} catch (err) {
|
|
73255
|
+
error(err instanceof Error ? err.message : String(err));
|
|
73256
|
+
return finishCommand(1);
|
|
73257
|
+
}
|
|
73258
|
+
}
|
|
73259
|
+
if (selected.length === 0) {
|
|
73260
|
+
info("Nothing selected for cleanup.");
|
|
73261
|
+
return;
|
|
73262
|
+
}
|
|
73263
|
+
const outcomes = await executeCleanupCandidates(selected, { dryRun: false });
|
|
73264
|
+
let failed = 0;
|
|
73265
|
+
for (const outcome of outcomes) {
|
|
73266
|
+
const label = outcome.candidate.kind === "orphan_worktree" ? outcome.candidate.worktreePath : `${outcome.candidate.projectName} agent ${outcome.candidate.agentId}`;
|
|
73267
|
+
if (outcome.ok) {
|
|
73268
|
+
success(`Cleaned ${label}`);
|
|
73269
|
+
} else {
|
|
73270
|
+
failed++;
|
|
73271
|
+
error(`${label}: ${outcome.error ?? "failed"}`);
|
|
73272
|
+
}
|
|
73273
|
+
}
|
|
73274
|
+
return finishCommand(failed > 0 ? 1 : 0);
|
|
73275
|
+
}
|
|
72339
73276
|
async function handleRunsList(argv) {
|
|
72340
|
-
const repoPath =
|
|
73277
|
+
const repoPath = path55.resolve(argv.repo);
|
|
72341
73278
|
const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
|
|
72342
73279
|
if (argv.json) {
|
|
72343
73280
|
process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
|
|
@@ -72354,7 +73291,7 @@ async function handleRunsList(argv) {
|
|
|
72354
73291
|
}
|
|
72355
73292
|
}
|
|
72356
73293
|
async function handleRunsGet(argv) {
|
|
72357
|
-
const run2 = getRun(
|
|
73294
|
+
const run2 = getRun(path55.resolve(argv.repo), argv.runId);
|
|
72358
73295
|
if (!run2) {
|
|
72359
73296
|
error(`Run not found: ${argv.runId}`);
|
|
72360
73297
|
return finishCommand(1);
|
|
@@ -72436,27 +73373,27 @@ function printNextSteps() {
|
|
|
72436
73373
|
}
|
|
72437
73374
|
|
|
72438
73375
|
// src/cli/commands/control.ts
|
|
72439
|
-
var
|
|
73376
|
+
var path59 = __toESM(require("path"));
|
|
72440
73377
|
init_control_config();
|
|
72441
73378
|
init_control_port();
|
|
72442
73379
|
init_control_sync();
|
|
72443
73380
|
|
|
72444
73381
|
// src/core/control-sync-selection.ts
|
|
72445
|
-
var
|
|
72446
|
-
var
|
|
72447
|
-
var
|
|
73382
|
+
var fs48 = __toESM(require("fs"));
|
|
73383
|
+
var os20 = __toESM(require("os"));
|
|
73384
|
+
var path56 = __toESM(require("path"));
|
|
72448
73385
|
init_control_repo_path();
|
|
72449
73386
|
function getSelectionPath() {
|
|
72450
73387
|
if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
|
|
72451
|
-
return
|
|
73388
|
+
return path56.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
|
|
72452
73389
|
}
|
|
72453
|
-
return
|
|
73390
|
+
return path56.join(os20.homedir(), ".har", "sync-selection.json");
|
|
72454
73391
|
}
|
|
72455
73392
|
function readSyncSelection() {
|
|
72456
73393
|
const selectionPath = getSelectionPath();
|
|
72457
73394
|
try {
|
|
72458
|
-
if (!
|
|
72459
|
-
const parsed = JSON.parse(
|
|
73395
|
+
if (!fs48.existsSync(selectionPath)) return null;
|
|
73396
|
+
const parsed = JSON.parse(fs48.readFileSync(selectionPath, "utf8"));
|
|
72460
73397
|
if (!Array.isArray(parsed.repos)) return null;
|
|
72461
73398
|
return parsed.repos.map((repoPath) => canonicalizeControlRepoPath(repoPath));
|
|
72462
73399
|
} catch {
|
|
@@ -72466,8 +73403,8 @@ function readSyncSelection() {
|
|
|
72466
73403
|
function writeSyncSelection(repos) {
|
|
72467
73404
|
const selectionPath = getSelectionPath();
|
|
72468
73405
|
const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
|
|
72469
|
-
|
|
72470
|
-
|
|
73406
|
+
fs48.mkdirSync(path56.dirname(selectionPath), { recursive: true });
|
|
73407
|
+
fs48.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
|
|
72471
73408
|
}
|
|
72472
73409
|
function resolveSyncSelection(input) {
|
|
72473
73410
|
const { discovered, stored, forceSelect, isTTY } = input;
|
|
@@ -72499,13 +73436,13 @@ init_portal_credentials();
|
|
|
72499
73436
|
// src/core/portal-login.ts
|
|
72500
73437
|
var http = __toESM(require("http"));
|
|
72501
73438
|
var import_crypto = require("crypto");
|
|
72502
|
-
var
|
|
73439
|
+
var import_child_process15 = require("child_process");
|
|
72503
73440
|
var CALLBACK_PATH = "/callback";
|
|
72504
73441
|
var LOGIN_TIMEOUT_MS = 3 * 6e4;
|
|
72505
73442
|
function openBrowser(url) {
|
|
72506
73443
|
const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
72507
73444
|
try {
|
|
72508
|
-
const child = (0,
|
|
73445
|
+
const child = (0, import_child_process15.spawn)(cmd, args, { stdio: "ignore", detached: true });
|
|
72509
73446
|
child.on("error", () => {
|
|
72510
73447
|
});
|
|
72511
73448
|
child.unref();
|
|
@@ -72514,7 +73451,7 @@ function openBrowser(url) {
|
|
|
72514
73451
|
}
|
|
72515
73452
|
async function loginViaBrowser(portalUrl, openUrl = openBrowser) {
|
|
72516
73453
|
const state = (0, import_crypto.randomUUID)();
|
|
72517
|
-
return new Promise((
|
|
73454
|
+
return new Promise((resolve50, reject) => {
|
|
72518
73455
|
let timer;
|
|
72519
73456
|
const server = http.createServer((req, res) => {
|
|
72520
73457
|
const requestUrl = new URL(req.url ?? "", "http://127.0.0.1");
|
|
@@ -72539,7 +73476,7 @@ async function loginViaBrowser(portalUrl, openUrl = openBrowser) {
|
|
|
72539
73476
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
72540
73477
|
res.end("<h1>Logged in</h1><p>You can close this tab and return to the terminal.</p>");
|
|
72541
73478
|
cleanup();
|
|
72542
|
-
|
|
73479
|
+
resolve50({
|
|
72543
73480
|
portalUrl,
|
|
72544
73481
|
token,
|
|
72545
73482
|
workspace,
|
|
@@ -72574,8 +73511,8 @@ If your browser did not open, paste that URL.
|
|
|
72574
73511
|
}
|
|
72575
73512
|
|
|
72576
73513
|
// src/core/control-unregister.ts
|
|
72577
|
-
var
|
|
72578
|
-
var
|
|
73514
|
+
var fs49 = __toESM(require("fs"));
|
|
73515
|
+
var path57 = __toESM(require("path"));
|
|
72579
73516
|
init_control_repo_path();
|
|
72580
73517
|
init_control_registry();
|
|
72581
73518
|
init_control_config();
|
|
@@ -72585,9 +73522,9 @@ function listUnregisterWorktreeCandidates(repoPath) {
|
|
|
72585
73522
|
const harnessRoot = canonicalizeControlRepoPath(repoPath);
|
|
72586
73523
|
const byPath = /* @__PURE__ */ new Map();
|
|
72587
73524
|
const add = (partial2) => {
|
|
72588
|
-
const resolved =
|
|
73525
|
+
const resolved = path57.resolve(partial2.worktreePath);
|
|
72589
73526
|
if (!resolved || resolved === harnessRoot) return;
|
|
72590
|
-
const exists = partial2.exists ??
|
|
73527
|
+
const exists = partial2.exists ?? fs49.existsSync(resolved);
|
|
72591
73528
|
const prev = byPath.get(resolved);
|
|
72592
73529
|
if (prev) {
|
|
72593
73530
|
byPath.set(resolved, {
|
|
@@ -72634,12 +73571,12 @@ function listUnregisterWorktreeCandidates(repoPath) {
|
|
|
72634
73571
|
}
|
|
72635
73572
|
return [...byPath.values()].sort((a, b2) => a.agentId - b2.agentId);
|
|
72636
73573
|
}
|
|
72637
|
-
async function
|
|
73574
|
+
async function askYesNo6(question) {
|
|
72638
73575
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
72639
73576
|
const readline8 = await import("readline");
|
|
72640
73577
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
72641
|
-
const answer = await new Promise((
|
|
72642
|
-
rl.question(question,
|
|
73578
|
+
const answer = await new Promise((resolve50) => {
|
|
73579
|
+
rl.question(question, resolve50);
|
|
72643
73580
|
});
|
|
72644
73581
|
rl.close();
|
|
72645
73582
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -72651,7 +73588,7 @@ async function confirmUnregister(options) {
|
|
|
72651
73588
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
72652
73589
|
throw new Error("Non-interactive terminal \u2014 pass --yes (and optionally --delete-worktrees)");
|
|
72653
73590
|
}
|
|
72654
|
-
const proceed = await
|
|
73591
|
+
const proceed = await askYesNo6("Unregister this repository from Mission Control? [y/N] ");
|
|
72655
73592
|
if (!proceed) return { proceed: false, deleteWorktrees: false };
|
|
72656
73593
|
const existing = options.worktrees.filter((w2) => w2.exists);
|
|
72657
73594
|
if (existing.length === 0) {
|
|
@@ -72663,7 +73600,7 @@ async function confirmUnregister(options) {
|
|
|
72663
73600
|
process.stderr.write(` agent-${wt.agentId}: ${wt.worktreePath}${dirty}
|
|
72664
73601
|
`);
|
|
72665
73602
|
}
|
|
72666
|
-
const deleteWorktrees = await
|
|
73603
|
+
const deleteWorktrees = await askYesNo6(
|
|
72667
73604
|
`Also delete ${existing.length} session worktree(s) on disk? [y/N] `
|
|
72668
73605
|
);
|
|
72669
73606
|
return { proceed: true, deleteWorktrees };
|
|
@@ -72701,28 +73638,28 @@ async function teardownWorktrees(repoPath, candidates, dryRun) {
|
|
|
72701
73638
|
trigger: "cli"
|
|
72702
73639
|
});
|
|
72703
73640
|
if (result.code !== 0) {
|
|
72704
|
-
if (
|
|
72705
|
-
|
|
73641
|
+
if (fs49.existsSync(candidate.worktreePath)) {
|
|
73642
|
+
fs49.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
72706
73643
|
}
|
|
72707
73644
|
}
|
|
72708
73645
|
outcomes.push({
|
|
72709
73646
|
path: candidate.worktreePath,
|
|
72710
73647
|
agentId: candidate.agentId,
|
|
72711
|
-
deleted: !
|
|
72712
|
-
error: result.code !== 0 &&
|
|
73648
|
+
deleted: !fs49.existsSync(candidate.worktreePath),
|
|
73649
|
+
error: result.code !== 0 && fs49.existsSync(candidate.worktreePath) ? result.stderr : void 0
|
|
72713
73650
|
});
|
|
72714
73651
|
} catch (err) {
|
|
72715
73652
|
const message = err instanceof Error ? err.message : String(err);
|
|
72716
73653
|
try {
|
|
72717
|
-
if (
|
|
72718
|
-
|
|
73654
|
+
if (fs49.existsSync(candidate.worktreePath)) {
|
|
73655
|
+
fs49.rmSync(candidate.worktreePath, { recursive: true, force: true });
|
|
72719
73656
|
}
|
|
72720
73657
|
} catch {
|
|
72721
73658
|
}
|
|
72722
73659
|
outcomes.push({
|
|
72723
73660
|
path: candidate.worktreePath,
|
|
72724
73661
|
agentId: candidate.agentId,
|
|
72725
|
-
deleted: !
|
|
73662
|
+
deleted: !fs49.existsSync(candidate.worktreePath),
|
|
72726
73663
|
error: message
|
|
72727
73664
|
});
|
|
72728
73665
|
}
|
|
@@ -72785,16 +73722,16 @@ init_control_config();
|
|
|
72785
73722
|
init_control_registry();
|
|
72786
73723
|
|
|
72787
73724
|
// src/core/harness-scrub.ts
|
|
72788
|
-
var
|
|
72789
|
-
var
|
|
73725
|
+
var fs50 = __toESM(require("fs"));
|
|
73726
|
+
var path58 = __toESM(require("path"));
|
|
72790
73727
|
var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
|
|
72791
73728
|
function scrubLocalHarnessDirs(repoPath) {
|
|
72792
73729
|
const results = [];
|
|
72793
|
-
const resolved =
|
|
72794
|
-
if (!
|
|
73730
|
+
const resolved = path58.resolve(repoPath);
|
|
73731
|
+
if (!fs50.existsSync(resolved)) {
|
|
72795
73732
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
72796
73733
|
results.push({
|
|
72797
|
-
path:
|
|
73734
|
+
path: path58.join(resolved, ".har", directory),
|
|
72798
73735
|
directory,
|
|
72799
73736
|
deleted: false,
|
|
72800
73737
|
error: "repository path does not exist"
|
|
@@ -72803,24 +73740,24 @@ function scrubLocalHarnessDirs(repoPath) {
|
|
|
72803
73740
|
return results;
|
|
72804
73741
|
}
|
|
72805
73742
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
72806
|
-
const target =
|
|
72807
|
-
if (!
|
|
73743
|
+
const target = path58.join(resolved, ".har", directory);
|
|
73744
|
+
if (!fs50.existsSync(target)) {
|
|
72808
73745
|
results.push({ path: target, directory, deleted: true });
|
|
72809
73746
|
continue;
|
|
72810
73747
|
}
|
|
72811
73748
|
try {
|
|
72812
|
-
|
|
73749
|
+
fs50.rmSync(target, { recursive: true, force: true });
|
|
72813
73750
|
results.push({
|
|
72814
73751
|
path: target,
|
|
72815
73752
|
directory,
|
|
72816
|
-
deleted: !
|
|
72817
|
-
error:
|
|
73753
|
+
deleted: !fs50.existsSync(target),
|
|
73754
|
+
error: fs50.existsSync(target) ? "failed to remove directory" : void 0
|
|
72818
73755
|
});
|
|
72819
73756
|
} catch (err) {
|
|
72820
73757
|
results.push({
|
|
72821
73758
|
path: target,
|
|
72822
73759
|
directory,
|
|
72823
|
-
deleted: !
|
|
73760
|
+
deleted: !fs50.existsSync(target),
|
|
72824
73761
|
error: err instanceof Error ? err.message : String(err)
|
|
72825
73762
|
});
|
|
72826
73763
|
}
|
|
@@ -72831,7 +73768,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
|
|
|
72831
73768
|
const results = [];
|
|
72832
73769
|
const seen = /* @__PURE__ */ new Set();
|
|
72833
73770
|
for (const repoPath of repoPaths) {
|
|
72834
|
-
const key =
|
|
73771
|
+
const key = path58.resolve(repoPath);
|
|
72835
73772
|
if (seen.has(key)) continue;
|
|
72836
73773
|
seen.add(key);
|
|
72837
73774
|
results.push(...scrubLocalHarnessDirs(key));
|
|
@@ -72840,12 +73777,12 @@ function scrubLocalHarnessForRepos(repoPaths) {
|
|
|
72840
73777
|
}
|
|
72841
73778
|
|
|
72842
73779
|
// src/core/control-reset.ts
|
|
72843
|
-
async function
|
|
73780
|
+
async function askYesNo7(question) {
|
|
72844
73781
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
72845
73782
|
const readline8 = await import("readline");
|
|
72846
73783
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
72847
|
-
const answer = await new Promise((
|
|
72848
|
-
rl.question(question,
|
|
73784
|
+
const answer = await new Promise((resolve50) => {
|
|
73785
|
+
rl.question(question, resolve50);
|
|
72849
73786
|
});
|
|
72850
73787
|
rl.close();
|
|
72851
73788
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -72855,7 +73792,7 @@ async function confirmControlReset(options) {
|
|
|
72855
73792
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
72856
73793
|
throw new Error("Non-interactive terminal \u2014 pass --yes");
|
|
72857
73794
|
}
|
|
72858
|
-
return
|
|
73795
|
+
return askYesNo7(
|
|
72859
73796
|
`Clear Mission Control data for ${options.repoCount} registered repositor${options.repoCount === 1 ? "y" : "ies"} (and scrub local .har history)? [y/N] `
|
|
72860
73797
|
);
|
|
72861
73798
|
}
|
|
@@ -73090,7 +74027,7 @@ async function handleDown() {
|
|
|
73090
74027
|
return finishCommand(code);
|
|
73091
74028
|
}
|
|
73092
74029
|
async function handleRegister(argv) {
|
|
73093
|
-
const repoPath =
|
|
74030
|
+
const repoPath = path59.resolve(argv.repo);
|
|
73094
74031
|
header("har control register");
|
|
73095
74032
|
info(`Repository: ${repoPath}`);
|
|
73096
74033
|
try {
|
|
@@ -73182,7 +74119,7 @@ async function handleReset(argv) {
|
|
|
73182
74119
|
}
|
|
73183
74120
|
}
|
|
73184
74121
|
async function handleUnregister(argv) {
|
|
73185
|
-
const repoPath =
|
|
74122
|
+
const repoPath = path59.resolve(argv.repo);
|
|
73186
74123
|
const worktrees = listUnregisterWorktreeCandidates(repoPath);
|
|
73187
74124
|
try {
|
|
73188
74125
|
let deleteWorktrees = argv.deleteWorktrees;
|
|
@@ -73364,12 +74301,12 @@ async function handleLogin(argv) {
|
|
|
73364
74301
|
}
|
|
73365
74302
|
|
|
73366
74303
|
// src/cli/commands/hooks.ts
|
|
73367
|
-
var
|
|
74304
|
+
var path61 = __toESM(require("path"));
|
|
73368
74305
|
init_hooks();
|
|
73369
74306
|
|
|
73370
74307
|
// src/core/claude-hooks.ts
|
|
73371
|
-
var
|
|
73372
|
-
var
|
|
74308
|
+
var fs51 = __toESM(require("fs"));
|
|
74309
|
+
var path60 = __toESM(require("path"));
|
|
73373
74310
|
var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
|
|
73374
74311
|
var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
|
|
73375
74312
|
var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
|
|
@@ -73380,8 +74317,8 @@ function isHarGuardEntry(entry) {
|
|
|
73380
74317
|
);
|
|
73381
74318
|
}
|
|
73382
74319
|
function readSettings(settingsPath) {
|
|
73383
|
-
if (!
|
|
73384
|
-
const raw =
|
|
74320
|
+
if (!fs51.existsSync(settingsPath)) return {};
|
|
74321
|
+
const raw = fs51.readFileSync(settingsPath, "utf8").trim();
|
|
73385
74322
|
if (raw === "") return {};
|
|
73386
74323
|
const parsed = JSON.parse(raw);
|
|
73387
74324
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
@@ -73390,19 +74327,19 @@ function readSettings(settingsPath) {
|
|
|
73390
74327
|
return parsed;
|
|
73391
74328
|
}
|
|
73392
74329
|
function writeSettings(settingsPath, settings) {
|
|
73393
|
-
|
|
73394
|
-
|
|
74330
|
+
fs51.mkdirSync(path60.dirname(settingsPath), { recursive: true });
|
|
74331
|
+
fs51.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
73395
74332
|
}
|
|
73396
74333
|
function installClaudeGuard(repoPath) {
|
|
73397
74334
|
const templatePath = resolveTemplateFile("claude-worktree-guard.sh.template");
|
|
73398
74335
|
if (!templatePath) {
|
|
73399
74336
|
throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
|
|
73400
74337
|
}
|
|
73401
|
-
const guardScript =
|
|
73402
|
-
|
|
73403
|
-
|
|
73404
|
-
|
|
73405
|
-
const settingsPath =
|
|
74338
|
+
const guardScript = path60.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
74339
|
+
fs51.mkdirSync(path60.dirname(guardScript), { recursive: true });
|
|
74340
|
+
fs51.copyFileSync(templatePath, guardScript);
|
|
74341
|
+
fs51.chmodSync(guardScript, 493);
|
|
74342
|
+
const settingsPath = path60.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
73406
74343
|
const settings = readSettings(settingsPath);
|
|
73407
74344
|
const hooks = settings.hooks ?? {};
|
|
73408
74345
|
const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
|
|
@@ -73416,15 +74353,15 @@ function installClaudeGuard(repoPath) {
|
|
|
73416
74353
|
}
|
|
73417
74354
|
function uninstallClaudeGuard(repoPath) {
|
|
73418
74355
|
let removed = false;
|
|
73419
|
-
const guardScript =
|
|
73420
|
-
if (
|
|
73421
|
-
|
|
74356
|
+
const guardScript = path60.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
74357
|
+
if (fs51.existsSync(guardScript)) {
|
|
74358
|
+
fs51.rmSync(guardScript);
|
|
73422
74359
|
removed = true;
|
|
73423
|
-
const parent =
|
|
73424
|
-
if (
|
|
74360
|
+
const parent = path60.dirname(guardScript);
|
|
74361
|
+
if (fs51.existsSync(parent) && fs51.readdirSync(parent).length === 0) fs51.rmdirSync(parent);
|
|
73425
74362
|
}
|
|
73426
|
-
const settingsPath =
|
|
73427
|
-
if (
|
|
74363
|
+
const settingsPath = path60.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
74364
|
+
if (fs51.existsSync(settingsPath)) {
|
|
73428
74365
|
const settings = readSettings(settingsPath);
|
|
73429
74366
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
73430
74367
|
if (preToolUse) {
|
|
@@ -73449,8 +74386,8 @@ function uninstallClaudeGuard(repoPath) {
|
|
|
73449
74386
|
return { removed };
|
|
73450
74387
|
}
|
|
73451
74388
|
function claudeGuardInstalled(repoPath) {
|
|
73452
|
-
const settingsPath =
|
|
73453
|
-
if (!
|
|
74389
|
+
const settingsPath = path60.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
74390
|
+
if (!fs51.existsSync(settingsPath)) return false;
|
|
73454
74391
|
try {
|
|
73455
74392
|
const settings = readSettings(settingsPath);
|
|
73456
74393
|
return (settings.hooks?.PreToolUse ?? []).some(isHarGuardEntry);
|
|
@@ -73467,7 +74404,7 @@ function repoOption(y) {
|
|
|
73467
74404
|
function handleInstall2(argv) {
|
|
73468
74405
|
try {
|
|
73469
74406
|
if (argv.claude) {
|
|
73470
|
-
const result2 = installClaudeGuard(
|
|
74407
|
+
const result2 = installClaudeGuard(path61.resolve(argv.repo));
|
|
73471
74408
|
success("Claude Code worktree guard installed.");
|
|
73472
74409
|
info(`Guard script: ${result2.guardScript}`);
|
|
73473
74410
|
info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
|
|
@@ -73475,7 +74412,7 @@ function handleInstall2(argv) {
|
|
|
73475
74412
|
info("Commit both files so the guard travels with the repo.");
|
|
73476
74413
|
return;
|
|
73477
74414
|
}
|
|
73478
|
-
const result = installHooks({ repoPath:
|
|
74415
|
+
const result = installHooks({ repoPath: path61.resolve(argv.repo), force: argv.force });
|
|
73479
74416
|
success(`Commit gate installed in ${result.hooksDir}`);
|
|
73480
74417
|
info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
|
|
73481
74418
|
info("Commits of unverified change batches will be blocked in agent worktrees.");
|
|
@@ -73488,7 +74425,7 @@ function handleInstall2(argv) {
|
|
|
73488
74425
|
function handleUninstall(argv) {
|
|
73489
74426
|
try {
|
|
73490
74427
|
if (argv.claude) {
|
|
73491
|
-
const result2 = uninstallClaudeGuard(
|
|
74428
|
+
const result2 = uninstallClaudeGuard(path61.resolve(argv.repo));
|
|
73492
74429
|
if (result2.removed) {
|
|
73493
74430
|
success("Claude Code worktree guard removed.");
|
|
73494
74431
|
} else {
|
|
@@ -73496,7 +74433,7 @@ function handleUninstall(argv) {
|
|
|
73496
74433
|
}
|
|
73497
74434
|
return;
|
|
73498
74435
|
}
|
|
73499
|
-
const result = uninstallHooks(
|
|
74436
|
+
const result = uninstallHooks(path61.resolve(argv.repo));
|
|
73500
74437
|
if (result.removed) {
|
|
73501
74438
|
success(`Commit gate removed from ${result.hooksDir}`);
|
|
73502
74439
|
} else {
|
|
@@ -73509,7 +74446,7 @@ function handleUninstall(argv) {
|
|
|
73509
74446
|
}
|
|
73510
74447
|
function handleStatus2(argv) {
|
|
73511
74448
|
try {
|
|
73512
|
-
const status = getHooksStatus(
|
|
74449
|
+
const status = getHooksStatus(path61.resolve(argv.repo));
|
|
73513
74450
|
if (argv.json) {
|
|
73514
74451
|
process.stdout.write(`${JSON.stringify(status, null, 2)}
|
|
73515
74452
|
`);
|
|
@@ -73527,7 +74464,7 @@ function handleStatus2(argv) {
|
|
|
73527
74464
|
);
|
|
73528
74465
|
info(`Effective: ${status.effectiveMode} (in this checkout)`);
|
|
73529
74466
|
info(
|
|
73530
|
-
`Claude guard: ${claudeGuardInstalled(
|
|
74467
|
+
`Claude guard: ${claudeGuardInstalled(path61.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
|
|
73531
74468
|
);
|
|
73532
74469
|
} catch (err) {
|
|
73533
74470
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -73788,10 +74725,10 @@ function assignProp(target, prop, value) {
|
|
|
73788
74725
|
configurable: true
|
|
73789
74726
|
});
|
|
73790
74727
|
}
|
|
73791
|
-
function getElementAtPath(obj,
|
|
73792
|
-
if (!
|
|
74728
|
+
function getElementAtPath(obj, path66) {
|
|
74729
|
+
if (!path66)
|
|
73793
74730
|
return obj;
|
|
73794
|
-
return
|
|
74731
|
+
return path66.reduce((acc, key) => acc?.[key], obj);
|
|
73795
74732
|
}
|
|
73796
74733
|
function promiseAllObject(promisesObj) {
|
|
73797
74734
|
const keys = Object.keys(promisesObj);
|
|
@@ -74111,11 +75048,11 @@ function aborted(x, startIndex = 0) {
|
|
|
74111
75048
|
}
|
|
74112
75049
|
return false;
|
|
74113
75050
|
}
|
|
74114
|
-
function prefixIssues(
|
|
75051
|
+
function prefixIssues(path66, issues) {
|
|
74115
75052
|
return issues.map((iss) => {
|
|
74116
75053
|
var _a2;
|
|
74117
75054
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
74118
|
-
iss.path.unshift(
|
|
75055
|
+
iss.path.unshift(path66);
|
|
74119
75056
|
return iss;
|
|
74120
75057
|
});
|
|
74121
75058
|
}
|
|
@@ -79438,7 +80375,7 @@ var Protocol = class {
|
|
|
79438
80375
|
return;
|
|
79439
80376
|
}
|
|
79440
80377
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
79441
|
-
await new Promise((
|
|
80378
|
+
await new Promise((resolve50) => setTimeout(resolve50, pollInterval));
|
|
79442
80379
|
options?.signal?.throwIfAborted();
|
|
79443
80380
|
}
|
|
79444
80381
|
} catch (error3) {
|
|
@@ -79455,7 +80392,7 @@ var Protocol = class {
|
|
|
79455
80392
|
*/
|
|
79456
80393
|
request(request, resultSchema, options) {
|
|
79457
80394
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
79458
|
-
return new Promise((
|
|
80395
|
+
return new Promise((resolve50, reject) => {
|
|
79459
80396
|
const earlyReject = (error3) => {
|
|
79460
80397
|
reject(error3);
|
|
79461
80398
|
};
|
|
@@ -79533,7 +80470,7 @@ var Protocol = class {
|
|
|
79533
80470
|
if (!parseResult.success) {
|
|
79534
80471
|
reject(parseResult.error);
|
|
79535
80472
|
} else {
|
|
79536
|
-
|
|
80473
|
+
resolve50(parseResult.data);
|
|
79537
80474
|
}
|
|
79538
80475
|
} catch (error3) {
|
|
79539
80476
|
reject(error3);
|
|
@@ -79794,12 +80731,12 @@ var Protocol = class {
|
|
|
79794
80731
|
}
|
|
79795
80732
|
} catch {
|
|
79796
80733
|
}
|
|
79797
|
-
return new Promise((
|
|
80734
|
+
return new Promise((resolve50, reject) => {
|
|
79798
80735
|
if (signal.aborted) {
|
|
79799
80736
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
79800
80737
|
return;
|
|
79801
80738
|
}
|
|
79802
|
-
const timeoutId = setTimeout(
|
|
80739
|
+
const timeoutId = setTimeout(resolve50, interval);
|
|
79803
80740
|
signal.addEventListener("abort", () => {
|
|
79804
80741
|
clearTimeout(timeoutId);
|
|
79805
80742
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -80589,7 +81526,7 @@ var Server = class extends Protocol {
|
|
|
80589
81526
|
};
|
|
80590
81527
|
|
|
80591
81528
|
// src/mcp/server.ts
|
|
80592
|
-
var
|
|
81529
|
+
var path62 = __toESM(require("path"));
|
|
80593
81530
|
|
|
80594
81531
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
80595
81532
|
var import_node_process3 = __toESM(require("node:process"), 1);
|
|
@@ -80672,12 +81609,12 @@ var StdioServerTransport = class {
|
|
|
80672
81609
|
this.onclose?.();
|
|
80673
81610
|
}
|
|
80674
81611
|
send(message) {
|
|
80675
|
-
return new Promise((
|
|
81612
|
+
return new Promise((resolve50) => {
|
|
80676
81613
|
const json = serializeMessage(message);
|
|
80677
81614
|
if (this._stdout.write(json)) {
|
|
80678
|
-
|
|
81615
|
+
resolve50();
|
|
80679
81616
|
} else {
|
|
80680
|
-
this._stdout.once("drain",
|
|
81617
|
+
this._stdout.once("drain", resolve50);
|
|
80681
81618
|
}
|
|
80682
81619
|
});
|
|
80683
81620
|
}
|
|
@@ -80686,6 +81623,8 @@ var StdioServerTransport = class {
|
|
|
80686
81623
|
// src/mcp/server.ts
|
|
80687
81624
|
init_telemetry_config();
|
|
80688
81625
|
init_runs();
|
|
81626
|
+
init_work_units();
|
|
81627
|
+
init_manifest();
|
|
80689
81628
|
|
|
80690
81629
|
// src/mcp/schema-tools.ts
|
|
80691
81630
|
init_schema2();
|
|
@@ -80770,7 +81709,21 @@ var LaunchEnvironmentInputSchema = external_exports.object({
|
|
|
80770
81709
|
source: external_exports.string().min(1).max(64).optional(),
|
|
80771
81710
|
sourceUrl: external_exports.string().url().optional(),
|
|
80772
81711
|
title: external_exports.string().min(1).max(256).optional(),
|
|
80773
|
-
parentWorkUnitId: external_exports.string().min(1).max(128).optional()
|
|
81712
|
+
parentWorkUnitId: external_exports.string().min(1).max(128).optional(),
|
|
81713
|
+
relatedLinks: external_exports.array(
|
|
81714
|
+
external_exports.object({
|
|
81715
|
+
source: external_exports.string().min(1).max(64),
|
|
81716
|
+
url: external_exports.string().url(),
|
|
81717
|
+
label: external_exports.string().min(1).max(128).optional()
|
|
81718
|
+
})
|
|
81719
|
+
).optional()
|
|
81720
|
+
});
|
|
81721
|
+
var AddWorkUnitLinkInputSchema = external_exports.object({
|
|
81722
|
+
repo: external_exports.string().default("."),
|
|
81723
|
+
workUnitId: external_exports.string().min(1).max(128),
|
|
81724
|
+
source: external_exports.string().min(1).max(64),
|
|
81725
|
+
url: external_exports.string().url(),
|
|
81726
|
+
label: external_exports.string().min(1).max(128).optional()
|
|
80774
81727
|
});
|
|
80775
81728
|
var LaunchEnvironmentOutputSchema = ShellRunOutputSchema.extend({
|
|
80776
81729
|
previewUrls: external_exports.record(external_exports.string()).optional(),
|
|
@@ -80917,11 +81870,41 @@ var HAR_MCP_TOOLS = [
|
|
|
80917
81870
|
parentWorkUnitId: {
|
|
80918
81871
|
type: "string",
|
|
80919
81872
|
description: "Optional parent work unit identifier."
|
|
81873
|
+
},
|
|
81874
|
+
relatedLinks: {
|
|
81875
|
+
type: "array",
|
|
81876
|
+
description: "Additional tracker links (append-only). Each item: source, url, optional label.",
|
|
81877
|
+
items: {
|
|
81878
|
+
type: "object",
|
|
81879
|
+
properties: {
|
|
81880
|
+
source: { type: "string" },
|
|
81881
|
+
url: { type: "string" },
|
|
81882
|
+
label: { type: "string" }
|
|
81883
|
+
},
|
|
81884
|
+
required: ["source", "url"]
|
|
81885
|
+
}
|
|
80920
81886
|
}
|
|
80921
81887
|
},
|
|
80922
81888
|
["agentId"]
|
|
80923
81889
|
)
|
|
80924
81890
|
},
|
|
81891
|
+
{
|
|
81892
|
+
name: "har_add_work_unit_link",
|
|
81893
|
+
description: "Append a related external link (PR, mirrored issue, alternate tracker) to an existing work unit.",
|
|
81894
|
+
inputSchema: objectJsonSchema(
|
|
81895
|
+
{
|
|
81896
|
+
repo: repoJsonProperty,
|
|
81897
|
+
workUnitId: {
|
|
81898
|
+
type: "string",
|
|
81899
|
+
description: "Repo-scoped work unit id bound at launch."
|
|
81900
|
+
},
|
|
81901
|
+
source: { type: "string", description: "Tracker provider (e.g. github, jira)." },
|
|
81902
|
+
url: { type: "string", description: "Canonical URL for the link." },
|
|
81903
|
+
label: { type: "string", description: "Optional display label." }
|
|
81904
|
+
},
|
|
81905
|
+
["workUnitId", "source", "url"]
|
|
81906
|
+
)
|
|
81907
|
+
},
|
|
80925
81908
|
{
|
|
80926
81909
|
name: "har_recover_environment",
|
|
80927
81910
|
description: "Resume a failed or partial agent launch without replacing the worktree. Alias for har_launch_environment with resume=true.",
|
|
@@ -81092,6 +82075,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
81092
82075
|
sourceUrl: input.sourceUrl,
|
|
81093
82076
|
title: input.title,
|
|
81094
82077
|
parentWorkUnitId: input.parentWorkUnitId,
|
|
82078
|
+
relatedLinks: input.relatedLinks,
|
|
81095
82079
|
capture: true
|
|
81096
82080
|
});
|
|
81097
82081
|
const parsed = LaunchEnvironmentOutputSchema.parse(result);
|
|
@@ -81114,6 +82098,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
81114
82098
|
sourceUrl: input.sourceUrl,
|
|
81115
82099
|
title: input.title,
|
|
81116
82100
|
parentWorkUnitId: input.parentWorkUnitId,
|
|
82101
|
+
relatedLinks: input.relatedLinks,
|
|
81117
82102
|
capture: true
|
|
81118
82103
|
});
|
|
81119
82104
|
const parsed = LaunchEnvironmentOutputSchema.parse(result);
|
|
@@ -81122,6 +82107,28 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
81122
82107
|
...result.blocked ? { isError: true } : {}
|
|
81123
82108
|
};
|
|
81124
82109
|
}
|
|
82110
|
+
case "har_add_work_unit_link": {
|
|
82111
|
+
const input = AddWorkUnitLinkInputSchema.parse({ ...args, repo });
|
|
82112
|
+
const harnessRoot = resolveHarnessRoot(repo);
|
|
82113
|
+
try {
|
|
82114
|
+
const record2 = addWorkUnitLinks(harnessRoot, input.workUnitId, [
|
|
82115
|
+
{ source: input.source, url: input.url, label: input.label }
|
|
82116
|
+
]);
|
|
82117
|
+
return jsonContent({
|
|
82118
|
+
ok: true,
|
|
82119
|
+
workUnitId: record2.workUnitId,
|
|
82120
|
+
relatedLinks: record2.relatedLinks
|
|
82121
|
+
});
|
|
82122
|
+
} catch (err) {
|
|
82123
|
+
return {
|
|
82124
|
+
...jsonContent({
|
|
82125
|
+
ok: false,
|
|
82126
|
+
error: err instanceof Error ? err.message : String(err)
|
|
82127
|
+
}),
|
|
82128
|
+
isError: true
|
|
82129
|
+
};
|
|
82130
|
+
}
|
|
82131
|
+
}
|
|
81125
82132
|
case "har_preflight_environment": {
|
|
81126
82133
|
const input = PreflightEnvironmentInputSchema.parse({ ...args, repo });
|
|
81127
82134
|
const agentId = validateAgentId(input.agentId, repo);
|
|
@@ -81232,7 +82239,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
81232
82239
|
const input = ControlUpInputSchema.parse({ ...args, repo });
|
|
81233
82240
|
const result = await startControlAndSync({
|
|
81234
82241
|
detach: input.detach,
|
|
81235
|
-
cwd:
|
|
82242
|
+
cwd: path62.resolve(input.repo)
|
|
81236
82243
|
});
|
|
81237
82244
|
if (result.code !== 0) {
|
|
81238
82245
|
return {
|
|
@@ -81296,11 +82303,11 @@ var mcpCommand = {
|
|
|
81296
82303
|
};
|
|
81297
82304
|
|
|
81298
82305
|
// src/cli/commands/onboard.ts
|
|
81299
|
-
var
|
|
82306
|
+
var path64 = __toESM(require("path"));
|
|
81300
82307
|
init_stages();
|
|
81301
82308
|
|
|
81302
82309
|
// src/core/onboarding.ts
|
|
81303
|
-
var
|
|
82310
|
+
var path63 = __toESM(require("path"));
|
|
81304
82311
|
init_control_config();
|
|
81305
82312
|
init_control_sync();
|
|
81306
82313
|
init_otel_hooks();
|
|
@@ -81345,7 +82352,8 @@ function listPluginChoices() {
|
|
|
81345
82352
|
return listPluginIds().map((id) => {
|
|
81346
82353
|
try {
|
|
81347
82354
|
const manifest = readPluginManifest(id);
|
|
81348
|
-
const
|
|
82355
|
+
const stages = normalizePluginStages(manifest);
|
|
82356
|
+
const description = typeof stages[0]?.description === "string" ? stages[0].description : `Adds stage ${primaryStageId(manifest)}`;
|
|
81349
82357
|
return {
|
|
81350
82358
|
id,
|
|
81351
82359
|
label: `${id} \u2014 ${description}`,
|
|
@@ -81435,7 +82443,7 @@ async function defaultEnsureControl(options) {
|
|
|
81435
82443
|
return { started: true, apiUrl: result.apiUrl };
|
|
81436
82444
|
}
|
|
81437
82445
|
async function runOnboarding(options, deps = {}) {
|
|
81438
|
-
const repoPath =
|
|
82446
|
+
const repoPath = path63.resolve(options.repoPath);
|
|
81439
82447
|
const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
|
|
81440
82448
|
const ensureControl = deps.ensureControl ?? defaultEnsureControl;
|
|
81441
82449
|
const init = deps.initHarness ?? initHarness;
|
|
@@ -81623,7 +82631,7 @@ async function promptChoices(args) {
|
|
|
81623
82631
|
};
|
|
81624
82632
|
}
|
|
81625
82633
|
const pluginChoices = listPluginChoices();
|
|
81626
|
-
const repoPath =
|
|
82634
|
+
const repoPath = path64.resolve(args.repo);
|
|
81627
82635
|
const alreadyPresent = harnessExists(repoPath);
|
|
81628
82636
|
const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
|
|
81629
82637
|
const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
|
|
@@ -81740,7 +82748,7 @@ function printSummary(result) {
|
|
|
81740
82748
|
console.error("");
|
|
81741
82749
|
}
|
|
81742
82750
|
async function handleOnboard(argv) {
|
|
81743
|
-
const repoPath =
|
|
82751
|
+
const repoPath = path64.resolve(argv.repo);
|
|
81744
82752
|
header("har onboard");
|
|
81745
82753
|
info(`Repository: ${repoPath}`);
|
|
81746
82754
|
try {
|
|
@@ -81971,7 +82979,7 @@ var preferencesCommand = {
|
|
|
81971
82979
|
};
|
|
81972
82980
|
|
|
81973
82981
|
// src/cli/commands/telemetry.ts
|
|
81974
|
-
var
|
|
82982
|
+
var path65 = __toESM(require("path"));
|
|
81975
82983
|
init_control_config();
|
|
81976
82984
|
init_control_sync();
|
|
81977
82985
|
init_manifest();
|
|
@@ -82064,7 +83072,7 @@ async function handleOff() {
|
|
|
82064
83072
|
info("Mission Control will not auto-start. Existing usage rows are kept.");
|
|
82065
83073
|
}
|
|
82066
83074
|
async function handleWriteEnv(argv) {
|
|
82067
|
-
const repoPath =
|
|
83075
|
+
const repoPath = path65.resolve(argv.repo);
|
|
82068
83076
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
82069
83077
|
const session = readSlotRegistry(harnessRoot, argv.agentId);
|
|
82070
83078
|
const workDir = argv.workDir ?? session?.workDir ?? repoPath;
|
|
@@ -82076,7 +83084,7 @@ async function handleWriteEnv(argv) {
|
|
|
82076
83084
|
suffix,
|
|
82077
83085
|
createdAt: session?.createdAt
|
|
82078
83086
|
});
|
|
82079
|
-
const envFile = argv.envFile ??
|
|
83087
|
+
const envFile = argv.envFile ?? path65.join(workDir, `.env.agent.${argv.agentId}`);
|
|
82080
83088
|
const attrs = {
|
|
82081
83089
|
sessionKey,
|
|
82082
83090
|
agentId: argv.agentId,
|
|
@@ -82092,7 +83100,7 @@ async function handleWriteEnv(argv) {
|
|
|
82092
83100
|
success(`Wrote session attribution to ${envFile}`);
|
|
82093
83101
|
}
|
|
82094
83102
|
function handlePrintEnv(argv) {
|
|
82095
|
-
const repoPath =
|
|
83103
|
+
const repoPath = path65.resolve(argv.repo);
|
|
82096
83104
|
const workDir = argv.workDir ?? repoPath;
|
|
82097
83105
|
const sessionKey = buildSessionKey({
|
|
82098
83106
|
branch: argv.branch,
|