@osfactory/har 0.64.0 → 0.64.2
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 +704 -504
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -593,8 +593,8 @@ var init_parseUtil = __esm({
|
|
|
593
593
|
init_errors();
|
|
594
594
|
init_en();
|
|
595
595
|
makeIssue = (params) => {
|
|
596
|
-
const { data, path:
|
|
597
|
-
const fullPath = [...
|
|
596
|
+
const { data, path: path69, errorMaps, issueData } = params;
|
|
597
|
+
const fullPath = [...path69, ...issueData.path || []];
|
|
598
598
|
const fullIssue = {
|
|
599
599
|
...issueData,
|
|
600
600
|
path: fullPath
|
|
@@ -902,11 +902,11 @@ var init_types = __esm({
|
|
|
902
902
|
init_parseUtil();
|
|
903
903
|
init_util();
|
|
904
904
|
ParseInputLazyPath = class {
|
|
905
|
-
constructor(parent, value,
|
|
905
|
+
constructor(parent, value, path69, key) {
|
|
906
906
|
this._cachedPath = [];
|
|
907
907
|
this.parent = parent;
|
|
908
908
|
this.data = value;
|
|
909
|
-
this._path =
|
|
909
|
+
this._path = path69;
|
|
910
910
|
this._key = key;
|
|
911
911
|
}
|
|
912
912
|
get path() {
|
|
@@ -4288,7 +4288,7 @@ var init_zod = __esm({
|
|
|
4288
4288
|
});
|
|
4289
4289
|
|
|
4290
4290
|
// packages/schemas/src/schema.ts
|
|
4291
|
-
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, AgentTrajectoryRecordSchema, AgentSessionUsageSchema, SyncUsageInputSchema, AgentSessionEventSchema, SyncSessionEventsInputSchema;
|
|
4291
|
+
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, AgentTrajectoryRecordSchema, USAGE_HARVEST_VERSION, PRE_DEDUPE_HARVEST_VERSION, AgentSessionUsageSchema, SyncUsageInputSchema, AgentSessionEventSchema, SyncSessionEventsInputSchema;
|
|
4292
4292
|
var init_schema = __esm({
|
|
4293
4293
|
"packages/schemas/src/schema.ts"() {
|
|
4294
4294
|
"use strict";
|
|
@@ -4774,6 +4774,8 @@ var init_schema = __esm({
|
|
|
4774
4774
|
attemptId: WorkAttemptIdSchema.optional()
|
|
4775
4775
|
}).passthrough();
|
|
4776
4776
|
AgentTrajectoryRecordSchema = AgentTrajectoryRecordV1Schema;
|
|
4777
|
+
USAGE_HARVEST_VERSION = 1;
|
|
4778
|
+
PRE_DEDUPE_HARVEST_VERSION = 0;
|
|
4777
4779
|
AgentSessionUsageSchema = external_exports.object({
|
|
4778
4780
|
sessionKey: external_exports.string().min(1),
|
|
4779
4781
|
agentId: external_exports.number().int().min(HAR_AGENT_SLOT_MIN),
|
|
@@ -4792,6 +4794,7 @@ var init_schema = __esm({
|
|
|
4792
4794
|
costUsd: external_exports.number().nonnegative().nullable().optional(),
|
|
4793
4795
|
modelBreakdown: external_exports.record(external_exports.unknown()).optional(),
|
|
4794
4796
|
sources: external_exports.array(UsageSourceSchema).default([]),
|
|
4797
|
+
harvestVersion: external_exports.number().int().nonnegative().default(PRE_DEDUPE_HARVEST_VERSION),
|
|
4795
4798
|
firstSeenAt: external_exports.string(),
|
|
4796
4799
|
lastSeenAt: external_exports.string()
|
|
4797
4800
|
});
|
|
@@ -4819,6 +4822,31 @@ var init_schema = __esm({
|
|
|
4819
4822
|
}
|
|
4820
4823
|
});
|
|
4821
4824
|
|
|
4825
|
+
// packages/schemas/src/usage-authority.ts
|
|
4826
|
+
function usageHarvestVersion(row) {
|
|
4827
|
+
const version2 = Number(row?.harvestVersion ?? PRE_DEDUPE_HARVEST_VERSION);
|
|
4828
|
+
return Number.isFinite(version2) && version2 > 0 ? Math.floor(version2) : PRE_DEDUPE_HARVEST_VERSION;
|
|
4829
|
+
}
|
|
4830
|
+
function includesSource(row, source) {
|
|
4831
|
+
return (row?.sources ?? []).includes(source);
|
|
4832
|
+
}
|
|
4833
|
+
function harvestSupersedes(existing, incoming) {
|
|
4834
|
+
if (!existing || !incoming) return false;
|
|
4835
|
+
if (includesSource(existing, "otel") || includesSource(incoming, "otel")) return false;
|
|
4836
|
+
return usageHarvestVersion(incoming) > usageHarvestVersion(existing);
|
|
4837
|
+
}
|
|
4838
|
+
function mergedHarvestVersion(existing, incoming) {
|
|
4839
|
+
if (!includesSource(existing, "harvest")) return usageHarvestVersion(incoming);
|
|
4840
|
+
if (!includesSource(incoming, "harvest")) return usageHarvestVersion(existing);
|
|
4841
|
+
return Math.min(usageHarvestVersion(existing), usageHarvestVersion(incoming));
|
|
4842
|
+
}
|
|
4843
|
+
var init_usage_authority = __esm({
|
|
4844
|
+
"packages/schemas/src/usage-authority.ts"() {
|
|
4845
|
+
"use strict";
|
|
4846
|
+
init_schema();
|
|
4847
|
+
}
|
|
4848
|
+
});
|
|
4849
|
+
|
|
4822
4850
|
// node_modules/@pydantic/genai-prices/dist/index.js
|
|
4823
4851
|
function h() {
|
|
4824
4852
|
return U;
|
|
@@ -28294,6 +28322,7 @@ var init_schema2 = __esm({
|
|
|
28294
28322
|
"src/harness/schema.ts"() {
|
|
28295
28323
|
"use strict";
|
|
28296
28324
|
init_schema();
|
|
28325
|
+
init_usage_authority();
|
|
28297
28326
|
init_usage_pricing();
|
|
28298
28327
|
}
|
|
28299
28328
|
});
|
|
@@ -28704,7 +28733,7 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
|
28704
28733
|
const stream = options.stream ?? false;
|
|
28705
28734
|
const echoStdout = stream && (options.streamStdout ?? true);
|
|
28706
28735
|
const { stream: _stream, streamStdout: _streamStdout, ...spawnOptions } = options;
|
|
28707
|
-
return new Promise((
|
|
28736
|
+
return new Promise((resolve52) => {
|
|
28708
28737
|
const proc = (0, import_child_process.spawn)("bash", [scriptPath, ...args], {
|
|
28709
28738
|
...spawnOptions,
|
|
28710
28739
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -28719,14 +28748,14 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
|
28719
28748
|
stderr += d;
|
|
28720
28749
|
if (stream) process.stderr.write(d);
|
|
28721
28750
|
});
|
|
28722
|
-
proc.on("close", (code) =>
|
|
28751
|
+
proc.on("close", (code) => resolve52({ stdout, stderr, code: code ?? 0 }));
|
|
28723
28752
|
});
|
|
28724
28753
|
}
|
|
28725
28754
|
function runShellCommand(command2, options = {}) {
|
|
28726
28755
|
const stream = options.stream ?? false;
|
|
28727
28756
|
const echoStdout = stream && (options.streamStdout ?? true);
|
|
28728
28757
|
const { stream: _stream, streamStdout: _streamStdout, ...spawnOptions } = options;
|
|
28729
|
-
return new Promise((
|
|
28758
|
+
return new Promise((resolve52) => {
|
|
28730
28759
|
const proc = (0, import_child_process.spawn)("bash", ["-lc", command2], {
|
|
28731
28760
|
...spawnOptions,
|
|
28732
28761
|
stdio: ["inherit", "pipe", "pipe"]
|
|
@@ -28741,7 +28770,7 @@ function runShellCommand(command2, options = {}) {
|
|
|
28741
28770
|
stderr += d;
|
|
28742
28771
|
if (stream) process.stderr.write(d);
|
|
28743
28772
|
});
|
|
28744
|
-
proc.on("close", (code) =>
|
|
28773
|
+
proc.on("close", (code) => resolve52({ stdout, stderr, code: code ?? 0 }));
|
|
28745
28774
|
});
|
|
28746
28775
|
}
|
|
28747
28776
|
var import_child_process;
|
|
@@ -31541,17 +31570,17 @@ function listWorkUnits(harnessRoot) {
|
|
|
31541
31570
|
).sort((a, b2) => b2.updatedAt.localeCompare(a.updatedAt));
|
|
31542
31571
|
}
|
|
31543
31572
|
function createWorkAttempt(harnessRoot, input) {
|
|
31544
|
-
const
|
|
31573
|
+
const attempt2 = WorkAttemptRecordSchema.parse({
|
|
31545
31574
|
...input,
|
|
31546
31575
|
version: 1,
|
|
31547
31576
|
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
31548
31577
|
});
|
|
31549
31578
|
ensureWorkEvidenceIgnored(harnessRoot);
|
|
31550
31579
|
writeRecord2(
|
|
31551
|
-
hashedRecordPath(harnessRoot, WORK_ATTEMPTS_DIR,
|
|
31552
|
-
|
|
31580
|
+
hashedRecordPath(harnessRoot, WORK_ATTEMPTS_DIR, attempt2.attemptId),
|
|
31581
|
+
attempt2
|
|
31553
31582
|
);
|
|
31554
|
-
return
|
|
31583
|
+
return attempt2;
|
|
31555
31584
|
}
|
|
31556
31585
|
function listWorkAttempts(harnessRoot) {
|
|
31557
31586
|
return listRecords(
|
|
@@ -32313,6 +32342,8 @@ function extractClaudeUsageFromRecords(records) {
|
|
|
32313
32342
|
let tokensCacheCreation = 0;
|
|
32314
32343
|
let costUsd = null;
|
|
32315
32344
|
const modelBreakdown = {};
|
|
32345
|
+
const billed = /* @__PURE__ */ new Map();
|
|
32346
|
+
const unkeyed = [];
|
|
32316
32347
|
for (const record2 of records) {
|
|
32317
32348
|
if (!record2 || typeof record2 !== "object") continue;
|
|
32318
32349
|
const payload = record2;
|
|
@@ -32327,29 +32358,34 @@ function extractClaudeUsageFromRecords(records) {
|
|
|
32327
32358
|
const message = payload.message;
|
|
32328
32359
|
const nestedUsage = payload.usage ?? message?.usage;
|
|
32329
32360
|
if (nestedUsage && payload.type !== "result") {
|
|
32330
|
-
const i = Number(nestedUsage.input_tokens ?? 0);
|
|
32331
|
-
const o = Number(nestedUsage.output_tokens ?? 0);
|
|
32332
|
-
const cr = Number(nestedUsage.cache_read_input_tokens ?? 0);
|
|
32333
|
-
const cc = Number(nestedUsage.cache_creation_input_tokens ?? 0);
|
|
32334
|
-
tokensInput += i;
|
|
32335
|
-
tokensOutput += o;
|
|
32336
|
-
tokensCacheRead += cr;
|
|
32337
|
-
tokensCacheCreation += cc;
|
|
32338
32361
|
const model = typeof message?.model === "string" ? message.model : void 0;
|
|
32339
|
-
|
|
32340
|
-
|
|
32341
|
-
|
|
32342
|
-
|
|
32343
|
-
|
|
32344
|
-
|
|
32345
|
-
|
|
32346
|
-
|
|
32347
|
-
|
|
32348
|
-
|
|
32349
|
-
|
|
32350
|
-
|
|
32351
|
-
|
|
32352
|
-
|
|
32362
|
+
const entry = { usage: nestedUsage, model };
|
|
32363
|
+
if (typeof message?.id === "string" && message.id) billed.set(message.id, entry);
|
|
32364
|
+
else unkeyed.push(entry);
|
|
32365
|
+
}
|
|
32366
|
+
}
|
|
32367
|
+
for (const { usage: usage2, model } of [...billed.values(), ...unkeyed]) {
|
|
32368
|
+
const i = Number(usage2.input_tokens ?? 0);
|
|
32369
|
+
const o = Number(usage2.output_tokens ?? 0);
|
|
32370
|
+
const cr = Number(usage2.cache_read_input_tokens ?? 0);
|
|
32371
|
+
const cc = Number(usage2.cache_creation_input_tokens ?? 0);
|
|
32372
|
+
tokensInput += i;
|
|
32373
|
+
tokensOutput += o;
|
|
32374
|
+
tokensCacheRead += cr;
|
|
32375
|
+
tokensCacheCreation += cc;
|
|
32376
|
+
if (model && model !== "<synthetic>") {
|
|
32377
|
+
const totals = modelBreakdown[model] ??= {
|
|
32378
|
+
tokensInput: 0,
|
|
32379
|
+
tokensOutput: 0,
|
|
32380
|
+
tokensCacheRead: 0,
|
|
32381
|
+
tokensCacheCreation: 0,
|
|
32382
|
+
tokensTotal: 0
|
|
32383
|
+
};
|
|
32384
|
+
totals.tokensInput += i;
|
|
32385
|
+
totals.tokensOutput += o;
|
|
32386
|
+
totals.tokensCacheRead += cr;
|
|
32387
|
+
totals.tokensCacheCreation += cc;
|
|
32388
|
+
totals.tokensTotal += i + o + cr + cc;
|
|
32353
32389
|
}
|
|
32354
32390
|
}
|
|
32355
32391
|
return { tokensInput, tokensOutput, tokensCacheRead, tokensCacheCreation, costUsd, modelBreakdown };
|
|
@@ -32388,8 +32424,9 @@ function findMatchingClaudeTranscripts(slot) {
|
|
|
32388
32424
|
}
|
|
32389
32425
|
}
|
|
32390
32426
|
}
|
|
32391
|
-
if (primaryHit) primary.push({ filePath, records, mtimeMs: stat.mtimeMs });
|
|
32392
|
-
else if (fallbackHit)
|
|
32427
|
+
if (primaryHit) primary.push({ filePath, records, mtimeMs: stat.mtimeMs, primary: true });
|
|
32428
|
+
else if (fallbackHit)
|
|
32429
|
+
fallback.push({ filePath, records, mtimeMs: stat.mtimeMs, primary: false });
|
|
32393
32430
|
}
|
|
32394
32431
|
}
|
|
32395
32432
|
primary.sort((a, b2) => b2.mtimeMs - a.mtimeMs);
|
|
@@ -32446,18 +32483,14 @@ function harvestClaudeUsage(slot) {
|
|
|
32446
32483
|
suffix: slot.suffix,
|
|
32447
32484
|
createdAt: slot.sessionCreatedAt
|
|
32448
32485
|
});
|
|
32449
|
-
|
|
32450
|
-
|
|
32451
|
-
|
|
32452
|
-
|
|
32453
|
-
|
|
32454
|
-
}
|
|
32455
|
-
best = usage2;
|
|
32456
|
-
break;
|
|
32486
|
+
const own = matches.filter((match) => match.primary);
|
|
32487
|
+
const usable = own.length > 0 ? own : matches;
|
|
32488
|
+
const usage2 = extractClaudeUsageFromRecords(usable.flatMap((match) => match.records));
|
|
32489
|
+
if (usage2.tokensInput + usage2.tokensOutput + usage2.tokensCacheRead === 0 && (usage2.costUsd == null || usage2.costUsd === 0)) {
|
|
32490
|
+
return null;
|
|
32457
32491
|
}
|
|
32458
|
-
if (!best) return null;
|
|
32459
32492
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
32460
|
-
const tokensTotal =
|
|
32493
|
+
const tokensTotal = usage2.tokensInput + usage2.tokensOutput + usage2.tokensCacheRead + usage2.tokensCacheCreation;
|
|
32461
32494
|
return {
|
|
32462
32495
|
sessionKey,
|
|
32463
32496
|
agentId: slot.agentId,
|
|
@@ -32465,14 +32498,15 @@ function harvestClaudeUsage(slot) {
|
|
|
32465
32498
|
workDir: slot.workDir,
|
|
32466
32499
|
branch: slot.branch,
|
|
32467
32500
|
suffix: slot.suffix,
|
|
32468
|
-
tokensInput:
|
|
32469
|
-
tokensOutput:
|
|
32470
|
-
tokensCacheRead:
|
|
32471
|
-
tokensCacheCreation:
|
|
32501
|
+
tokensInput: usage2.tokensInput,
|
|
32502
|
+
tokensOutput: usage2.tokensOutput,
|
|
32503
|
+
tokensCacheRead: usage2.tokensCacheRead,
|
|
32504
|
+
tokensCacheCreation: usage2.tokensCacheCreation,
|
|
32472
32505
|
tokensTotal,
|
|
32473
|
-
costUsd:
|
|
32474
|
-
...Object.keys(
|
|
32506
|
+
costUsd: usage2.costUsd,
|
|
32507
|
+
...Object.keys(usage2.modelBreakdown).length > 0 ? { modelBreakdown: usage2.modelBreakdown } : {},
|
|
32475
32508
|
sources: ["harvest"],
|
|
32509
|
+
harvestVersion: USAGE_HARVEST_VERSION,
|
|
32476
32510
|
firstSeenAt: slot.sessionCreatedAt ?? now,
|
|
32477
32511
|
lastSeenAt: now
|
|
32478
32512
|
};
|
|
@@ -32496,6 +32530,7 @@ var init_claude = __esm({
|
|
|
32496
32530
|
fs23 = __toESM(require("fs"));
|
|
32497
32531
|
os11 = __toESM(require("os"));
|
|
32498
32532
|
path25 = __toESM(require("path"));
|
|
32533
|
+
init_schema2();
|
|
32499
32534
|
init_telemetry_config();
|
|
32500
32535
|
init_telemetry_env();
|
|
32501
32536
|
init_workspace_path_match();
|
|
@@ -32614,6 +32649,7 @@ function harvestCodexUsage(slot) {
|
|
|
32614
32649
|
tokensTotal,
|
|
32615
32650
|
costUsd: null,
|
|
32616
32651
|
sources: ["harvest"],
|
|
32652
|
+
harvestVersion: USAGE_HARVEST_VERSION,
|
|
32617
32653
|
firstSeenAt: slot.sessionCreatedAt ?? now,
|
|
32618
32654
|
lastSeenAt: now
|
|
32619
32655
|
};
|
|
@@ -32625,6 +32661,7 @@ var init_codex = __esm({
|
|
|
32625
32661
|
fs24 = __toESM(require("fs"));
|
|
32626
32662
|
os12 = __toESM(require("os"));
|
|
32627
32663
|
path26 = __toESM(require("path"));
|
|
32664
|
+
init_schema2();
|
|
32628
32665
|
init_telemetry_env();
|
|
32629
32666
|
init_workspace_path_match();
|
|
32630
32667
|
}
|
|
@@ -32754,25 +32791,85 @@ var init_portal_watermark = __esm({
|
|
|
32754
32791
|
}
|
|
32755
32792
|
});
|
|
32756
32793
|
|
|
32757
|
-
// src/core/control-
|
|
32758
|
-
|
|
32794
|
+
// src/core/control-api-read.ts
|
|
32795
|
+
function numberFromEnv(name, fallback) {
|
|
32796
|
+
const raw = Number(process.env[name]);
|
|
32797
|
+
return Number.isFinite(raw) && raw > 0 ? raw : fallback;
|
|
32798
|
+
}
|
|
32799
|
+
async function attempt(url) {
|
|
32759
32800
|
try {
|
|
32760
32801
|
const response = await fetch(url, {
|
|
32761
32802
|
method: "GET",
|
|
32762
|
-
signal: AbortSignal.timeout(
|
|
32803
|
+
signal: AbortSignal.timeout(numberFromEnv("HAR_CONTROL_READ_TIMEOUT_MS", DEFAULT_TIMEOUT_MS))
|
|
32763
32804
|
});
|
|
32764
|
-
if (!response.ok)
|
|
32765
|
-
|
|
32766
|
-
|
|
32767
|
-
|
|
32768
|
-
|
|
32805
|
+
if (!response.ok) {
|
|
32806
|
+
return {
|
|
32807
|
+
read: { ok: false, error: `HTTP ${response.status}` },
|
|
32808
|
+
retryable: response.status >= 500
|
|
32809
|
+
};
|
|
32810
|
+
}
|
|
32811
|
+
return { read: { ok: true, data: await response.json() }, retryable: false };
|
|
32812
|
+
} catch (err) {
|
|
32813
|
+
return {
|
|
32814
|
+
read: { ok: false, error: err instanceof Error ? err.message : String(err) },
|
|
32815
|
+
retryable: true
|
|
32816
|
+
};
|
|
32817
|
+
}
|
|
32818
|
+
}
|
|
32819
|
+
async function readControlJson(url) {
|
|
32820
|
+
const first = await attempt(url);
|
|
32821
|
+
if (first.read.ok || !first.retryable) return first.read;
|
|
32822
|
+
await new Promise((resolve52) => setTimeout(resolve52, RETRY_DELAY_MS));
|
|
32823
|
+
return (await attempt(url)).read;
|
|
32824
|
+
}
|
|
32825
|
+
async function readControlPages(options) {
|
|
32826
|
+
const limit = numberFromEnv("HAR_CONTROL_READ_PAGE_SIZE", DEFAULT_PAGE_SIZE);
|
|
32827
|
+
const collected = [];
|
|
32828
|
+
let since = options.since;
|
|
32829
|
+
let sinceId = null;
|
|
32830
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
32831
|
+
const query = new URLSearchParams({ limit: String(limit) });
|
|
32832
|
+
if (since) query.set("since", since);
|
|
32833
|
+
if (sinceId) query.set("sinceId", sinceId);
|
|
32834
|
+
const read = await readControlJson(`${options.url}?${query.toString()}`);
|
|
32835
|
+
if (!read.ok) return { ok: false, error: read.error };
|
|
32836
|
+
const rows = options.rows(read.data);
|
|
32837
|
+
collected.push(...rows);
|
|
32838
|
+
if (rows.length < limit) return { ok: true, rows: collected, truncated: false };
|
|
32839
|
+
const last = options.cursor(rows[rows.length - 1]);
|
|
32840
|
+
const nextSince = last.createdAt ?? null;
|
|
32841
|
+
const nextSinceId = last.id ?? null;
|
|
32842
|
+
if (!nextSince || nextSince === since && nextSinceId === sinceId) {
|
|
32843
|
+
return { ok: true, rows: collected, truncated: false };
|
|
32844
|
+
}
|
|
32845
|
+
since = nextSince;
|
|
32846
|
+
sinceId = nextSinceId;
|
|
32847
|
+
}
|
|
32848
|
+
return { ok: true, rows: collected, truncated: true };
|
|
32769
32849
|
}
|
|
32770
32850
|
async function resolveControlRepoId(apiUrl, repoPath) {
|
|
32771
|
-
const repos = await
|
|
32772
|
-
if (!
|
|
32851
|
+
const repos = await readControlJson(`${apiUrl}/api/repos`);
|
|
32852
|
+
if (!repos.ok) return repos;
|
|
32853
|
+
if (!Array.isArray(repos.data)) return { ok: false, error: "unexpected /api/repos payload" };
|
|
32773
32854
|
const target = path28.resolve(repoPath);
|
|
32774
|
-
return
|
|
32855
|
+
return {
|
|
32856
|
+
ok: true,
|
|
32857
|
+
data: repos.data.find((repo) => path28.resolve(repo.path) === target)?.id ?? null
|
|
32858
|
+
};
|
|
32775
32859
|
}
|
|
32860
|
+
var path28, DEFAULT_TIMEOUT_MS, RETRY_DELAY_MS, DEFAULT_PAGE_SIZE, MAX_PAGES;
|
|
32861
|
+
var init_control_api_read = __esm({
|
|
32862
|
+
"src/core/control-api-read.ts"() {
|
|
32863
|
+
"use strict";
|
|
32864
|
+
path28 = __toESM(require("path"));
|
|
32865
|
+
DEFAULT_TIMEOUT_MS = 1e4;
|
|
32866
|
+
RETRY_DELAY_MS = 250;
|
|
32867
|
+
DEFAULT_PAGE_SIZE = 1e3;
|
|
32868
|
+
MAX_PAGES = 20;
|
|
32869
|
+
}
|
|
32870
|
+
});
|
|
32871
|
+
|
|
32872
|
+
// src/core/control-persisted-usage.ts
|
|
32776
32873
|
function optionalString(value) {
|
|
32777
32874
|
return value == null ? void 0 : value;
|
|
32778
32875
|
}
|
|
@@ -32798,6 +32895,7 @@ function normalizeUsage(row) {
|
|
|
32798
32895
|
costUsd: row.costUsd == null ? null : Number(row.costUsd),
|
|
32799
32896
|
...row.modelBreakdown ? { modelBreakdown: row.modelBreakdown } : {},
|
|
32800
32897
|
sources: toSources(row.sources),
|
|
32898
|
+
harvestVersion: Number(row.harvestVersion ?? 0),
|
|
32801
32899
|
firstSeenAt: row.firstSeenAt,
|
|
32802
32900
|
lastSeenAt: row.lastSeenAt
|
|
32803
32901
|
};
|
|
@@ -32825,50 +32923,54 @@ function maxTimestamp(a, b2) {
|
|
|
32825
32923
|
return a > b2 ? a : b2;
|
|
32826
32924
|
}
|
|
32827
32925
|
async function fetchPersistedPortalTelemetry(repoPath, apiUrl, options) {
|
|
32828
|
-
const
|
|
32829
|
-
|
|
32926
|
+
const empty = { usage: [], events: [], maxSyncedAt: null, failures: [], truncated: [] };
|
|
32927
|
+
const repo = await resolveControlRepoId(apiUrl, repoPath);
|
|
32928
|
+
if (!repo.ok) {
|
|
32929
|
+
return { ...empty, failures: [{ channel: "repos", reason: repo.error }] };
|
|
32930
|
+
}
|
|
32931
|
+
if (!repo.data) return empty;
|
|
32830
32932
|
const since = options?.since ?? null;
|
|
32831
|
-
const [
|
|
32832
|
-
|
|
32833
|
-
|
|
32933
|
+
const [usageRead, eventsRead] = await Promise.all([
|
|
32934
|
+
readControlJson(`${apiUrl}/api/repos/${repo.data}/usage`),
|
|
32935
|
+
readControlPages({
|
|
32936
|
+
url: `${apiUrl}/api/repos/${repo.data}/events`,
|
|
32937
|
+
since,
|
|
32938
|
+
rows: (data) => data?.events ?? [],
|
|
32939
|
+
cursor: (row) => ({ createdAt: row.createdAt, id: row.id })
|
|
32940
|
+
})
|
|
32834
32941
|
]);
|
|
32835
|
-
const
|
|
32836
|
-
const
|
|
32942
|
+
const failures = [];
|
|
32943
|
+
const truncated = [];
|
|
32944
|
+
if (!usageRead.ok) failures.push({ channel: "usage", reason: usageRead.error });
|
|
32945
|
+
if (!eventsRead.ok) failures.push({ channel: "events", reason: eventsRead.error });
|
|
32946
|
+
else if (eventsRead.truncated) truncated.push("events");
|
|
32947
|
+
const usage2 = selectSince(
|
|
32948
|
+
usageRead.ok ? usageRead.data?.usage ?? [] : [],
|
|
32949
|
+
since,
|
|
32950
|
+
(row) => row.updatedAt ?? row.lastSeenAt
|
|
32951
|
+
);
|
|
32952
|
+
const events = selectSince(
|
|
32953
|
+
eventsRead.ok ? eventsRead.rows : [],
|
|
32954
|
+
since,
|
|
32955
|
+
(row) => row.createdAt ?? row.timestamp
|
|
32956
|
+
);
|
|
32837
32957
|
return {
|
|
32838
32958
|
usage: usage2.selected.map(normalizeUsage),
|
|
32839
32959
|
events: events.selected.map(normalizeEvent),
|
|
32840
|
-
maxSyncedAt: maxTimestamp(usage2.maxSyncedAt, events.maxSyncedAt)
|
|
32960
|
+
maxSyncedAt: maxTimestamp(usage2.maxSyncedAt, events.maxSyncedAt),
|
|
32961
|
+
failures,
|
|
32962
|
+
truncated
|
|
32841
32963
|
};
|
|
32842
32964
|
}
|
|
32843
|
-
var path28, FETCH_TIMEOUT_MS;
|
|
32844
32965
|
var init_control_persisted_usage = __esm({
|
|
32845
32966
|
"src/core/control-persisted-usage.ts"() {
|
|
32846
32967
|
"use strict";
|
|
32847
|
-
path28 = __toESM(require("path"));
|
|
32848
32968
|
init_portal_watermark();
|
|
32849
|
-
|
|
32969
|
+
init_control_api_read();
|
|
32850
32970
|
}
|
|
32851
32971
|
});
|
|
32852
32972
|
|
|
32853
32973
|
// src/core/control-persisted-trajectory.ts
|
|
32854
|
-
async function getJson2(url) {
|
|
32855
|
-
try {
|
|
32856
|
-
const response = await fetch(url, {
|
|
32857
|
-
method: "GET",
|
|
32858
|
-
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
32859
|
-
});
|
|
32860
|
-
if (!response.ok) return null;
|
|
32861
|
-
return await response.json();
|
|
32862
|
-
} catch {
|
|
32863
|
-
return null;
|
|
32864
|
-
}
|
|
32865
|
-
}
|
|
32866
|
-
async function resolveControlRepoId2(apiUrl, repoPath) {
|
|
32867
|
-
const repos = await getJson2(`${apiUrl}/api/repos`);
|
|
32868
|
-
if (!Array.isArray(repos)) return null;
|
|
32869
|
-
const target = path29.resolve(repoPath);
|
|
32870
|
-
return repos.find((repo) => path29.resolve(repo.path) === target)?.id ?? null;
|
|
32871
|
-
}
|
|
32872
32974
|
function optional(value) {
|
|
32873
32975
|
return value == null ? void 0 : value;
|
|
32874
32976
|
}
|
|
@@ -32924,24 +33026,44 @@ async function fetchPersistedTrajectory(repoPath, apiUrl, request) {
|
|
|
32924
33026
|
records: [],
|
|
32925
33027
|
spans: [],
|
|
32926
33028
|
recordsMaxSyncedAt: null,
|
|
32927
|
-
spansMaxSyncedAt: null
|
|
33029
|
+
spansMaxSyncedAt: null,
|
|
33030
|
+
failures: [],
|
|
33031
|
+
truncated: []
|
|
32928
33032
|
};
|
|
32929
33033
|
if (!request.records && !request.spans) return empty;
|
|
32930
|
-
const
|
|
32931
|
-
if (!
|
|
32932
|
-
|
|
32933
|
-
|
|
32934
|
-
|
|
32935
|
-
|
|
32936
|
-
|
|
33034
|
+
const repo = await resolveControlRepoId(apiUrl, repoPath);
|
|
33035
|
+
if (!repo.ok) return { ...empty, failures: [{ channel: "repos", reason: repo.error }] };
|
|
33036
|
+
if (!repo.data) return empty;
|
|
33037
|
+
const [trajectoryRead, spansRead] = await Promise.all([
|
|
33038
|
+
request.records ? readControlPages({
|
|
33039
|
+
url: `${apiUrl}/api/repos/${repo.data}/trajectory`,
|
|
33040
|
+
since: request.records.since,
|
|
33041
|
+
rows: (data) => data?.records ?? [],
|
|
33042
|
+
cursor: (row) => ({ createdAt: row.createdAt, id: row.id })
|
|
33043
|
+
}) : null,
|
|
33044
|
+
request.spans ? readControlPages({
|
|
33045
|
+
url: `${apiUrl}/api/repos/${repo.data}/spans`,
|
|
33046
|
+
since: request.spans.since,
|
|
33047
|
+
rows: (data) => data?.spans ?? [],
|
|
33048
|
+
cursor: (row) => ({ createdAt: row.createdAt, id: row.id })
|
|
33049
|
+
}) : null
|
|
32937
33050
|
]);
|
|
33051
|
+
const failures = [];
|
|
33052
|
+
const truncated = [];
|
|
33053
|
+
if (trajectoryRead && !trajectoryRead.ok) {
|
|
33054
|
+
failures.push({ channel: "trajectory", reason: trajectoryRead.error });
|
|
33055
|
+
} else if (trajectoryRead?.ok && trajectoryRead.truncated) {
|
|
33056
|
+
truncated.push("trajectory");
|
|
33057
|
+
}
|
|
33058
|
+
if (spansRead && !spansRead.ok) failures.push({ channel: "spans", reason: spansRead.error });
|
|
33059
|
+
else if (spansRead?.ok && spansRead.truncated) truncated.push("spans");
|
|
32938
33060
|
const trajectory = selectSince(
|
|
32939
|
-
|
|
33061
|
+
trajectoryRead?.ok ? trajectoryRead.rows : [],
|
|
32940
33062
|
request.records ? request.records.since : null,
|
|
32941
33063
|
(row) => row.createdAt ?? null
|
|
32942
33064
|
);
|
|
32943
33065
|
const spans = selectSince(
|
|
32944
|
-
|
|
33066
|
+
spansRead?.ok ? spansRead.rows : [],
|
|
32945
33067
|
request.spans ? request.spans.since : null,
|
|
32946
33068
|
(row) => row.createdAt ?? null
|
|
32947
33069
|
);
|
|
@@ -32952,17 +33074,17 @@ async function fetchPersistedTrajectory(repoPath, apiUrl, request) {
|
|
|
32952
33074
|
}),
|
|
32953
33075
|
spans: spans.selected.map(toPortalSpan),
|
|
32954
33076
|
recordsMaxSyncedAt: trajectory.maxSyncedAt,
|
|
32955
|
-
spansMaxSyncedAt: spans.maxSyncedAt
|
|
33077
|
+
spansMaxSyncedAt: spans.maxSyncedAt,
|
|
33078
|
+
failures,
|
|
33079
|
+
truncated
|
|
32956
33080
|
};
|
|
32957
33081
|
}
|
|
32958
|
-
var path29, FETCH_TIMEOUT_MS2;
|
|
32959
33082
|
var init_control_persisted_trajectory = __esm({
|
|
32960
33083
|
"src/core/control-persisted-trajectory.ts"() {
|
|
32961
33084
|
"use strict";
|
|
32962
|
-
path29 = __toESM(require("path"));
|
|
32963
33085
|
init_schema2();
|
|
32964
33086
|
init_portal_watermark();
|
|
32965
|
-
|
|
33087
|
+
init_control_api_read();
|
|
32966
33088
|
}
|
|
32967
33089
|
});
|
|
32968
33090
|
|
|
@@ -33003,10 +33125,34 @@ function mergeModelBreakdown(a, b2) {
|
|
|
33003
33125
|
}
|
|
33004
33126
|
return out;
|
|
33005
33127
|
}
|
|
33006
|
-
function
|
|
33128
|
+
function replaceCounters(row) {
|
|
33129
|
+
return {
|
|
33130
|
+
tokensInput: num2(row.tokensInput),
|
|
33131
|
+
tokensOutput: num2(row.tokensOutput),
|
|
33132
|
+
tokensCacheRead: num2(row.tokensCacheRead),
|
|
33133
|
+
tokensCacheCreation: num2(row.tokensCacheCreation),
|
|
33134
|
+
tokensTotal: num2(row.tokensTotal),
|
|
33135
|
+
costUsd: row.costUsd ?? null,
|
|
33136
|
+
modelBreakdown: row.modelBreakdown,
|
|
33137
|
+
harvestVersion: usageHarvestVersion(row)
|
|
33138
|
+
};
|
|
33139
|
+
}
|
|
33140
|
+
function maxCounters(a, b2) {
|
|
33007
33141
|
const costA = a.costUsd ?? null;
|
|
33008
33142
|
const costB = b2.costUsd ?? null;
|
|
33009
|
-
|
|
33143
|
+
return {
|
|
33144
|
+
tokensInput: Math.max(num2(a.tokensInput), num2(b2.tokensInput)),
|
|
33145
|
+
tokensOutput: Math.max(num2(a.tokensOutput), num2(b2.tokensOutput)),
|
|
33146
|
+
tokensCacheRead: Math.max(num2(a.tokensCacheRead), num2(b2.tokensCacheRead)),
|
|
33147
|
+
tokensCacheCreation: Math.max(num2(a.tokensCacheCreation), num2(b2.tokensCacheCreation)),
|
|
33148
|
+
tokensTotal: Math.max(num2(a.tokensTotal), num2(b2.tokensTotal)),
|
|
33149
|
+
costUsd: costA != null || costB != null ? Math.max(num2(costA), num2(costB)) : a.costUsd ?? b2.costUsd,
|
|
33150
|
+
modelBreakdown: mergeModelBreakdown(a.modelBreakdown, b2.modelBreakdown),
|
|
33151
|
+
harvestVersion: mergedHarvestVersion(a, b2)
|
|
33152
|
+
};
|
|
33153
|
+
}
|
|
33154
|
+
function mergeUsageRow(a, b2) {
|
|
33155
|
+
const counters = harvestSupersedes(a, b2) ? replaceCounters(b2) : harvestSupersedes(b2, a) ? replaceCounters(a) : maxCounters(a, b2);
|
|
33010
33156
|
return {
|
|
33011
33157
|
...a,
|
|
33012
33158
|
...b2,
|
|
@@ -33015,13 +33161,7 @@ function mergeUsageRow(a, b2) {
|
|
|
33015
33161
|
suffix: b2.suffix ?? a.suffix,
|
|
33016
33162
|
workUnitId: b2.workUnitId ?? a.workUnitId,
|
|
33017
33163
|
attemptId: b2.attemptId ?? a.attemptId,
|
|
33018
|
-
|
|
33019
|
-
tokensOutput: Math.max(num2(a.tokensOutput), num2(b2.tokensOutput)),
|
|
33020
|
-
tokensCacheRead: Math.max(num2(a.tokensCacheRead), num2(b2.tokensCacheRead)),
|
|
33021
|
-
tokensCacheCreation: Math.max(num2(a.tokensCacheCreation), num2(b2.tokensCacheCreation)),
|
|
33022
|
-
tokensTotal: Math.max(num2(a.tokensTotal), num2(b2.tokensTotal)),
|
|
33023
|
-
costUsd,
|
|
33024
|
-
modelBreakdown: mergeModelBreakdown(a.modelBreakdown, b2.modelBreakdown),
|
|
33164
|
+
...counters,
|
|
33025
33165
|
sources: [.../* @__PURE__ */ new Set([...a.sources ?? [], ...b2.sources ?? []])],
|
|
33026
33166
|
firstSeenAt: earlier(a.firstSeenAt, b2.firstSeenAt),
|
|
33027
33167
|
lastSeenAt: later(a.lastSeenAt, b2.lastSeenAt)
|
|
@@ -33048,6 +33188,7 @@ var KEY_SEP;
|
|
|
33048
33188
|
var init_portal_usage_merge = __esm({
|
|
33049
33189
|
"src/core/portal-usage-merge.ts"() {
|
|
33050
33190
|
"use strict";
|
|
33191
|
+
init_schema2();
|
|
33051
33192
|
KEY_SEP = "\0";
|
|
33052
33193
|
}
|
|
33053
33194
|
});
|
|
@@ -33157,13 +33298,13 @@ function describeFetchFailure(url, bodyBytes, err) {
|
|
|
33157
33298
|
}
|
|
33158
33299
|
async function postForResponse(url, headers, payload) {
|
|
33159
33300
|
let lastErr;
|
|
33160
|
-
for (let
|
|
33301
|
+
for (let attempt2 = 1; attempt2 <= MAX_FETCH_ATTEMPTS; attempt2++) {
|
|
33161
33302
|
try {
|
|
33162
33303
|
return await fetch(url, { method: "POST", headers, body: payload });
|
|
33163
33304
|
} catch (err) {
|
|
33164
33305
|
lastErr = err;
|
|
33165
|
-
if (
|
|
33166
|
-
await new Promise((
|
|
33306
|
+
if (attempt2 < MAX_FETCH_ATTEMPTS) {
|
|
33307
|
+
await new Promise((resolve52) => setTimeout(resolve52, attempt2 * 100));
|
|
33167
33308
|
}
|
|
33168
33309
|
}
|
|
33169
33310
|
}
|
|
@@ -33258,8 +33399,17 @@ function modelsFromBreakdown(breakdown) {
|
|
|
33258
33399
|
...totals && typeof totals === "object" ? totals : {}
|
|
33259
33400
|
}));
|
|
33260
33401
|
}
|
|
33402
|
+
function describeReadFailures(repoPath, failures) {
|
|
33403
|
+
const detail = failures.map((f) => `${f.channel} (${f.reason})`).join(", ");
|
|
33404
|
+
return `${path29.basename(repoPath)}: could not read ${detail} from Mission Control \u2014 that telemetry is missing from this sync and its watermark is held, so the next sync retries it.`;
|
|
33405
|
+
}
|
|
33406
|
+
function describeTruncatedReads(repoPath, channels) {
|
|
33407
|
+
return `${path29.basename(repoPath)}: ${channels.join(", ")} hit the read page cap \u2014 the remainder syncs on the next run.`;
|
|
33408
|
+
}
|
|
33261
33409
|
async function collectPortalTelemetry(repoPath, slots, controlApiUrl, since, portal) {
|
|
33262
|
-
if (!isTelemetryEnabled())
|
|
33410
|
+
if (!isTelemetryEnabled()) {
|
|
33411
|
+
return { usage: [], events: [], maxSyncedAt: null, failures: [], truncated: [] };
|
|
33412
|
+
}
|
|
33263
33413
|
try {
|
|
33264
33414
|
const userEmail = resolvePortalUserEmail(portal);
|
|
33265
33415
|
const fallbackAgentId = slots.length > 0 ? Math.min(...slots.map((slot) => slot.agentId)) : null;
|
|
@@ -33318,9 +33468,23 @@ async function collectPortalTelemetry(repoPath, slots, controlApiUrl, since, por
|
|
|
33318
33468
|
const events = dedupePortalEvents(harvestedEvents, persisted.events).map(
|
|
33319
33469
|
(event) => dropNullFields({ ...event })
|
|
33320
33470
|
);
|
|
33321
|
-
return {
|
|
33322
|
-
|
|
33323
|
-
|
|
33471
|
+
return {
|
|
33472
|
+
usage: usage2,
|
|
33473
|
+
events,
|
|
33474
|
+
maxSyncedAt: persisted.maxSyncedAt,
|
|
33475
|
+
failures: persisted.failures,
|
|
33476
|
+
truncated: persisted.truncated
|
|
33477
|
+
};
|
|
33478
|
+
} catch (err) {
|
|
33479
|
+
return {
|
|
33480
|
+
usage: [],
|
|
33481
|
+
events: [],
|
|
33482
|
+
maxSyncedAt: null,
|
|
33483
|
+
failures: [
|
|
33484
|
+
{ channel: "telemetry", reason: err instanceof Error ? err.message : String(err) }
|
|
33485
|
+
],
|
|
33486
|
+
truncated: []
|
|
33487
|
+
};
|
|
33324
33488
|
}
|
|
33325
33489
|
}
|
|
33326
33490
|
async function buildPortalPayload(repoPath, controlApiUrl, since, full = false, portal) {
|
|
@@ -33334,16 +33498,16 @@ async function buildPortalPayload(repoPath, controlApiUrl, since, full = false,
|
|
|
33334
33498
|
const attempts = listWorkAttempts(harnessRoot);
|
|
33335
33499
|
const validationBindings = listValidationBindings(harnessRoot);
|
|
33336
33500
|
const userEmail = resolvePortalUserEmail(portal);
|
|
33337
|
-
const { usage: usage2, events, maxSyncedAt } = await collectPortalTelemetry(
|
|
33501
|
+
const { usage: usage2, events, maxSyncedAt, failures, truncated } = await collectPortalTelemetry(
|
|
33338
33502
|
repoPath,
|
|
33339
33503
|
status.slots,
|
|
33340
33504
|
controlApiUrl,
|
|
33341
33505
|
since,
|
|
33342
33506
|
portal
|
|
33343
33507
|
);
|
|
33344
|
-
if (full && isTelemetryEnabled() && usage2.length === 0 && runs.some((r) => r.agentId != null)) {
|
|
33508
|
+
if (full && isTelemetryEnabled() && failures.length === 0 && usage2.length === 0 && runs.some((r) => r.agentId != null)) {
|
|
33345
33509
|
warn(
|
|
33346
|
-
`${
|
|
33510
|
+
`${path29.basename(repoPath)}: agent runs found but no usage harvested \u2014 attribution will be missing. This happens when agent sessions ran outside the har worktree slot (e.g. in the main checkout). Run agents inside \`har env launch\`.`
|
|
33347
33511
|
);
|
|
33348
33512
|
}
|
|
33349
33513
|
const syncBody = {
|
|
@@ -33363,7 +33527,7 @@ async function buildPortalPayload(repoPath, controlApiUrl, since, full = false,
|
|
|
33363
33527
|
...usage2.length > 0 ? { usage: usage2 } : {}
|
|
33364
33528
|
};
|
|
33365
33529
|
const runsPayload = userEmail ? runs.map((run2) => ({ ...run2, userEmail })) : runs;
|
|
33366
|
-
return { syncBody, runs: runsPayload, events, maxSyncedAt };
|
|
33530
|
+
return { syncBody, runs: runsPayload, events, maxSyncedAt, failures, truncated };
|
|
33367
33531
|
}
|
|
33368
33532
|
async function isControlApiReachable(apiUrl = getControlApiUrl()) {
|
|
33369
33533
|
try {
|
|
@@ -33380,7 +33544,7 @@ async function waitForControlApi(apiUrl = getControlApiUrl(), timeoutMs = 6e4, i
|
|
|
33380
33544
|
const deadline = Date.now() + timeoutMs;
|
|
33381
33545
|
while (Date.now() < deadline) {
|
|
33382
33546
|
if (await isControlApiReachable(apiUrl)) return true;
|
|
33383
|
-
await new Promise((
|
|
33547
|
+
await new Promise((resolve52) => setTimeout(resolve52, intervalMs));
|
|
33384
33548
|
}
|
|
33385
33549
|
return false;
|
|
33386
33550
|
}
|
|
@@ -33397,13 +33561,14 @@ async function syncReposWithControl(options) {
|
|
|
33397
33561
|
const results = [];
|
|
33398
33562
|
let synced = 0;
|
|
33399
33563
|
let failed = 0;
|
|
33564
|
+
let incomplete = 0;
|
|
33400
33565
|
for (const repoPath of options.repoPaths) {
|
|
33401
33566
|
const destinationAliases = destinationAliasesForSync(repoPath, options.portalTargets);
|
|
33402
33567
|
if (destinationAliases.length > 1) {
|
|
33403
33568
|
const targetResults = [];
|
|
33404
33569
|
for (const alias of destinationAliases) {
|
|
33405
33570
|
try {
|
|
33406
|
-
await withTimeout(
|
|
33571
|
+
const outcome = await withTimeout(
|
|
33407
33572
|
syncRepoWithControl({
|
|
33408
33573
|
repoPath,
|
|
33409
33574
|
apiUrl,
|
|
@@ -33415,7 +33580,11 @@ async function syncReposWithControl(options) {
|
|
|
33415
33580
|
EXPLICIT_SYNC_TIMEOUT_MS,
|
|
33416
33581
|
"control sync"
|
|
33417
33582
|
);
|
|
33418
|
-
targetResults.push({
|
|
33583
|
+
targetResults.push({
|
|
33584
|
+
alias,
|
|
33585
|
+
ok: true,
|
|
33586
|
+
...outcome.warnings.length > 0 ? { warnings: outcome.warnings } : {}
|
|
33587
|
+
});
|
|
33419
33588
|
} catch (err) {
|
|
33420
33589
|
targetResults.push({
|
|
33421
33590
|
alias,
|
|
@@ -33427,11 +33596,12 @@ async function syncReposWithControl(options) {
|
|
|
33427
33596
|
const ok = targetResults.every((entry) => entry.ok);
|
|
33428
33597
|
if (ok) synced++;
|
|
33429
33598
|
else failed++;
|
|
33599
|
+
if (ok && targetResults.some((entry) => entry.warnings)) incomplete++;
|
|
33430
33600
|
results.push({ repoPath, ok, targets: targetResults, error: ok ? void 0 : "one or more targets failed" });
|
|
33431
33601
|
continue;
|
|
33432
33602
|
}
|
|
33433
33603
|
try {
|
|
33434
|
-
await withTimeout(
|
|
33604
|
+
const outcome = await withTimeout(
|
|
33435
33605
|
syncRepoWithControl({
|
|
33436
33606
|
repoPath,
|
|
33437
33607
|
apiUrl,
|
|
@@ -33444,13 +33614,18 @@ async function syncReposWithControl(options) {
|
|
|
33444
33614
|
"control sync"
|
|
33445
33615
|
);
|
|
33446
33616
|
synced++;
|
|
33447
|
-
|
|
33617
|
+
if (outcome.warnings.length > 0) incomplete++;
|
|
33618
|
+
results.push({
|
|
33619
|
+
repoPath,
|
|
33620
|
+
ok: true,
|
|
33621
|
+
...outcome.warnings.length > 0 ? { warnings: outcome.warnings } : {}
|
|
33622
|
+
});
|
|
33448
33623
|
} catch (err) {
|
|
33449
33624
|
failed++;
|
|
33450
33625
|
results.push({ repoPath, ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
33451
33626
|
}
|
|
33452
33627
|
}
|
|
33453
|
-
return { synced, failed, results };
|
|
33628
|
+
return { synced, failed, incomplete, results };
|
|
33454
33629
|
}
|
|
33455
33630
|
function destinationAliasesForSync(repoPath, explicit) {
|
|
33456
33631
|
if (explicit && explicit.length > 0) return explicit;
|
|
@@ -33515,7 +33690,7 @@ async function syncRepoWithLocalControl(options) {
|
|
|
33515
33690
|
const listResponse = await fetch(`${apiUrl}/api/repos`);
|
|
33516
33691
|
if (!listResponse.ok) throw new Error("Failed to list repos from Control API");
|
|
33517
33692
|
const repos = await listResponse.json();
|
|
33518
|
-
const existing = repos.find((r) =>
|
|
33693
|
+
const existing = repos.find((r) => path29.resolve(r.path) === repoPath);
|
|
33519
33694
|
if (!existing) {
|
|
33520
33695
|
return;
|
|
33521
33696
|
}
|
|
@@ -33527,7 +33702,7 @@ async function syncRepoWithLocalControl(options) {
|
|
|
33527
33702
|
}
|
|
33528
33703
|
}
|
|
33529
33704
|
async function syncRepoWithPortal(options, controlApiUrl, portal) {
|
|
33530
|
-
if (!isRepoPortalSyncEnabled(options.repoPath)) return;
|
|
33705
|
+
if (!isRepoPortalSyncEnabled(options.repoPath)) return [];
|
|
33531
33706
|
const { repoPath, dryRun, full } = options;
|
|
33532
33707
|
const watermarkKey = watermarkKeyForTarget(portal);
|
|
33533
33708
|
const since = full ? null : readPortalWatermarkForTarget(repoPath, portal);
|
|
@@ -33540,7 +33715,7 @@ async function syncRepoWithPortal(options, controlApiUrl, portal) {
|
|
|
33540
33715
|
}
|
|
33541
33716
|
}
|
|
33542
33717
|
const runsSince = rewindSince(stored?.lastSyncedAt ?? null);
|
|
33543
|
-
const { syncBody, runs, events, maxSyncedAt } = await buildPortalPayload(
|
|
33718
|
+
const { syncBody, runs, events, maxSyncedAt, failures, truncated } = await buildPortalPayload(
|
|
33544
33719
|
repoPath,
|
|
33545
33720
|
controlApiUrl,
|
|
33546
33721
|
since,
|
|
@@ -33563,18 +33738,25 @@ async function syncRepoWithPortal(options, controlApiUrl, portal) {
|
|
|
33563
33738
|
for (const batch of chunkBySerializedSize(events, maxSyncBatchBytes())) {
|
|
33564
33739
|
await postPortal(portal, "/api/otel", { path: repoPath, events: batch }, dryRun);
|
|
33565
33740
|
}
|
|
33566
|
-
if (!dryRun && maxSyncedAt) {
|
|
33741
|
+
if (!dryRun && maxSyncedAt && failures.length === 0) {
|
|
33567
33742
|
writePortalWatermark(repoPath, watermarkKey, maxSyncedAt);
|
|
33568
33743
|
}
|
|
33569
|
-
|
|
33744
|
+
const warnings = [];
|
|
33745
|
+
if (failures.length > 0) warnings.push(describeReadFailures(repoPath, failures));
|
|
33746
|
+
if (truncated.length > 0) warnings.push(describeTruncatedReads(repoPath, truncated));
|
|
33747
|
+
warnings.push(
|
|
33748
|
+
...await syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun, full)
|
|
33749
|
+
);
|
|
33750
|
+
for (const message of warnings) warn(message);
|
|
33751
|
+
return warnings;
|
|
33570
33752
|
}
|
|
33571
33753
|
async function syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun, full) {
|
|
33572
33754
|
const wantRecords = isPortalTrajectoryEnabledForTarget(portal);
|
|
33573
33755
|
const wantSpans = isTelemetryEnabled();
|
|
33574
|
-
if (!wantRecords && !wantSpans) return;
|
|
33756
|
+
if (!wantRecords && !wantSpans) return [];
|
|
33575
33757
|
const recordsTarget = trajectoryWatermarkTarget(portal);
|
|
33576
33758
|
const spansTarget = spansWatermarkTarget(portal);
|
|
33577
|
-
const { records, spans, recordsMaxSyncedAt, spansMaxSyncedAt } = await fetchPersistedTrajectory(repoPath, controlApiUrl, {
|
|
33759
|
+
const { records, spans, recordsMaxSyncedAt, spansMaxSyncedAt, failures, truncated } = await fetchPersistedTrajectory(repoPath, controlApiUrl, {
|
|
33578
33760
|
records: wantRecords ? {
|
|
33579
33761
|
since: full ? null : readScopedPortalWatermark(
|
|
33580
33762
|
repoPath,
|
|
@@ -33590,10 +33772,11 @@ async function syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun,
|
|
|
33590
33772
|
)
|
|
33591
33773
|
} : false
|
|
33592
33774
|
});
|
|
33775
|
+
const failedChannel = (channel) => failures.some((failure) => failure.channel === channel || failure.channel === "repos");
|
|
33593
33776
|
for (const batch of chunkBySerializedSize(spans, maxSyncBatchBytes())) {
|
|
33594
33777
|
await postPortal(portal, "/api/otel", { path: repoPath, spans: batch }, dryRun);
|
|
33595
33778
|
}
|
|
33596
|
-
if (!dryRun && spansMaxSyncedAt) {
|
|
33779
|
+
if (!dryRun && spansMaxSyncedAt && !failedChannel("spans")) {
|
|
33597
33780
|
writePortalWatermark(repoPath, spansTarget, spansMaxSyncedAt);
|
|
33598
33781
|
}
|
|
33599
33782
|
let recordsLanded = true;
|
|
@@ -33607,14 +33790,18 @@ async function syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun,
|
|
|
33607
33790
|
if (!supported) {
|
|
33608
33791
|
recordsLanded = false;
|
|
33609
33792
|
warn(
|
|
33610
|
-
`${
|
|
33793
|
+
`${path29.basename(repoPath)}: this har-portal has no /api/trajectory endpoint \u2014 trajectory forwarding skipped (upgrade the portal; records are kept for the next sync).`
|
|
33611
33794
|
);
|
|
33612
33795
|
break;
|
|
33613
33796
|
}
|
|
33614
33797
|
}
|
|
33615
|
-
if (!dryRun && recordsLanded && recordsMaxSyncedAt) {
|
|
33798
|
+
if (!dryRun && recordsLanded && recordsMaxSyncedAt && !failedChannel("trajectory")) {
|
|
33616
33799
|
writePortalWatermark(repoPath, recordsTarget, recordsMaxSyncedAt);
|
|
33617
33800
|
}
|
|
33801
|
+
return [
|
|
33802
|
+
...failures.length > 0 ? [describeReadFailures(repoPath, failures)] : [],
|
|
33803
|
+
...truncated.length > 0 ? [describeTruncatedReads(repoPath, truncated)] : []
|
|
33804
|
+
];
|
|
33618
33805
|
}
|
|
33619
33806
|
async function syncRepoWithControl(options) {
|
|
33620
33807
|
const repoPath = canonicalizeControlRepoPath(options.repoPath);
|
|
@@ -33646,19 +33833,20 @@ async function syncRepoWithControl(options) {
|
|
|
33646
33833
|
if (!response.ok) {
|
|
33647
33834
|
throw new Error(`Cloud sync failed: ${response.status}`);
|
|
33648
33835
|
}
|
|
33649
|
-
return;
|
|
33836
|
+
return { warnings: [] };
|
|
33650
33837
|
}
|
|
33651
33838
|
await syncRepoWithLocalControl({ ...options, repoPath, apiUrl });
|
|
33652
|
-
if (!isRepoPortalSyncEnabled(repoPath)) return;
|
|
33839
|
+
if (!isRepoPortalSyncEnabled(repoPath)) return { warnings: [] };
|
|
33653
33840
|
const resolved = resolvePortalTargetsForRepo({
|
|
33654
33841
|
repoPath,
|
|
33655
33842
|
explicitTargets: options.portalTargets
|
|
33656
33843
|
});
|
|
33657
|
-
if (!resolved) return;
|
|
33844
|
+
if (!resolved) return { warnings: [] };
|
|
33845
|
+
const warnings = [];
|
|
33658
33846
|
const failures = [];
|
|
33659
33847
|
for (const portal of resolved.targets) {
|
|
33660
33848
|
try {
|
|
33661
|
-
await syncRepoWithPortal({ ...options, repoPath }, apiUrl, portal);
|
|
33849
|
+
warnings.push(...await syncRepoWithPortal({ ...options, repoPath }, apiUrl, portal));
|
|
33662
33850
|
} catch (err) {
|
|
33663
33851
|
failures.push({
|
|
33664
33852
|
alias: portal.alias ?? portal.identityKey,
|
|
@@ -33666,7 +33854,7 @@ async function syncRepoWithControl(options) {
|
|
|
33666
33854
|
});
|
|
33667
33855
|
}
|
|
33668
33856
|
}
|
|
33669
|
-
if (failures.length === 0) return;
|
|
33857
|
+
if (failures.length === 0) return { warnings };
|
|
33670
33858
|
if (failures.length === resolved.targets.length && failures.length === 1) {
|
|
33671
33859
|
throw new Error(failures[0].error);
|
|
33672
33860
|
}
|
|
@@ -33806,7 +33994,7 @@ async function syncRunWithLocalControl(repoPath, run2, apiUrl) {
|
|
|
33806
33994
|
const listResponse = await fetch(`${apiUrl}/api/repos`);
|
|
33807
33995
|
if (!listResponse.ok) return;
|
|
33808
33996
|
const repos = await listResponse.json();
|
|
33809
|
-
repoId = repos.find((r) =>
|
|
33997
|
+
repoId = repos.find((r) => path29.resolve(r.path) === repoPath)?.id;
|
|
33810
33998
|
}
|
|
33811
33999
|
if (!repoId) return;
|
|
33812
34000
|
const runsBody = SyncRunsInputSchema.parse({ runs: [run2] });
|
|
@@ -33839,11 +34027,11 @@ async function syncRunWithControlAsync(repoPath, run2) {
|
|
|
33839
34027
|
}
|
|
33840
34028
|
}
|
|
33841
34029
|
}
|
|
33842
|
-
var
|
|
34030
|
+
var path29, DEFAULT_MAX_BATCH_BYTES, DEFAULT_SYNC_OVERLAP_MS, MAX_FETCH_ATTEMPTS, SYNC_TIMEOUT_MS, EXPLICIT_SYNC_TIMEOUT_MS;
|
|
33843
34031
|
var init_control_sync = __esm({
|
|
33844
34032
|
"src/core/control-sync.ts"() {
|
|
33845
34033
|
"use strict";
|
|
33846
|
-
|
|
34034
|
+
path29 = __toESM(require("path"));
|
|
33847
34035
|
init_manifest();
|
|
33848
34036
|
init_stages();
|
|
33849
34037
|
init_schema2();
|
|
@@ -33878,7 +34066,7 @@ var init_control_sync = __esm({
|
|
|
33878
34066
|
// src/core/sync-context.ts
|
|
33879
34067
|
function markDirty(repoPath) {
|
|
33880
34068
|
if (!repoPath) return;
|
|
33881
|
-
dirtyRepos.add(
|
|
34069
|
+
dirtyRepos.add(path30.resolve(repoPath));
|
|
33882
34070
|
}
|
|
33883
34071
|
function markAllRegisteredDirty() {
|
|
33884
34072
|
syncAllRegistered = true;
|
|
@@ -33903,11 +34091,11 @@ async function syncDirtyRepos() {
|
|
|
33903
34091
|
} catch {
|
|
33904
34092
|
}
|
|
33905
34093
|
}
|
|
33906
|
-
var
|
|
34094
|
+
var path30, dirtyRepos, syncAllRegistered;
|
|
33907
34095
|
var init_sync_context = __esm({
|
|
33908
34096
|
"src/core/sync-context.ts"() {
|
|
33909
34097
|
"use strict";
|
|
33910
|
-
|
|
34098
|
+
path30 = __toESM(require("path"));
|
|
33911
34099
|
dirtyRepos = /* @__PURE__ */ new Set();
|
|
33912
34100
|
syncAllRegistered = false;
|
|
33913
34101
|
}
|
|
@@ -35005,15 +35193,15 @@ var require_route = __commonJS({
|
|
|
35005
35193
|
};
|
|
35006
35194
|
}
|
|
35007
35195
|
function wrapConversion(toModel, graph) {
|
|
35008
|
-
const
|
|
35196
|
+
const path69 = [graph[toModel].parent, toModel];
|
|
35009
35197
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
35010
35198
|
let cur = graph[toModel].parent;
|
|
35011
35199
|
while (graph[cur].parent) {
|
|
35012
|
-
|
|
35200
|
+
path69.unshift(graph[cur].parent);
|
|
35013
35201
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
35014
35202
|
cur = graph[cur].parent;
|
|
35015
35203
|
}
|
|
35016
|
-
fn.conversion =
|
|
35204
|
+
fn.conversion = path69;
|
|
35017
35205
|
return fn;
|
|
35018
35206
|
}
|
|
35019
35207
|
module2.exports = function(fromModel) {
|
|
@@ -41507,7 +41695,7 @@ var require_lib2 = __commonJS({
|
|
|
41507
41695
|
return matches;
|
|
41508
41696
|
};
|
|
41509
41697
|
exports2.analyse = analyse;
|
|
41510
|
-
var detectFile = (filepath, opts = {}) => new Promise((
|
|
41698
|
+
var detectFile = (filepath, opts = {}) => new Promise((resolve52, reject) => {
|
|
41511
41699
|
let fd;
|
|
41512
41700
|
const fs54 = (0, node_1.default)();
|
|
41513
41701
|
const handler = (err, buffer) => {
|
|
@@ -41517,7 +41705,7 @@ var require_lib2 = __commonJS({
|
|
|
41517
41705
|
if (err) {
|
|
41518
41706
|
reject(err);
|
|
41519
41707
|
} else if (buffer) {
|
|
41520
|
-
|
|
41708
|
+
resolve52((0, exports2.detect)(buffer));
|
|
41521
41709
|
} else {
|
|
41522
41710
|
reject(new Error("No error and no buffer received"));
|
|
41523
41711
|
}
|
|
@@ -46066,7 +46254,7 @@ var require_Observable = __commonJS({
|
|
|
46066
46254
|
Observable2.prototype.forEach = function(next, promiseCtor) {
|
|
46067
46255
|
var _this = this;
|
|
46068
46256
|
promiseCtor = getPromiseCtor(promiseCtor);
|
|
46069
|
-
return new promiseCtor(function(
|
|
46257
|
+
return new promiseCtor(function(resolve52, reject) {
|
|
46070
46258
|
var subscriber = new Subscriber_1.SafeSubscriber({
|
|
46071
46259
|
next: function(value) {
|
|
46072
46260
|
try {
|
|
@@ -46077,7 +46265,7 @@ var require_Observable = __commonJS({
|
|
|
46077
46265
|
}
|
|
46078
46266
|
},
|
|
46079
46267
|
error: reject,
|
|
46080
|
-
complete:
|
|
46268
|
+
complete: resolve52
|
|
46081
46269
|
});
|
|
46082
46270
|
_this.subscribe(subscriber);
|
|
46083
46271
|
});
|
|
@@ -46099,14 +46287,14 @@ var require_Observable = __commonJS({
|
|
|
46099
46287
|
Observable2.prototype.toPromise = function(promiseCtor) {
|
|
46100
46288
|
var _this = this;
|
|
46101
46289
|
promiseCtor = getPromiseCtor(promiseCtor);
|
|
46102
|
-
return new promiseCtor(function(
|
|
46290
|
+
return new promiseCtor(function(resolve52, reject) {
|
|
46103
46291
|
var value;
|
|
46104
46292
|
_this.subscribe(function(x) {
|
|
46105
46293
|
return value = x;
|
|
46106
46294
|
}, function(err) {
|
|
46107
46295
|
return reject(err);
|
|
46108
46296
|
}, function() {
|
|
46109
|
-
return
|
|
46297
|
+
return resolve52(value);
|
|
46110
46298
|
});
|
|
46111
46299
|
});
|
|
46112
46300
|
};
|
|
@@ -48202,11 +48390,11 @@ var require_innerFrom = __commonJS({
|
|
|
48202
48390
|
"use strict";
|
|
48203
48391
|
var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P2, generator) {
|
|
48204
48392
|
function adopt(value) {
|
|
48205
|
-
return value instanceof P2 ? value : new P2(function(
|
|
48206
|
-
|
|
48393
|
+
return value instanceof P2 ? value : new P2(function(resolve52) {
|
|
48394
|
+
resolve52(value);
|
|
48207
48395
|
});
|
|
48208
48396
|
}
|
|
48209
|
-
return new (P2 || (P2 = Promise))(function(
|
|
48397
|
+
return new (P2 || (P2 = Promise))(function(resolve52, reject) {
|
|
48210
48398
|
function fulfilled(value) {
|
|
48211
48399
|
try {
|
|
48212
48400
|
step(generator.next(value));
|
|
@@ -48222,7 +48410,7 @@ var require_innerFrom = __commonJS({
|
|
|
48222
48410
|
}
|
|
48223
48411
|
}
|
|
48224
48412
|
function step(result) {
|
|
48225
|
-
result.done ?
|
|
48413
|
+
result.done ? resolve52(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
48226
48414
|
}
|
|
48227
48415
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
48228
48416
|
});
|
|
@@ -48304,14 +48492,14 @@ var require_innerFrom = __commonJS({
|
|
|
48304
48492
|
}, i);
|
|
48305
48493
|
function verb(n) {
|
|
48306
48494
|
i[n] = o[n] && function(v2) {
|
|
48307
|
-
return new Promise(function(
|
|
48308
|
-
v2 = o[n](v2), settle(
|
|
48495
|
+
return new Promise(function(resolve52, reject) {
|
|
48496
|
+
v2 = o[n](v2), settle(resolve52, reject, v2.done, v2.value);
|
|
48309
48497
|
});
|
|
48310
48498
|
};
|
|
48311
48499
|
}
|
|
48312
|
-
function settle(
|
|
48500
|
+
function settle(resolve52, reject, d, v2) {
|
|
48313
48501
|
Promise.resolve(v2).then(function(v3) {
|
|
48314
|
-
|
|
48502
|
+
resolve52({ value: v3, done: d });
|
|
48315
48503
|
}, reject);
|
|
48316
48504
|
}
|
|
48317
48505
|
};
|
|
@@ -48930,7 +49118,7 @@ var require_lastValueFrom = __commonJS({
|
|
|
48930
49118
|
var EmptyError_1 = require_EmptyError();
|
|
48931
49119
|
function lastValueFrom2(source, config2) {
|
|
48932
49120
|
var hasConfig = typeof config2 === "object";
|
|
48933
|
-
return new Promise(function(
|
|
49121
|
+
return new Promise(function(resolve52, reject) {
|
|
48934
49122
|
var _hasValue = false;
|
|
48935
49123
|
var _value;
|
|
48936
49124
|
source.subscribe({
|
|
@@ -48941,9 +49129,9 @@ var require_lastValueFrom = __commonJS({
|
|
|
48941
49129
|
error: reject,
|
|
48942
49130
|
complete: function() {
|
|
48943
49131
|
if (_hasValue) {
|
|
48944
|
-
|
|
49132
|
+
resolve52(_value);
|
|
48945
49133
|
} else if (hasConfig) {
|
|
48946
|
-
|
|
49134
|
+
resolve52(config2.defaultValue);
|
|
48947
49135
|
} else {
|
|
48948
49136
|
reject(new EmptyError_1.EmptyError());
|
|
48949
49137
|
}
|
|
@@ -48965,16 +49153,16 @@ var require_firstValueFrom = __commonJS({
|
|
|
48965
49153
|
var Subscriber_1 = require_Subscriber();
|
|
48966
49154
|
function firstValueFrom(source, config2) {
|
|
48967
49155
|
var hasConfig = typeof config2 === "object";
|
|
48968
|
-
return new Promise(function(
|
|
49156
|
+
return new Promise(function(resolve52, reject) {
|
|
48969
49157
|
var subscriber = new Subscriber_1.SafeSubscriber({
|
|
48970
49158
|
next: function(value) {
|
|
48971
|
-
|
|
49159
|
+
resolve52(value);
|
|
48972
49160
|
subscriber.unsubscribe();
|
|
48973
49161
|
},
|
|
48974
49162
|
error: reject,
|
|
48975
49163
|
complete: function() {
|
|
48976
49164
|
if (hasConfig) {
|
|
48977
|
-
|
|
49165
|
+
resolve52(config2.defaultValue);
|
|
48978
49166
|
} else {
|
|
48979
49167
|
reject(new EmptyError_1.EmptyError());
|
|
48980
49168
|
}
|
|
@@ -54766,14 +54954,14 @@ var require_run_async = __commonJS({
|
|
|
54766
54954
|
return function() {
|
|
54767
54955
|
var args = arguments;
|
|
54768
54956
|
var originalThis = this;
|
|
54769
|
-
var promise = new Promise(function(
|
|
54957
|
+
var promise = new Promise(function(resolve52, reject) {
|
|
54770
54958
|
var resolved = false;
|
|
54771
54959
|
const wrappedResolve = function(value) {
|
|
54772
54960
|
if (resolved) {
|
|
54773
54961
|
console.warn("Run-async promise already resolved.");
|
|
54774
54962
|
}
|
|
54775
54963
|
resolved = true;
|
|
54776
|
-
|
|
54964
|
+
resolve52(value);
|
|
54777
54965
|
};
|
|
54778
54966
|
var rejected = false;
|
|
54779
54967
|
const wrappedReject = function(value) {
|
|
@@ -54881,25 +55069,25 @@ __export(otel_hooks_exports, {
|
|
|
54881
55069
|
});
|
|
54882
55070
|
function getOtelHooksHome() {
|
|
54883
55071
|
if (process.env.HAR_OTEL_HOOKS_HOME) {
|
|
54884
|
-
return
|
|
55072
|
+
return path53.resolve(process.env.HAR_OTEL_HOOKS_HOME);
|
|
54885
55073
|
}
|
|
54886
|
-
return
|
|
55074
|
+
return path53.join(os19.homedir(), ".har", "otel-hooks");
|
|
54887
55075
|
}
|
|
54888
55076
|
function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
|
|
54889
|
-
return
|
|
55077
|
+
return path53.join(hooksHome, "otel_config.json");
|
|
54890
55078
|
}
|
|
54891
55079
|
function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
|
|
54892
|
-
return
|
|
55080
|
+
return path53.join(hooksHome, "run-otel-hook.sh");
|
|
54893
55081
|
}
|
|
54894
55082
|
function getOtelHooksStateDir(hooksHome = getOtelHooksHome()) {
|
|
54895
|
-
return
|
|
55083
|
+
return path53.join(hooksHome, "state");
|
|
54896
55084
|
}
|
|
54897
55085
|
function localOtelHookBin(hooksHome) {
|
|
54898
|
-
return
|
|
55086
|
+
return path53.join(hooksHome, "node_modules", ".bin", "otel-hook");
|
|
54899
55087
|
}
|
|
54900
55088
|
function installedPackageVersion(hooksHome) {
|
|
54901
55089
|
try {
|
|
54902
|
-
const pkgPath =
|
|
55090
|
+
const pkgPath = path53.join(
|
|
54903
55091
|
hooksHome,
|
|
54904
55092
|
"node_modules",
|
|
54905
55093
|
"@osfactory",
|
|
@@ -55046,9 +55234,9 @@ function uninstallLegacyPythonHooks(hooksHome) {
|
|
|
55046
55234
|
}
|
|
55047
55235
|
function removeLegacyPythonArtifacts(hooksHome) {
|
|
55048
55236
|
const legacyPaths = [
|
|
55049
|
-
|
|
55050
|
-
|
|
55051
|
-
|
|
55237
|
+
path53.join(hooksHome, ".venv"),
|
|
55238
|
+
path53.join(hooksHome, "otel_config.yaml"),
|
|
55239
|
+
path53.join(hooksHome, "venv")
|
|
55052
55240
|
];
|
|
55053
55241
|
for (const target of legacyPaths) {
|
|
55054
55242
|
try {
|
|
@@ -55194,14 +55382,14 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
|
55194
55382
|
function rewriteKnownHookRegistrations(wrapperPath) {
|
|
55195
55383
|
const home = os19.homedir();
|
|
55196
55384
|
const candidates = [
|
|
55197
|
-
|
|
55198
|
-
|
|
55199
|
-
|
|
55385
|
+
path53.join(home, ".cursor", "hooks.json"),
|
|
55386
|
+
path53.join(home, ".claude", "settings.json"),
|
|
55387
|
+
path53.join(home, ".codex", "hooks.json")
|
|
55200
55388
|
];
|
|
55201
55389
|
for (const filePath of candidates) {
|
|
55202
55390
|
try {
|
|
55203
55391
|
rewriteHookCommandsToWrapper(filePath, wrapperPath);
|
|
55204
|
-
if (filePath.endsWith(`${
|
|
55392
|
+
if (filePath.endsWith(`${path53.sep}.cursor${path53.sep}hooks.json`)) {
|
|
55205
55393
|
pruneLegacyCursorHookEvents(filePath, wrapperPath);
|
|
55206
55394
|
}
|
|
55207
55395
|
} catch {
|
|
@@ -55311,14 +55499,14 @@ function ensureOtelHooks(options) {
|
|
|
55311
55499
|
function disableOtelHooksExport() {
|
|
55312
55500
|
return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
|
|
55313
55501
|
}
|
|
55314
|
-
var import_child_process14, fs46, os19,
|
|
55502
|
+
var import_child_process14, fs46, os19, path53, OTEL_HOOKS_PACKAGE, OTEL_HOOKS_PROVIDERS, OTEL_HOOKS_AGENTS, LEGACY_CURSOR_ONLY_HOOK_EVENTS;
|
|
55315
55503
|
var init_otel_hooks = __esm({
|
|
55316
55504
|
"src/core/otel-hooks.ts"() {
|
|
55317
55505
|
"use strict";
|
|
55318
55506
|
import_child_process14 = require("child_process");
|
|
55319
55507
|
fs46 = __toESM(require("fs"));
|
|
55320
55508
|
os19 = __toESM(require("os"));
|
|
55321
|
-
|
|
55509
|
+
path53 = __toESM(require("path"));
|
|
55322
55510
|
init_control_config();
|
|
55323
55511
|
init_telemetry_config();
|
|
55324
55512
|
OTEL_HOOKS_PACKAGE = "@osfactory/otel-hook@0.2.0";
|
|
@@ -58293,7 +58481,7 @@ var require_compile = __commonJS({
|
|
|
58293
58481
|
const schOrFunc = root.refs[ref];
|
|
58294
58482
|
if (schOrFunc)
|
|
58295
58483
|
return schOrFunc;
|
|
58296
|
-
let _sch =
|
|
58484
|
+
let _sch = resolve52.call(this, root, ref);
|
|
58297
58485
|
if (_sch === void 0) {
|
|
58298
58486
|
const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
|
|
58299
58487
|
const { schemaId } = this.opts;
|
|
@@ -58320,7 +58508,7 @@ var require_compile = __commonJS({
|
|
|
58320
58508
|
function sameSchemaEnv(s1, s2) {
|
|
58321
58509
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
58322
58510
|
}
|
|
58323
|
-
function
|
|
58511
|
+
function resolve52(root, ref) {
|
|
58324
58512
|
let sch;
|
|
58325
58513
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
58326
58514
|
ref = sch;
|
|
@@ -58538,8 +58726,8 @@ var require_utils2 = __commonJS({
|
|
|
58538
58726
|
}
|
|
58539
58727
|
return ind;
|
|
58540
58728
|
}
|
|
58541
|
-
function removeDotSegments(
|
|
58542
|
-
let input =
|
|
58729
|
+
function removeDotSegments(path69) {
|
|
58730
|
+
let input = path69;
|
|
58543
58731
|
const output = [];
|
|
58544
58732
|
let nextSlash = -1;
|
|
58545
58733
|
let len = 0;
|
|
@@ -58791,8 +58979,8 @@ var require_schemes = __commonJS({
|
|
|
58791
58979
|
wsComponent.secure = void 0;
|
|
58792
58980
|
}
|
|
58793
58981
|
if (wsComponent.resourceName) {
|
|
58794
|
-
const [
|
|
58795
|
-
wsComponent.path =
|
|
58982
|
+
const [path69, query] = wsComponent.resourceName.split("?");
|
|
58983
|
+
wsComponent.path = path69 && path69 !== "/" ? path69 : void 0;
|
|
58796
58984
|
wsComponent.query = query;
|
|
58797
58985
|
wsComponent.resourceName = void 0;
|
|
58798
58986
|
}
|
|
@@ -58951,7 +59139,7 @@ var require_fast_uri = __commonJS({
|
|
|
58951
59139
|
}
|
|
58952
59140
|
return uri;
|
|
58953
59141
|
}
|
|
58954
|
-
function
|
|
59142
|
+
function resolve52(baseURI, relativeURI, options) {
|
|
58955
59143
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
58956
59144
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
58957
59145
|
schemelessOptions.skipEscape = true;
|
|
@@ -59209,7 +59397,7 @@ var require_fast_uri = __commonJS({
|
|
|
59209
59397
|
var fastUri = {
|
|
59210
59398
|
SCHEMES,
|
|
59211
59399
|
normalize: normalize3,
|
|
59212
|
-
resolve:
|
|
59400
|
+
resolve: resolve52,
|
|
59213
59401
|
resolveComponent,
|
|
59214
59402
|
equal,
|
|
59215
59403
|
serialize,
|
|
@@ -63474,11 +63662,11 @@ var parser = new YargsParser({
|
|
|
63474
63662
|
resolve: import_path2.resolve,
|
|
63475
63663
|
// TODO: figure out a way to combine ESM and CJS coverage, such that
|
|
63476
63664
|
// we can exercise all the lines below:
|
|
63477
|
-
require: (
|
|
63665
|
+
require: (path69) => {
|
|
63478
63666
|
if (typeof require !== "undefined") {
|
|
63479
|
-
return require(
|
|
63480
|
-
} else if (
|
|
63481
|
-
return JSON.parse((0, import_fs2.readFileSync)(
|
|
63667
|
+
return require(path69);
|
|
63668
|
+
} else if (path69.match(/\.json$/)) {
|
|
63669
|
+
return JSON.parse((0, import_fs2.readFileSync)(path69, "utf8"));
|
|
63482
63670
|
} else {
|
|
63483
63671
|
throw Error("only .json config files are supported in ESM");
|
|
63484
63672
|
}
|
|
@@ -66004,12 +66192,12 @@ var YargsInstance = class {
|
|
|
66004
66192
|
async getCompletion(args, done) {
|
|
66005
66193
|
argsert("<array> [function]", [args, done], arguments.length);
|
|
66006
66194
|
if (!done) {
|
|
66007
|
-
return new Promise((
|
|
66195
|
+
return new Promise((resolve52, reject) => {
|
|
66008
66196
|
__classPrivateFieldGet(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
|
|
66009
66197
|
if (err)
|
|
66010
66198
|
reject(err);
|
|
66011
66199
|
else
|
|
66012
|
-
|
|
66200
|
+
resolve52(completions);
|
|
66013
66201
|
});
|
|
66014
66202
|
});
|
|
66015
66203
|
} else {
|
|
@@ -67054,33 +67242,33 @@ init_telemetry_config();
|
|
|
67054
67242
|
init_sync_context();
|
|
67055
67243
|
|
|
67056
67244
|
// src/cli/commands/agents.ts
|
|
67057
|
-
var
|
|
67245
|
+
var path33 = __toESM(require("path"));
|
|
67058
67246
|
|
|
67059
67247
|
// src/harness/agent-skills.ts
|
|
67060
67248
|
var fs27 = __toESM(require("fs"));
|
|
67061
67249
|
var os14 = __toESM(require("os"));
|
|
67062
|
-
var
|
|
67250
|
+
var path32 = __toESM(require("path"));
|
|
67063
67251
|
var readline = __toESM(require("readline"));
|
|
67064
67252
|
init_file_ops();
|
|
67065
67253
|
init_logging();
|
|
67066
67254
|
|
|
67067
67255
|
// src/utils/paths.ts
|
|
67068
67256
|
var fs26 = __toESM(require("fs"));
|
|
67069
|
-
var
|
|
67257
|
+
var path31 = __toESM(require("path"));
|
|
67070
67258
|
function resolveTemplatesDir() {
|
|
67071
67259
|
const candidates = [
|
|
67072
|
-
|
|
67073
|
-
|
|
67074
|
-
|
|
67260
|
+
path31.join(__dirname, "templates"),
|
|
67261
|
+
path31.join(__dirname, "..", "templates"),
|
|
67262
|
+
path31.join(__dirname, "..", "harness", "templates")
|
|
67075
67263
|
];
|
|
67076
67264
|
for (const dir of candidates) {
|
|
67077
|
-
if (fs26.existsSync(
|
|
67265
|
+
if (fs26.existsSync(path31.join(dir, "har-boilerplate"))) return dir;
|
|
67078
67266
|
}
|
|
67079
67267
|
throw new Error("Templates directory not found. Run npm run build.");
|
|
67080
67268
|
}
|
|
67081
67269
|
function resolveTemplateFile(name) {
|
|
67082
67270
|
const dir = resolveTemplatesDir();
|
|
67083
|
-
const filePath =
|
|
67271
|
+
const filePath = path31.join(dir, name);
|
|
67084
67272
|
return fs26.existsSync(filePath) ? filePath : null;
|
|
67085
67273
|
}
|
|
67086
67274
|
|
|
@@ -67089,18 +67277,18 @@ init_manifest();
|
|
|
67089
67277
|
var AGENT_SKILL_TARGETS = ["claude", "cursor", "codex"];
|
|
67090
67278
|
var MANAGED_HEADER = "<!-- managed by har \u2014 regenerated by `har agents install` / `har env maintain`; edit at your own risk -->";
|
|
67091
67279
|
function agentSkillsTemplateDir() {
|
|
67092
|
-
const dir =
|
|
67280
|
+
const dir = path32.join(resolveTemplatesDir(), "agent-skills");
|
|
67093
67281
|
if (!fs27.existsSync(dir)) {
|
|
67094
67282
|
throw new Error("Agent skills templates not found (templates/agent-skills). Run npm run build.");
|
|
67095
67283
|
}
|
|
67096
67284
|
return dir;
|
|
67097
67285
|
}
|
|
67098
67286
|
function readSkillsManifest() {
|
|
67099
|
-
const manifestPath =
|
|
67287
|
+
const manifestPath = path32.join(agentSkillsTemplateDir(), "skills.manifest.json");
|
|
67100
67288
|
return JSON.parse(fs27.readFileSync(manifestPath, "utf8"));
|
|
67101
67289
|
}
|
|
67102
67290
|
function readSkillBody(entry) {
|
|
67103
|
-
return fs27.readFileSync(
|
|
67291
|
+
return fs27.readFileSync(path32.join(agentSkillsTemplateDir(), entry.body), "utf8");
|
|
67104
67292
|
}
|
|
67105
67293
|
function renderYamlValue(value) {
|
|
67106
67294
|
if (typeof value === "string") return JSON.stringify(value);
|
|
@@ -67132,7 +67320,7 @@ function renderSkillFiles(agents) {
|
|
|
67132
67320
|
agent: "claude",
|
|
67133
67321
|
skill: entry.id,
|
|
67134
67322
|
scope: "repo",
|
|
67135
|
-
relPath:
|
|
67323
|
+
relPath: path32.join(".claude", "skills", entry.id, "SKILL.md"),
|
|
67136
67324
|
content: renderClaudeSkill(entry, body)
|
|
67137
67325
|
});
|
|
67138
67326
|
}
|
|
@@ -67141,7 +67329,7 @@ function renderSkillFiles(agents) {
|
|
|
67141
67329
|
agent: "cursor",
|
|
67142
67330
|
skill: entry.id,
|
|
67143
67331
|
scope: "repo",
|
|
67144
|
-
relPath:
|
|
67332
|
+
relPath: path32.join(".cursor", "commands", `${entry.id}.md`),
|
|
67145
67333
|
content: renderPlainSkill(body)
|
|
67146
67334
|
});
|
|
67147
67335
|
}
|
|
@@ -67150,7 +67338,7 @@ function renderSkillFiles(agents) {
|
|
|
67150
67338
|
agent: "codex",
|
|
67151
67339
|
skill: entry.id,
|
|
67152
67340
|
scope: "global",
|
|
67153
|
-
relPath:
|
|
67341
|
+
relPath: path32.posix.join("~", ".codex", "prompts", `${entry.codex.promptName}.md`),
|
|
67154
67342
|
content: renderPlainSkill(body)
|
|
67155
67343
|
});
|
|
67156
67344
|
}
|
|
@@ -67159,9 +67347,9 @@ function renderSkillFiles(agents) {
|
|
|
67159
67347
|
}
|
|
67160
67348
|
function resolveScaffoldPath(repoPath, file) {
|
|
67161
67349
|
if (file.scope === "global") {
|
|
67162
|
-
return
|
|
67350
|
+
return path32.join(os14.homedir(), file.relPath.replace(/^~\//, ""));
|
|
67163
67351
|
}
|
|
67164
|
-
return
|
|
67352
|
+
return path32.join(repoPath, file.relPath);
|
|
67165
67353
|
}
|
|
67166
67354
|
function isHarManaged(filePath) {
|
|
67167
67355
|
return fs27.readFileSync(filePath, "utf8").includes(MANAGED_HEADER);
|
|
@@ -67213,7 +67401,7 @@ function removeAgentSkills(repoPath, agents) {
|
|
|
67213
67401
|
}
|
|
67214
67402
|
fs27.rmSync(destPath);
|
|
67215
67403
|
removed.push(file.relPath);
|
|
67216
|
-
const parent =
|
|
67404
|
+
const parent = path32.dirname(destPath);
|
|
67217
67405
|
if (fs27.existsSync(parent) && fs27.readdirSync(parent).length === 0) {
|
|
67218
67406
|
fs27.rmdirSync(parent);
|
|
67219
67407
|
}
|
|
@@ -67234,9 +67422,9 @@ function detectAgentTargets(repoPath) {
|
|
|
67234
67422
|
const manifest = readManifest(repoPath);
|
|
67235
67423
|
const scaffolded = new Set((manifest?.scaffoldedAgentFiles ?? []).map((entry) => entry.agent));
|
|
67236
67424
|
const detected = new Set(scaffolded);
|
|
67237
|
-
if (fs27.existsSync(
|
|
67238
|
-
if (fs27.existsSync(
|
|
67239
|
-
if (fs27.existsSync(
|
|
67425
|
+
if (fs27.existsSync(path32.join(repoPath, ".claude"))) detected.add("claude");
|
|
67426
|
+
if (fs27.existsSync(path32.join(repoPath, ".cursor"))) detected.add("cursor");
|
|
67427
|
+
if (fs27.existsSync(path32.join(os14.homedir(), ".codex"))) detected.add("codex");
|
|
67240
67428
|
return AGENT_SKILL_TARGETS.filter((agent) => detected.has(agent));
|
|
67241
67429
|
}
|
|
67242
67430
|
function parseAgentTargets(raw) {
|
|
@@ -67280,16 +67468,16 @@ async function handleAgentSkills(options) {
|
|
|
67280
67468
|
}
|
|
67281
67469
|
async function askYesNo(question) {
|
|
67282
67470
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
67283
|
-
return new Promise((
|
|
67471
|
+
return new Promise((resolve52) => {
|
|
67284
67472
|
process.stderr.write(`${question} `);
|
|
67285
67473
|
rl.once("line", (answer) => {
|
|
67286
67474
|
rl.close();
|
|
67287
67475
|
const trimmed = answer.trim();
|
|
67288
67476
|
if (trimmed === "") {
|
|
67289
|
-
|
|
67477
|
+
resolve52(true);
|
|
67290
67478
|
return;
|
|
67291
67479
|
}
|
|
67292
|
-
|
|
67480
|
+
resolve52(/^y(es)?$/i.test(trimmed));
|
|
67293
67481
|
});
|
|
67294
67482
|
});
|
|
67295
67483
|
}
|
|
@@ -67323,7 +67511,7 @@ var agentsCommand = {
|
|
|
67323
67511
|
}
|
|
67324
67512
|
};
|
|
67325
67513
|
function handleInstall(argv) {
|
|
67326
|
-
const repoPath =
|
|
67514
|
+
const repoPath = path33.resolve(argv.repo);
|
|
67327
67515
|
header("har agents install");
|
|
67328
67516
|
try {
|
|
67329
67517
|
const targets = resolveTargets(argv, repoPath);
|
|
@@ -67349,7 +67537,7 @@ function handleInstall(argv) {
|
|
|
67349
67537
|
}
|
|
67350
67538
|
}
|
|
67351
67539
|
function handleRemove(argv) {
|
|
67352
|
-
const repoPath =
|
|
67540
|
+
const repoPath = path33.resolve(argv.repo);
|
|
67353
67541
|
header("har agents remove");
|
|
67354
67542
|
try {
|
|
67355
67543
|
const targets = resolveTargets(argv, repoPath);
|
|
@@ -67369,7 +67557,7 @@ function handleRemove(argv) {
|
|
|
67369
67557
|
}
|
|
67370
67558
|
|
|
67371
67559
|
// src/cli/commands/env.ts
|
|
67372
|
-
var
|
|
67560
|
+
var path57 = __toESM(require("path"));
|
|
67373
67561
|
|
|
67374
67562
|
// src/cli/finish-command.ts
|
|
67375
67563
|
init_sync_context();
|
|
@@ -67380,23 +67568,23 @@ async function finishCommand(code) {
|
|
|
67380
67568
|
|
|
67381
67569
|
// src/core/harness.ts
|
|
67382
67570
|
var fs42 = __toESM(require("fs"));
|
|
67383
|
-
var
|
|
67571
|
+
var path48 = __toESM(require("path"));
|
|
67384
67572
|
|
|
67385
67573
|
// src/harness/generator.ts
|
|
67386
67574
|
var fs32 = __toESM(require("fs"));
|
|
67387
|
-
var
|
|
67575
|
+
var path38 = __toESM(require("path"));
|
|
67388
67576
|
init_file_ops();
|
|
67389
67577
|
init_logging();
|
|
67390
67578
|
|
|
67391
67579
|
// src/core/gitignore.ts
|
|
67392
67580
|
var fs28 = __toESM(require("fs"));
|
|
67393
|
-
var
|
|
67581
|
+
var path34 = __toESM(require("path"));
|
|
67394
67582
|
var HARNESS_ROOT_GITIGNORE_PATTERNS = [
|
|
67395
67583
|
".env.agent.*",
|
|
67396
67584
|
"ecosystem.agent.*.config.cjs"
|
|
67397
67585
|
];
|
|
67398
67586
|
function ensureRootGitignorePatterns(checkoutDir) {
|
|
67399
|
-
const gitignorePath =
|
|
67587
|
+
const gitignorePath = path34.join(checkoutDir, ".gitignore");
|
|
67400
67588
|
const content = fs28.existsSync(gitignorePath) ? fs28.readFileSync(gitignorePath, "utf8") : "";
|
|
67401
67589
|
const lines = content.split("\n").map((line) => line.trim());
|
|
67402
67590
|
const missing = HARNESS_ROOT_GITIGNORE_PATTERNS.filter((pattern) => !lines.includes(pattern));
|
|
@@ -67411,7 +67599,7 @@ function ensureRootGitignorePatterns(checkoutDir) {
|
|
|
67411
67599
|
|
|
67412
67600
|
// src/harness/gitignore-template.ts
|
|
67413
67601
|
var fs29 = __toESM(require("fs"));
|
|
67414
|
-
var
|
|
67602
|
+
var path35 = __toESM(require("path"));
|
|
67415
67603
|
var HARNESS_GITIGNORE_TEMPLATE = "gitignore.template";
|
|
67416
67604
|
var HARNESS_GITIGNORE_FILE = ".gitignore";
|
|
67417
67605
|
function harnessFileForTemplate(templateFile) {
|
|
@@ -67421,16 +67609,16 @@ function templateFileForHarness(harnessFile) {
|
|
|
67421
67609
|
return harnessFile === HARNESS_GITIGNORE_FILE ? HARNESS_GITIGNORE_TEMPLATE : harnessFile;
|
|
67422
67610
|
}
|
|
67423
67611
|
function resolveGitignoreTemplateSource(boilerplateDir) {
|
|
67424
|
-
const primary =
|
|
67612
|
+
const primary = path35.join(boilerplateDir, HARNESS_GITIGNORE_TEMPLATE);
|
|
67425
67613
|
if (fs29.existsSync(primary)) return primary;
|
|
67426
|
-
const legacy =
|
|
67614
|
+
const legacy = path35.join(boilerplateDir, HARNESS_GITIGNORE_FILE);
|
|
67427
67615
|
if (fs29.existsSync(legacy)) return legacy;
|
|
67428
67616
|
return null;
|
|
67429
67617
|
}
|
|
67430
67618
|
function writeHarnessGitignore(harnessDir, boilerplateDir) {
|
|
67431
67619
|
const src = resolveGitignoreTemplateSource(boilerplateDir);
|
|
67432
67620
|
if (!src) return;
|
|
67433
|
-
fs29.writeFileSync(
|
|
67621
|
+
fs29.writeFileSync(path35.join(harnessDir, HARNESS_GITIGNORE_FILE), fs29.readFileSync(src, "utf8"));
|
|
67434
67622
|
}
|
|
67435
67623
|
function isExpectedHarnessOnlyFile(harnessFile, templateFiles) {
|
|
67436
67624
|
return harnessFile === HARNESS_GITIGNORE_FILE && templateFiles.includes(HARNESS_GITIGNORE_TEMPLATE);
|
|
@@ -67441,7 +67629,7 @@ init_manifest();
|
|
|
67441
67629
|
|
|
67442
67630
|
// src/harness/plugin-ledger.ts
|
|
67443
67631
|
var fs30 = __toESM(require("fs"));
|
|
67444
|
-
var
|
|
67632
|
+
var path36 = __toESM(require("path"));
|
|
67445
67633
|
init_zod();
|
|
67446
67634
|
init_file_ops();
|
|
67447
67635
|
init_manifest();
|
|
@@ -67464,7 +67652,7 @@ var PluginLedgerSchema = external_exports.object({
|
|
|
67464
67652
|
plugins: external_exports.array(PluginLedgerEntrySchema).default([])
|
|
67465
67653
|
});
|
|
67466
67654
|
function getPluginLedgerPath(repoPath) {
|
|
67467
|
-
return
|
|
67655
|
+
return path36.join(path36.resolve(repoPath), DEFAULT_HAR_DIR, "plugins.json");
|
|
67468
67656
|
}
|
|
67469
67657
|
function readPluginLedger(repoPath) {
|
|
67470
67658
|
const ledgerPath = getPluginLedgerPath(repoPath);
|
|
@@ -67479,7 +67667,7 @@ function readPluginLedger(repoPath) {
|
|
|
67479
67667
|
}
|
|
67480
67668
|
function writePluginLedger(repoPath, ledger) {
|
|
67481
67669
|
const ledgerPath = getPluginLedgerPath(repoPath);
|
|
67482
|
-
const harnessDir =
|
|
67670
|
+
const harnessDir = path36.dirname(ledgerPath);
|
|
67483
67671
|
if (!fs30.existsSync(harnessDir)) {
|
|
67484
67672
|
fs30.mkdirSync(harnessDir, { recursive: true });
|
|
67485
67673
|
}
|
|
@@ -67517,7 +67705,7 @@ function ensurePluginLedgerScaffold(repoPath, options) {
|
|
|
67517
67705
|
|
|
67518
67706
|
// src/harness/profiles.ts
|
|
67519
67707
|
var fs31 = __toESM(require("fs"));
|
|
67520
|
-
var
|
|
67708
|
+
var path37 = __toESM(require("path"));
|
|
67521
67709
|
init_zod();
|
|
67522
67710
|
var HARNESS_PROFILES = ["default", "cli", "ios"];
|
|
67523
67711
|
var ProfileBundleRefSchema = external_exports.object({
|
|
@@ -67570,7 +67758,7 @@ var PROFILE_DIRS = {
|
|
|
67570
67758
|
};
|
|
67571
67759
|
function readProfileManifest(profile) {
|
|
67572
67760
|
const templates = resolveTemplatesDir();
|
|
67573
|
-
const manifestPath =
|
|
67761
|
+
const manifestPath = path37.join(templates, "profiles", profile, "profile.manifest.json");
|
|
67574
67762
|
if (fs31.existsSync(manifestPath)) {
|
|
67575
67763
|
const parsed = ProfileManifestSchema.safeParse(
|
|
67576
67764
|
JSON.parse(fs31.readFileSync(manifestPath, "utf8"))
|
|
@@ -67586,7 +67774,7 @@ function readProfileManifest(profile) {
|
|
|
67586
67774
|
return PROFILE_COMPOSITIONS[profile];
|
|
67587
67775
|
}
|
|
67588
67776
|
function resolveProfileBundleDir(bundle) {
|
|
67589
|
-
const dir =
|
|
67777
|
+
const dir = path37.join(resolveTemplatesDir(), bundle.path);
|
|
67590
67778
|
if (!fs31.existsSync(dir)) {
|
|
67591
67779
|
throw new Error(`Profile bundle not found: ${bundle.id} (${bundle.path}). Run npm run build.`);
|
|
67592
67780
|
}
|
|
@@ -67602,20 +67790,20 @@ var CLI_PRUNE_FILES = [
|
|
|
67602
67790
|
];
|
|
67603
67791
|
function pruneCliProfile(harnessDir) {
|
|
67604
67792
|
for (const file of CLI_PRUNE_FILES) {
|
|
67605
|
-
const filePath =
|
|
67793
|
+
const filePath = path38.join(harnessDir, file);
|
|
67606
67794
|
if (fs32.existsSync(filePath)) {
|
|
67607
67795
|
fs32.unlinkSync(filePath);
|
|
67608
67796
|
}
|
|
67609
67797
|
}
|
|
67610
67798
|
}
|
|
67611
67799
|
function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
67612
|
-
const harnessDir =
|
|
67613
|
-
const projectName =
|
|
67800
|
+
const harnessDir = path38.join(repoPath, DEFAULT_HAR_DIR);
|
|
67801
|
+
const projectName = path38.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
67614
67802
|
const profile = options.profile ?? "default";
|
|
67615
67803
|
const profileManifest = readProfileManifest(profile);
|
|
67616
67804
|
const bundleIds = profileManifest.bundles.map((b2) => b2.id);
|
|
67617
67805
|
const primaryOverlay = PROFILE_DIRS[profile];
|
|
67618
|
-
const boilerplateDir =
|
|
67806
|
+
const boilerplateDir = path38.join(resolveTemplatesDir(), primaryOverlay);
|
|
67619
67807
|
if (fs32.existsSync(harnessDir) && !options.force) {
|
|
67620
67808
|
throw new Error(
|
|
67621
67809
|
'.har/ already exists. Use --force to overwrite or run "har env maintain" to update in place.'
|
|
@@ -67637,7 +67825,7 @@ function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
|
67637
67825
|
pruneCliProfile(harnessDir);
|
|
67638
67826
|
}
|
|
67639
67827
|
syncAgentSlotsToHarnessEnv(repoPath);
|
|
67640
|
-
const harnessEnvPath =
|
|
67828
|
+
const harnessEnvPath = path38.join(harnessDir, "harness.env");
|
|
67641
67829
|
if (fs32.existsSync(harnessEnvPath)) {
|
|
67642
67830
|
let content = fs32.readFileSync(harnessEnvPath, "utf8");
|
|
67643
67831
|
content = content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
|
|
@@ -67666,7 +67854,7 @@ function finalizeHarness(repoPath, adaptationSummary, stack) {
|
|
|
67666
67854
|
|
|
67667
67855
|
// src/harness/agent-md.ts
|
|
67668
67856
|
var fs34 = __toESM(require("fs"));
|
|
67669
|
-
var
|
|
67857
|
+
var path41 = __toESM(require("path"));
|
|
67670
67858
|
init_file_ops();
|
|
67671
67859
|
init_logging();
|
|
67672
67860
|
init_manifest();
|
|
@@ -67674,7 +67862,7 @@ init_manifest();
|
|
|
67674
67862
|
// src/harness/instruction-files.ts
|
|
67675
67863
|
var fs33 = __toESM(require("fs"));
|
|
67676
67864
|
var os16 = __toESM(require("os"));
|
|
67677
|
-
var
|
|
67865
|
+
var path40 = __toESM(require("path"));
|
|
67678
67866
|
|
|
67679
67867
|
// node_modules/@inquirer/core/dist/esm/lib/key.js
|
|
67680
67868
|
var isUpKey = (key, keybindings = []) => (
|
|
@@ -68708,13 +68896,13 @@ var PromisePolyfill = class extends Promise {
|
|
|
68708
68896
|
// Available starting from Node 22
|
|
68709
68897
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
|
68710
68898
|
static withResolver() {
|
|
68711
|
-
let
|
|
68899
|
+
let resolve52;
|
|
68712
68900
|
let reject;
|
|
68713
68901
|
const promise = new Promise((res, rej) => {
|
|
68714
|
-
|
|
68902
|
+
resolve52 = res;
|
|
68715
68903
|
reject = rej;
|
|
68716
68904
|
});
|
|
68717
|
-
return { promise, resolve:
|
|
68905
|
+
return { promise, resolve: resolve52, reject };
|
|
68718
68906
|
}
|
|
68719
68907
|
};
|
|
68720
68908
|
|
|
@@ -68748,7 +68936,7 @@ function createPrompt(view) {
|
|
|
68748
68936
|
output
|
|
68749
68937
|
});
|
|
68750
68938
|
const screen = new ScreenManager(rl);
|
|
68751
|
-
const { promise, resolve:
|
|
68939
|
+
const { promise, resolve: resolve52, reject } = PromisePolyfill.withResolver();
|
|
68752
68940
|
const cancel = () => reject(new CancelPromptError());
|
|
68753
68941
|
if (signal) {
|
|
68754
68942
|
const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
|
|
@@ -68775,7 +68963,7 @@ function createPrompt(view) {
|
|
|
68775
68963
|
cycle(() => {
|
|
68776
68964
|
try {
|
|
68777
68965
|
const nextView = view(config2, (value) => {
|
|
68778
|
-
setImmediate(() =>
|
|
68966
|
+
setImmediate(() => resolve52(value));
|
|
68779
68967
|
});
|
|
68780
68968
|
if (nextView === void 0) {
|
|
68781
68969
|
const callerFilename = callSites[1]?.getFileName();
|
|
@@ -70084,9 +70272,9 @@ var import_rxjs = __toESM(require_cjs(), 1);
|
|
|
70084
70272
|
var import_run_async = __toESM(require_run_async(), 1);
|
|
70085
70273
|
var import_mute_stream2 = __toESM(require_lib(), 1);
|
|
70086
70274
|
var _ = {
|
|
70087
|
-
set: (obj,
|
|
70275
|
+
set: (obj, path69 = "", value) => {
|
|
70088
70276
|
let pointer = obj;
|
|
70089
|
-
|
|
70277
|
+
path69.split(".").forEach((key, index, arr) => {
|
|
70090
70278
|
if (key === "__proto__" || key === "constructor")
|
|
70091
70279
|
return;
|
|
70092
70280
|
if (index === arr.length - 1) {
|
|
@@ -70097,8 +70285,8 @@ var _ = {
|
|
|
70097
70285
|
pointer = pointer[key];
|
|
70098
70286
|
});
|
|
70099
70287
|
},
|
|
70100
|
-
get: (obj,
|
|
70101
|
-
const travel = (regexp) => String.prototype.split.call(
|
|
70288
|
+
get: (obj, path69 = "", defaultValue) => {
|
|
70289
|
+
const travel = (regexp) => String.prototype.split.call(path69, regexp).filter(Boolean).reduce(
|
|
70102
70290
|
// @ts-expect-error implicit any on res[key]
|
|
70103
70291
|
(res, key) => res == null ? res : res[key],
|
|
70104
70292
|
obj
|
|
@@ -70216,7 +70404,7 @@ var PromptsRunner = class {
|
|
|
70216
70404
|
throw new Error(`Prompt for type ${question.type} not found`);
|
|
70217
70405
|
}
|
|
70218
70406
|
let cleanupSignal;
|
|
70219
|
-
const promptFn = isPromptConstructor(prompt2) ? (q, opt) => new Promise((
|
|
70407
|
+
const promptFn = isPromptConstructor(prompt2) ? (q, opt) => new Promise((resolve52, reject) => {
|
|
70220
70408
|
const { signal: signal2 } = opt;
|
|
70221
70409
|
if (signal2.aborted) {
|
|
70222
70410
|
reject(new AbortPromptError({ cause: signal2.reason }));
|
|
@@ -70253,7 +70441,7 @@ var PromptsRunner = class {
|
|
|
70253
70441
|
signal2.removeEventListener("abort", abort);
|
|
70254
70442
|
cleanupSignal = void 0;
|
|
70255
70443
|
};
|
|
70256
|
-
activePrompt.run().then(
|
|
70444
|
+
activePrompt.run().then(resolve52, reject).finally(cleanup);
|
|
70257
70445
|
}) : prompt2;
|
|
70258
70446
|
let cleanupModuleSignal;
|
|
70259
70447
|
const { signal: moduleSignal } = this.opt;
|
|
@@ -70423,12 +70611,12 @@ function outsideContentShrinkMessage(beforeLines, afterLines) {
|
|
|
70423
70611
|
}
|
|
70424
70612
|
function detectInstructionFiles(repoPath) {
|
|
70425
70613
|
return {
|
|
70426
|
-
agentsMd: fs33.existsSync(
|
|
70427
|
-
agentMd: fs33.existsSync(
|
|
70428
|
-
claudeMd: fs33.existsSync(
|
|
70429
|
-
cursorDir: fs33.existsSync(
|
|
70430
|
-
claudeDir: fs33.existsSync(
|
|
70431
|
-
codexHome: fs33.existsSync(
|
|
70614
|
+
agentsMd: fs33.existsSync(path40.join(repoPath, AGENTS_MD)),
|
|
70615
|
+
agentMd: fs33.existsSync(path40.join(repoPath, LEGACY_AGENT_MD)),
|
|
70616
|
+
claudeMd: fs33.existsSync(path40.join(repoPath, CLAUDE_MD)),
|
|
70617
|
+
cursorDir: fs33.existsSync(path40.join(repoPath, ".cursor")),
|
|
70618
|
+
claudeDir: fs33.existsSync(path40.join(repoPath, ".claude")),
|
|
70619
|
+
codexHome: fs33.existsSync(path40.join(os16.homedir(), ".codex"))
|
|
70432
70620
|
};
|
|
70433
70621
|
}
|
|
70434
70622
|
function formatDetectionReport(detection) {
|
|
@@ -70529,7 +70717,7 @@ function mergeAgentsMdContent(existing, incoming) {
|
|
|
70529
70717
|
return content;
|
|
70530
70718
|
}
|
|
70531
70719
|
function upsertAgentsMdHarSection(repoPath, options = {}) {
|
|
70532
|
-
const dest =
|
|
70720
|
+
const dest = path40.join(repoPath, AGENTS_MD);
|
|
70533
70721
|
const section = loadHarAgentsSectionFromTemplate();
|
|
70534
70722
|
if (!fs33.existsSync(dest)) {
|
|
70535
70723
|
writeFileSafe(dest, loadAgentsMdTemplate());
|
|
@@ -70560,8 +70748,8 @@ function upsertAgentsMdHarSection(repoPath, options = {}) {
|
|
|
70560
70748
|
return action;
|
|
70561
70749
|
}
|
|
70562
70750
|
function migrateLegacyAgentMd(repoPath) {
|
|
70563
|
-
const legacyPath =
|
|
70564
|
-
const agentsPath =
|
|
70751
|
+
const legacyPath = path40.join(repoPath, LEGACY_AGENT_MD);
|
|
70752
|
+
const agentsPath = path40.join(repoPath, AGENTS_MD);
|
|
70565
70753
|
if (!fs33.existsSync(legacyPath)) return false;
|
|
70566
70754
|
const legacy = fs33.readFileSync(legacyPath, "utf8");
|
|
70567
70755
|
if (!fs33.existsSync(agentsPath)) {
|
|
@@ -70602,8 +70790,8 @@ This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
|
|
|
70602
70790
|
[\`.har/README.md\`](./.har/README.md) before making changes.
|
|
70603
70791
|
${CLAUDE_HAR_SECTION_END}`;
|
|
70604
70792
|
function ensureClaudeMdPointer(repoPath, options = {}) {
|
|
70605
|
-
const dest =
|
|
70606
|
-
const projectName =
|
|
70793
|
+
const dest = path40.join(repoPath, CLAUDE_MD);
|
|
70794
|
+
const projectName = path40.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
70607
70795
|
const thin = loadClaudeMdTemplate(projectName);
|
|
70608
70796
|
if (!fs33.existsSync(dest)) {
|
|
70609
70797
|
writeFileSafe(dest, thin);
|
|
@@ -70758,10 +70946,10 @@ var AGENT_MD_PROPOSAL = "AGENT.md.proposed";
|
|
|
70758
70946
|
var AGENT_MD_PROPOSAL_META = "AGENT.md.proposed.meta.json";
|
|
70759
70947
|
function readAgentMdProposal(repoPath) {
|
|
70760
70948
|
const harnessDir = getHarnessDir(repoPath);
|
|
70761
|
-
const proposalPath =
|
|
70762
|
-
const metaPath =
|
|
70763
|
-
const legacyProposalPath =
|
|
70764
|
-
const legacyMetaPath =
|
|
70949
|
+
const proposalPath = path41.join(harnessDir, AGENTS_MD_PROPOSAL);
|
|
70950
|
+
const metaPath = path41.join(harnessDir, AGENTS_MD_PROPOSAL_META);
|
|
70951
|
+
const legacyProposalPath = path41.join(harnessDir, AGENT_MD_PROPOSAL);
|
|
70952
|
+
const legacyMetaPath = path41.join(harnessDir, AGENT_MD_PROPOSAL_META);
|
|
70765
70953
|
const resolvedProposal = fs34.existsSync(proposalPath) ? proposalPath : fs34.existsSync(legacyProposalPath) ? legacyProposalPath : null;
|
|
70766
70954
|
if (!resolvedProposal) return null;
|
|
70767
70955
|
const resolvedMeta = resolvedProposal === proposalPath ? metaPath : legacyMetaPath;
|
|
@@ -70787,7 +70975,7 @@ function clearAgentMdProposal(repoPath) {
|
|
|
70787
70975
|
AGENT_MD_PROPOSAL,
|
|
70788
70976
|
AGENT_MD_PROPOSAL_META
|
|
70789
70977
|
]) {
|
|
70790
|
-
const p =
|
|
70978
|
+
const p = path41.join(harnessDir, file);
|
|
70791
70979
|
if (fs34.existsSync(p)) fs34.unlinkSync(p);
|
|
70792
70980
|
}
|
|
70793
70981
|
}
|
|
@@ -70801,7 +70989,7 @@ function wouldProposalShrinkExisting(existing, proposal) {
|
|
|
70801
70989
|
function applyAgentMdProposalMerge(repoPath, options = {}) {
|
|
70802
70990
|
const proposal = readAgentMdProposal(repoPath);
|
|
70803
70991
|
if (!proposal) return false;
|
|
70804
|
-
const agentsMdPath =
|
|
70992
|
+
const agentsMdPath = path41.join(repoPath, AGENTS_MD);
|
|
70805
70993
|
if (fs34.existsSync(agentsMdPath)) {
|
|
70806
70994
|
const existing = fs34.readFileSync(agentsMdPath, "utf8");
|
|
70807
70995
|
if (wouldProposalShrinkExisting(existing, proposal.content)) {
|
|
@@ -70827,7 +71015,7 @@ function finalizeAgentsMdInstructionFiles(repoPath) {
|
|
|
70827
71015
|
|
|
70828
71016
|
// src/harness/validator.ts
|
|
70829
71017
|
var fs35 = __toESM(require("fs"));
|
|
70830
|
-
var
|
|
71018
|
+
var path42 = __toESM(require("path"));
|
|
70831
71019
|
init_shell();
|
|
70832
71020
|
init_manifest();
|
|
70833
71021
|
init_stages();
|
|
@@ -70889,13 +71077,13 @@ function validateHarness(repoPath) {
|
|
|
70889
71077
|
};
|
|
70890
71078
|
}
|
|
70891
71079
|
for (const file of getRequiredFiles(repoPath)) {
|
|
70892
|
-
const filePath =
|
|
71080
|
+
const filePath = path42.join(harnessDir, file);
|
|
70893
71081
|
if (!fs35.existsSync(filePath)) {
|
|
70894
71082
|
issues.push({ file, message: "Required file missing", severity: "error" });
|
|
70895
71083
|
}
|
|
70896
71084
|
}
|
|
70897
71085
|
for (const script of SHELL_SCRIPTS) {
|
|
70898
|
-
const scriptPath =
|
|
71086
|
+
const scriptPath = path42.join(harnessDir, script);
|
|
70899
71087
|
if (!fs35.existsSync(scriptPath)) continue;
|
|
70900
71088
|
const stat = fs35.statSync(scriptPath);
|
|
70901
71089
|
if (!(stat.mode & 73)) {
|
|
@@ -70912,7 +71100,7 @@ function validateHarness(repoPath) {
|
|
|
70912
71100
|
}
|
|
70913
71101
|
const manifest = readManifest(repoPath);
|
|
70914
71102
|
const profile = manifest?.profile ?? "default";
|
|
70915
|
-
const ecosystemPath =
|
|
71103
|
+
const ecosystemPath = path42.join(harnessDir, "ecosystem.agent.template.cjs");
|
|
70916
71104
|
if (profile !== "cli" && fs35.existsSync(ecosystemPath)) {
|
|
70917
71105
|
const content = fs35.readFileSync(ecosystemPath, "utf8");
|
|
70918
71106
|
if (!content.includes("module.exports")) {
|
|
@@ -70923,7 +71111,7 @@ function validateHarness(repoPath) {
|
|
|
70923
71111
|
});
|
|
70924
71112
|
}
|
|
70925
71113
|
}
|
|
70926
|
-
const harnessEnvPath =
|
|
71114
|
+
const harnessEnvPath = path42.join(harnessDir, "harness.env");
|
|
70927
71115
|
if (fs35.existsSync(harnessEnvPath)) {
|
|
70928
71116
|
const content = fs35.readFileSync(harnessEnvPath, "utf8");
|
|
70929
71117
|
if (content.includes("TODO: set migrate command")) {
|
|
@@ -70933,14 +71121,14 @@ function validateHarness(repoPath) {
|
|
|
70933
71121
|
issues.push({ file: "harness.env", message: "Seed command still has TODO", severity: "warning" });
|
|
70934
71122
|
}
|
|
70935
71123
|
}
|
|
70936
|
-
const verifyPath =
|
|
71124
|
+
const verifyPath = path42.join(harnessDir, "verify.sh");
|
|
70937
71125
|
if (fs35.existsSync(verifyPath)) {
|
|
70938
71126
|
const content = fs35.readFileSync(verifyPath, "utf8");
|
|
70939
71127
|
if (content.includes("echo 'TODO:")) {
|
|
70940
71128
|
issues.push({ file: "verify.sh", message: "Verification steps still have TODO placeholders", severity: "warning" });
|
|
70941
71129
|
}
|
|
70942
71130
|
}
|
|
70943
|
-
const stagesPath =
|
|
71131
|
+
const stagesPath = path42.join(harnessDir, "stages.json");
|
|
70944
71132
|
if (fs35.existsSync(stagesPath)) {
|
|
70945
71133
|
try {
|
|
70946
71134
|
JSON.parse(fs35.readFileSync(stagesPath, "utf8"));
|
|
@@ -70958,7 +71146,7 @@ function validateHarness(repoPath) {
|
|
|
70958
71146
|
} else {
|
|
70959
71147
|
issues.push({ file: "stages.json", message: "Stage registry missing", severity: "warning" });
|
|
70960
71148
|
}
|
|
70961
|
-
const readmePath =
|
|
71149
|
+
const readmePath = path42.join(harnessDir, "README.md");
|
|
70962
71150
|
if (fs35.existsSync(readmePath)) {
|
|
70963
71151
|
const content = fs35.readFileSync(readmePath, "utf8");
|
|
70964
71152
|
if (!content.includes(".har")) {
|
|
@@ -70974,7 +71162,7 @@ function validateHarness(repoPath) {
|
|
|
70974
71162
|
async function smokeTestHarness(repoPath) {
|
|
70975
71163
|
const harnessDir = getHarnessDir(repoPath);
|
|
70976
71164
|
const issues = [];
|
|
70977
|
-
const setupScript =
|
|
71165
|
+
const setupScript = path42.join(harnessDir, "setup-infra.sh");
|
|
70978
71166
|
if (fs35.existsSync(setupScript)) {
|
|
70979
71167
|
const result = run(`bash "${setupScript}"`, { cwd: repoPath });
|
|
70980
71168
|
if (result.code !== 0) {
|
|
@@ -70991,7 +71179,7 @@ async function smokeTestHarness(repoPath) {
|
|
|
70991
71179
|
|
|
70992
71180
|
// src/harness/drift.ts
|
|
70993
71181
|
var fs36 = __toESM(require("fs"));
|
|
70994
|
-
var
|
|
71182
|
+
var path43 = __toESM(require("path"));
|
|
70995
71183
|
init_env();
|
|
70996
71184
|
init_manifest();
|
|
70997
71185
|
init_stages();
|
|
@@ -71061,12 +71249,12 @@ function listBoilerplateFiles(boilerplateDir) {
|
|
|
71061
71249
|
return fs36.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
71062
71250
|
}
|
|
71063
71251
|
function compareHarnessToTemplate(repoPath) {
|
|
71064
|
-
const resolved =
|
|
71252
|
+
const resolved = path43.resolve(repoPath);
|
|
71065
71253
|
const manifest = readManifest(resolved);
|
|
71066
71254
|
const profile = manifest?.profile ?? "default";
|
|
71067
71255
|
const harnessDir = getHarnessDir(resolved);
|
|
71068
|
-
const projectName =
|
|
71069
|
-
const boilerplateDir =
|
|
71256
|
+
const projectName = path43.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
71257
|
+
const boilerplateDir = path43.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
|
|
71070
71258
|
const templateFiles = listBoilerplateFiles(boilerplateDir);
|
|
71071
71259
|
const missing = [];
|
|
71072
71260
|
const checksumMismatch = [];
|
|
@@ -71074,8 +71262,8 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
71074
71262
|
const unchanged = [];
|
|
71075
71263
|
for (const file of templateFiles) {
|
|
71076
71264
|
const harnessFile = harnessFileForTemplate(file);
|
|
71077
|
-
const templatePath =
|
|
71078
|
-
const harnessPath =
|
|
71265
|
+
const templatePath = path43.join(boilerplateDir, file);
|
|
71266
|
+
const harnessPath = path43.join(harnessDir, harnessFile);
|
|
71079
71267
|
let templateContent = fs36.readFileSync(templatePath, "utf8");
|
|
71080
71268
|
if (file === "harness.env") {
|
|
71081
71269
|
templateContent = substituteProjectName(templateContent, projectName);
|
|
@@ -71094,7 +71282,7 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
71094
71282
|
}
|
|
71095
71283
|
if (fs36.existsSync(harnessDir)) {
|
|
71096
71284
|
for (const file of fs36.readdirSync(harnessDir)) {
|
|
71097
|
-
const full =
|
|
71285
|
+
const full = path43.join(harnessDir, file);
|
|
71098
71286
|
if (!fs36.statSync(full).isFile()) continue;
|
|
71099
71287
|
if (file === "manifest.json" || file === "plugins.json" || file.startsWith("ADAPT-PROMPT")) {
|
|
71100
71288
|
continue;
|
|
@@ -71124,19 +71312,19 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
71124
71312
|
// src/harness/maintain-bundle.ts
|
|
71125
71313
|
var fs41 = __toESM(require("fs"));
|
|
71126
71314
|
var os18 = __toESM(require("os"));
|
|
71127
|
-
var
|
|
71315
|
+
var path47 = __toESM(require("path"));
|
|
71128
71316
|
init_file_ops();
|
|
71129
71317
|
init_shell();
|
|
71130
71318
|
init_manifest();
|
|
71131
71319
|
|
|
71132
71320
|
// src/harness/plugin-drift.ts
|
|
71133
71321
|
var fs40 = __toESM(require("fs"));
|
|
71134
|
-
var
|
|
71322
|
+
var path46 = __toESM(require("path"));
|
|
71135
71323
|
init_manifest();
|
|
71136
71324
|
|
|
71137
71325
|
// src/harness/plugins.ts
|
|
71138
71326
|
var fs39 = __toESM(require("fs"));
|
|
71139
|
-
var
|
|
71327
|
+
var path45 = __toESM(require("path"));
|
|
71140
71328
|
init_zod();
|
|
71141
71329
|
init_logging();
|
|
71142
71330
|
|
|
@@ -71151,12 +71339,12 @@ function harnessExists(repoPath) {
|
|
|
71151
71339
|
var import_child_process11 = require("child_process");
|
|
71152
71340
|
var fs38 = __toESM(require("fs"));
|
|
71153
71341
|
var os17 = __toESM(require("os"));
|
|
71154
|
-
var
|
|
71342
|
+
var path44 = __toESM(require("path"));
|
|
71155
71343
|
function hasManifest(dir) {
|
|
71156
|
-
return fs38.existsSync(
|
|
71344
|
+
return fs38.existsSync(path44.join(dir, "template.manifest.json"));
|
|
71157
71345
|
}
|
|
71158
71346
|
function readPackageVersion(dir) {
|
|
71159
|
-
const pkgPath =
|
|
71347
|
+
const pkgPath = path44.join(dir, "package.json");
|
|
71160
71348
|
if (!fs38.existsSync(pkgPath)) return void 0;
|
|
71161
71349
|
try {
|
|
71162
71350
|
const pkg = JSON.parse(fs38.readFileSync(pkgPath, "utf8"));
|
|
@@ -71166,7 +71354,7 @@ function readPackageVersion(dir) {
|
|
|
71166
71354
|
}
|
|
71167
71355
|
}
|
|
71168
71356
|
function readManifestId(dir) {
|
|
71169
|
-
const manifestPath =
|
|
71357
|
+
const manifestPath = path44.join(dir, "template.manifest.json");
|
|
71170
71358
|
if (!fs38.existsSync(manifestPath)) return void 0;
|
|
71171
71359
|
try {
|
|
71172
71360
|
const raw = JSON.parse(fs38.readFileSync(manifestPath, "utf8"));
|
|
@@ -71187,24 +71375,24 @@ function looksLikeNpm(spec) {
|
|
|
71187
71375
|
return /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@.+)?$/i.test(spec);
|
|
71188
71376
|
}
|
|
71189
71377
|
function resolveBundledDir(pluginId) {
|
|
71190
|
-
const dir =
|
|
71378
|
+
const dir = path44.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
71191
71379
|
return hasManifest(dir) ? dir : null;
|
|
71192
71380
|
}
|
|
71193
71381
|
function expandHome(p) {
|
|
71194
|
-
if (p.startsWith("~/")) return
|
|
71382
|
+
if (p.startsWith("~/")) return path44.join(os17.homedir(), p.slice(2));
|
|
71195
71383
|
if (p === "~") return os17.homedir();
|
|
71196
71384
|
return p;
|
|
71197
71385
|
}
|
|
71198
71386
|
function resolvePathSpec(spec) {
|
|
71199
71387
|
const raw = spec.startsWith("file:") ? spec.slice("file:".length) : spec;
|
|
71200
|
-
const dir =
|
|
71388
|
+
const dir = path44.resolve(expandHome(raw));
|
|
71201
71389
|
if (!fs38.existsSync(dir) || !fs38.statSync(dir).isDirectory()) {
|
|
71202
71390
|
throw new Error(`Plugin path not found: ${spec}`);
|
|
71203
71391
|
}
|
|
71204
71392
|
if (!hasManifest(dir)) {
|
|
71205
71393
|
throw new Error(`No template.manifest.json in ${dir}`);
|
|
71206
71394
|
}
|
|
71207
|
-
const id = readManifestId(dir) ??
|
|
71395
|
+
const id = readManifestId(dir) ?? path44.basename(dir);
|
|
71208
71396
|
return {
|
|
71209
71397
|
id,
|
|
71210
71398
|
kind: "path",
|
|
@@ -71215,7 +71403,7 @@ function resolvePathSpec(spec) {
|
|
|
71215
71403
|
};
|
|
71216
71404
|
}
|
|
71217
71405
|
function makeTempDir(prefix) {
|
|
71218
|
-
return fs38.mkdtempSync(
|
|
71406
|
+
return fs38.mkdtempSync(path44.join(os17.tmpdir(), prefix));
|
|
71219
71407
|
}
|
|
71220
71408
|
function resolveNpmSpec(spec) {
|
|
71221
71409
|
const tmp = makeTempDir("har-plugin-npm-");
|
|
@@ -71230,16 +71418,16 @@ function resolveNpmSpec(spec) {
|
|
|
71230
71418
|
if (tarballs.length === 0) {
|
|
71231
71419
|
throw new Error(`npm pack produced no tarball for ${spec}`);
|
|
71232
71420
|
}
|
|
71233
|
-
const extractDir =
|
|
71421
|
+
const extractDir = path44.join(tmp, "extract");
|
|
71234
71422
|
fs38.mkdirSync(extractDir);
|
|
71235
|
-
(0, import_child_process11.execFileSync)("tar", ["-xzf",
|
|
71423
|
+
(0, import_child_process11.execFileSync)("tar", ["-xzf", path44.join(tmp, tarballs[0]), "-C", extractDir], {
|
|
71236
71424
|
encoding: "utf8",
|
|
71237
71425
|
stdio: ["ignore", "pipe", "pipe"]
|
|
71238
71426
|
});
|
|
71239
|
-
const packageDir =
|
|
71427
|
+
const packageDir = path44.join(extractDir, "package");
|
|
71240
71428
|
let dir = packageDir;
|
|
71241
71429
|
if (!hasManifest(dir)) {
|
|
71242
|
-
const nested = fs38.readdirSync(extractDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) =>
|
|
71430
|
+
const nested = fs38.readdirSync(extractDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path44.join(extractDir, e.name)).find((d) => hasManifest(d));
|
|
71243
71431
|
if (!nested) {
|
|
71244
71432
|
throw new Error(
|
|
71245
71433
|
`npm package ${spec} has no template.manifest.json (not a HAR plugin bundle)`
|
|
@@ -71267,7 +71455,7 @@ function resolveNpmSpec(spec) {
|
|
|
71267
71455
|
function resolveGitSpec(spec) {
|
|
71268
71456
|
const tmp = makeTempDir("har-plugin-git-");
|
|
71269
71457
|
const cleanupDirs = [tmp];
|
|
71270
|
-
const cloneDir =
|
|
71458
|
+
const cloneDir = path44.join(tmp, "repo");
|
|
71271
71459
|
try {
|
|
71272
71460
|
let url = spec;
|
|
71273
71461
|
if (spec.startsWith("github:")) {
|
|
@@ -71286,16 +71474,16 @@ function resolveGitSpec(spec) {
|
|
|
71286
71474
|
});
|
|
71287
71475
|
let dir = cloneDir;
|
|
71288
71476
|
if (!hasManifest(dir)) {
|
|
71289
|
-
const pluginsRoot =
|
|
71477
|
+
const pluginsRoot = path44.join(cloneDir, "plugins");
|
|
71290
71478
|
if (fs38.existsSync(pluginsRoot)) {
|
|
71291
|
-
const child = fs38.readdirSync(pluginsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) =>
|
|
71479
|
+
const child = fs38.readdirSync(pluginsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path44.join(pluginsRoot, e.name)).find((d) => hasManifest(d));
|
|
71292
71480
|
if (child) dir = child;
|
|
71293
71481
|
}
|
|
71294
71482
|
}
|
|
71295
71483
|
if (!hasManifest(dir)) {
|
|
71296
71484
|
throw new Error(`Git repo ${spec} has no template.manifest.json (not a HAR plugin bundle)`);
|
|
71297
71485
|
}
|
|
71298
|
-
const id = readManifestId(dir) ??
|
|
71486
|
+
const id = readManifestId(dir) ?? path44.basename(url.replace(/\.git$/, ""));
|
|
71299
71487
|
return {
|
|
71300
71488
|
id,
|
|
71301
71489
|
kind: "git",
|
|
@@ -71354,9 +71542,9 @@ function resolvePluginSource(spec) {
|
|
|
71354
71542
|
);
|
|
71355
71543
|
}
|
|
71356
71544
|
function listBundledPluginIds() {
|
|
71357
|
-
const root =
|
|
71545
|
+
const root = path44.join(resolveTemplatesDir(), "plugins");
|
|
71358
71546
|
if (!fs38.existsSync(root)) return [];
|
|
71359
|
-
return fs38.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(
|
|
71547
|
+
return fs38.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => hasManifest(path44.join(root, name))).sort();
|
|
71360
71548
|
}
|
|
71361
71549
|
function cleanupResolvedPlugin(source) {
|
|
71362
71550
|
for (const dir of source.cleanupDirs) {
|
|
@@ -71412,14 +71600,14 @@ function primaryStageId(manifest) {
|
|
|
71412
71600
|
return manifest.stageId ?? stages[0].id;
|
|
71413
71601
|
}
|
|
71414
71602
|
function resolveBundledPluginDir(pluginId) {
|
|
71415
|
-
const dir =
|
|
71603
|
+
const dir = path45.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
71416
71604
|
if (!fs39.existsSync(dir)) {
|
|
71417
71605
|
throw new Error(`Plugin not found: ${pluginId}. Run npm run build.`);
|
|
71418
71606
|
}
|
|
71419
71607
|
return dir;
|
|
71420
71608
|
}
|
|
71421
71609
|
function readPluginManifestFromDir(pluginDir, expectedId) {
|
|
71422
|
-
const manifestPath =
|
|
71610
|
+
const manifestPath = path45.join(pluginDir, "template.manifest.json");
|
|
71423
71611
|
if (!fs39.existsSync(manifestPath)) {
|
|
71424
71612
|
throw new Error(`No template.manifest.json in ${pluginDir}`);
|
|
71425
71613
|
}
|
|
@@ -71438,14 +71626,14 @@ function readPluginManifest(pluginId) {
|
|
|
71438
71626
|
return readPluginManifestFromDir(resolveBundledPluginDir(pluginId), pluginId);
|
|
71439
71627
|
}
|
|
71440
71628
|
function ensureParentDir(filePath) {
|
|
71441
|
-
const parent =
|
|
71629
|
+
const parent = path45.dirname(filePath);
|
|
71442
71630
|
if (!fs39.existsSync(parent)) {
|
|
71443
71631
|
fs39.mkdirSync(parent, { recursive: true });
|
|
71444
71632
|
}
|
|
71445
71633
|
}
|
|
71446
71634
|
function copyPluginFile(pluginDir, file, repoPath, force) {
|
|
71447
|
-
const srcPath =
|
|
71448
|
-
const destPath =
|
|
71635
|
+
const srcPath = path45.join(pluginDir, file.src);
|
|
71636
|
+
const destPath = path45.join(repoPath, file.dest);
|
|
71449
71637
|
if (!fs39.existsSync(srcPath)) {
|
|
71450
71638
|
throw new Error(`Plugin file missing: ${file.src}`);
|
|
71451
71639
|
}
|
|
@@ -71462,11 +71650,11 @@ function copyPluginFile(pluginDir, file, repoPath, force) {
|
|
|
71462
71650
|
return { written: true, path: file.dest };
|
|
71463
71651
|
}
|
|
71464
71652
|
function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
|
|
71465
|
-
const packagePath =
|
|
71653
|
+
const packagePath = path45.join(repoPath, "package.json");
|
|
71466
71654
|
if (!fs39.existsSync(packagePath)) {
|
|
71467
71655
|
throw new Error("No package.json in repo root. Add one before applying this plugin.");
|
|
71468
71656
|
}
|
|
71469
|
-
const fragmentPath =
|
|
71657
|
+
const fragmentPath = path45.join(pluginDir, fragmentRelPath);
|
|
71470
71658
|
if (!fs39.existsSync(fragmentPath)) {
|
|
71471
71659
|
throw new Error(`Package fragment missing: ${fragmentRelPath}`);
|
|
71472
71660
|
}
|
|
@@ -71528,7 +71716,7 @@ function assertStagesNotPresent(repoPath, stageIds, force) {
|
|
|
71528
71716
|
if (force) return;
|
|
71529
71717
|
const registry2 = readStageRegistry(repoPath);
|
|
71530
71718
|
for (const stageId of stageIds) {
|
|
71531
|
-
const scriptPath =
|
|
71719
|
+
const scriptPath = path45.join(repoPath, ".har", "stages", `${stageId}.sh`);
|
|
71532
71720
|
if (fs39.existsSync(scriptPath)) {
|
|
71533
71721
|
throw new Error(
|
|
71534
71722
|
`Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
|
|
@@ -71542,7 +71730,7 @@ function assertStagesNotPresent(repoPath, stageIds, force) {
|
|
|
71542
71730
|
}
|
|
71543
71731
|
}
|
|
71544
71732
|
function applyPluginFromDir(repoPath, pluginDir, options, meta) {
|
|
71545
|
-
const resolved =
|
|
71733
|
+
const resolved = path45.resolve(repoPath);
|
|
71546
71734
|
const force = options.force ?? false;
|
|
71547
71735
|
const warnings = [];
|
|
71548
71736
|
const filesWritten = [];
|
|
@@ -71562,7 +71750,7 @@ function applyPluginFromDir(repoPath, pluginDir, options, meta) {
|
|
|
71562
71750
|
if (file.skipFlag === "skipCi" && options.skipCi) {
|
|
71563
71751
|
continue;
|
|
71564
71752
|
}
|
|
71565
|
-
if (fs39.existsSync(
|
|
71753
|
+
if (fs39.existsSync(path45.join(resolved, file.dest)) && !force) {
|
|
71566
71754
|
warnings.push(`Skipped optional file (exists): ${file.dest}`);
|
|
71567
71755
|
continue;
|
|
71568
71756
|
}
|
|
@@ -71628,12 +71816,12 @@ function listPluginIds() {
|
|
|
71628
71816
|
init_stages();
|
|
71629
71817
|
var PACKAGE_SECTIONS = ["scripts", "devDependencies"];
|
|
71630
71818
|
function detectInstalledPlugins(repoPath) {
|
|
71631
|
-
const resolved =
|
|
71819
|
+
const resolved = path46.resolve(repoPath);
|
|
71632
71820
|
const ledger = readPluginLedger(resolved);
|
|
71633
71821
|
if (ledger && ledger.plugins.length > 0) {
|
|
71634
71822
|
return ledger.plugins.map((p) => p.id).sort();
|
|
71635
71823
|
}
|
|
71636
|
-
const registryPath =
|
|
71824
|
+
const registryPath = path46.join(resolved, ".har", "stages.json");
|
|
71637
71825
|
if (!fs40.existsSync(registryPath)) return [];
|
|
71638
71826
|
const registry2 = readStageRegistry(resolved);
|
|
71639
71827
|
const stageIds = new Set(registry2.stages.map((stage) => stage.id));
|
|
@@ -71651,7 +71839,7 @@ function detectInstalledPlugins(repoPath) {
|
|
|
71651
71839
|
return installed.sort();
|
|
71652
71840
|
}
|
|
71653
71841
|
function pluginTemplatePath(pluginId, srcRel) {
|
|
71654
|
-
return
|
|
71842
|
+
return path46.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
|
|
71655
71843
|
}
|
|
71656
71844
|
function resolvePluginTemplateDir(repoPath, pluginId) {
|
|
71657
71845
|
const ledger = readPluginLedger(repoPath);
|
|
@@ -71663,8 +71851,8 @@ function resolvePluginTemplateDir(repoPath, pluginId) {
|
|
|
71663
71851
|
} catch {
|
|
71664
71852
|
}
|
|
71665
71853
|
}
|
|
71666
|
-
const bundled =
|
|
71667
|
-
if (fs40.existsSync(
|
|
71854
|
+
const bundled = path46.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
71855
|
+
if (fs40.existsSync(path46.join(bundled, "template.manifest.json"))) {
|
|
71668
71856
|
return bundled;
|
|
71669
71857
|
}
|
|
71670
71858
|
return null;
|
|
@@ -71678,7 +71866,7 @@ function listPluginDestPaths(pluginId, repoPath) {
|
|
|
71678
71866
|
const paths = manifest.files.map((file) => file.dest);
|
|
71679
71867
|
if (manifest.optionalFiles) {
|
|
71680
71868
|
for (const file of manifest.optionalFiles) {
|
|
71681
|
-
if (fs40.existsSync(
|
|
71869
|
+
if (fs40.existsSync(path46.join(repoPath, file.dest))) {
|
|
71682
71870
|
paths.push(file.dest);
|
|
71683
71871
|
}
|
|
71684
71872
|
}
|
|
@@ -71737,7 +71925,7 @@ function readTemplatePluginFile(pluginId, dest) {
|
|
|
71737
71925
|
return null;
|
|
71738
71926
|
}
|
|
71739
71927
|
function readInstalledPluginFile(repoPath, pluginId, dest) {
|
|
71740
|
-
const installedPath =
|
|
71928
|
+
const installedPath = path46.join(path46.resolve(repoPath), dest);
|
|
71741
71929
|
if (!fs40.existsSync(installedPath)) return null;
|
|
71742
71930
|
const content = fs40.readFileSync(installedPath, "utf8");
|
|
71743
71931
|
const manifest = readPluginManifest(pluginId);
|
|
@@ -71758,7 +71946,7 @@ function pluginActionHint(pluginId, dest, kind) {
|
|
|
71758
71946
|
}
|
|
71759
71947
|
function comparePluginToTemplate(repoPath, pluginId) {
|
|
71760
71948
|
const manifest = readPluginManifest(pluginId);
|
|
71761
|
-
const resolved =
|
|
71949
|
+
const resolved = path46.resolve(repoPath);
|
|
71762
71950
|
const destPaths = listPluginDestPaths(pluginId, resolved);
|
|
71763
71951
|
const missing = [];
|
|
71764
71952
|
const checksumMismatch = [];
|
|
@@ -71773,7 +71961,7 @@ function comparePluginToTemplate(repoPath, pluginId) {
|
|
|
71773
71961
|
}
|
|
71774
71962
|
if (dest === "package.json") {
|
|
71775
71963
|
const fragmentRel = manifest.merge?.[dest];
|
|
71776
|
-
const installedPath =
|
|
71964
|
+
const installedPath = path46.join(resolved, dest);
|
|
71777
71965
|
const installedRaw = fs40.readFileSync(installedPath, "utf8");
|
|
71778
71966
|
if (fragmentRel && pluginKeysMatch(installedRaw, readBundledPluginFile(pluginId, fragmentRel))) {
|
|
71779
71967
|
unchanged.push(dest);
|
|
@@ -71800,7 +71988,7 @@ function comparePluginToTemplate(repoPath, pluginId) {
|
|
|
71800
71988
|
}
|
|
71801
71989
|
function compareInstalledPluginsToTemplate(repoPath) {
|
|
71802
71990
|
return detectInstalledPlugins(repoPath).filter((pluginId) => {
|
|
71803
|
-
const bundled =
|
|
71991
|
+
const bundled = path46.join(resolveTemplatesDir(), "plugins", pluginId, "template.manifest.json");
|
|
71804
71992
|
return fs40.existsSync(bundled);
|
|
71805
71993
|
}).map((pluginId) => comparePluginToTemplate(repoPath, pluginId));
|
|
71806
71994
|
}
|
|
@@ -71839,13 +72027,13 @@ function substituteProjectName2(content, projectName) {
|
|
|
71839
72027
|
return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
|
|
71840
72028
|
}
|
|
71841
72029
|
function projectNameFromRepo(repoPath) {
|
|
71842
|
-
return
|
|
72030
|
+
return path47.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
71843
72031
|
}
|
|
71844
72032
|
function boilerplateDirForProfile(profile) {
|
|
71845
|
-
return
|
|
72033
|
+
return path47.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
|
|
71846
72034
|
}
|
|
71847
72035
|
function readBundledTemplateContent(repoPath, profile, file) {
|
|
71848
|
-
const templatePath =
|
|
72036
|
+
const templatePath = path47.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
|
|
71849
72037
|
let content = fs41.readFileSync(templatePath, "utf8");
|
|
71850
72038
|
if (file === "harness.env") {
|
|
71851
72039
|
content = substituteProjectName2(content, projectNameFromRepo(repoPath));
|
|
@@ -71877,10 +72065,10 @@ function actionHint(file, kind) {
|
|
|
71877
72065
|
return `Read maintain/diffs/${file}.diff and merge into .har/${file}.`;
|
|
71878
72066
|
}
|
|
71879
72067
|
function createUnifiedDiff(installedContent, templateContent, installedLabel, templateLabel) {
|
|
71880
|
-
const tmpDir = fs41.mkdtempSync(
|
|
72068
|
+
const tmpDir = fs41.mkdtempSync(path47.join(os18.tmpdir(), "har-maintain-diff-"));
|
|
71881
72069
|
try {
|
|
71882
|
-
const installedPath =
|
|
71883
|
-
const templatePath =
|
|
72070
|
+
const installedPath = path47.join(tmpDir, "installed");
|
|
72071
|
+
const templatePath = path47.join(tmpDir, "template");
|
|
71884
72072
|
fs41.writeFileSync(installedPath, installedContent);
|
|
71885
72073
|
fs41.writeFileSync(templatePath, templateContent);
|
|
71886
72074
|
const result = run(`diff -u "${installedPath}" "${templatePath}"`);
|
|
@@ -71906,7 +72094,7 @@ function buildActions(repoPath, profile, drift) {
|
|
|
71906
72094
|
});
|
|
71907
72095
|
}
|
|
71908
72096
|
for (const file of drift.checksumMismatch) {
|
|
71909
|
-
const installedPath =
|
|
72097
|
+
const installedPath = path47.join(harnessDir, file);
|
|
71910
72098
|
const installedRel = `maintain/installed/${file}`;
|
|
71911
72099
|
const templateRel = `maintain/templates/${file}`;
|
|
71912
72100
|
const diffRel = `maintain/diffs/${file}.diff`;
|
|
@@ -72066,16 +72254,16 @@ function buildReadme(report) {
|
|
|
72066
72254
|
}
|
|
72067
72255
|
function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
72068
72256
|
const harnessDir = getHarnessDir(repoPath);
|
|
72069
|
-
const bundleDir =
|
|
72257
|
+
const bundleDir = path47.join(harnessDir, MAINTAIN_DIR);
|
|
72070
72258
|
if (fs41.existsSync(bundleDir)) {
|
|
72071
72259
|
fs41.rmSync(bundleDir, { recursive: true, force: true });
|
|
72072
72260
|
}
|
|
72073
72261
|
const dirs = [
|
|
72074
72262
|
bundleDir,
|
|
72075
|
-
|
|
72076
|
-
|
|
72077
|
-
|
|
72078
|
-
|
|
72263
|
+
path47.join(bundleDir, "templates"),
|
|
72264
|
+
path47.join(bundleDir, "installed"),
|
|
72265
|
+
path47.join(bundleDir, "diffs"),
|
|
72266
|
+
path47.join(bundleDir, "stale")
|
|
72079
72267
|
];
|
|
72080
72268
|
for (const dir of dirs) {
|
|
72081
72269
|
fs41.mkdirSync(dir, { recursive: true });
|
|
@@ -72083,11 +72271,11 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
72083
72271
|
const affectedFiles = [...drift.missing, ...drift.checksumMismatch];
|
|
72084
72272
|
for (const file of affectedFiles) {
|
|
72085
72273
|
const templateContent = readBundledTemplateContent(repoPath, profile, file);
|
|
72086
|
-
writeFileSafe(
|
|
72087
|
-
const harnessPath =
|
|
72274
|
+
writeFileSafe(path47.join(bundleDir, "templates", file), templateContent);
|
|
72275
|
+
const harnessPath = path47.join(harnessDir, file);
|
|
72088
72276
|
if (fs41.existsSync(harnessPath)) {
|
|
72089
72277
|
const installedContent = fs41.readFileSync(harnessPath, "utf8");
|
|
72090
|
-
writeFileSafe(
|
|
72278
|
+
writeFileSafe(path47.join(bundleDir, "installed", file), installedContent);
|
|
72091
72279
|
const diff = createUnifiedDiff(
|
|
72092
72280
|
installedContent,
|
|
72093
72281
|
templateContent,
|
|
@@ -72095,14 +72283,14 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
72095
72283
|
`templates/${file}`
|
|
72096
72284
|
);
|
|
72097
72285
|
if (diff) {
|
|
72098
|
-
writeFileSafe(
|
|
72286
|
+
writeFileSafe(path47.join(bundleDir, "diffs", `${file}.diff`), diff);
|
|
72099
72287
|
}
|
|
72100
72288
|
}
|
|
72101
72289
|
}
|
|
72102
|
-
writeFileSafe(
|
|
72103
|
-
writeFileSafe(
|
|
72290
|
+
writeFileSafe(path47.join(bundleDir, "README.md"), buildReadme(report));
|
|
72291
|
+
writeFileSafe(path47.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
|
|
72104
72292
|
writeFileSafe(
|
|
72105
|
-
|
|
72293
|
+
path47.join(bundleDir, "validation.json"),
|
|
72106
72294
|
JSON.stringify(report.validation, null, 2) + "\n"
|
|
72107
72295
|
);
|
|
72108
72296
|
if (report.stale.length > 0) {
|
|
@@ -72114,12 +72302,12 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
72114
72302
|
...report.stale.map((s) => `- **${s.file}** \u2014 ${s.hint}`),
|
|
72115
72303
|
""
|
|
72116
72304
|
];
|
|
72117
|
-
writeFileSafe(
|
|
72305
|
+
writeFileSafe(path47.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
|
|
72118
72306
|
}
|
|
72119
72307
|
return bundleDir;
|
|
72120
72308
|
}
|
|
72121
72309
|
function ensureParentDir2(filePath) {
|
|
72122
|
-
const parent =
|
|
72310
|
+
const parent = path47.dirname(filePath);
|
|
72123
72311
|
if (!fs41.existsSync(parent)) {
|
|
72124
72312
|
fs41.mkdirSync(parent, { recursive: true });
|
|
72125
72313
|
}
|
|
@@ -72127,21 +72315,21 @@ function ensureParentDir2(filePath) {
|
|
|
72127
72315
|
function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
72128
72316
|
if (report.pluginActions.length === 0) return;
|
|
72129
72317
|
for (const action of report.pluginActions) {
|
|
72130
|
-
const pluginRoot =
|
|
72131
|
-
const templatesDir =
|
|
72132
|
-
const installedDir =
|
|
72133
|
-
const diffsDir =
|
|
72318
|
+
const pluginRoot = path47.join(bundleDir, "plugins", action.pluginId);
|
|
72319
|
+
const templatesDir = path47.join(pluginRoot, "templates");
|
|
72320
|
+
const installedDir = path47.join(pluginRoot, "installed");
|
|
72321
|
+
const diffsDir = path47.join(pluginRoot, "diffs");
|
|
72134
72322
|
for (const dir of [templatesDir, installedDir, diffsDir]) {
|
|
72135
72323
|
fs41.mkdirSync(dir, { recursive: true });
|
|
72136
72324
|
}
|
|
72137
72325
|
const templateContent = readTemplatePluginFile(action.pluginId, action.file);
|
|
72138
72326
|
if (templateContent === null) continue;
|
|
72139
|
-
const templatePath =
|
|
72327
|
+
const templatePath = path47.join(templatesDir, action.file);
|
|
72140
72328
|
ensureParentDir2(templatePath);
|
|
72141
72329
|
writeFileSafe(templatePath, templateContent);
|
|
72142
72330
|
const installedContent = readInstalledPluginFile(repoPath, action.pluginId, action.file);
|
|
72143
72331
|
if (installedContent !== null) {
|
|
72144
|
-
const installedPath =
|
|
72332
|
+
const installedPath = path47.join(installedDir, action.file);
|
|
72145
72333
|
ensureParentDir2(installedPath);
|
|
72146
72334
|
writeFileSafe(installedPath, installedContent);
|
|
72147
72335
|
const diff = createUnifiedDiff(
|
|
@@ -72151,7 +72339,7 @@ function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
|
72151
72339
|
`templates/${action.file}`
|
|
72152
72340
|
);
|
|
72153
72341
|
if (diff) {
|
|
72154
|
-
const diffPath =
|
|
72342
|
+
const diffPath = path47.join(diffsDir, `${action.file}.diff`);
|
|
72155
72343
|
ensureParentDir2(diffPath);
|
|
72156
72344
|
writeFileSafe(diffPath, diff);
|
|
72157
72345
|
}
|
|
@@ -72186,7 +72374,7 @@ function buildMaintainBundle(repoPath, validation2, drift) {
|
|
|
72186
72374
|
return { bundleDir, report };
|
|
72187
72375
|
}
|
|
72188
72376
|
function removeMaintainBundle(repoPath) {
|
|
72189
|
-
const bundleDir =
|
|
72377
|
+
const bundleDir = path47.join(getHarnessDir(repoPath), MAINTAIN_DIR);
|
|
72190
72378
|
if (fs41.existsSync(bundleDir)) {
|
|
72191
72379
|
fs41.rmSync(bundleDir, { recursive: true, force: true });
|
|
72192
72380
|
}
|
|
@@ -72281,7 +72469,7 @@ function listHarnessScripts(repoPath) {
|
|
|
72281
72469
|
return fs42.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
|
|
72282
72470
|
}
|
|
72283
72471
|
function describeProject(repoPath) {
|
|
72284
|
-
const resolved =
|
|
72472
|
+
const resolved = path48.resolve(repoPath);
|
|
72285
72473
|
const manifest = readManifest(resolved);
|
|
72286
72474
|
const present = harnessExists(resolved);
|
|
72287
72475
|
return {
|
|
@@ -72301,7 +72489,7 @@ function describeProject(repoPath) {
|
|
|
72301
72489
|
};
|
|
72302
72490
|
}
|
|
72303
72491
|
async function initHarness(options) {
|
|
72304
|
-
const repoPath =
|
|
72492
|
+
const repoPath = path48.resolve(options.repoPath);
|
|
72305
72493
|
if (!fs42.existsSync(repoPath)) {
|
|
72306
72494
|
throw new Error(`Path not found: ${repoPath}`);
|
|
72307
72495
|
}
|
|
@@ -72322,7 +72510,7 @@ async function initHarness(options) {
|
|
|
72322
72510
|
};
|
|
72323
72511
|
}
|
|
72324
72512
|
async function maintainHarness(options) {
|
|
72325
|
-
const repoPath =
|
|
72513
|
+
const repoPath = path48.resolve(options.repoPath);
|
|
72326
72514
|
const harnessDir = getHarnessDir(repoPath);
|
|
72327
72515
|
if (!fs42.existsSync(harnessDir)) {
|
|
72328
72516
|
throw new Error('No .har/ found. Run "har env init" first.');
|
|
@@ -72360,12 +72548,12 @@ function addPlugin(repoPath, pluginId, options = {}) {
|
|
|
72360
72548
|
|
|
72361
72549
|
// src/harness/custom-stage.ts
|
|
72362
72550
|
var fs43 = __toESM(require("fs"));
|
|
72363
|
-
var
|
|
72551
|
+
var path49 = __toESM(require("path"));
|
|
72364
72552
|
init_schema2();
|
|
72365
72553
|
init_stages();
|
|
72366
72554
|
var STAGE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
72367
72555
|
function addCustomStage(repoPath, options) {
|
|
72368
|
-
const resolved =
|
|
72556
|
+
const resolved = path49.resolve(repoPath);
|
|
72369
72557
|
if (!harnessExists(resolved)) {
|
|
72370
72558
|
throw new Error('No .har/ harness found. Run "har env init" first.');
|
|
72371
72559
|
}
|
|
@@ -72402,18 +72590,18 @@ function addCustomStage(repoPath, options) {
|
|
|
72402
72590
|
if (options.command) {
|
|
72403
72591
|
stage.command = options.command;
|
|
72404
72592
|
} else {
|
|
72405
|
-
const scriptRel =
|
|
72406
|
-
const scriptAbs =
|
|
72593
|
+
const scriptRel = path49.join("stages", `${id}.sh`);
|
|
72594
|
+
const scriptAbs = path49.join(resolved, ".har", scriptRel);
|
|
72407
72595
|
if (fs43.existsSync(scriptAbs) && !options.force) {
|
|
72408
72596
|
throw new Error(`Stage script already exists: .har/${scriptRel}. Use --force to overwrite.`);
|
|
72409
72597
|
}
|
|
72410
|
-
const skeletonPath =
|
|
72598
|
+
const skeletonPath = path49.join(
|
|
72411
72599
|
resolveTemplatesDir(),
|
|
72412
72600
|
"plugins",
|
|
72413
72601
|
"custom-stage-skeleton.sh"
|
|
72414
72602
|
);
|
|
72415
72603
|
const skeleton = fs43.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
|
|
72416
|
-
fs43.mkdirSync(
|
|
72604
|
+
fs43.mkdirSync(path49.dirname(scriptAbs), { recursive: true });
|
|
72417
72605
|
fs43.writeFileSync(scriptAbs, skeleton);
|
|
72418
72606
|
fs43.chmodSync(scriptAbs, 493);
|
|
72419
72607
|
filesWritten.push(`.har/${scriptRel}`);
|
|
@@ -72464,7 +72652,7 @@ function addCustomStage(repoPath, options) {
|
|
|
72464
72652
|
|
|
72465
72653
|
// src/harness/adaptation-prompt.ts
|
|
72466
72654
|
var fs44 = __toESM(require("fs"));
|
|
72467
|
-
var
|
|
72655
|
+
var path50 = __toESM(require("path"));
|
|
72468
72656
|
var readline5 = __toESM(require("readline"));
|
|
72469
72657
|
|
|
72470
72658
|
// src/utils/clipboard.ts
|
|
@@ -72576,7 +72764,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
|
|
|
72576
72764
|
}
|
|
72577
72765
|
function writeAdaptationPrompt(repoPath, content) {
|
|
72578
72766
|
const harnessDir = getHarnessDir(repoPath);
|
|
72579
|
-
const filePath =
|
|
72767
|
+
const filePath = path50.join(harnessDir, ADAPTATION_PROMPT_FILE);
|
|
72580
72768
|
writeFileSafe(filePath, content);
|
|
72581
72769
|
return filePath;
|
|
72582
72770
|
}
|
|
@@ -72595,12 +72783,12 @@ function printAdaptationPrompt(content) {
|
|
|
72595
72783
|
}
|
|
72596
72784
|
function askYesNo2(question) {
|
|
72597
72785
|
const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
|
|
72598
|
-
return new Promise((
|
|
72786
|
+
return new Promise((resolve52) => {
|
|
72599
72787
|
process.stderr.write(`${question} `);
|
|
72600
72788
|
rl.once("line", (answer) => {
|
|
72601
72789
|
rl.close();
|
|
72602
72790
|
const trimmed = answer.trim();
|
|
72603
|
-
|
|
72791
|
+
resolve52(trimmed === "" || /^y(es)?$/i.test(trimmed));
|
|
72604
72792
|
});
|
|
72605
72793
|
});
|
|
72606
72794
|
}
|
|
@@ -72632,16 +72820,16 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
|
|
|
72632
72820
|
|
|
72633
72821
|
// src/harness/cursor-rule.ts
|
|
72634
72822
|
var fs45 = __toESM(require("fs"));
|
|
72635
|
-
var
|
|
72823
|
+
var path51 = __toESM(require("path"));
|
|
72636
72824
|
var readline6 = __toESM(require("readline"));
|
|
72637
72825
|
init_file_ops();
|
|
72638
72826
|
init_logging();
|
|
72639
72827
|
var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
|
|
72640
72828
|
function getCursorRulePath(repoPath) {
|
|
72641
|
-
return
|
|
72829
|
+
return path51.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
|
|
72642
72830
|
}
|
|
72643
72831
|
function isCursorWorkspace(repoPath) {
|
|
72644
|
-
return fs45.existsSync(
|
|
72832
|
+
return fs45.existsSync(path51.join(repoPath, ".cursor"));
|
|
72645
72833
|
}
|
|
72646
72834
|
function cursorRuleExists(repoPath) {
|
|
72647
72835
|
return fs45.existsSync(getCursorRulePath(repoPath));
|
|
@@ -72689,16 +72877,16 @@ async function promptScaffoldCursorRule(exists) {
|
|
|
72689
72877
|
}
|
|
72690
72878
|
async function askYesNo3(question) {
|
|
72691
72879
|
const rl = readline6.createInterface({ input: process.stdin, output: process.stderr });
|
|
72692
|
-
return new Promise((
|
|
72880
|
+
return new Promise((resolve52) => {
|
|
72693
72881
|
process.stderr.write(`${question} `);
|
|
72694
72882
|
rl.once("line", (answer) => {
|
|
72695
72883
|
rl.close();
|
|
72696
72884
|
const trimmed = answer.trim();
|
|
72697
72885
|
if (trimmed === "") {
|
|
72698
|
-
|
|
72886
|
+
resolve52(true);
|
|
72699
72887
|
return;
|
|
72700
72888
|
}
|
|
72701
|
-
|
|
72889
|
+
resolve52(/^y(es)?$/i.test(trimmed));
|
|
72702
72890
|
});
|
|
72703
72891
|
});
|
|
72704
72892
|
}
|
|
@@ -72741,7 +72929,7 @@ init_control_config();
|
|
|
72741
72929
|
|
|
72742
72930
|
// src/core/control-lifecycle.ts
|
|
72743
72931
|
var import_child_process13 = require("child_process");
|
|
72744
|
-
var
|
|
72932
|
+
var path52 = __toESM(require("path"));
|
|
72745
72933
|
|
|
72746
72934
|
// src/core/control-image.ts
|
|
72747
72935
|
init_package_version();
|
|
@@ -72768,10 +72956,10 @@ var CONTROL_DATA_VOLUME = "har_control_data";
|
|
|
72768
72956
|
var CONTROL_CONTAINER_PORT = 3847;
|
|
72769
72957
|
var CONTROL_DATA_DB_URL = "file:/data/har_control.db";
|
|
72770
72958
|
function resolveControlDir() {
|
|
72771
|
-
return
|
|
72959
|
+
return path52.resolve(__dirname, "..", "control");
|
|
72772
72960
|
}
|
|
72773
72961
|
function resolveControlBuildContext() {
|
|
72774
|
-
return
|
|
72962
|
+
return path52.resolve(resolveControlDir(), "..");
|
|
72775
72963
|
}
|
|
72776
72964
|
function buildDockerRunArgs(options) {
|
|
72777
72965
|
const name = options.containerName ?? CONTROL_CONTAINER_NAME;
|
|
@@ -72827,7 +73015,7 @@ async function startMissionControl(options) {
|
|
|
72827
73015
|
"-t",
|
|
72828
73016
|
imageRef,
|
|
72829
73017
|
"-f",
|
|
72830
|
-
|
|
73018
|
+
path52.join(resolveControlDir(), "Dockerfile"),
|
|
72831
73019
|
resolveControlBuildContext()
|
|
72832
73020
|
]);
|
|
72833
73021
|
if (buildCode !== 0) {
|
|
@@ -72974,7 +73162,7 @@ async function ensureTelemetryInfrastructure(options) {
|
|
|
72974
73162
|
// src/core/run-service.ts
|
|
72975
73163
|
init_telemetry_config();
|
|
72976
73164
|
init_telemetry_env();
|
|
72977
|
-
var
|
|
73165
|
+
var path54 = __toESM(require("path"));
|
|
72978
73166
|
init_local_executor();
|
|
72979
73167
|
function extractShellOutput(result) {
|
|
72980
73168
|
const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
|
|
@@ -73180,12 +73368,12 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
|
|
|
73180
73368
|
suffix: session.suffix,
|
|
73181
73369
|
createdAt: session.createdAt
|
|
73182
73370
|
});
|
|
73183
|
-
const envFile =
|
|
73371
|
+
const envFile = path54.join(session.workDir, `.env.agent.${options.agentId}`);
|
|
73184
73372
|
try {
|
|
73185
73373
|
appendTelemetryEnvToFile(envFile, {
|
|
73186
73374
|
sessionKey,
|
|
73187
73375
|
agentId: options.agentId,
|
|
73188
|
-
repoPath:
|
|
73376
|
+
repoPath: path54.resolve(options.repoPath),
|
|
73189
73377
|
workDir: session.workDir,
|
|
73190
73378
|
branch: session.branch,
|
|
73191
73379
|
suffix: session.suffix,
|
|
@@ -73424,7 +73612,7 @@ init_slot_status();
|
|
|
73424
73612
|
// src/core/cleanup-service.ts
|
|
73425
73613
|
var fs47 = __toESM(require("fs"));
|
|
73426
73614
|
var os20 = __toESM(require("os"));
|
|
73427
|
-
var
|
|
73615
|
+
var path55 = __toESM(require("path"));
|
|
73428
73616
|
var import_child_process15 = require("child_process");
|
|
73429
73617
|
init_control_sync();
|
|
73430
73618
|
init_control_repo_path();
|
|
@@ -73433,9 +73621,9 @@ init_manifest();
|
|
|
73433
73621
|
var DEFAULT_STALE_DAYS = 7;
|
|
73434
73622
|
function getWorktreesRoot() {
|
|
73435
73623
|
if (process.env.HAR_WORKTREES_ROOT) {
|
|
73436
|
-
return
|
|
73624
|
+
return path55.resolve(process.env.HAR_WORKTREES_ROOT);
|
|
73437
73625
|
}
|
|
73438
|
-
return
|
|
73626
|
+
return path55.join(process.env.HOME || os20.homedir(), "worktrees");
|
|
73439
73627
|
}
|
|
73440
73628
|
function runGit3(cwd, args) {
|
|
73441
73629
|
try {
|
|
@@ -73449,7 +73637,7 @@ function runGit3(cwd, args) {
|
|
|
73449
73637
|
}
|
|
73450
73638
|
}
|
|
73451
73639
|
function basenameRepo(repoPath) {
|
|
73452
|
-
return
|
|
73640
|
+
return path55.basename(canonicalizeControlRepoPath(repoPath));
|
|
73453
73641
|
}
|
|
73454
73642
|
function ageDaysFrom(iso) {
|
|
73455
73643
|
if (!iso) return void 0;
|
|
@@ -73461,12 +73649,12 @@ function matchesKeep(candidate, keep) {
|
|
|
73461
73649
|
if (!keep?.length) return false;
|
|
73462
73650
|
for (const pin of keep) {
|
|
73463
73651
|
if (pin.worktreePath && candidate.worktreePath) {
|
|
73464
|
-
if (
|
|
73652
|
+
if (path55.resolve(pin.worktreePath) === path55.resolve(candidate.worktreePath)) return true;
|
|
73465
73653
|
}
|
|
73466
73654
|
if (pin.repoPath && pin.agentId !== void 0 && candidate.agentId !== void 0) {
|
|
73467
73655
|
const repo = canonicalizeControlRepoPath(pin.repoPath);
|
|
73468
|
-
const candidateRepo =
|
|
73469
|
-
if ((repo === candidateRepo ||
|
|
73656
|
+
const candidateRepo = path55.resolve(candidate.repoPath);
|
|
73657
|
+
if ((repo === candidateRepo || path55.resolve(pin.repoPath) === candidateRepo) && pin.agentId === candidate.agentId) {
|
|
73470
73658
|
return true;
|
|
73471
73659
|
}
|
|
73472
73660
|
}
|
|
@@ -73524,7 +73712,7 @@ function resolveRepoForWorktree(worktreePath) {
|
|
|
73524
73712
|
if (!fs47.existsSync(worktreePath)) return void 0;
|
|
73525
73713
|
const commonDir = runGit3(worktreePath, "rev-parse --git-common-dir");
|
|
73526
73714
|
if (!commonDir) return void 0;
|
|
73527
|
-
const gitRoot =
|
|
73715
|
+
const gitRoot = path55.resolve(worktreePath, commonDir, "..");
|
|
73528
73716
|
if (!readManifest(gitRoot)) return void 0;
|
|
73529
73717
|
return canonicalizeControlRepoPath(gitRoot);
|
|
73530
73718
|
}
|
|
@@ -73534,7 +73722,7 @@ function discoverOrphanWorktrees(knownPaths) {
|
|
|
73534
73722
|
const orphans = [];
|
|
73535
73723
|
for (const entry of fs47.readdirSync(worktreesRoot, { withFileTypes: true })) {
|
|
73536
73724
|
if (!entry.isDirectory() || !entry.name.includes("-har-agent-")) continue;
|
|
73537
|
-
const worktreePath =
|
|
73725
|
+
const worktreePath = path55.resolve(path55.join(worktreesRoot, entry.name));
|
|
73538
73726
|
if (knownPaths.has(worktreePath)) continue;
|
|
73539
73727
|
const repoPath = resolveRepoForWorktree(worktreePath) ?? worktreesRoot;
|
|
73540
73728
|
const porcelain = runGit3(worktreePath, "status --porcelain");
|
|
@@ -73565,8 +73753,8 @@ async function discoverCleanupCandidates(options = {}) {
|
|
|
73565
73753
|
const status = collectEnvironmentStatus(harnessRoot);
|
|
73566
73754
|
const projectName = basenameRepo(harnessRoot);
|
|
73567
73755
|
for (const slot of status.slots) {
|
|
73568
|
-
if (slot.worktreePath) knownWorktreePaths.add(
|
|
73569
|
-
if (slot.workDir) knownWorktreePaths.add(
|
|
73756
|
+
if (slot.worktreePath) knownWorktreePaths.add(path55.resolve(slot.worktreePath));
|
|
73757
|
+
if (slot.workDir) knownWorktreePaths.add(path55.resolve(slot.workDir));
|
|
73570
73758
|
const candidate = classifySlotCandidate(canonicalRepo, projectName, slot, {
|
|
73571
73759
|
staleDays: options.staleDays,
|
|
73572
73760
|
keep: options.keep
|
|
@@ -73626,8 +73814,8 @@ async function askYesNo4(question) {
|
|
|
73626
73814
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
73627
73815
|
const readline8 = await import("readline");
|
|
73628
73816
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
73629
|
-
const answer = await new Promise((
|
|
73630
|
-
rl.question(question,
|
|
73817
|
+
const answer = await new Promise((resolve52) => {
|
|
73818
|
+
rl.question(question, resolve52);
|
|
73631
73819
|
});
|
|
73632
73820
|
rl.close();
|
|
73633
73821
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -73710,7 +73898,7 @@ function parseCleanupKeepPins(values) {
|
|
|
73710
73898
|
}
|
|
73711
73899
|
if (raw.startsWith("/") || raw.startsWith("~")) {
|
|
73712
73900
|
return {
|
|
73713
|
-
worktreePath: raw.startsWith("~") ?
|
|
73901
|
+
worktreePath: raw.startsWith("~") ? path55.join(process.env.HOME || os20.homedir(), raw.slice(2)) : path55.resolve(raw)
|
|
73714
73902
|
};
|
|
73715
73903
|
}
|
|
73716
73904
|
return { repoPath: raw };
|
|
@@ -73724,12 +73912,12 @@ init_stages();
|
|
|
73724
73912
|
init_logging();
|
|
73725
73913
|
function askYesNo5(question) {
|
|
73726
73914
|
const rl = readline7.createInterface({ input: process.stdin, output: process.stderr });
|
|
73727
|
-
return new Promise((
|
|
73915
|
+
return new Promise((resolve52) => {
|
|
73728
73916
|
process.stderr.write(`${question} `);
|
|
73729
73917
|
rl.once("line", (answer) => {
|
|
73730
73918
|
rl.close();
|
|
73731
73919
|
const trimmed = answer.trim();
|
|
73732
|
-
|
|
73920
|
+
resolve52(trimmed === "" || /^y(es)?$/i.test(trimmed));
|
|
73733
73921
|
});
|
|
73734
73922
|
});
|
|
73735
73923
|
}
|
|
@@ -73832,13 +74020,13 @@ function warnIfDockerUnavailable(status = detectDockerStatus()) {
|
|
|
73832
74020
|
// src/core/onboarding-preferences.ts
|
|
73833
74021
|
var fs48 = __toESM(require("fs"));
|
|
73834
74022
|
var os21 = __toESM(require("os"));
|
|
73835
|
-
var
|
|
74023
|
+
var path56 = __toESM(require("path"));
|
|
73836
74024
|
init_schema2();
|
|
73837
74025
|
function getOnboardingPreferencesPath() {
|
|
73838
74026
|
if (process.env.HAR_PREFERENCES_PATH) {
|
|
73839
|
-
return
|
|
74027
|
+
return path56.resolve(process.env.HAR_PREFERENCES_PATH);
|
|
73840
74028
|
}
|
|
73841
|
-
return
|
|
74029
|
+
return path56.join(os21.homedir(), ".har", "preferences.json");
|
|
73842
74030
|
}
|
|
73843
74031
|
function readOnboardingPreferences() {
|
|
73844
74032
|
const preferencePath = getOnboardingPreferencesPath();
|
|
@@ -73869,7 +74057,7 @@ function writeOnboardingPreferences(overrides) {
|
|
|
73869
74057
|
};
|
|
73870
74058
|
const parsed = OnboardingPreferencesSchema.parse(preference);
|
|
73871
74059
|
const preferencePath = getOnboardingPreferencesPath();
|
|
73872
|
-
fs48.mkdirSync(
|
|
74060
|
+
fs48.mkdirSync(path56.dirname(preferencePath), { recursive: true });
|
|
73873
74061
|
fs48.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
|
|
73874
74062
|
`);
|
|
73875
74063
|
return parsed;
|
|
@@ -74215,7 +74403,7 @@ var envCommand = {
|
|
|
74215
74403
|
}
|
|
74216
74404
|
};
|
|
74217
74405
|
async function handleInit(argv) {
|
|
74218
|
-
const repoPath =
|
|
74406
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74219
74407
|
const onboarding = resolveOnboardingOptions(argv);
|
|
74220
74408
|
header("har env init");
|
|
74221
74409
|
info(`Repository: ${repoPath}`);
|
|
@@ -74262,7 +74450,7 @@ async function handleInit(argv) {
|
|
|
74262
74450
|
}
|
|
74263
74451
|
}
|
|
74264
74452
|
async function handleMaintain(argv) {
|
|
74265
|
-
const repoPath =
|
|
74453
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74266
74454
|
const onboarding = resolveOnboardingOptions(argv);
|
|
74267
74455
|
header("har env maintain");
|
|
74268
74456
|
info(`Repository: ${repoPath}`);
|
|
@@ -74393,7 +74581,7 @@ async function applyAgentIntegrations(options) {
|
|
|
74393
74581
|
}
|
|
74394
74582
|
}
|
|
74395
74583
|
async function handleAddPlugin(argv) {
|
|
74396
|
-
const repoPath =
|
|
74584
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74397
74585
|
const available = listPluginIds();
|
|
74398
74586
|
if (argv.list) {
|
|
74399
74587
|
for (const id of available) {
|
|
@@ -74433,7 +74621,7 @@ async function handleAddPlugin(argv) {
|
|
|
74433
74621
|
}
|
|
74434
74622
|
}
|
|
74435
74623
|
async function handleAddStage(argv) {
|
|
74436
|
-
const repoPath =
|
|
74624
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74437
74625
|
const available = listPluginIds();
|
|
74438
74626
|
if (argv.list) {
|
|
74439
74627
|
warn("har env add-stage --list is deprecated; prefer: har env add-plugin --list");
|
|
@@ -74499,7 +74687,7 @@ async function handleAddStage(argv) {
|
|
|
74499
74687
|
});
|
|
74500
74688
|
}
|
|
74501
74689
|
async function handlePreflight(argv) {
|
|
74502
|
-
const repo =
|
|
74690
|
+
const repo = path57.resolve(argv.repo);
|
|
74503
74691
|
const agentId = validateAgentId(argv.id, repo);
|
|
74504
74692
|
const result = await preflightEnvironment({
|
|
74505
74693
|
repoPath: repo,
|
|
@@ -74515,7 +74703,7 @@ async function handlePreflight(argv) {
|
|
|
74515
74703
|
return finishCommand(result.code);
|
|
74516
74704
|
}
|
|
74517
74705
|
async function handleLaunch(argv) {
|
|
74518
|
-
const repo =
|
|
74706
|
+
const repo = path57.resolve(argv.repo);
|
|
74519
74707
|
const agentId = validateAgentId(argv.id, repo);
|
|
74520
74708
|
if (!argv.resume) {
|
|
74521
74709
|
const guard = checkLaunchGuard2(repo, agentId, { worktree: argv.worktree });
|
|
@@ -74564,7 +74752,7 @@ async function handleWorkLink(argv) {
|
|
|
74564
74752
|
error("Provide --link or both --source and --url");
|
|
74565
74753
|
return finishCommand(1);
|
|
74566
74754
|
}
|
|
74567
|
-
const harnessRoot = resolveHarnessRoot(
|
|
74755
|
+
const harnessRoot = resolveHarnessRoot(path57.resolve(argv.repo));
|
|
74568
74756
|
const links = argv.link ? [parseWorkLinkSpec(argv.link)] : [{ source: argv.source, url: argv.url, label: argv.label }];
|
|
74569
74757
|
try {
|
|
74570
74758
|
const record2 = addWorkUnitLinks(harnessRoot, argv.workId, links);
|
|
@@ -74590,7 +74778,7 @@ async function handleRecover(argv) {
|
|
|
74590
74778
|
});
|
|
74591
74779
|
}
|
|
74592
74780
|
async function handleVerify(argv) {
|
|
74593
|
-
const repo =
|
|
74781
|
+
const repo = path57.resolve(argv.repo);
|
|
74594
74782
|
const agentId = validateAgentId(argv.id, repo);
|
|
74595
74783
|
const result = await runVerification({
|
|
74596
74784
|
repoPath: repo,
|
|
@@ -74619,7 +74807,7 @@ async function handleVerify(argv) {
|
|
|
74619
74807
|
return finishCommand(result.code);
|
|
74620
74808
|
}
|
|
74621
74809
|
async function handleTeardown(argv) {
|
|
74622
|
-
const repo =
|
|
74810
|
+
const repo = path57.resolve(argv.repo);
|
|
74623
74811
|
const agentId = validateAgentId(argv.id, repo);
|
|
74624
74812
|
const result = await teardownEnvironment({
|
|
74625
74813
|
repoPath: repo,
|
|
@@ -74630,7 +74818,7 @@ async function handleTeardown(argv) {
|
|
|
74630
74818
|
return finishCommand(result.code);
|
|
74631
74819
|
}
|
|
74632
74820
|
async function handleComplete(argv) {
|
|
74633
|
-
const repo =
|
|
74821
|
+
const repo = path57.resolve(argv.repo);
|
|
74634
74822
|
const agentId = validateAgentId(argv.id, repo);
|
|
74635
74823
|
const result = await completeEnvironment({
|
|
74636
74824
|
repoPath: repo,
|
|
@@ -74651,7 +74839,7 @@ async function handleComplete(argv) {
|
|
|
74651
74839
|
return finishCommand(result.code);
|
|
74652
74840
|
}
|
|
74653
74841
|
async function handleStatus(argv) {
|
|
74654
|
-
const repoPath =
|
|
74842
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74655
74843
|
if (argv.json) {
|
|
74656
74844
|
const status = collectEnvironmentStatus(repoPath);
|
|
74657
74845
|
const output = EnvironmentStatusSchema.parse(status);
|
|
@@ -74666,7 +74854,7 @@ async function handleStatus(argv) {
|
|
|
74666
74854
|
async function handleCleanup(argv) {
|
|
74667
74855
|
const keepValues = argv.keep?.split(",").map((value) => value.trim()).filter(Boolean);
|
|
74668
74856
|
const keep = parseCleanupKeepPins(keepValues);
|
|
74669
|
-
const repoPaths = argv.repo ? [
|
|
74857
|
+
const repoPaths = argv.repo ? [path57.resolve(argv.repo)] : void 0;
|
|
74670
74858
|
const plan = await discoverCleanupCandidates({
|
|
74671
74859
|
cwd: process.cwd(),
|
|
74672
74860
|
repoPaths,
|
|
@@ -74715,7 +74903,7 @@ async function handleCleanup(argv) {
|
|
|
74715
74903
|
return finishCommand(failed > 0 ? 1 : 0);
|
|
74716
74904
|
}
|
|
74717
74905
|
async function handleRunsList(argv) {
|
|
74718
|
-
const repoPath =
|
|
74906
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74719
74907
|
const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
|
|
74720
74908
|
if (argv.json) {
|
|
74721
74909
|
process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
|
|
@@ -74732,7 +74920,7 @@ async function handleRunsList(argv) {
|
|
|
74732
74920
|
}
|
|
74733
74921
|
}
|
|
74734
74922
|
async function handleRunsGet(argv) {
|
|
74735
|
-
const run2 = getRun(
|
|
74923
|
+
const run2 = getRun(path57.resolve(argv.repo), argv.runId);
|
|
74736
74924
|
if (!run2) {
|
|
74737
74925
|
error(`Run not found: ${argv.runId}`);
|
|
74738
74926
|
return finishCommand(1);
|
|
@@ -74809,7 +74997,7 @@ function printNextSteps() {
|
|
|
74809
74997
|
}
|
|
74810
74998
|
|
|
74811
74999
|
// src/cli/commands/control.ts
|
|
74812
|
-
var
|
|
75000
|
+
var path62 = __toESM(require("path"));
|
|
74813
75001
|
init_control_config();
|
|
74814
75002
|
init_portal_targets();
|
|
74815
75003
|
|
|
@@ -74818,7 +75006,7 @@ init_control_config();
|
|
|
74818
75006
|
|
|
74819
75007
|
// src/core/portal-connect.ts
|
|
74820
75008
|
var fs49 = __toESM(require("fs"));
|
|
74821
|
-
var
|
|
75009
|
+
var path58 = __toESM(require("path"));
|
|
74822
75010
|
var import_crypto2 = require("crypto");
|
|
74823
75011
|
init_control_repo_path();
|
|
74824
75012
|
init_control_registry();
|
|
@@ -74864,7 +75052,7 @@ async function loginViaBrowser(portalUrl, openUrlOrOptions = openBrowser) {
|
|
|
74864
75052
|
const options = typeof openUrlOrOptions === "function" ? { openUrl: openUrlOrOptions } : openUrlOrOptions;
|
|
74865
75053
|
const openUrl = options.openUrl ?? openBrowser;
|
|
74866
75054
|
const state = (0, import_crypto.randomUUID)();
|
|
74867
|
-
return new Promise((
|
|
75055
|
+
return new Promise((resolve52, reject) => {
|
|
74868
75056
|
let timer;
|
|
74869
75057
|
const server = http.createServer((req, res) => {
|
|
74870
75058
|
const requestUrl = new URL(req.url ?? "", "http://127.0.0.1");
|
|
@@ -74892,7 +75080,7 @@ async function loginViaBrowser(portalUrl, openUrlOrOptions = openBrowser) {
|
|
|
74892
75080
|
res.end("<h1>Logged in</h1><p>You can close this tab and return to the terminal.</p>");
|
|
74893
75081
|
cleanup();
|
|
74894
75082
|
const targets = parseCliTargetsParam(requestUrl.searchParams.get("targets"));
|
|
74895
|
-
|
|
75083
|
+
resolve52({
|
|
74896
75084
|
portalUrl,
|
|
74897
75085
|
token,
|
|
74898
75086
|
workspace: workspaceSlug ?? workspace,
|
|
@@ -74987,7 +75175,7 @@ function remainingConnections(connections, usedAliases) {
|
|
|
74987
75175
|
// src/core/portal-connect.ts
|
|
74988
75176
|
init_portal_targets();
|
|
74989
75177
|
function attachRepoIfPresent(alias, repoPath) {
|
|
74990
|
-
const resolved =
|
|
75178
|
+
const resolved = path58.resolve(repoPath ?? ".");
|
|
74991
75179
|
if (!fs49.existsSync(resolved)) return null;
|
|
74992
75180
|
const canonical = canonicalizeControlRepoPath(resolved);
|
|
74993
75181
|
attachRepoPortalTarget(canonical, alias);
|
|
@@ -75055,7 +75243,7 @@ async function runPortalConnect(input) {
|
|
|
75055
75243
|
return { record: record2, attachedRepo, extraAttached, mappedInBrowser: true };
|
|
75056
75244
|
}
|
|
75057
75245
|
function listRegisteredReposForConnect(repoPath) {
|
|
75058
|
-
const resolved = repoPath ?
|
|
75246
|
+
const resolved = repoPath ? path58.resolve(repoPath) : null;
|
|
75059
75247
|
const current = resolved && fs49.existsSync(resolved) ? canonicalizeControlRepoPath(resolved) : null;
|
|
75060
75248
|
return [.../* @__PURE__ */ new Set([...current ? [current] : [], ...listRegisteredRepos()])];
|
|
75061
75249
|
}
|
|
@@ -75374,13 +75562,13 @@ init_control_sync();
|
|
|
75374
75562
|
// src/core/control-sync-selection.ts
|
|
75375
75563
|
var fs50 = __toESM(require("fs"));
|
|
75376
75564
|
var os22 = __toESM(require("os"));
|
|
75377
|
-
var
|
|
75565
|
+
var path59 = __toESM(require("path"));
|
|
75378
75566
|
init_control_repo_path();
|
|
75379
75567
|
function getSelectionPath() {
|
|
75380
75568
|
if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
|
|
75381
|
-
return
|
|
75569
|
+
return path59.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
|
|
75382
75570
|
}
|
|
75383
|
-
return
|
|
75571
|
+
return path59.join(os22.homedir(), ".har", "sync-selection.json");
|
|
75384
75572
|
}
|
|
75385
75573
|
function readSyncSelection() {
|
|
75386
75574
|
const selectionPath = getSelectionPath();
|
|
@@ -75396,7 +75584,7 @@ function readSyncSelection() {
|
|
|
75396
75584
|
function writeSyncSelection(repos) {
|
|
75397
75585
|
const selectionPath = getSelectionPath();
|
|
75398
75586
|
const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
|
|
75399
|
-
fs50.mkdirSync(
|
|
75587
|
+
fs50.mkdirSync(path59.dirname(selectionPath), { recursive: true });
|
|
75400
75588
|
fs50.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
|
|
75401
75589
|
}
|
|
75402
75590
|
function resolveSyncSelection(input) {
|
|
@@ -75425,7 +75613,7 @@ function resolveSyncSelection(input) {
|
|
|
75425
75613
|
|
|
75426
75614
|
// src/core/control-unregister.ts
|
|
75427
75615
|
var fs51 = __toESM(require("fs"));
|
|
75428
|
-
var
|
|
75616
|
+
var path60 = __toESM(require("path"));
|
|
75429
75617
|
init_control_repo_path();
|
|
75430
75618
|
init_control_registry();
|
|
75431
75619
|
init_control_config();
|
|
@@ -75435,7 +75623,7 @@ function listUnregisterWorktreeCandidates(repoPath) {
|
|
|
75435
75623
|
const harnessRoot = canonicalizeControlRepoPath(repoPath);
|
|
75436
75624
|
const byPath = /* @__PURE__ */ new Map();
|
|
75437
75625
|
const add = (partial2) => {
|
|
75438
|
-
const resolved =
|
|
75626
|
+
const resolved = path60.resolve(partial2.worktreePath);
|
|
75439
75627
|
if (!resolved || resolved === harnessRoot) return;
|
|
75440
75628
|
const exists = partial2.exists ?? fs51.existsSync(resolved);
|
|
75441
75629
|
const prev = byPath.get(resolved);
|
|
@@ -75488,8 +75676,8 @@ async function askYesNo6(question) {
|
|
|
75488
75676
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
75489
75677
|
const readline8 = await import("readline");
|
|
75490
75678
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
75491
|
-
const answer = await new Promise((
|
|
75492
|
-
rl.question(question,
|
|
75679
|
+
const answer = await new Promise((resolve52) => {
|
|
75680
|
+
rl.question(question, resolve52);
|
|
75493
75681
|
});
|
|
75494
75682
|
rl.close();
|
|
75495
75683
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -75636,15 +75824,15 @@ init_control_registry();
|
|
|
75636
75824
|
|
|
75637
75825
|
// src/core/harness-scrub.ts
|
|
75638
75826
|
var fs52 = __toESM(require("fs"));
|
|
75639
|
-
var
|
|
75827
|
+
var path61 = __toESM(require("path"));
|
|
75640
75828
|
var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
|
|
75641
75829
|
function scrubLocalHarnessDirs(repoPath) {
|
|
75642
75830
|
const results = [];
|
|
75643
|
-
const resolved =
|
|
75831
|
+
const resolved = path61.resolve(repoPath);
|
|
75644
75832
|
if (!fs52.existsSync(resolved)) {
|
|
75645
75833
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
75646
75834
|
results.push({
|
|
75647
|
-
path:
|
|
75835
|
+
path: path61.join(resolved, ".har", directory),
|
|
75648
75836
|
directory,
|
|
75649
75837
|
deleted: false,
|
|
75650
75838
|
error: "repository path does not exist"
|
|
@@ -75653,7 +75841,7 @@ function scrubLocalHarnessDirs(repoPath) {
|
|
|
75653
75841
|
return results;
|
|
75654
75842
|
}
|
|
75655
75843
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
75656
|
-
const target =
|
|
75844
|
+
const target = path61.join(resolved, ".har", directory);
|
|
75657
75845
|
if (!fs52.existsSync(target)) {
|
|
75658
75846
|
results.push({ path: target, directory, deleted: true });
|
|
75659
75847
|
continue;
|
|
@@ -75681,7 +75869,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
|
|
|
75681
75869
|
const results = [];
|
|
75682
75870
|
const seen = /* @__PURE__ */ new Set();
|
|
75683
75871
|
for (const repoPath of repoPaths) {
|
|
75684
|
-
const key =
|
|
75872
|
+
const key = path61.resolve(repoPath);
|
|
75685
75873
|
if (seen.has(key)) continue;
|
|
75686
75874
|
seen.add(key);
|
|
75687
75875
|
results.push(...scrubLocalHarnessDirs(key));
|
|
@@ -75694,8 +75882,8 @@ async function askYesNo7(question) {
|
|
|
75694
75882
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
75695
75883
|
const readline8 = await import("readline");
|
|
75696
75884
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
75697
|
-
const answer = await new Promise((
|
|
75698
|
-
rl.question(question,
|
|
75885
|
+
const answer = await new Promise((resolve52) => {
|
|
75886
|
+
rl.question(question, resolve52);
|
|
75699
75887
|
});
|
|
75700
75888
|
rl.close();
|
|
75701
75889
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -75974,7 +76162,7 @@ async function handleDown() {
|
|
|
75974
76162
|
return finishCommand(code);
|
|
75975
76163
|
}
|
|
75976
76164
|
async function handleRegister(argv) {
|
|
75977
|
-
const repoPath =
|
|
76165
|
+
const repoPath = path62.resolve(argv.repo);
|
|
75978
76166
|
header("har control register");
|
|
75979
76167
|
info(`Repository: ${repoPath}`);
|
|
75980
76168
|
try {
|
|
@@ -76072,7 +76260,7 @@ async function handleReset(argv) {
|
|
|
76072
76260
|
}
|
|
76073
76261
|
}
|
|
76074
76262
|
async function handleUnregister(argv) {
|
|
76075
|
-
const repoPath =
|
|
76263
|
+
const repoPath = path62.resolve(argv.repo);
|
|
76076
76264
|
const worktrees = listUnregisterWorktreeCandidates(repoPath);
|
|
76077
76265
|
try {
|
|
76078
76266
|
let deleteWorktrees = argv.deleteWorktrees;
|
|
@@ -76210,7 +76398,7 @@ async function handleSync(argv) {
|
|
|
76210
76398
|
);
|
|
76211
76399
|
}
|
|
76212
76400
|
}
|
|
76213
|
-
const { synced, failed, results } = await syncReposWithControl({
|
|
76401
|
+
const { synced, failed, incomplete, results } = await syncReposWithControl({
|
|
76214
76402
|
repoPaths,
|
|
76215
76403
|
apiUrl: argv.apiUrl,
|
|
76216
76404
|
dryRun: argv.dryRun,
|
|
@@ -76219,7 +76407,9 @@ async function handleSync(argv) {
|
|
|
76219
76407
|
portalTargets
|
|
76220
76408
|
});
|
|
76221
76409
|
if (argv.json) {
|
|
76222
|
-
process.stdout.write(
|
|
76410
|
+
process.stdout.write(
|
|
76411
|
+
JSON.stringify({ ok: failed === 0, synced, failed, incomplete, results }, null, 2) + "\n"
|
|
76412
|
+
);
|
|
76223
76413
|
if (failed > 0) return finishCommand(1);
|
|
76224
76414
|
return;
|
|
76225
76415
|
}
|
|
@@ -76228,22 +76418,32 @@ async function handleSync(argv) {
|
|
|
76228
76418
|
for (const target of result.targets) {
|
|
76229
76419
|
const record2 = findPortalTargetRecord(target.alias);
|
|
76230
76420
|
const label = record2 ? displayPortalTargetLabel(record2) : target.alias;
|
|
76231
|
-
if (target.ok) {
|
|
76232
|
-
success(`Synced ${result.repoPath} \u2192 ${label}`);
|
|
76233
|
-
} else {
|
|
76421
|
+
if (!target.ok) {
|
|
76234
76422
|
warn(`Failed ${result.repoPath} \u2192 ${label}: ${target.error}`);
|
|
76423
|
+
} else if (target.warnings && target.warnings.length > 0) {
|
|
76424
|
+
warn(`Synced ${result.repoPath} \u2192 ${label} \u2014 incomplete`);
|
|
76425
|
+
} else {
|
|
76426
|
+
success(`Synced ${result.repoPath} \u2192 ${label}`);
|
|
76235
76427
|
}
|
|
76236
76428
|
}
|
|
76237
76429
|
continue;
|
|
76238
76430
|
}
|
|
76239
|
-
if (result.ok) {
|
|
76240
|
-
success(`Synced ${result.repoPath}`);
|
|
76241
|
-
} else {
|
|
76431
|
+
if (!result.ok) {
|
|
76242
76432
|
warn(`Failed ${result.repoPath}: ${result.error}`);
|
|
76433
|
+
} else if (result.warnings && result.warnings.length > 0) {
|
|
76434
|
+
warn(`Synced ${result.repoPath} \u2014 incomplete`);
|
|
76435
|
+
} else {
|
|
76436
|
+
success(`Synced ${result.repoPath}`);
|
|
76243
76437
|
}
|
|
76244
76438
|
}
|
|
76245
|
-
if (synced >
|
|
76246
|
-
|
|
76439
|
+
if (synced > incomplete) {
|
|
76440
|
+
const complete = synced - incomplete;
|
|
76441
|
+
success(`Synced ${complete} ${complete === 1 ? "repository" : "repositories"}`);
|
|
76442
|
+
}
|
|
76443
|
+
if (incomplete > 0) {
|
|
76444
|
+
warn(
|
|
76445
|
+
`${incomplete} ${incomplete === 1 ? "repository" : "repositories"} synced with incomplete telemetry \u2014 see the warnings above`
|
|
76446
|
+
);
|
|
76247
76447
|
}
|
|
76248
76448
|
if (failed > 0) {
|
|
76249
76449
|
warn(`${failed} ${failed === 1 ? "repository" : "repositories"} could not be synced`);
|
|
@@ -76341,12 +76541,12 @@ async function handleTrajectory(argv) {
|
|
|
76341
76541
|
}
|
|
76342
76542
|
|
|
76343
76543
|
// src/cli/commands/hooks.ts
|
|
76344
|
-
var
|
|
76544
|
+
var path64 = __toESM(require("path"));
|
|
76345
76545
|
init_hooks();
|
|
76346
76546
|
|
|
76347
76547
|
// src/core/claude-hooks.ts
|
|
76348
76548
|
var fs53 = __toESM(require("fs"));
|
|
76349
|
-
var
|
|
76549
|
+
var path63 = __toESM(require("path"));
|
|
76350
76550
|
var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
|
|
76351
76551
|
var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
|
|
76352
76552
|
var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
|
|
@@ -76367,7 +76567,7 @@ function readSettings(settingsPath) {
|
|
|
76367
76567
|
return parsed;
|
|
76368
76568
|
}
|
|
76369
76569
|
function writeSettings(settingsPath, settings) {
|
|
76370
|
-
fs53.mkdirSync(
|
|
76570
|
+
fs53.mkdirSync(path63.dirname(settingsPath), { recursive: true });
|
|
76371
76571
|
fs53.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
76372
76572
|
}
|
|
76373
76573
|
function installClaudeGuard(repoPath) {
|
|
@@ -76375,11 +76575,11 @@ function installClaudeGuard(repoPath) {
|
|
|
76375
76575
|
if (!templatePath) {
|
|
76376
76576
|
throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
|
|
76377
76577
|
}
|
|
76378
|
-
const guardScript =
|
|
76379
|
-
fs53.mkdirSync(
|
|
76578
|
+
const guardScript = path63.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
76579
|
+
fs53.mkdirSync(path63.dirname(guardScript), { recursive: true });
|
|
76380
76580
|
fs53.copyFileSync(templatePath, guardScript);
|
|
76381
76581
|
fs53.chmodSync(guardScript, 493);
|
|
76382
|
-
const settingsPath =
|
|
76582
|
+
const settingsPath = path63.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
76383
76583
|
const settings = readSettings(settingsPath);
|
|
76384
76584
|
const hooks = settings.hooks ?? {};
|
|
76385
76585
|
const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
|
|
@@ -76393,14 +76593,14 @@ function installClaudeGuard(repoPath) {
|
|
|
76393
76593
|
}
|
|
76394
76594
|
function uninstallClaudeGuard(repoPath) {
|
|
76395
76595
|
let removed = false;
|
|
76396
|
-
const guardScript =
|
|
76596
|
+
const guardScript = path63.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
76397
76597
|
if (fs53.existsSync(guardScript)) {
|
|
76398
76598
|
fs53.rmSync(guardScript);
|
|
76399
76599
|
removed = true;
|
|
76400
|
-
const parent =
|
|
76600
|
+
const parent = path63.dirname(guardScript);
|
|
76401
76601
|
if (fs53.existsSync(parent) && fs53.readdirSync(parent).length === 0) fs53.rmdirSync(parent);
|
|
76402
76602
|
}
|
|
76403
|
-
const settingsPath =
|
|
76603
|
+
const settingsPath = path63.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
76404
76604
|
if (fs53.existsSync(settingsPath)) {
|
|
76405
76605
|
const settings = readSettings(settingsPath);
|
|
76406
76606
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
@@ -76426,7 +76626,7 @@ function uninstallClaudeGuard(repoPath) {
|
|
|
76426
76626
|
return { removed };
|
|
76427
76627
|
}
|
|
76428
76628
|
function claudeGuardInstalled(repoPath) {
|
|
76429
|
-
const settingsPath =
|
|
76629
|
+
const settingsPath = path63.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
76430
76630
|
if (!fs53.existsSync(settingsPath)) return false;
|
|
76431
76631
|
try {
|
|
76432
76632
|
const settings = readSettings(settingsPath);
|
|
@@ -76444,7 +76644,7 @@ function repoOption(y) {
|
|
|
76444
76644
|
function handleInstall2(argv) {
|
|
76445
76645
|
try {
|
|
76446
76646
|
if (argv.claude) {
|
|
76447
|
-
const result2 = installClaudeGuard(
|
|
76647
|
+
const result2 = installClaudeGuard(path64.resolve(argv.repo));
|
|
76448
76648
|
success("Claude Code worktree guard installed.");
|
|
76449
76649
|
info(`Guard script: ${result2.guardScript}`);
|
|
76450
76650
|
info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
|
|
@@ -76452,7 +76652,7 @@ function handleInstall2(argv) {
|
|
|
76452
76652
|
info("Commit both files so the guard travels with the repo.");
|
|
76453
76653
|
return;
|
|
76454
76654
|
}
|
|
76455
|
-
const result = installHooks({ repoPath:
|
|
76655
|
+
const result = installHooks({ repoPath: path64.resolve(argv.repo), force: argv.force });
|
|
76456
76656
|
success(`Commit gate installed in ${result.hooksDir}`);
|
|
76457
76657
|
info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
|
|
76458
76658
|
info("Commits of unverified change batches will be blocked in agent worktrees.");
|
|
@@ -76465,7 +76665,7 @@ function handleInstall2(argv) {
|
|
|
76465
76665
|
function handleUninstall(argv) {
|
|
76466
76666
|
try {
|
|
76467
76667
|
if (argv.claude) {
|
|
76468
|
-
const result2 = uninstallClaudeGuard(
|
|
76668
|
+
const result2 = uninstallClaudeGuard(path64.resolve(argv.repo));
|
|
76469
76669
|
if (result2.removed) {
|
|
76470
76670
|
success("Claude Code worktree guard removed.");
|
|
76471
76671
|
} else {
|
|
@@ -76473,7 +76673,7 @@ function handleUninstall(argv) {
|
|
|
76473
76673
|
}
|
|
76474
76674
|
return;
|
|
76475
76675
|
}
|
|
76476
|
-
const result = uninstallHooks(
|
|
76676
|
+
const result = uninstallHooks(path64.resolve(argv.repo));
|
|
76477
76677
|
if (result.removed) {
|
|
76478
76678
|
success(`Commit gate removed from ${result.hooksDir}`);
|
|
76479
76679
|
} else {
|
|
@@ -76486,7 +76686,7 @@ function handleUninstall(argv) {
|
|
|
76486
76686
|
}
|
|
76487
76687
|
function handleStatus2(argv) {
|
|
76488
76688
|
try {
|
|
76489
|
-
const status = getHooksStatus(
|
|
76689
|
+
const status = getHooksStatus(path64.resolve(argv.repo));
|
|
76490
76690
|
if (argv.json) {
|
|
76491
76691
|
process.stdout.write(`${JSON.stringify(status, null, 2)}
|
|
76492
76692
|
`);
|
|
@@ -76504,7 +76704,7 @@ function handleStatus2(argv) {
|
|
|
76504
76704
|
);
|
|
76505
76705
|
info(`Effective: ${status.effectiveMode} (in this checkout)`);
|
|
76506
76706
|
info(
|
|
76507
|
-
`Claude guard: ${claudeGuardInstalled(
|
|
76707
|
+
`Claude guard: ${claudeGuardInstalled(path64.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
|
|
76508
76708
|
);
|
|
76509
76709
|
} catch (err) {
|
|
76510
76710
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -76765,10 +76965,10 @@ function assignProp(target, prop, value) {
|
|
|
76765
76965
|
configurable: true
|
|
76766
76966
|
});
|
|
76767
76967
|
}
|
|
76768
|
-
function getElementAtPath(obj,
|
|
76769
|
-
if (!
|
|
76968
|
+
function getElementAtPath(obj, path69) {
|
|
76969
|
+
if (!path69)
|
|
76770
76970
|
return obj;
|
|
76771
|
-
return
|
|
76971
|
+
return path69.reduce((acc, key) => acc?.[key], obj);
|
|
76772
76972
|
}
|
|
76773
76973
|
function promiseAllObject(promisesObj) {
|
|
76774
76974
|
const keys = Object.keys(promisesObj);
|
|
@@ -77088,11 +77288,11 @@ function aborted(x, startIndex = 0) {
|
|
|
77088
77288
|
}
|
|
77089
77289
|
return false;
|
|
77090
77290
|
}
|
|
77091
|
-
function prefixIssues(
|
|
77291
|
+
function prefixIssues(path69, issues) {
|
|
77092
77292
|
return issues.map((iss) => {
|
|
77093
77293
|
var _a2;
|
|
77094
77294
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
77095
|
-
iss.path.unshift(
|
|
77295
|
+
iss.path.unshift(path69);
|
|
77096
77296
|
return iss;
|
|
77097
77297
|
});
|
|
77098
77298
|
}
|
|
@@ -82415,7 +82615,7 @@ var Protocol = class {
|
|
|
82415
82615
|
return;
|
|
82416
82616
|
}
|
|
82417
82617
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
82418
|
-
await new Promise((
|
|
82618
|
+
await new Promise((resolve52) => setTimeout(resolve52, pollInterval));
|
|
82419
82619
|
options?.signal?.throwIfAborted();
|
|
82420
82620
|
}
|
|
82421
82621
|
} catch (error3) {
|
|
@@ -82432,7 +82632,7 @@ var Protocol = class {
|
|
|
82432
82632
|
*/
|
|
82433
82633
|
request(request, resultSchema, options) {
|
|
82434
82634
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
82435
|
-
return new Promise((
|
|
82635
|
+
return new Promise((resolve52, reject) => {
|
|
82436
82636
|
const earlyReject = (error3) => {
|
|
82437
82637
|
reject(error3);
|
|
82438
82638
|
};
|
|
@@ -82510,7 +82710,7 @@ var Protocol = class {
|
|
|
82510
82710
|
if (!parseResult.success) {
|
|
82511
82711
|
reject(parseResult.error);
|
|
82512
82712
|
} else {
|
|
82513
|
-
|
|
82713
|
+
resolve52(parseResult.data);
|
|
82514
82714
|
}
|
|
82515
82715
|
} catch (error3) {
|
|
82516
82716
|
reject(error3);
|
|
@@ -82771,12 +82971,12 @@ var Protocol = class {
|
|
|
82771
82971
|
}
|
|
82772
82972
|
} catch {
|
|
82773
82973
|
}
|
|
82774
|
-
return new Promise((
|
|
82974
|
+
return new Promise((resolve52, reject) => {
|
|
82775
82975
|
if (signal.aborted) {
|
|
82776
82976
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
82777
82977
|
return;
|
|
82778
82978
|
}
|
|
82779
|
-
const timeoutId = setTimeout(
|
|
82979
|
+
const timeoutId = setTimeout(resolve52, interval);
|
|
82780
82980
|
signal.addEventListener("abort", () => {
|
|
82781
82981
|
clearTimeout(timeoutId);
|
|
82782
82982
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -83566,7 +83766,7 @@ var Server = class extends Protocol {
|
|
|
83566
83766
|
};
|
|
83567
83767
|
|
|
83568
83768
|
// src/mcp/server.ts
|
|
83569
|
-
var
|
|
83769
|
+
var path65 = __toESM(require("path"));
|
|
83570
83770
|
|
|
83571
83771
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
83572
83772
|
var import_node_process3 = __toESM(require("node:process"), 1);
|
|
@@ -83649,12 +83849,12 @@ var StdioServerTransport = class {
|
|
|
83649
83849
|
this.onclose?.();
|
|
83650
83850
|
}
|
|
83651
83851
|
send(message) {
|
|
83652
|
-
return new Promise((
|
|
83852
|
+
return new Promise((resolve52) => {
|
|
83653
83853
|
const json = serializeMessage(message);
|
|
83654
83854
|
if (this._stdout.write(json)) {
|
|
83655
|
-
|
|
83855
|
+
resolve52();
|
|
83656
83856
|
} else {
|
|
83657
|
-
this._stdout.once("drain",
|
|
83857
|
+
this._stdout.once("drain", resolve52);
|
|
83658
83858
|
}
|
|
83659
83859
|
});
|
|
83660
83860
|
}
|
|
@@ -84293,7 +84493,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
84293
84493
|
const input = ControlUpInputSchema.parse({ ...args, repo });
|
|
84294
84494
|
const result = await startControlAndSync({
|
|
84295
84495
|
detach: input.detach,
|
|
84296
|
-
cwd:
|
|
84496
|
+
cwd: path65.resolve(input.repo)
|
|
84297
84497
|
});
|
|
84298
84498
|
if (result.code !== 0) {
|
|
84299
84499
|
return {
|
|
@@ -84357,11 +84557,11 @@ var mcpCommand = {
|
|
|
84357
84557
|
};
|
|
84358
84558
|
|
|
84359
84559
|
// src/cli/commands/onboard.ts
|
|
84360
|
-
var
|
|
84560
|
+
var path67 = __toESM(require("path"));
|
|
84361
84561
|
init_stages();
|
|
84362
84562
|
|
|
84363
84563
|
// src/core/onboarding.ts
|
|
84364
|
-
var
|
|
84564
|
+
var path66 = __toESM(require("path"));
|
|
84365
84565
|
init_control_config();
|
|
84366
84566
|
init_control_sync();
|
|
84367
84567
|
init_otel_hooks();
|
|
@@ -84505,7 +84705,7 @@ async function defaultEnsureControl(options) {
|
|
|
84505
84705
|
return { started: true, apiUrl: result.apiUrl };
|
|
84506
84706
|
}
|
|
84507
84707
|
async function runOnboarding(options, deps = {}) {
|
|
84508
|
-
const repoPath =
|
|
84708
|
+
const repoPath = path66.resolve(options.repoPath);
|
|
84509
84709
|
const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
|
|
84510
84710
|
const ensureControl = deps.ensureControl ?? defaultEnsureControl;
|
|
84511
84711
|
const init = deps.initHarness ?? initHarness;
|
|
@@ -84703,7 +84903,7 @@ async function promptChoices(args, docker) {
|
|
|
84703
84903
|
};
|
|
84704
84904
|
}
|
|
84705
84905
|
const pluginChoices = listPluginChoices();
|
|
84706
|
-
const repoPath =
|
|
84906
|
+
const repoPath = path67.resolve(args.repo);
|
|
84707
84907
|
const alreadyPresent = harnessExists(repoPath);
|
|
84708
84908
|
const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
|
|
84709
84909
|
const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
|
|
@@ -84824,7 +85024,7 @@ function printSummary(result) {
|
|
|
84824
85024
|
console.error("");
|
|
84825
85025
|
}
|
|
84826
85026
|
async function handleOnboard(argv) {
|
|
84827
|
-
const repoPath =
|
|
85027
|
+
const repoPath = path67.resolve(argv.repo);
|
|
84828
85028
|
header("har onboard");
|
|
84829
85029
|
info(`Repository: ${repoPath}`);
|
|
84830
85030
|
try {
|
|
@@ -85058,7 +85258,7 @@ var preferencesCommand = {
|
|
|
85058
85258
|
};
|
|
85059
85259
|
|
|
85060
85260
|
// src/cli/commands/telemetry.ts
|
|
85061
|
-
var
|
|
85261
|
+
var path68 = __toESM(require("path"));
|
|
85062
85262
|
init_control_config();
|
|
85063
85263
|
init_control_sync();
|
|
85064
85264
|
init_manifest();
|
|
@@ -85151,7 +85351,7 @@ async function handleOff() {
|
|
|
85151
85351
|
info("Mission Control will not auto-start. Existing usage rows are kept.");
|
|
85152
85352
|
}
|
|
85153
85353
|
async function handleWriteEnv(argv) {
|
|
85154
|
-
const repoPath =
|
|
85354
|
+
const repoPath = path68.resolve(argv.repo);
|
|
85155
85355
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
85156
85356
|
const session = readSlotRegistry(harnessRoot, argv.agentId);
|
|
85157
85357
|
const workDir = argv.workDir ?? session?.workDir ?? repoPath;
|
|
@@ -85163,7 +85363,7 @@ async function handleWriteEnv(argv) {
|
|
|
85163
85363
|
suffix,
|
|
85164
85364
|
createdAt: session?.createdAt
|
|
85165
85365
|
});
|
|
85166
|
-
const envFile = argv.envFile ??
|
|
85366
|
+
const envFile = argv.envFile ?? path68.join(workDir, `.env.agent.${argv.agentId}`);
|
|
85167
85367
|
const attrs = {
|
|
85168
85368
|
sessionKey,
|
|
85169
85369
|
agentId: argv.agentId,
|
|
@@ -85179,7 +85379,7 @@ async function handleWriteEnv(argv) {
|
|
|
85179
85379
|
success(`Wrote session attribution to ${envFile}`);
|
|
85180
85380
|
}
|
|
85181
85381
|
function handlePrintEnv(argv) {
|
|
85182
|
-
const repoPath =
|
|
85382
|
+
const repoPath = path68.resolve(argv.repo);
|
|
85183
85383
|
const workDir = argv.workDir ?? repoPath;
|
|
85184
85384
|
const sessionKey = buildSessionKey({
|
|
85185
85385
|
branch: argv.branch,
|