@osfactory/har 0.64.1 → 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 +660 -464
- 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(
|
|
@@ -32477,6 +32506,7 @@ function harvestClaudeUsage(slot) {
|
|
|
32477
32506
|
costUsd: usage2.costUsd,
|
|
32478
32507
|
...Object.keys(usage2.modelBreakdown).length > 0 ? { modelBreakdown: usage2.modelBreakdown } : {},
|
|
32479
32508
|
sources: ["harvest"],
|
|
32509
|
+
harvestVersion: USAGE_HARVEST_VERSION,
|
|
32480
32510
|
firstSeenAt: slot.sessionCreatedAt ?? now,
|
|
32481
32511
|
lastSeenAt: now
|
|
32482
32512
|
};
|
|
@@ -32500,6 +32530,7 @@ var init_claude = __esm({
|
|
|
32500
32530
|
fs23 = __toESM(require("fs"));
|
|
32501
32531
|
os11 = __toESM(require("os"));
|
|
32502
32532
|
path25 = __toESM(require("path"));
|
|
32533
|
+
init_schema2();
|
|
32503
32534
|
init_telemetry_config();
|
|
32504
32535
|
init_telemetry_env();
|
|
32505
32536
|
init_workspace_path_match();
|
|
@@ -32618,6 +32649,7 @@ function harvestCodexUsage(slot) {
|
|
|
32618
32649
|
tokensTotal,
|
|
32619
32650
|
costUsd: null,
|
|
32620
32651
|
sources: ["harvest"],
|
|
32652
|
+
harvestVersion: USAGE_HARVEST_VERSION,
|
|
32621
32653
|
firstSeenAt: slot.sessionCreatedAt ?? now,
|
|
32622
32654
|
lastSeenAt: now
|
|
32623
32655
|
};
|
|
@@ -32629,6 +32661,7 @@ var init_codex = __esm({
|
|
|
32629
32661
|
fs24 = __toESM(require("fs"));
|
|
32630
32662
|
os12 = __toESM(require("os"));
|
|
32631
32663
|
path26 = __toESM(require("path"));
|
|
32664
|
+
init_schema2();
|
|
32632
32665
|
init_telemetry_env();
|
|
32633
32666
|
init_workspace_path_match();
|
|
32634
32667
|
}
|
|
@@ -32758,25 +32791,85 @@ var init_portal_watermark = __esm({
|
|
|
32758
32791
|
}
|
|
32759
32792
|
});
|
|
32760
32793
|
|
|
32761
|
-
// src/core/control-
|
|
32762
|
-
|
|
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) {
|
|
32763
32800
|
try {
|
|
32764
32801
|
const response = await fetch(url, {
|
|
32765
32802
|
method: "GET",
|
|
32766
|
-
signal: AbortSignal.timeout(
|
|
32803
|
+
signal: AbortSignal.timeout(numberFromEnv("HAR_CONTROL_READ_TIMEOUT_MS", DEFAULT_TIMEOUT_MS))
|
|
32767
32804
|
});
|
|
32768
|
-
if (!response.ok)
|
|
32769
|
-
|
|
32770
|
-
|
|
32771
|
-
|
|
32772
|
-
|
|
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 };
|
|
32773
32849
|
}
|
|
32774
32850
|
async function resolveControlRepoId(apiUrl, repoPath) {
|
|
32775
|
-
const repos = await
|
|
32776
|
-
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" };
|
|
32777
32854
|
const target = path28.resolve(repoPath);
|
|
32778
|
-
return
|
|
32855
|
+
return {
|
|
32856
|
+
ok: true,
|
|
32857
|
+
data: repos.data.find((repo) => path28.resolve(repo.path) === target)?.id ?? null
|
|
32858
|
+
};
|
|
32779
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
|
|
32780
32873
|
function optionalString(value) {
|
|
32781
32874
|
return value == null ? void 0 : value;
|
|
32782
32875
|
}
|
|
@@ -32802,6 +32895,7 @@ function normalizeUsage(row) {
|
|
|
32802
32895
|
costUsd: row.costUsd == null ? null : Number(row.costUsd),
|
|
32803
32896
|
...row.modelBreakdown ? { modelBreakdown: row.modelBreakdown } : {},
|
|
32804
32897
|
sources: toSources(row.sources),
|
|
32898
|
+
harvestVersion: Number(row.harvestVersion ?? 0),
|
|
32805
32899
|
firstSeenAt: row.firstSeenAt,
|
|
32806
32900
|
lastSeenAt: row.lastSeenAt
|
|
32807
32901
|
};
|
|
@@ -32829,50 +32923,54 @@ function maxTimestamp(a, b2) {
|
|
|
32829
32923
|
return a > b2 ? a : b2;
|
|
32830
32924
|
}
|
|
32831
32925
|
async function fetchPersistedPortalTelemetry(repoPath, apiUrl, options) {
|
|
32832
|
-
const
|
|
32833
|
-
|
|
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;
|
|
32834
32932
|
const since = options?.since ?? null;
|
|
32835
|
-
const [
|
|
32836
|
-
|
|
32837
|
-
|
|
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
|
+
})
|
|
32838
32941
|
]);
|
|
32839
|
-
const
|
|
32840
|
-
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
|
+
);
|
|
32841
32957
|
return {
|
|
32842
32958
|
usage: usage2.selected.map(normalizeUsage),
|
|
32843
32959
|
events: events.selected.map(normalizeEvent),
|
|
32844
|
-
maxSyncedAt: maxTimestamp(usage2.maxSyncedAt, events.maxSyncedAt)
|
|
32960
|
+
maxSyncedAt: maxTimestamp(usage2.maxSyncedAt, events.maxSyncedAt),
|
|
32961
|
+
failures,
|
|
32962
|
+
truncated
|
|
32845
32963
|
};
|
|
32846
32964
|
}
|
|
32847
|
-
var path28, FETCH_TIMEOUT_MS;
|
|
32848
32965
|
var init_control_persisted_usage = __esm({
|
|
32849
32966
|
"src/core/control-persisted-usage.ts"() {
|
|
32850
32967
|
"use strict";
|
|
32851
|
-
path28 = __toESM(require("path"));
|
|
32852
32968
|
init_portal_watermark();
|
|
32853
|
-
|
|
32969
|
+
init_control_api_read();
|
|
32854
32970
|
}
|
|
32855
32971
|
});
|
|
32856
32972
|
|
|
32857
32973
|
// src/core/control-persisted-trajectory.ts
|
|
32858
|
-
async function getJson2(url) {
|
|
32859
|
-
try {
|
|
32860
|
-
const response = await fetch(url, {
|
|
32861
|
-
method: "GET",
|
|
32862
|
-
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
32863
|
-
});
|
|
32864
|
-
if (!response.ok) return null;
|
|
32865
|
-
return await response.json();
|
|
32866
|
-
} catch {
|
|
32867
|
-
return null;
|
|
32868
|
-
}
|
|
32869
|
-
}
|
|
32870
|
-
async function resolveControlRepoId2(apiUrl, repoPath) {
|
|
32871
|
-
const repos = await getJson2(`${apiUrl}/api/repos`);
|
|
32872
|
-
if (!Array.isArray(repos)) return null;
|
|
32873
|
-
const target = path29.resolve(repoPath);
|
|
32874
|
-
return repos.find((repo) => path29.resolve(repo.path) === target)?.id ?? null;
|
|
32875
|
-
}
|
|
32876
32974
|
function optional(value) {
|
|
32877
32975
|
return value == null ? void 0 : value;
|
|
32878
32976
|
}
|
|
@@ -32928,24 +33026,44 @@ async function fetchPersistedTrajectory(repoPath, apiUrl, request) {
|
|
|
32928
33026
|
records: [],
|
|
32929
33027
|
spans: [],
|
|
32930
33028
|
recordsMaxSyncedAt: null,
|
|
32931
|
-
spansMaxSyncedAt: null
|
|
33029
|
+
spansMaxSyncedAt: null,
|
|
33030
|
+
failures: [],
|
|
33031
|
+
truncated: []
|
|
32932
33032
|
};
|
|
32933
33033
|
if (!request.records && !request.spans) return empty;
|
|
32934
|
-
const
|
|
32935
|
-
if (!
|
|
32936
|
-
|
|
32937
|
-
|
|
32938
|
-
|
|
32939
|
-
|
|
32940
|
-
|
|
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
|
|
32941
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");
|
|
32942
33060
|
const trajectory = selectSince(
|
|
32943
|
-
|
|
33061
|
+
trajectoryRead?.ok ? trajectoryRead.rows : [],
|
|
32944
33062
|
request.records ? request.records.since : null,
|
|
32945
33063
|
(row) => row.createdAt ?? null
|
|
32946
33064
|
);
|
|
32947
33065
|
const spans = selectSince(
|
|
32948
|
-
|
|
33066
|
+
spansRead?.ok ? spansRead.rows : [],
|
|
32949
33067
|
request.spans ? request.spans.since : null,
|
|
32950
33068
|
(row) => row.createdAt ?? null
|
|
32951
33069
|
);
|
|
@@ -32956,17 +33074,17 @@ async function fetchPersistedTrajectory(repoPath, apiUrl, request) {
|
|
|
32956
33074
|
}),
|
|
32957
33075
|
spans: spans.selected.map(toPortalSpan),
|
|
32958
33076
|
recordsMaxSyncedAt: trajectory.maxSyncedAt,
|
|
32959
|
-
spansMaxSyncedAt: spans.maxSyncedAt
|
|
33077
|
+
spansMaxSyncedAt: spans.maxSyncedAt,
|
|
33078
|
+
failures,
|
|
33079
|
+
truncated
|
|
32960
33080
|
};
|
|
32961
33081
|
}
|
|
32962
|
-
var path29, FETCH_TIMEOUT_MS2;
|
|
32963
33082
|
var init_control_persisted_trajectory = __esm({
|
|
32964
33083
|
"src/core/control-persisted-trajectory.ts"() {
|
|
32965
33084
|
"use strict";
|
|
32966
|
-
path29 = __toESM(require("path"));
|
|
32967
33085
|
init_schema2();
|
|
32968
33086
|
init_portal_watermark();
|
|
32969
|
-
|
|
33087
|
+
init_control_api_read();
|
|
32970
33088
|
}
|
|
32971
33089
|
});
|
|
32972
33090
|
|
|
@@ -33007,10 +33125,34 @@ function mergeModelBreakdown(a, b2) {
|
|
|
33007
33125
|
}
|
|
33008
33126
|
return out;
|
|
33009
33127
|
}
|
|
33010
|
-
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) {
|
|
33011
33141
|
const costA = a.costUsd ?? null;
|
|
33012
33142
|
const costB = b2.costUsd ?? null;
|
|
33013
|
-
|
|
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);
|
|
33014
33156
|
return {
|
|
33015
33157
|
...a,
|
|
33016
33158
|
...b2,
|
|
@@ -33019,13 +33161,7 @@ function mergeUsageRow(a, b2) {
|
|
|
33019
33161
|
suffix: b2.suffix ?? a.suffix,
|
|
33020
33162
|
workUnitId: b2.workUnitId ?? a.workUnitId,
|
|
33021
33163
|
attemptId: b2.attemptId ?? a.attemptId,
|
|
33022
|
-
|
|
33023
|
-
tokensOutput: Math.max(num2(a.tokensOutput), num2(b2.tokensOutput)),
|
|
33024
|
-
tokensCacheRead: Math.max(num2(a.tokensCacheRead), num2(b2.tokensCacheRead)),
|
|
33025
|
-
tokensCacheCreation: Math.max(num2(a.tokensCacheCreation), num2(b2.tokensCacheCreation)),
|
|
33026
|
-
tokensTotal: Math.max(num2(a.tokensTotal), num2(b2.tokensTotal)),
|
|
33027
|
-
costUsd,
|
|
33028
|
-
modelBreakdown: mergeModelBreakdown(a.modelBreakdown, b2.modelBreakdown),
|
|
33164
|
+
...counters,
|
|
33029
33165
|
sources: [.../* @__PURE__ */ new Set([...a.sources ?? [], ...b2.sources ?? []])],
|
|
33030
33166
|
firstSeenAt: earlier(a.firstSeenAt, b2.firstSeenAt),
|
|
33031
33167
|
lastSeenAt: later(a.lastSeenAt, b2.lastSeenAt)
|
|
@@ -33052,6 +33188,7 @@ var KEY_SEP;
|
|
|
33052
33188
|
var init_portal_usage_merge = __esm({
|
|
33053
33189
|
"src/core/portal-usage-merge.ts"() {
|
|
33054
33190
|
"use strict";
|
|
33191
|
+
init_schema2();
|
|
33055
33192
|
KEY_SEP = "\0";
|
|
33056
33193
|
}
|
|
33057
33194
|
});
|
|
@@ -33161,13 +33298,13 @@ function describeFetchFailure(url, bodyBytes, err) {
|
|
|
33161
33298
|
}
|
|
33162
33299
|
async function postForResponse(url, headers, payload) {
|
|
33163
33300
|
let lastErr;
|
|
33164
|
-
for (let
|
|
33301
|
+
for (let attempt2 = 1; attempt2 <= MAX_FETCH_ATTEMPTS; attempt2++) {
|
|
33165
33302
|
try {
|
|
33166
33303
|
return await fetch(url, { method: "POST", headers, body: payload });
|
|
33167
33304
|
} catch (err) {
|
|
33168
33305
|
lastErr = err;
|
|
33169
|
-
if (
|
|
33170
|
-
await new Promise((
|
|
33306
|
+
if (attempt2 < MAX_FETCH_ATTEMPTS) {
|
|
33307
|
+
await new Promise((resolve52) => setTimeout(resolve52, attempt2 * 100));
|
|
33171
33308
|
}
|
|
33172
33309
|
}
|
|
33173
33310
|
}
|
|
@@ -33262,8 +33399,17 @@ function modelsFromBreakdown(breakdown) {
|
|
|
33262
33399
|
...totals && typeof totals === "object" ? totals : {}
|
|
33263
33400
|
}));
|
|
33264
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
|
+
}
|
|
33265
33409
|
async function collectPortalTelemetry(repoPath, slots, controlApiUrl, since, portal) {
|
|
33266
|
-
if (!isTelemetryEnabled())
|
|
33410
|
+
if (!isTelemetryEnabled()) {
|
|
33411
|
+
return { usage: [], events: [], maxSyncedAt: null, failures: [], truncated: [] };
|
|
33412
|
+
}
|
|
33267
33413
|
try {
|
|
33268
33414
|
const userEmail = resolvePortalUserEmail(portal);
|
|
33269
33415
|
const fallbackAgentId = slots.length > 0 ? Math.min(...slots.map((slot) => slot.agentId)) : null;
|
|
@@ -33322,9 +33468,23 @@ async function collectPortalTelemetry(repoPath, slots, controlApiUrl, since, por
|
|
|
33322
33468
|
const events = dedupePortalEvents(harvestedEvents, persisted.events).map(
|
|
33323
33469
|
(event) => dropNullFields({ ...event })
|
|
33324
33470
|
);
|
|
33325
|
-
return {
|
|
33326
|
-
|
|
33327
|
-
|
|
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
|
+
};
|
|
33328
33488
|
}
|
|
33329
33489
|
}
|
|
33330
33490
|
async function buildPortalPayload(repoPath, controlApiUrl, since, full = false, portal) {
|
|
@@ -33338,16 +33498,16 @@ async function buildPortalPayload(repoPath, controlApiUrl, since, full = false,
|
|
|
33338
33498
|
const attempts = listWorkAttempts(harnessRoot);
|
|
33339
33499
|
const validationBindings = listValidationBindings(harnessRoot);
|
|
33340
33500
|
const userEmail = resolvePortalUserEmail(portal);
|
|
33341
|
-
const { usage: usage2, events, maxSyncedAt } = await collectPortalTelemetry(
|
|
33501
|
+
const { usage: usage2, events, maxSyncedAt, failures, truncated } = await collectPortalTelemetry(
|
|
33342
33502
|
repoPath,
|
|
33343
33503
|
status.slots,
|
|
33344
33504
|
controlApiUrl,
|
|
33345
33505
|
since,
|
|
33346
33506
|
portal
|
|
33347
33507
|
);
|
|
33348
|
-
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)) {
|
|
33349
33509
|
warn(
|
|
33350
|
-
`${
|
|
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\`.`
|
|
33351
33511
|
);
|
|
33352
33512
|
}
|
|
33353
33513
|
const syncBody = {
|
|
@@ -33367,7 +33527,7 @@ async function buildPortalPayload(repoPath, controlApiUrl, since, full = false,
|
|
|
33367
33527
|
...usage2.length > 0 ? { usage: usage2 } : {}
|
|
33368
33528
|
};
|
|
33369
33529
|
const runsPayload = userEmail ? runs.map((run2) => ({ ...run2, userEmail })) : runs;
|
|
33370
|
-
return { syncBody, runs: runsPayload, events, maxSyncedAt };
|
|
33530
|
+
return { syncBody, runs: runsPayload, events, maxSyncedAt, failures, truncated };
|
|
33371
33531
|
}
|
|
33372
33532
|
async function isControlApiReachable(apiUrl = getControlApiUrl()) {
|
|
33373
33533
|
try {
|
|
@@ -33384,7 +33544,7 @@ async function waitForControlApi(apiUrl = getControlApiUrl(), timeoutMs = 6e4, i
|
|
|
33384
33544
|
const deadline = Date.now() + timeoutMs;
|
|
33385
33545
|
while (Date.now() < deadline) {
|
|
33386
33546
|
if (await isControlApiReachable(apiUrl)) return true;
|
|
33387
|
-
await new Promise((
|
|
33547
|
+
await new Promise((resolve52) => setTimeout(resolve52, intervalMs));
|
|
33388
33548
|
}
|
|
33389
33549
|
return false;
|
|
33390
33550
|
}
|
|
@@ -33401,13 +33561,14 @@ async function syncReposWithControl(options) {
|
|
|
33401
33561
|
const results = [];
|
|
33402
33562
|
let synced = 0;
|
|
33403
33563
|
let failed = 0;
|
|
33564
|
+
let incomplete = 0;
|
|
33404
33565
|
for (const repoPath of options.repoPaths) {
|
|
33405
33566
|
const destinationAliases = destinationAliasesForSync(repoPath, options.portalTargets);
|
|
33406
33567
|
if (destinationAliases.length > 1) {
|
|
33407
33568
|
const targetResults = [];
|
|
33408
33569
|
for (const alias of destinationAliases) {
|
|
33409
33570
|
try {
|
|
33410
|
-
await withTimeout(
|
|
33571
|
+
const outcome = await withTimeout(
|
|
33411
33572
|
syncRepoWithControl({
|
|
33412
33573
|
repoPath,
|
|
33413
33574
|
apiUrl,
|
|
@@ -33419,7 +33580,11 @@ async function syncReposWithControl(options) {
|
|
|
33419
33580
|
EXPLICIT_SYNC_TIMEOUT_MS,
|
|
33420
33581
|
"control sync"
|
|
33421
33582
|
);
|
|
33422
|
-
targetResults.push({
|
|
33583
|
+
targetResults.push({
|
|
33584
|
+
alias,
|
|
33585
|
+
ok: true,
|
|
33586
|
+
...outcome.warnings.length > 0 ? { warnings: outcome.warnings } : {}
|
|
33587
|
+
});
|
|
33423
33588
|
} catch (err) {
|
|
33424
33589
|
targetResults.push({
|
|
33425
33590
|
alias,
|
|
@@ -33431,11 +33596,12 @@ async function syncReposWithControl(options) {
|
|
|
33431
33596
|
const ok = targetResults.every((entry) => entry.ok);
|
|
33432
33597
|
if (ok) synced++;
|
|
33433
33598
|
else failed++;
|
|
33599
|
+
if (ok && targetResults.some((entry) => entry.warnings)) incomplete++;
|
|
33434
33600
|
results.push({ repoPath, ok, targets: targetResults, error: ok ? void 0 : "one or more targets failed" });
|
|
33435
33601
|
continue;
|
|
33436
33602
|
}
|
|
33437
33603
|
try {
|
|
33438
|
-
await withTimeout(
|
|
33604
|
+
const outcome = await withTimeout(
|
|
33439
33605
|
syncRepoWithControl({
|
|
33440
33606
|
repoPath,
|
|
33441
33607
|
apiUrl,
|
|
@@ -33448,13 +33614,18 @@ async function syncReposWithControl(options) {
|
|
|
33448
33614
|
"control sync"
|
|
33449
33615
|
);
|
|
33450
33616
|
synced++;
|
|
33451
|
-
|
|
33617
|
+
if (outcome.warnings.length > 0) incomplete++;
|
|
33618
|
+
results.push({
|
|
33619
|
+
repoPath,
|
|
33620
|
+
ok: true,
|
|
33621
|
+
...outcome.warnings.length > 0 ? { warnings: outcome.warnings } : {}
|
|
33622
|
+
});
|
|
33452
33623
|
} catch (err) {
|
|
33453
33624
|
failed++;
|
|
33454
33625
|
results.push({ repoPath, ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
33455
33626
|
}
|
|
33456
33627
|
}
|
|
33457
|
-
return { synced, failed, results };
|
|
33628
|
+
return { synced, failed, incomplete, results };
|
|
33458
33629
|
}
|
|
33459
33630
|
function destinationAliasesForSync(repoPath, explicit) {
|
|
33460
33631
|
if (explicit && explicit.length > 0) return explicit;
|
|
@@ -33519,7 +33690,7 @@ async function syncRepoWithLocalControl(options) {
|
|
|
33519
33690
|
const listResponse = await fetch(`${apiUrl}/api/repos`);
|
|
33520
33691
|
if (!listResponse.ok) throw new Error("Failed to list repos from Control API");
|
|
33521
33692
|
const repos = await listResponse.json();
|
|
33522
|
-
const existing = repos.find((r) =>
|
|
33693
|
+
const existing = repos.find((r) => path29.resolve(r.path) === repoPath);
|
|
33523
33694
|
if (!existing) {
|
|
33524
33695
|
return;
|
|
33525
33696
|
}
|
|
@@ -33531,7 +33702,7 @@ async function syncRepoWithLocalControl(options) {
|
|
|
33531
33702
|
}
|
|
33532
33703
|
}
|
|
33533
33704
|
async function syncRepoWithPortal(options, controlApiUrl, portal) {
|
|
33534
|
-
if (!isRepoPortalSyncEnabled(options.repoPath)) return;
|
|
33705
|
+
if (!isRepoPortalSyncEnabled(options.repoPath)) return [];
|
|
33535
33706
|
const { repoPath, dryRun, full } = options;
|
|
33536
33707
|
const watermarkKey = watermarkKeyForTarget(portal);
|
|
33537
33708
|
const since = full ? null : readPortalWatermarkForTarget(repoPath, portal);
|
|
@@ -33544,7 +33715,7 @@ async function syncRepoWithPortal(options, controlApiUrl, portal) {
|
|
|
33544
33715
|
}
|
|
33545
33716
|
}
|
|
33546
33717
|
const runsSince = rewindSince(stored?.lastSyncedAt ?? null);
|
|
33547
|
-
const { syncBody, runs, events, maxSyncedAt } = await buildPortalPayload(
|
|
33718
|
+
const { syncBody, runs, events, maxSyncedAt, failures, truncated } = await buildPortalPayload(
|
|
33548
33719
|
repoPath,
|
|
33549
33720
|
controlApiUrl,
|
|
33550
33721
|
since,
|
|
@@ -33567,18 +33738,25 @@ async function syncRepoWithPortal(options, controlApiUrl, portal) {
|
|
|
33567
33738
|
for (const batch of chunkBySerializedSize(events, maxSyncBatchBytes())) {
|
|
33568
33739
|
await postPortal(portal, "/api/otel", { path: repoPath, events: batch }, dryRun);
|
|
33569
33740
|
}
|
|
33570
|
-
if (!dryRun && maxSyncedAt) {
|
|
33741
|
+
if (!dryRun && maxSyncedAt && failures.length === 0) {
|
|
33571
33742
|
writePortalWatermark(repoPath, watermarkKey, maxSyncedAt);
|
|
33572
33743
|
}
|
|
33573
|
-
|
|
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;
|
|
33574
33752
|
}
|
|
33575
33753
|
async function syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun, full) {
|
|
33576
33754
|
const wantRecords = isPortalTrajectoryEnabledForTarget(portal);
|
|
33577
33755
|
const wantSpans = isTelemetryEnabled();
|
|
33578
|
-
if (!wantRecords && !wantSpans) return;
|
|
33756
|
+
if (!wantRecords && !wantSpans) return [];
|
|
33579
33757
|
const recordsTarget = trajectoryWatermarkTarget(portal);
|
|
33580
33758
|
const spansTarget = spansWatermarkTarget(portal);
|
|
33581
|
-
const { records, spans, recordsMaxSyncedAt, spansMaxSyncedAt } = await fetchPersistedTrajectory(repoPath, controlApiUrl, {
|
|
33759
|
+
const { records, spans, recordsMaxSyncedAt, spansMaxSyncedAt, failures, truncated } = await fetchPersistedTrajectory(repoPath, controlApiUrl, {
|
|
33582
33760
|
records: wantRecords ? {
|
|
33583
33761
|
since: full ? null : readScopedPortalWatermark(
|
|
33584
33762
|
repoPath,
|
|
@@ -33594,10 +33772,11 @@ async function syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun,
|
|
|
33594
33772
|
)
|
|
33595
33773
|
} : false
|
|
33596
33774
|
});
|
|
33775
|
+
const failedChannel = (channel) => failures.some((failure) => failure.channel === channel || failure.channel === "repos");
|
|
33597
33776
|
for (const batch of chunkBySerializedSize(spans, maxSyncBatchBytes())) {
|
|
33598
33777
|
await postPortal(portal, "/api/otel", { path: repoPath, spans: batch }, dryRun);
|
|
33599
33778
|
}
|
|
33600
|
-
if (!dryRun && spansMaxSyncedAt) {
|
|
33779
|
+
if (!dryRun && spansMaxSyncedAt && !failedChannel("spans")) {
|
|
33601
33780
|
writePortalWatermark(repoPath, spansTarget, spansMaxSyncedAt);
|
|
33602
33781
|
}
|
|
33603
33782
|
let recordsLanded = true;
|
|
@@ -33611,14 +33790,18 @@ async function syncTrajectoryWithPortal(portal, repoPath, controlApiUrl, dryRun,
|
|
|
33611
33790
|
if (!supported) {
|
|
33612
33791
|
recordsLanded = false;
|
|
33613
33792
|
warn(
|
|
33614
|
-
`${
|
|
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).`
|
|
33615
33794
|
);
|
|
33616
33795
|
break;
|
|
33617
33796
|
}
|
|
33618
33797
|
}
|
|
33619
|
-
if (!dryRun && recordsLanded && recordsMaxSyncedAt) {
|
|
33798
|
+
if (!dryRun && recordsLanded && recordsMaxSyncedAt && !failedChannel("trajectory")) {
|
|
33620
33799
|
writePortalWatermark(repoPath, recordsTarget, recordsMaxSyncedAt);
|
|
33621
33800
|
}
|
|
33801
|
+
return [
|
|
33802
|
+
...failures.length > 0 ? [describeReadFailures(repoPath, failures)] : [],
|
|
33803
|
+
...truncated.length > 0 ? [describeTruncatedReads(repoPath, truncated)] : []
|
|
33804
|
+
];
|
|
33622
33805
|
}
|
|
33623
33806
|
async function syncRepoWithControl(options) {
|
|
33624
33807
|
const repoPath = canonicalizeControlRepoPath(options.repoPath);
|
|
@@ -33650,19 +33833,20 @@ async function syncRepoWithControl(options) {
|
|
|
33650
33833
|
if (!response.ok) {
|
|
33651
33834
|
throw new Error(`Cloud sync failed: ${response.status}`);
|
|
33652
33835
|
}
|
|
33653
|
-
return;
|
|
33836
|
+
return { warnings: [] };
|
|
33654
33837
|
}
|
|
33655
33838
|
await syncRepoWithLocalControl({ ...options, repoPath, apiUrl });
|
|
33656
|
-
if (!isRepoPortalSyncEnabled(repoPath)) return;
|
|
33839
|
+
if (!isRepoPortalSyncEnabled(repoPath)) return { warnings: [] };
|
|
33657
33840
|
const resolved = resolvePortalTargetsForRepo({
|
|
33658
33841
|
repoPath,
|
|
33659
33842
|
explicitTargets: options.portalTargets
|
|
33660
33843
|
});
|
|
33661
|
-
if (!resolved) return;
|
|
33844
|
+
if (!resolved) return { warnings: [] };
|
|
33845
|
+
const warnings = [];
|
|
33662
33846
|
const failures = [];
|
|
33663
33847
|
for (const portal of resolved.targets) {
|
|
33664
33848
|
try {
|
|
33665
|
-
await syncRepoWithPortal({ ...options, repoPath }, apiUrl, portal);
|
|
33849
|
+
warnings.push(...await syncRepoWithPortal({ ...options, repoPath }, apiUrl, portal));
|
|
33666
33850
|
} catch (err) {
|
|
33667
33851
|
failures.push({
|
|
33668
33852
|
alias: portal.alias ?? portal.identityKey,
|
|
@@ -33670,7 +33854,7 @@ async function syncRepoWithControl(options) {
|
|
|
33670
33854
|
});
|
|
33671
33855
|
}
|
|
33672
33856
|
}
|
|
33673
|
-
if (failures.length === 0) return;
|
|
33857
|
+
if (failures.length === 0) return { warnings };
|
|
33674
33858
|
if (failures.length === resolved.targets.length && failures.length === 1) {
|
|
33675
33859
|
throw new Error(failures[0].error);
|
|
33676
33860
|
}
|
|
@@ -33810,7 +33994,7 @@ async function syncRunWithLocalControl(repoPath, run2, apiUrl) {
|
|
|
33810
33994
|
const listResponse = await fetch(`${apiUrl}/api/repos`);
|
|
33811
33995
|
if (!listResponse.ok) return;
|
|
33812
33996
|
const repos = await listResponse.json();
|
|
33813
|
-
repoId = repos.find((r) =>
|
|
33997
|
+
repoId = repos.find((r) => path29.resolve(r.path) === repoPath)?.id;
|
|
33814
33998
|
}
|
|
33815
33999
|
if (!repoId) return;
|
|
33816
34000
|
const runsBody = SyncRunsInputSchema.parse({ runs: [run2] });
|
|
@@ -33843,11 +34027,11 @@ async function syncRunWithControlAsync(repoPath, run2) {
|
|
|
33843
34027
|
}
|
|
33844
34028
|
}
|
|
33845
34029
|
}
|
|
33846
|
-
var
|
|
34030
|
+
var path29, DEFAULT_MAX_BATCH_BYTES, DEFAULT_SYNC_OVERLAP_MS, MAX_FETCH_ATTEMPTS, SYNC_TIMEOUT_MS, EXPLICIT_SYNC_TIMEOUT_MS;
|
|
33847
34031
|
var init_control_sync = __esm({
|
|
33848
34032
|
"src/core/control-sync.ts"() {
|
|
33849
34033
|
"use strict";
|
|
33850
|
-
|
|
34034
|
+
path29 = __toESM(require("path"));
|
|
33851
34035
|
init_manifest();
|
|
33852
34036
|
init_stages();
|
|
33853
34037
|
init_schema2();
|
|
@@ -33882,7 +34066,7 @@ var init_control_sync = __esm({
|
|
|
33882
34066
|
// src/core/sync-context.ts
|
|
33883
34067
|
function markDirty(repoPath) {
|
|
33884
34068
|
if (!repoPath) return;
|
|
33885
|
-
dirtyRepos.add(
|
|
34069
|
+
dirtyRepos.add(path30.resolve(repoPath));
|
|
33886
34070
|
}
|
|
33887
34071
|
function markAllRegisteredDirty() {
|
|
33888
34072
|
syncAllRegistered = true;
|
|
@@ -33907,11 +34091,11 @@ async function syncDirtyRepos() {
|
|
|
33907
34091
|
} catch {
|
|
33908
34092
|
}
|
|
33909
34093
|
}
|
|
33910
|
-
var
|
|
34094
|
+
var path30, dirtyRepos, syncAllRegistered;
|
|
33911
34095
|
var init_sync_context = __esm({
|
|
33912
34096
|
"src/core/sync-context.ts"() {
|
|
33913
34097
|
"use strict";
|
|
33914
|
-
|
|
34098
|
+
path30 = __toESM(require("path"));
|
|
33915
34099
|
dirtyRepos = /* @__PURE__ */ new Set();
|
|
33916
34100
|
syncAllRegistered = false;
|
|
33917
34101
|
}
|
|
@@ -35009,15 +35193,15 @@ var require_route = __commonJS({
|
|
|
35009
35193
|
};
|
|
35010
35194
|
}
|
|
35011
35195
|
function wrapConversion(toModel, graph) {
|
|
35012
|
-
const
|
|
35196
|
+
const path69 = [graph[toModel].parent, toModel];
|
|
35013
35197
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
35014
35198
|
let cur = graph[toModel].parent;
|
|
35015
35199
|
while (graph[cur].parent) {
|
|
35016
|
-
|
|
35200
|
+
path69.unshift(graph[cur].parent);
|
|
35017
35201
|
fn = link(conversions[graph[cur].parent][cur], fn);
|
|
35018
35202
|
cur = graph[cur].parent;
|
|
35019
35203
|
}
|
|
35020
|
-
fn.conversion =
|
|
35204
|
+
fn.conversion = path69;
|
|
35021
35205
|
return fn;
|
|
35022
35206
|
}
|
|
35023
35207
|
module2.exports = function(fromModel) {
|
|
@@ -41511,7 +41695,7 @@ var require_lib2 = __commonJS({
|
|
|
41511
41695
|
return matches;
|
|
41512
41696
|
};
|
|
41513
41697
|
exports2.analyse = analyse;
|
|
41514
|
-
var detectFile = (filepath, opts = {}) => new Promise((
|
|
41698
|
+
var detectFile = (filepath, opts = {}) => new Promise((resolve52, reject) => {
|
|
41515
41699
|
let fd;
|
|
41516
41700
|
const fs54 = (0, node_1.default)();
|
|
41517
41701
|
const handler = (err, buffer) => {
|
|
@@ -41521,7 +41705,7 @@ var require_lib2 = __commonJS({
|
|
|
41521
41705
|
if (err) {
|
|
41522
41706
|
reject(err);
|
|
41523
41707
|
} else if (buffer) {
|
|
41524
|
-
|
|
41708
|
+
resolve52((0, exports2.detect)(buffer));
|
|
41525
41709
|
} else {
|
|
41526
41710
|
reject(new Error("No error and no buffer received"));
|
|
41527
41711
|
}
|
|
@@ -46070,7 +46254,7 @@ var require_Observable = __commonJS({
|
|
|
46070
46254
|
Observable2.prototype.forEach = function(next, promiseCtor) {
|
|
46071
46255
|
var _this = this;
|
|
46072
46256
|
promiseCtor = getPromiseCtor(promiseCtor);
|
|
46073
|
-
return new promiseCtor(function(
|
|
46257
|
+
return new promiseCtor(function(resolve52, reject) {
|
|
46074
46258
|
var subscriber = new Subscriber_1.SafeSubscriber({
|
|
46075
46259
|
next: function(value) {
|
|
46076
46260
|
try {
|
|
@@ -46081,7 +46265,7 @@ var require_Observable = __commonJS({
|
|
|
46081
46265
|
}
|
|
46082
46266
|
},
|
|
46083
46267
|
error: reject,
|
|
46084
|
-
complete:
|
|
46268
|
+
complete: resolve52
|
|
46085
46269
|
});
|
|
46086
46270
|
_this.subscribe(subscriber);
|
|
46087
46271
|
});
|
|
@@ -46103,14 +46287,14 @@ var require_Observable = __commonJS({
|
|
|
46103
46287
|
Observable2.prototype.toPromise = function(promiseCtor) {
|
|
46104
46288
|
var _this = this;
|
|
46105
46289
|
promiseCtor = getPromiseCtor(promiseCtor);
|
|
46106
|
-
return new promiseCtor(function(
|
|
46290
|
+
return new promiseCtor(function(resolve52, reject) {
|
|
46107
46291
|
var value;
|
|
46108
46292
|
_this.subscribe(function(x) {
|
|
46109
46293
|
return value = x;
|
|
46110
46294
|
}, function(err) {
|
|
46111
46295
|
return reject(err);
|
|
46112
46296
|
}, function() {
|
|
46113
|
-
return
|
|
46297
|
+
return resolve52(value);
|
|
46114
46298
|
});
|
|
46115
46299
|
});
|
|
46116
46300
|
};
|
|
@@ -48206,11 +48390,11 @@ var require_innerFrom = __commonJS({
|
|
|
48206
48390
|
"use strict";
|
|
48207
48391
|
var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P2, generator) {
|
|
48208
48392
|
function adopt(value) {
|
|
48209
|
-
return value instanceof P2 ? value : new P2(function(
|
|
48210
|
-
|
|
48393
|
+
return value instanceof P2 ? value : new P2(function(resolve52) {
|
|
48394
|
+
resolve52(value);
|
|
48211
48395
|
});
|
|
48212
48396
|
}
|
|
48213
|
-
return new (P2 || (P2 = Promise))(function(
|
|
48397
|
+
return new (P2 || (P2 = Promise))(function(resolve52, reject) {
|
|
48214
48398
|
function fulfilled(value) {
|
|
48215
48399
|
try {
|
|
48216
48400
|
step(generator.next(value));
|
|
@@ -48226,7 +48410,7 @@ var require_innerFrom = __commonJS({
|
|
|
48226
48410
|
}
|
|
48227
48411
|
}
|
|
48228
48412
|
function step(result) {
|
|
48229
|
-
result.done ?
|
|
48413
|
+
result.done ? resolve52(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
48230
48414
|
}
|
|
48231
48415
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
48232
48416
|
});
|
|
@@ -48308,14 +48492,14 @@ var require_innerFrom = __commonJS({
|
|
|
48308
48492
|
}, i);
|
|
48309
48493
|
function verb(n) {
|
|
48310
48494
|
i[n] = o[n] && function(v2) {
|
|
48311
|
-
return new Promise(function(
|
|
48312
|
-
v2 = o[n](v2), settle(
|
|
48495
|
+
return new Promise(function(resolve52, reject) {
|
|
48496
|
+
v2 = o[n](v2), settle(resolve52, reject, v2.done, v2.value);
|
|
48313
48497
|
});
|
|
48314
48498
|
};
|
|
48315
48499
|
}
|
|
48316
|
-
function settle(
|
|
48500
|
+
function settle(resolve52, reject, d, v2) {
|
|
48317
48501
|
Promise.resolve(v2).then(function(v3) {
|
|
48318
|
-
|
|
48502
|
+
resolve52({ value: v3, done: d });
|
|
48319
48503
|
}, reject);
|
|
48320
48504
|
}
|
|
48321
48505
|
};
|
|
@@ -48934,7 +49118,7 @@ var require_lastValueFrom = __commonJS({
|
|
|
48934
49118
|
var EmptyError_1 = require_EmptyError();
|
|
48935
49119
|
function lastValueFrom2(source, config2) {
|
|
48936
49120
|
var hasConfig = typeof config2 === "object";
|
|
48937
|
-
return new Promise(function(
|
|
49121
|
+
return new Promise(function(resolve52, reject) {
|
|
48938
49122
|
var _hasValue = false;
|
|
48939
49123
|
var _value;
|
|
48940
49124
|
source.subscribe({
|
|
@@ -48945,9 +49129,9 @@ var require_lastValueFrom = __commonJS({
|
|
|
48945
49129
|
error: reject,
|
|
48946
49130
|
complete: function() {
|
|
48947
49131
|
if (_hasValue) {
|
|
48948
|
-
|
|
49132
|
+
resolve52(_value);
|
|
48949
49133
|
} else if (hasConfig) {
|
|
48950
|
-
|
|
49134
|
+
resolve52(config2.defaultValue);
|
|
48951
49135
|
} else {
|
|
48952
49136
|
reject(new EmptyError_1.EmptyError());
|
|
48953
49137
|
}
|
|
@@ -48969,16 +49153,16 @@ var require_firstValueFrom = __commonJS({
|
|
|
48969
49153
|
var Subscriber_1 = require_Subscriber();
|
|
48970
49154
|
function firstValueFrom(source, config2) {
|
|
48971
49155
|
var hasConfig = typeof config2 === "object";
|
|
48972
|
-
return new Promise(function(
|
|
49156
|
+
return new Promise(function(resolve52, reject) {
|
|
48973
49157
|
var subscriber = new Subscriber_1.SafeSubscriber({
|
|
48974
49158
|
next: function(value) {
|
|
48975
|
-
|
|
49159
|
+
resolve52(value);
|
|
48976
49160
|
subscriber.unsubscribe();
|
|
48977
49161
|
},
|
|
48978
49162
|
error: reject,
|
|
48979
49163
|
complete: function() {
|
|
48980
49164
|
if (hasConfig) {
|
|
48981
|
-
|
|
49165
|
+
resolve52(config2.defaultValue);
|
|
48982
49166
|
} else {
|
|
48983
49167
|
reject(new EmptyError_1.EmptyError());
|
|
48984
49168
|
}
|
|
@@ -54770,14 +54954,14 @@ var require_run_async = __commonJS({
|
|
|
54770
54954
|
return function() {
|
|
54771
54955
|
var args = arguments;
|
|
54772
54956
|
var originalThis = this;
|
|
54773
|
-
var promise = new Promise(function(
|
|
54957
|
+
var promise = new Promise(function(resolve52, reject) {
|
|
54774
54958
|
var resolved = false;
|
|
54775
54959
|
const wrappedResolve = function(value) {
|
|
54776
54960
|
if (resolved) {
|
|
54777
54961
|
console.warn("Run-async promise already resolved.");
|
|
54778
54962
|
}
|
|
54779
54963
|
resolved = true;
|
|
54780
|
-
|
|
54964
|
+
resolve52(value);
|
|
54781
54965
|
};
|
|
54782
54966
|
var rejected = false;
|
|
54783
54967
|
const wrappedReject = function(value) {
|
|
@@ -54885,25 +55069,25 @@ __export(otel_hooks_exports, {
|
|
|
54885
55069
|
});
|
|
54886
55070
|
function getOtelHooksHome() {
|
|
54887
55071
|
if (process.env.HAR_OTEL_HOOKS_HOME) {
|
|
54888
|
-
return
|
|
55072
|
+
return path53.resolve(process.env.HAR_OTEL_HOOKS_HOME);
|
|
54889
55073
|
}
|
|
54890
|
-
return
|
|
55074
|
+
return path53.join(os19.homedir(), ".har", "otel-hooks");
|
|
54891
55075
|
}
|
|
54892
55076
|
function getOtelHooksConfigPath(hooksHome = getOtelHooksHome()) {
|
|
54893
|
-
return
|
|
55077
|
+
return path53.join(hooksHome, "otel_config.json");
|
|
54894
55078
|
}
|
|
54895
55079
|
function getOtelHooksWrapperPath(hooksHome = getOtelHooksHome()) {
|
|
54896
|
-
return
|
|
55080
|
+
return path53.join(hooksHome, "run-otel-hook.sh");
|
|
54897
55081
|
}
|
|
54898
55082
|
function getOtelHooksStateDir(hooksHome = getOtelHooksHome()) {
|
|
54899
|
-
return
|
|
55083
|
+
return path53.join(hooksHome, "state");
|
|
54900
55084
|
}
|
|
54901
55085
|
function localOtelHookBin(hooksHome) {
|
|
54902
|
-
return
|
|
55086
|
+
return path53.join(hooksHome, "node_modules", ".bin", "otel-hook");
|
|
54903
55087
|
}
|
|
54904
55088
|
function installedPackageVersion(hooksHome) {
|
|
54905
55089
|
try {
|
|
54906
|
-
const pkgPath =
|
|
55090
|
+
const pkgPath = path53.join(
|
|
54907
55091
|
hooksHome,
|
|
54908
55092
|
"node_modules",
|
|
54909
55093
|
"@osfactory",
|
|
@@ -55050,9 +55234,9 @@ function uninstallLegacyPythonHooks(hooksHome) {
|
|
|
55050
55234
|
}
|
|
55051
55235
|
function removeLegacyPythonArtifacts(hooksHome) {
|
|
55052
55236
|
const legacyPaths = [
|
|
55053
|
-
|
|
55054
|
-
|
|
55055
|
-
|
|
55237
|
+
path53.join(hooksHome, ".venv"),
|
|
55238
|
+
path53.join(hooksHome, "otel_config.yaml"),
|
|
55239
|
+
path53.join(hooksHome, "venv")
|
|
55056
55240
|
];
|
|
55057
55241
|
for (const target of legacyPaths) {
|
|
55058
55242
|
try {
|
|
@@ -55198,14 +55382,14 @@ function pruneLegacyCursorHookEvents(filePath, wrapperPath) {
|
|
|
55198
55382
|
function rewriteKnownHookRegistrations(wrapperPath) {
|
|
55199
55383
|
const home = os19.homedir();
|
|
55200
55384
|
const candidates = [
|
|
55201
|
-
|
|
55202
|
-
|
|
55203
|
-
|
|
55385
|
+
path53.join(home, ".cursor", "hooks.json"),
|
|
55386
|
+
path53.join(home, ".claude", "settings.json"),
|
|
55387
|
+
path53.join(home, ".codex", "hooks.json")
|
|
55204
55388
|
];
|
|
55205
55389
|
for (const filePath of candidates) {
|
|
55206
55390
|
try {
|
|
55207
55391
|
rewriteHookCommandsToWrapper(filePath, wrapperPath);
|
|
55208
|
-
if (filePath.endsWith(`${
|
|
55392
|
+
if (filePath.endsWith(`${path53.sep}.cursor${path53.sep}hooks.json`)) {
|
|
55209
55393
|
pruneLegacyCursorHookEvents(filePath, wrapperPath);
|
|
55210
55394
|
}
|
|
55211
55395
|
} catch {
|
|
@@ -55315,14 +55499,14 @@ function ensureOtelHooks(options) {
|
|
|
55315
55499
|
function disableOtelHooksExport() {
|
|
55316
55500
|
return writeOtelHooksConfig(buildOtelHooksConfig({ enabled: false }));
|
|
55317
55501
|
}
|
|
55318
|
-
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;
|
|
55319
55503
|
var init_otel_hooks = __esm({
|
|
55320
55504
|
"src/core/otel-hooks.ts"() {
|
|
55321
55505
|
"use strict";
|
|
55322
55506
|
import_child_process14 = require("child_process");
|
|
55323
55507
|
fs46 = __toESM(require("fs"));
|
|
55324
55508
|
os19 = __toESM(require("os"));
|
|
55325
|
-
|
|
55509
|
+
path53 = __toESM(require("path"));
|
|
55326
55510
|
init_control_config();
|
|
55327
55511
|
init_telemetry_config();
|
|
55328
55512
|
OTEL_HOOKS_PACKAGE = "@osfactory/otel-hook@0.2.0";
|
|
@@ -58297,7 +58481,7 @@ var require_compile = __commonJS({
|
|
|
58297
58481
|
const schOrFunc = root.refs[ref];
|
|
58298
58482
|
if (schOrFunc)
|
|
58299
58483
|
return schOrFunc;
|
|
58300
|
-
let _sch =
|
|
58484
|
+
let _sch = resolve52.call(this, root, ref);
|
|
58301
58485
|
if (_sch === void 0) {
|
|
58302
58486
|
const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
|
|
58303
58487
|
const { schemaId } = this.opts;
|
|
@@ -58324,7 +58508,7 @@ var require_compile = __commonJS({
|
|
|
58324
58508
|
function sameSchemaEnv(s1, s2) {
|
|
58325
58509
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
58326
58510
|
}
|
|
58327
|
-
function
|
|
58511
|
+
function resolve52(root, ref) {
|
|
58328
58512
|
let sch;
|
|
58329
58513
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
58330
58514
|
ref = sch;
|
|
@@ -58542,8 +58726,8 @@ var require_utils2 = __commonJS({
|
|
|
58542
58726
|
}
|
|
58543
58727
|
return ind;
|
|
58544
58728
|
}
|
|
58545
|
-
function removeDotSegments(
|
|
58546
|
-
let input =
|
|
58729
|
+
function removeDotSegments(path69) {
|
|
58730
|
+
let input = path69;
|
|
58547
58731
|
const output = [];
|
|
58548
58732
|
let nextSlash = -1;
|
|
58549
58733
|
let len = 0;
|
|
@@ -58795,8 +58979,8 @@ var require_schemes = __commonJS({
|
|
|
58795
58979
|
wsComponent.secure = void 0;
|
|
58796
58980
|
}
|
|
58797
58981
|
if (wsComponent.resourceName) {
|
|
58798
|
-
const [
|
|
58799
|
-
wsComponent.path =
|
|
58982
|
+
const [path69, query] = wsComponent.resourceName.split("?");
|
|
58983
|
+
wsComponent.path = path69 && path69 !== "/" ? path69 : void 0;
|
|
58800
58984
|
wsComponent.query = query;
|
|
58801
58985
|
wsComponent.resourceName = void 0;
|
|
58802
58986
|
}
|
|
@@ -58955,7 +59139,7 @@ var require_fast_uri = __commonJS({
|
|
|
58955
59139
|
}
|
|
58956
59140
|
return uri;
|
|
58957
59141
|
}
|
|
58958
|
-
function
|
|
59142
|
+
function resolve52(baseURI, relativeURI, options) {
|
|
58959
59143
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
58960
59144
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
58961
59145
|
schemelessOptions.skipEscape = true;
|
|
@@ -59213,7 +59397,7 @@ var require_fast_uri = __commonJS({
|
|
|
59213
59397
|
var fastUri = {
|
|
59214
59398
|
SCHEMES,
|
|
59215
59399
|
normalize: normalize3,
|
|
59216
|
-
resolve:
|
|
59400
|
+
resolve: resolve52,
|
|
59217
59401
|
resolveComponent,
|
|
59218
59402
|
equal,
|
|
59219
59403
|
serialize,
|
|
@@ -63478,11 +63662,11 @@ var parser = new YargsParser({
|
|
|
63478
63662
|
resolve: import_path2.resolve,
|
|
63479
63663
|
// TODO: figure out a way to combine ESM and CJS coverage, such that
|
|
63480
63664
|
// we can exercise all the lines below:
|
|
63481
|
-
require: (
|
|
63665
|
+
require: (path69) => {
|
|
63482
63666
|
if (typeof require !== "undefined") {
|
|
63483
|
-
return require(
|
|
63484
|
-
} else if (
|
|
63485
|
-
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"));
|
|
63486
63670
|
} else {
|
|
63487
63671
|
throw Error("only .json config files are supported in ESM");
|
|
63488
63672
|
}
|
|
@@ -66008,12 +66192,12 @@ var YargsInstance = class {
|
|
|
66008
66192
|
async getCompletion(args, done) {
|
|
66009
66193
|
argsert("<array> [function]", [args, done], arguments.length);
|
|
66010
66194
|
if (!done) {
|
|
66011
|
-
return new Promise((
|
|
66195
|
+
return new Promise((resolve52, reject) => {
|
|
66012
66196
|
__classPrivateFieldGet(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
|
|
66013
66197
|
if (err)
|
|
66014
66198
|
reject(err);
|
|
66015
66199
|
else
|
|
66016
|
-
|
|
66200
|
+
resolve52(completions);
|
|
66017
66201
|
});
|
|
66018
66202
|
});
|
|
66019
66203
|
} else {
|
|
@@ -67058,33 +67242,33 @@ init_telemetry_config();
|
|
|
67058
67242
|
init_sync_context();
|
|
67059
67243
|
|
|
67060
67244
|
// src/cli/commands/agents.ts
|
|
67061
|
-
var
|
|
67245
|
+
var path33 = __toESM(require("path"));
|
|
67062
67246
|
|
|
67063
67247
|
// src/harness/agent-skills.ts
|
|
67064
67248
|
var fs27 = __toESM(require("fs"));
|
|
67065
67249
|
var os14 = __toESM(require("os"));
|
|
67066
|
-
var
|
|
67250
|
+
var path32 = __toESM(require("path"));
|
|
67067
67251
|
var readline = __toESM(require("readline"));
|
|
67068
67252
|
init_file_ops();
|
|
67069
67253
|
init_logging();
|
|
67070
67254
|
|
|
67071
67255
|
// src/utils/paths.ts
|
|
67072
67256
|
var fs26 = __toESM(require("fs"));
|
|
67073
|
-
var
|
|
67257
|
+
var path31 = __toESM(require("path"));
|
|
67074
67258
|
function resolveTemplatesDir() {
|
|
67075
67259
|
const candidates = [
|
|
67076
|
-
|
|
67077
|
-
|
|
67078
|
-
|
|
67260
|
+
path31.join(__dirname, "templates"),
|
|
67261
|
+
path31.join(__dirname, "..", "templates"),
|
|
67262
|
+
path31.join(__dirname, "..", "harness", "templates")
|
|
67079
67263
|
];
|
|
67080
67264
|
for (const dir of candidates) {
|
|
67081
|
-
if (fs26.existsSync(
|
|
67265
|
+
if (fs26.existsSync(path31.join(dir, "har-boilerplate"))) return dir;
|
|
67082
67266
|
}
|
|
67083
67267
|
throw new Error("Templates directory not found. Run npm run build.");
|
|
67084
67268
|
}
|
|
67085
67269
|
function resolveTemplateFile(name) {
|
|
67086
67270
|
const dir = resolveTemplatesDir();
|
|
67087
|
-
const filePath =
|
|
67271
|
+
const filePath = path31.join(dir, name);
|
|
67088
67272
|
return fs26.existsSync(filePath) ? filePath : null;
|
|
67089
67273
|
}
|
|
67090
67274
|
|
|
@@ -67093,18 +67277,18 @@ init_manifest();
|
|
|
67093
67277
|
var AGENT_SKILL_TARGETS = ["claude", "cursor", "codex"];
|
|
67094
67278
|
var MANAGED_HEADER = "<!-- managed by har \u2014 regenerated by `har agents install` / `har env maintain`; edit at your own risk -->";
|
|
67095
67279
|
function agentSkillsTemplateDir() {
|
|
67096
|
-
const dir =
|
|
67280
|
+
const dir = path32.join(resolveTemplatesDir(), "agent-skills");
|
|
67097
67281
|
if (!fs27.existsSync(dir)) {
|
|
67098
67282
|
throw new Error("Agent skills templates not found (templates/agent-skills). Run npm run build.");
|
|
67099
67283
|
}
|
|
67100
67284
|
return dir;
|
|
67101
67285
|
}
|
|
67102
67286
|
function readSkillsManifest() {
|
|
67103
|
-
const manifestPath =
|
|
67287
|
+
const manifestPath = path32.join(agentSkillsTemplateDir(), "skills.manifest.json");
|
|
67104
67288
|
return JSON.parse(fs27.readFileSync(manifestPath, "utf8"));
|
|
67105
67289
|
}
|
|
67106
67290
|
function readSkillBody(entry) {
|
|
67107
|
-
return fs27.readFileSync(
|
|
67291
|
+
return fs27.readFileSync(path32.join(agentSkillsTemplateDir(), entry.body), "utf8");
|
|
67108
67292
|
}
|
|
67109
67293
|
function renderYamlValue(value) {
|
|
67110
67294
|
if (typeof value === "string") return JSON.stringify(value);
|
|
@@ -67136,7 +67320,7 @@ function renderSkillFiles(agents) {
|
|
|
67136
67320
|
agent: "claude",
|
|
67137
67321
|
skill: entry.id,
|
|
67138
67322
|
scope: "repo",
|
|
67139
|
-
relPath:
|
|
67323
|
+
relPath: path32.join(".claude", "skills", entry.id, "SKILL.md"),
|
|
67140
67324
|
content: renderClaudeSkill(entry, body)
|
|
67141
67325
|
});
|
|
67142
67326
|
}
|
|
@@ -67145,7 +67329,7 @@ function renderSkillFiles(agents) {
|
|
|
67145
67329
|
agent: "cursor",
|
|
67146
67330
|
skill: entry.id,
|
|
67147
67331
|
scope: "repo",
|
|
67148
|
-
relPath:
|
|
67332
|
+
relPath: path32.join(".cursor", "commands", `${entry.id}.md`),
|
|
67149
67333
|
content: renderPlainSkill(body)
|
|
67150
67334
|
});
|
|
67151
67335
|
}
|
|
@@ -67154,7 +67338,7 @@ function renderSkillFiles(agents) {
|
|
|
67154
67338
|
agent: "codex",
|
|
67155
67339
|
skill: entry.id,
|
|
67156
67340
|
scope: "global",
|
|
67157
|
-
relPath:
|
|
67341
|
+
relPath: path32.posix.join("~", ".codex", "prompts", `${entry.codex.promptName}.md`),
|
|
67158
67342
|
content: renderPlainSkill(body)
|
|
67159
67343
|
});
|
|
67160
67344
|
}
|
|
@@ -67163,9 +67347,9 @@ function renderSkillFiles(agents) {
|
|
|
67163
67347
|
}
|
|
67164
67348
|
function resolveScaffoldPath(repoPath, file) {
|
|
67165
67349
|
if (file.scope === "global") {
|
|
67166
|
-
return
|
|
67350
|
+
return path32.join(os14.homedir(), file.relPath.replace(/^~\//, ""));
|
|
67167
67351
|
}
|
|
67168
|
-
return
|
|
67352
|
+
return path32.join(repoPath, file.relPath);
|
|
67169
67353
|
}
|
|
67170
67354
|
function isHarManaged(filePath) {
|
|
67171
67355
|
return fs27.readFileSync(filePath, "utf8").includes(MANAGED_HEADER);
|
|
@@ -67217,7 +67401,7 @@ function removeAgentSkills(repoPath, agents) {
|
|
|
67217
67401
|
}
|
|
67218
67402
|
fs27.rmSync(destPath);
|
|
67219
67403
|
removed.push(file.relPath);
|
|
67220
|
-
const parent =
|
|
67404
|
+
const parent = path32.dirname(destPath);
|
|
67221
67405
|
if (fs27.existsSync(parent) && fs27.readdirSync(parent).length === 0) {
|
|
67222
67406
|
fs27.rmdirSync(parent);
|
|
67223
67407
|
}
|
|
@@ -67238,9 +67422,9 @@ function detectAgentTargets(repoPath) {
|
|
|
67238
67422
|
const manifest = readManifest(repoPath);
|
|
67239
67423
|
const scaffolded = new Set((manifest?.scaffoldedAgentFiles ?? []).map((entry) => entry.agent));
|
|
67240
67424
|
const detected = new Set(scaffolded);
|
|
67241
|
-
if (fs27.existsSync(
|
|
67242
|
-
if (fs27.existsSync(
|
|
67243
|
-
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");
|
|
67244
67428
|
return AGENT_SKILL_TARGETS.filter((agent) => detected.has(agent));
|
|
67245
67429
|
}
|
|
67246
67430
|
function parseAgentTargets(raw) {
|
|
@@ -67284,16 +67468,16 @@ async function handleAgentSkills(options) {
|
|
|
67284
67468
|
}
|
|
67285
67469
|
async function askYesNo(question) {
|
|
67286
67470
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
67287
|
-
return new Promise((
|
|
67471
|
+
return new Promise((resolve52) => {
|
|
67288
67472
|
process.stderr.write(`${question} `);
|
|
67289
67473
|
rl.once("line", (answer) => {
|
|
67290
67474
|
rl.close();
|
|
67291
67475
|
const trimmed = answer.trim();
|
|
67292
67476
|
if (trimmed === "") {
|
|
67293
|
-
|
|
67477
|
+
resolve52(true);
|
|
67294
67478
|
return;
|
|
67295
67479
|
}
|
|
67296
|
-
|
|
67480
|
+
resolve52(/^y(es)?$/i.test(trimmed));
|
|
67297
67481
|
});
|
|
67298
67482
|
});
|
|
67299
67483
|
}
|
|
@@ -67327,7 +67511,7 @@ var agentsCommand = {
|
|
|
67327
67511
|
}
|
|
67328
67512
|
};
|
|
67329
67513
|
function handleInstall(argv) {
|
|
67330
|
-
const repoPath =
|
|
67514
|
+
const repoPath = path33.resolve(argv.repo);
|
|
67331
67515
|
header("har agents install");
|
|
67332
67516
|
try {
|
|
67333
67517
|
const targets = resolveTargets(argv, repoPath);
|
|
@@ -67353,7 +67537,7 @@ function handleInstall(argv) {
|
|
|
67353
67537
|
}
|
|
67354
67538
|
}
|
|
67355
67539
|
function handleRemove(argv) {
|
|
67356
|
-
const repoPath =
|
|
67540
|
+
const repoPath = path33.resolve(argv.repo);
|
|
67357
67541
|
header("har agents remove");
|
|
67358
67542
|
try {
|
|
67359
67543
|
const targets = resolveTargets(argv, repoPath);
|
|
@@ -67373,7 +67557,7 @@ function handleRemove(argv) {
|
|
|
67373
67557
|
}
|
|
67374
67558
|
|
|
67375
67559
|
// src/cli/commands/env.ts
|
|
67376
|
-
var
|
|
67560
|
+
var path57 = __toESM(require("path"));
|
|
67377
67561
|
|
|
67378
67562
|
// src/cli/finish-command.ts
|
|
67379
67563
|
init_sync_context();
|
|
@@ -67384,23 +67568,23 @@ async function finishCommand(code) {
|
|
|
67384
67568
|
|
|
67385
67569
|
// src/core/harness.ts
|
|
67386
67570
|
var fs42 = __toESM(require("fs"));
|
|
67387
|
-
var
|
|
67571
|
+
var path48 = __toESM(require("path"));
|
|
67388
67572
|
|
|
67389
67573
|
// src/harness/generator.ts
|
|
67390
67574
|
var fs32 = __toESM(require("fs"));
|
|
67391
|
-
var
|
|
67575
|
+
var path38 = __toESM(require("path"));
|
|
67392
67576
|
init_file_ops();
|
|
67393
67577
|
init_logging();
|
|
67394
67578
|
|
|
67395
67579
|
// src/core/gitignore.ts
|
|
67396
67580
|
var fs28 = __toESM(require("fs"));
|
|
67397
|
-
var
|
|
67581
|
+
var path34 = __toESM(require("path"));
|
|
67398
67582
|
var HARNESS_ROOT_GITIGNORE_PATTERNS = [
|
|
67399
67583
|
".env.agent.*",
|
|
67400
67584
|
"ecosystem.agent.*.config.cjs"
|
|
67401
67585
|
];
|
|
67402
67586
|
function ensureRootGitignorePatterns(checkoutDir) {
|
|
67403
|
-
const gitignorePath =
|
|
67587
|
+
const gitignorePath = path34.join(checkoutDir, ".gitignore");
|
|
67404
67588
|
const content = fs28.existsSync(gitignorePath) ? fs28.readFileSync(gitignorePath, "utf8") : "";
|
|
67405
67589
|
const lines = content.split("\n").map((line) => line.trim());
|
|
67406
67590
|
const missing = HARNESS_ROOT_GITIGNORE_PATTERNS.filter((pattern) => !lines.includes(pattern));
|
|
@@ -67415,7 +67599,7 @@ function ensureRootGitignorePatterns(checkoutDir) {
|
|
|
67415
67599
|
|
|
67416
67600
|
// src/harness/gitignore-template.ts
|
|
67417
67601
|
var fs29 = __toESM(require("fs"));
|
|
67418
|
-
var
|
|
67602
|
+
var path35 = __toESM(require("path"));
|
|
67419
67603
|
var HARNESS_GITIGNORE_TEMPLATE = "gitignore.template";
|
|
67420
67604
|
var HARNESS_GITIGNORE_FILE = ".gitignore";
|
|
67421
67605
|
function harnessFileForTemplate(templateFile) {
|
|
@@ -67425,16 +67609,16 @@ function templateFileForHarness(harnessFile) {
|
|
|
67425
67609
|
return harnessFile === HARNESS_GITIGNORE_FILE ? HARNESS_GITIGNORE_TEMPLATE : harnessFile;
|
|
67426
67610
|
}
|
|
67427
67611
|
function resolveGitignoreTemplateSource(boilerplateDir) {
|
|
67428
|
-
const primary =
|
|
67612
|
+
const primary = path35.join(boilerplateDir, HARNESS_GITIGNORE_TEMPLATE);
|
|
67429
67613
|
if (fs29.existsSync(primary)) return primary;
|
|
67430
|
-
const legacy =
|
|
67614
|
+
const legacy = path35.join(boilerplateDir, HARNESS_GITIGNORE_FILE);
|
|
67431
67615
|
if (fs29.existsSync(legacy)) return legacy;
|
|
67432
67616
|
return null;
|
|
67433
67617
|
}
|
|
67434
67618
|
function writeHarnessGitignore(harnessDir, boilerplateDir) {
|
|
67435
67619
|
const src = resolveGitignoreTemplateSource(boilerplateDir);
|
|
67436
67620
|
if (!src) return;
|
|
67437
|
-
fs29.writeFileSync(
|
|
67621
|
+
fs29.writeFileSync(path35.join(harnessDir, HARNESS_GITIGNORE_FILE), fs29.readFileSync(src, "utf8"));
|
|
67438
67622
|
}
|
|
67439
67623
|
function isExpectedHarnessOnlyFile(harnessFile, templateFiles) {
|
|
67440
67624
|
return harnessFile === HARNESS_GITIGNORE_FILE && templateFiles.includes(HARNESS_GITIGNORE_TEMPLATE);
|
|
@@ -67445,7 +67629,7 @@ init_manifest();
|
|
|
67445
67629
|
|
|
67446
67630
|
// src/harness/plugin-ledger.ts
|
|
67447
67631
|
var fs30 = __toESM(require("fs"));
|
|
67448
|
-
var
|
|
67632
|
+
var path36 = __toESM(require("path"));
|
|
67449
67633
|
init_zod();
|
|
67450
67634
|
init_file_ops();
|
|
67451
67635
|
init_manifest();
|
|
@@ -67468,7 +67652,7 @@ var PluginLedgerSchema = external_exports.object({
|
|
|
67468
67652
|
plugins: external_exports.array(PluginLedgerEntrySchema).default([])
|
|
67469
67653
|
});
|
|
67470
67654
|
function getPluginLedgerPath(repoPath) {
|
|
67471
|
-
return
|
|
67655
|
+
return path36.join(path36.resolve(repoPath), DEFAULT_HAR_DIR, "plugins.json");
|
|
67472
67656
|
}
|
|
67473
67657
|
function readPluginLedger(repoPath) {
|
|
67474
67658
|
const ledgerPath = getPluginLedgerPath(repoPath);
|
|
@@ -67483,7 +67667,7 @@ function readPluginLedger(repoPath) {
|
|
|
67483
67667
|
}
|
|
67484
67668
|
function writePluginLedger(repoPath, ledger) {
|
|
67485
67669
|
const ledgerPath = getPluginLedgerPath(repoPath);
|
|
67486
|
-
const harnessDir =
|
|
67670
|
+
const harnessDir = path36.dirname(ledgerPath);
|
|
67487
67671
|
if (!fs30.existsSync(harnessDir)) {
|
|
67488
67672
|
fs30.mkdirSync(harnessDir, { recursive: true });
|
|
67489
67673
|
}
|
|
@@ -67521,7 +67705,7 @@ function ensurePluginLedgerScaffold(repoPath, options) {
|
|
|
67521
67705
|
|
|
67522
67706
|
// src/harness/profiles.ts
|
|
67523
67707
|
var fs31 = __toESM(require("fs"));
|
|
67524
|
-
var
|
|
67708
|
+
var path37 = __toESM(require("path"));
|
|
67525
67709
|
init_zod();
|
|
67526
67710
|
var HARNESS_PROFILES = ["default", "cli", "ios"];
|
|
67527
67711
|
var ProfileBundleRefSchema = external_exports.object({
|
|
@@ -67574,7 +67758,7 @@ var PROFILE_DIRS = {
|
|
|
67574
67758
|
};
|
|
67575
67759
|
function readProfileManifest(profile) {
|
|
67576
67760
|
const templates = resolveTemplatesDir();
|
|
67577
|
-
const manifestPath =
|
|
67761
|
+
const manifestPath = path37.join(templates, "profiles", profile, "profile.manifest.json");
|
|
67578
67762
|
if (fs31.existsSync(manifestPath)) {
|
|
67579
67763
|
const parsed = ProfileManifestSchema.safeParse(
|
|
67580
67764
|
JSON.parse(fs31.readFileSync(manifestPath, "utf8"))
|
|
@@ -67590,7 +67774,7 @@ function readProfileManifest(profile) {
|
|
|
67590
67774
|
return PROFILE_COMPOSITIONS[profile];
|
|
67591
67775
|
}
|
|
67592
67776
|
function resolveProfileBundleDir(bundle) {
|
|
67593
|
-
const dir =
|
|
67777
|
+
const dir = path37.join(resolveTemplatesDir(), bundle.path);
|
|
67594
67778
|
if (!fs31.existsSync(dir)) {
|
|
67595
67779
|
throw new Error(`Profile bundle not found: ${bundle.id} (${bundle.path}). Run npm run build.`);
|
|
67596
67780
|
}
|
|
@@ -67606,20 +67790,20 @@ var CLI_PRUNE_FILES = [
|
|
|
67606
67790
|
];
|
|
67607
67791
|
function pruneCliProfile(harnessDir) {
|
|
67608
67792
|
for (const file of CLI_PRUNE_FILES) {
|
|
67609
|
-
const filePath =
|
|
67793
|
+
const filePath = path38.join(harnessDir, file);
|
|
67610
67794
|
if (fs32.existsSync(filePath)) {
|
|
67611
67795
|
fs32.unlinkSync(filePath);
|
|
67612
67796
|
}
|
|
67613
67797
|
}
|
|
67614
67798
|
}
|
|
67615
67799
|
function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
67616
|
-
const harnessDir =
|
|
67617
|
-
const projectName =
|
|
67800
|
+
const harnessDir = path38.join(repoPath, DEFAULT_HAR_DIR);
|
|
67801
|
+
const projectName = path38.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
67618
67802
|
const profile = options.profile ?? "default";
|
|
67619
67803
|
const profileManifest = readProfileManifest(profile);
|
|
67620
67804
|
const bundleIds = profileManifest.bundles.map((b2) => b2.id);
|
|
67621
67805
|
const primaryOverlay = PROFILE_DIRS[profile];
|
|
67622
|
-
const boilerplateDir =
|
|
67806
|
+
const boilerplateDir = path38.join(resolveTemplatesDir(), primaryOverlay);
|
|
67623
67807
|
if (fs32.existsSync(harnessDir) && !options.force) {
|
|
67624
67808
|
throw new Error(
|
|
67625
67809
|
'.har/ already exists. Use --force to overwrite or run "har env maintain" to update in place.'
|
|
@@ -67641,7 +67825,7 @@ function scaffoldHarnessBoilerplate(repoPath, options = {}) {
|
|
|
67641
67825
|
pruneCliProfile(harnessDir);
|
|
67642
67826
|
}
|
|
67643
67827
|
syncAgentSlotsToHarnessEnv(repoPath);
|
|
67644
|
-
const harnessEnvPath =
|
|
67828
|
+
const harnessEnvPath = path38.join(harnessDir, "harness.env");
|
|
67645
67829
|
if (fs32.existsSync(harnessEnvPath)) {
|
|
67646
67830
|
let content = fs32.readFileSync(harnessEnvPath, "utf8");
|
|
67647
67831
|
content = content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
|
|
@@ -67670,7 +67854,7 @@ function finalizeHarness(repoPath, adaptationSummary, stack) {
|
|
|
67670
67854
|
|
|
67671
67855
|
// src/harness/agent-md.ts
|
|
67672
67856
|
var fs34 = __toESM(require("fs"));
|
|
67673
|
-
var
|
|
67857
|
+
var path41 = __toESM(require("path"));
|
|
67674
67858
|
init_file_ops();
|
|
67675
67859
|
init_logging();
|
|
67676
67860
|
init_manifest();
|
|
@@ -67678,7 +67862,7 @@ init_manifest();
|
|
|
67678
67862
|
// src/harness/instruction-files.ts
|
|
67679
67863
|
var fs33 = __toESM(require("fs"));
|
|
67680
67864
|
var os16 = __toESM(require("os"));
|
|
67681
|
-
var
|
|
67865
|
+
var path40 = __toESM(require("path"));
|
|
67682
67866
|
|
|
67683
67867
|
// node_modules/@inquirer/core/dist/esm/lib/key.js
|
|
67684
67868
|
var isUpKey = (key, keybindings = []) => (
|
|
@@ -68712,13 +68896,13 @@ var PromisePolyfill = class extends Promise {
|
|
|
68712
68896
|
// Available starting from Node 22
|
|
68713
68897
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
|
68714
68898
|
static withResolver() {
|
|
68715
|
-
let
|
|
68899
|
+
let resolve52;
|
|
68716
68900
|
let reject;
|
|
68717
68901
|
const promise = new Promise((res, rej) => {
|
|
68718
|
-
|
|
68902
|
+
resolve52 = res;
|
|
68719
68903
|
reject = rej;
|
|
68720
68904
|
});
|
|
68721
|
-
return { promise, resolve:
|
|
68905
|
+
return { promise, resolve: resolve52, reject };
|
|
68722
68906
|
}
|
|
68723
68907
|
};
|
|
68724
68908
|
|
|
@@ -68752,7 +68936,7 @@ function createPrompt(view) {
|
|
|
68752
68936
|
output
|
|
68753
68937
|
});
|
|
68754
68938
|
const screen = new ScreenManager(rl);
|
|
68755
|
-
const { promise, resolve:
|
|
68939
|
+
const { promise, resolve: resolve52, reject } = PromisePolyfill.withResolver();
|
|
68756
68940
|
const cancel = () => reject(new CancelPromptError());
|
|
68757
68941
|
if (signal) {
|
|
68758
68942
|
const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
|
|
@@ -68779,7 +68963,7 @@ function createPrompt(view) {
|
|
|
68779
68963
|
cycle(() => {
|
|
68780
68964
|
try {
|
|
68781
68965
|
const nextView = view(config2, (value) => {
|
|
68782
|
-
setImmediate(() =>
|
|
68966
|
+
setImmediate(() => resolve52(value));
|
|
68783
68967
|
});
|
|
68784
68968
|
if (nextView === void 0) {
|
|
68785
68969
|
const callerFilename = callSites[1]?.getFileName();
|
|
@@ -70088,9 +70272,9 @@ var import_rxjs = __toESM(require_cjs(), 1);
|
|
|
70088
70272
|
var import_run_async = __toESM(require_run_async(), 1);
|
|
70089
70273
|
var import_mute_stream2 = __toESM(require_lib(), 1);
|
|
70090
70274
|
var _ = {
|
|
70091
|
-
set: (obj,
|
|
70275
|
+
set: (obj, path69 = "", value) => {
|
|
70092
70276
|
let pointer = obj;
|
|
70093
|
-
|
|
70277
|
+
path69.split(".").forEach((key, index, arr) => {
|
|
70094
70278
|
if (key === "__proto__" || key === "constructor")
|
|
70095
70279
|
return;
|
|
70096
70280
|
if (index === arr.length - 1) {
|
|
@@ -70101,8 +70285,8 @@ var _ = {
|
|
|
70101
70285
|
pointer = pointer[key];
|
|
70102
70286
|
});
|
|
70103
70287
|
},
|
|
70104
|
-
get: (obj,
|
|
70105
|
-
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(
|
|
70106
70290
|
// @ts-expect-error implicit any on res[key]
|
|
70107
70291
|
(res, key) => res == null ? res : res[key],
|
|
70108
70292
|
obj
|
|
@@ -70220,7 +70404,7 @@ var PromptsRunner = class {
|
|
|
70220
70404
|
throw new Error(`Prompt for type ${question.type} not found`);
|
|
70221
70405
|
}
|
|
70222
70406
|
let cleanupSignal;
|
|
70223
|
-
const promptFn = isPromptConstructor(prompt2) ? (q, opt) => new Promise((
|
|
70407
|
+
const promptFn = isPromptConstructor(prompt2) ? (q, opt) => new Promise((resolve52, reject) => {
|
|
70224
70408
|
const { signal: signal2 } = opt;
|
|
70225
70409
|
if (signal2.aborted) {
|
|
70226
70410
|
reject(new AbortPromptError({ cause: signal2.reason }));
|
|
@@ -70257,7 +70441,7 @@ var PromptsRunner = class {
|
|
|
70257
70441
|
signal2.removeEventListener("abort", abort);
|
|
70258
70442
|
cleanupSignal = void 0;
|
|
70259
70443
|
};
|
|
70260
|
-
activePrompt.run().then(
|
|
70444
|
+
activePrompt.run().then(resolve52, reject).finally(cleanup);
|
|
70261
70445
|
}) : prompt2;
|
|
70262
70446
|
let cleanupModuleSignal;
|
|
70263
70447
|
const { signal: moduleSignal } = this.opt;
|
|
@@ -70427,12 +70611,12 @@ function outsideContentShrinkMessage(beforeLines, afterLines) {
|
|
|
70427
70611
|
}
|
|
70428
70612
|
function detectInstructionFiles(repoPath) {
|
|
70429
70613
|
return {
|
|
70430
|
-
agentsMd: fs33.existsSync(
|
|
70431
|
-
agentMd: fs33.existsSync(
|
|
70432
|
-
claudeMd: fs33.existsSync(
|
|
70433
|
-
cursorDir: fs33.existsSync(
|
|
70434
|
-
claudeDir: fs33.existsSync(
|
|
70435
|
-
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"))
|
|
70436
70620
|
};
|
|
70437
70621
|
}
|
|
70438
70622
|
function formatDetectionReport(detection) {
|
|
@@ -70533,7 +70717,7 @@ function mergeAgentsMdContent(existing, incoming) {
|
|
|
70533
70717
|
return content;
|
|
70534
70718
|
}
|
|
70535
70719
|
function upsertAgentsMdHarSection(repoPath, options = {}) {
|
|
70536
|
-
const dest =
|
|
70720
|
+
const dest = path40.join(repoPath, AGENTS_MD);
|
|
70537
70721
|
const section = loadHarAgentsSectionFromTemplate();
|
|
70538
70722
|
if (!fs33.existsSync(dest)) {
|
|
70539
70723
|
writeFileSafe(dest, loadAgentsMdTemplate());
|
|
@@ -70564,8 +70748,8 @@ function upsertAgentsMdHarSection(repoPath, options = {}) {
|
|
|
70564
70748
|
return action;
|
|
70565
70749
|
}
|
|
70566
70750
|
function migrateLegacyAgentMd(repoPath) {
|
|
70567
|
-
const legacyPath =
|
|
70568
|
-
const agentsPath =
|
|
70751
|
+
const legacyPath = path40.join(repoPath, LEGACY_AGENT_MD);
|
|
70752
|
+
const agentsPath = path40.join(repoPath, AGENTS_MD);
|
|
70569
70753
|
if (!fs33.existsSync(legacyPath)) return false;
|
|
70570
70754
|
const legacy = fs33.readFileSync(legacyPath, "utf8");
|
|
70571
70755
|
if (!fs33.existsSync(agentsPath)) {
|
|
@@ -70606,8 +70790,8 @@ This repository uses a \`.har/\` harness. Read [AGENTS.md](./AGENTS.md) and
|
|
|
70606
70790
|
[\`.har/README.md\`](./.har/README.md) before making changes.
|
|
70607
70791
|
${CLAUDE_HAR_SECTION_END}`;
|
|
70608
70792
|
function ensureClaudeMdPointer(repoPath, options = {}) {
|
|
70609
|
-
const dest =
|
|
70610
|
-
const projectName =
|
|
70793
|
+
const dest = path40.join(repoPath, CLAUDE_MD);
|
|
70794
|
+
const projectName = path40.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
70611
70795
|
const thin = loadClaudeMdTemplate(projectName);
|
|
70612
70796
|
if (!fs33.existsSync(dest)) {
|
|
70613
70797
|
writeFileSafe(dest, thin);
|
|
@@ -70762,10 +70946,10 @@ var AGENT_MD_PROPOSAL = "AGENT.md.proposed";
|
|
|
70762
70946
|
var AGENT_MD_PROPOSAL_META = "AGENT.md.proposed.meta.json";
|
|
70763
70947
|
function readAgentMdProposal(repoPath) {
|
|
70764
70948
|
const harnessDir = getHarnessDir(repoPath);
|
|
70765
|
-
const proposalPath =
|
|
70766
|
-
const metaPath =
|
|
70767
|
-
const legacyProposalPath =
|
|
70768
|
-
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);
|
|
70769
70953
|
const resolvedProposal = fs34.existsSync(proposalPath) ? proposalPath : fs34.existsSync(legacyProposalPath) ? legacyProposalPath : null;
|
|
70770
70954
|
if (!resolvedProposal) return null;
|
|
70771
70955
|
const resolvedMeta = resolvedProposal === proposalPath ? metaPath : legacyMetaPath;
|
|
@@ -70791,7 +70975,7 @@ function clearAgentMdProposal(repoPath) {
|
|
|
70791
70975
|
AGENT_MD_PROPOSAL,
|
|
70792
70976
|
AGENT_MD_PROPOSAL_META
|
|
70793
70977
|
]) {
|
|
70794
|
-
const p =
|
|
70978
|
+
const p = path41.join(harnessDir, file);
|
|
70795
70979
|
if (fs34.existsSync(p)) fs34.unlinkSync(p);
|
|
70796
70980
|
}
|
|
70797
70981
|
}
|
|
@@ -70805,7 +70989,7 @@ function wouldProposalShrinkExisting(existing, proposal) {
|
|
|
70805
70989
|
function applyAgentMdProposalMerge(repoPath, options = {}) {
|
|
70806
70990
|
const proposal = readAgentMdProposal(repoPath);
|
|
70807
70991
|
if (!proposal) return false;
|
|
70808
|
-
const agentsMdPath =
|
|
70992
|
+
const agentsMdPath = path41.join(repoPath, AGENTS_MD);
|
|
70809
70993
|
if (fs34.existsSync(agentsMdPath)) {
|
|
70810
70994
|
const existing = fs34.readFileSync(agentsMdPath, "utf8");
|
|
70811
70995
|
if (wouldProposalShrinkExisting(existing, proposal.content)) {
|
|
@@ -70831,7 +71015,7 @@ function finalizeAgentsMdInstructionFiles(repoPath) {
|
|
|
70831
71015
|
|
|
70832
71016
|
// src/harness/validator.ts
|
|
70833
71017
|
var fs35 = __toESM(require("fs"));
|
|
70834
|
-
var
|
|
71018
|
+
var path42 = __toESM(require("path"));
|
|
70835
71019
|
init_shell();
|
|
70836
71020
|
init_manifest();
|
|
70837
71021
|
init_stages();
|
|
@@ -70893,13 +71077,13 @@ function validateHarness(repoPath) {
|
|
|
70893
71077
|
};
|
|
70894
71078
|
}
|
|
70895
71079
|
for (const file of getRequiredFiles(repoPath)) {
|
|
70896
|
-
const filePath =
|
|
71080
|
+
const filePath = path42.join(harnessDir, file);
|
|
70897
71081
|
if (!fs35.existsSync(filePath)) {
|
|
70898
71082
|
issues.push({ file, message: "Required file missing", severity: "error" });
|
|
70899
71083
|
}
|
|
70900
71084
|
}
|
|
70901
71085
|
for (const script of SHELL_SCRIPTS) {
|
|
70902
|
-
const scriptPath =
|
|
71086
|
+
const scriptPath = path42.join(harnessDir, script);
|
|
70903
71087
|
if (!fs35.existsSync(scriptPath)) continue;
|
|
70904
71088
|
const stat = fs35.statSync(scriptPath);
|
|
70905
71089
|
if (!(stat.mode & 73)) {
|
|
@@ -70916,7 +71100,7 @@ function validateHarness(repoPath) {
|
|
|
70916
71100
|
}
|
|
70917
71101
|
const manifest = readManifest(repoPath);
|
|
70918
71102
|
const profile = manifest?.profile ?? "default";
|
|
70919
|
-
const ecosystemPath =
|
|
71103
|
+
const ecosystemPath = path42.join(harnessDir, "ecosystem.agent.template.cjs");
|
|
70920
71104
|
if (profile !== "cli" && fs35.existsSync(ecosystemPath)) {
|
|
70921
71105
|
const content = fs35.readFileSync(ecosystemPath, "utf8");
|
|
70922
71106
|
if (!content.includes("module.exports")) {
|
|
@@ -70927,7 +71111,7 @@ function validateHarness(repoPath) {
|
|
|
70927
71111
|
});
|
|
70928
71112
|
}
|
|
70929
71113
|
}
|
|
70930
|
-
const harnessEnvPath =
|
|
71114
|
+
const harnessEnvPath = path42.join(harnessDir, "harness.env");
|
|
70931
71115
|
if (fs35.existsSync(harnessEnvPath)) {
|
|
70932
71116
|
const content = fs35.readFileSync(harnessEnvPath, "utf8");
|
|
70933
71117
|
if (content.includes("TODO: set migrate command")) {
|
|
@@ -70937,14 +71121,14 @@ function validateHarness(repoPath) {
|
|
|
70937
71121
|
issues.push({ file: "harness.env", message: "Seed command still has TODO", severity: "warning" });
|
|
70938
71122
|
}
|
|
70939
71123
|
}
|
|
70940
|
-
const verifyPath =
|
|
71124
|
+
const verifyPath = path42.join(harnessDir, "verify.sh");
|
|
70941
71125
|
if (fs35.existsSync(verifyPath)) {
|
|
70942
71126
|
const content = fs35.readFileSync(verifyPath, "utf8");
|
|
70943
71127
|
if (content.includes("echo 'TODO:")) {
|
|
70944
71128
|
issues.push({ file: "verify.sh", message: "Verification steps still have TODO placeholders", severity: "warning" });
|
|
70945
71129
|
}
|
|
70946
71130
|
}
|
|
70947
|
-
const stagesPath =
|
|
71131
|
+
const stagesPath = path42.join(harnessDir, "stages.json");
|
|
70948
71132
|
if (fs35.existsSync(stagesPath)) {
|
|
70949
71133
|
try {
|
|
70950
71134
|
JSON.parse(fs35.readFileSync(stagesPath, "utf8"));
|
|
@@ -70962,7 +71146,7 @@ function validateHarness(repoPath) {
|
|
|
70962
71146
|
} else {
|
|
70963
71147
|
issues.push({ file: "stages.json", message: "Stage registry missing", severity: "warning" });
|
|
70964
71148
|
}
|
|
70965
|
-
const readmePath =
|
|
71149
|
+
const readmePath = path42.join(harnessDir, "README.md");
|
|
70966
71150
|
if (fs35.existsSync(readmePath)) {
|
|
70967
71151
|
const content = fs35.readFileSync(readmePath, "utf8");
|
|
70968
71152
|
if (!content.includes(".har")) {
|
|
@@ -70978,7 +71162,7 @@ function validateHarness(repoPath) {
|
|
|
70978
71162
|
async function smokeTestHarness(repoPath) {
|
|
70979
71163
|
const harnessDir = getHarnessDir(repoPath);
|
|
70980
71164
|
const issues = [];
|
|
70981
|
-
const setupScript =
|
|
71165
|
+
const setupScript = path42.join(harnessDir, "setup-infra.sh");
|
|
70982
71166
|
if (fs35.existsSync(setupScript)) {
|
|
70983
71167
|
const result = run(`bash "${setupScript}"`, { cwd: repoPath });
|
|
70984
71168
|
if (result.code !== 0) {
|
|
@@ -70995,7 +71179,7 @@ async function smokeTestHarness(repoPath) {
|
|
|
70995
71179
|
|
|
70996
71180
|
// src/harness/drift.ts
|
|
70997
71181
|
var fs36 = __toESM(require("fs"));
|
|
70998
|
-
var
|
|
71182
|
+
var path43 = __toESM(require("path"));
|
|
70999
71183
|
init_env();
|
|
71000
71184
|
init_manifest();
|
|
71001
71185
|
init_stages();
|
|
@@ -71065,12 +71249,12 @@ function listBoilerplateFiles(boilerplateDir) {
|
|
|
71065
71249
|
return fs36.readdirSync(boilerplateDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
71066
71250
|
}
|
|
71067
71251
|
function compareHarnessToTemplate(repoPath) {
|
|
71068
|
-
const resolved =
|
|
71252
|
+
const resolved = path43.resolve(repoPath);
|
|
71069
71253
|
const manifest = readManifest(resolved);
|
|
71070
71254
|
const profile = manifest?.profile ?? "default";
|
|
71071
71255
|
const harnessDir = getHarnessDir(resolved);
|
|
71072
|
-
const projectName =
|
|
71073
|
-
const boilerplateDir =
|
|
71256
|
+
const projectName = path43.basename(resolved).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
71257
|
+
const boilerplateDir = path43.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
|
|
71074
71258
|
const templateFiles = listBoilerplateFiles(boilerplateDir);
|
|
71075
71259
|
const missing = [];
|
|
71076
71260
|
const checksumMismatch = [];
|
|
@@ -71078,8 +71262,8 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
71078
71262
|
const unchanged = [];
|
|
71079
71263
|
for (const file of templateFiles) {
|
|
71080
71264
|
const harnessFile = harnessFileForTemplate(file);
|
|
71081
|
-
const templatePath =
|
|
71082
|
-
const harnessPath =
|
|
71265
|
+
const templatePath = path43.join(boilerplateDir, file);
|
|
71266
|
+
const harnessPath = path43.join(harnessDir, harnessFile);
|
|
71083
71267
|
let templateContent = fs36.readFileSync(templatePath, "utf8");
|
|
71084
71268
|
if (file === "harness.env") {
|
|
71085
71269
|
templateContent = substituteProjectName(templateContent, projectName);
|
|
@@ -71098,7 +71282,7 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
71098
71282
|
}
|
|
71099
71283
|
if (fs36.existsSync(harnessDir)) {
|
|
71100
71284
|
for (const file of fs36.readdirSync(harnessDir)) {
|
|
71101
|
-
const full =
|
|
71285
|
+
const full = path43.join(harnessDir, file);
|
|
71102
71286
|
if (!fs36.statSync(full).isFile()) continue;
|
|
71103
71287
|
if (file === "manifest.json" || file === "plugins.json" || file.startsWith("ADAPT-PROMPT")) {
|
|
71104
71288
|
continue;
|
|
@@ -71128,19 +71312,19 @@ function compareHarnessToTemplate(repoPath) {
|
|
|
71128
71312
|
// src/harness/maintain-bundle.ts
|
|
71129
71313
|
var fs41 = __toESM(require("fs"));
|
|
71130
71314
|
var os18 = __toESM(require("os"));
|
|
71131
|
-
var
|
|
71315
|
+
var path47 = __toESM(require("path"));
|
|
71132
71316
|
init_file_ops();
|
|
71133
71317
|
init_shell();
|
|
71134
71318
|
init_manifest();
|
|
71135
71319
|
|
|
71136
71320
|
// src/harness/plugin-drift.ts
|
|
71137
71321
|
var fs40 = __toESM(require("fs"));
|
|
71138
|
-
var
|
|
71322
|
+
var path46 = __toESM(require("path"));
|
|
71139
71323
|
init_manifest();
|
|
71140
71324
|
|
|
71141
71325
|
// src/harness/plugins.ts
|
|
71142
71326
|
var fs39 = __toESM(require("fs"));
|
|
71143
|
-
var
|
|
71327
|
+
var path45 = __toESM(require("path"));
|
|
71144
71328
|
init_zod();
|
|
71145
71329
|
init_logging();
|
|
71146
71330
|
|
|
@@ -71155,12 +71339,12 @@ function harnessExists(repoPath) {
|
|
|
71155
71339
|
var import_child_process11 = require("child_process");
|
|
71156
71340
|
var fs38 = __toESM(require("fs"));
|
|
71157
71341
|
var os17 = __toESM(require("os"));
|
|
71158
|
-
var
|
|
71342
|
+
var path44 = __toESM(require("path"));
|
|
71159
71343
|
function hasManifest(dir) {
|
|
71160
|
-
return fs38.existsSync(
|
|
71344
|
+
return fs38.existsSync(path44.join(dir, "template.manifest.json"));
|
|
71161
71345
|
}
|
|
71162
71346
|
function readPackageVersion(dir) {
|
|
71163
|
-
const pkgPath =
|
|
71347
|
+
const pkgPath = path44.join(dir, "package.json");
|
|
71164
71348
|
if (!fs38.existsSync(pkgPath)) return void 0;
|
|
71165
71349
|
try {
|
|
71166
71350
|
const pkg = JSON.parse(fs38.readFileSync(pkgPath, "utf8"));
|
|
@@ -71170,7 +71354,7 @@ function readPackageVersion(dir) {
|
|
|
71170
71354
|
}
|
|
71171
71355
|
}
|
|
71172
71356
|
function readManifestId(dir) {
|
|
71173
|
-
const manifestPath =
|
|
71357
|
+
const manifestPath = path44.join(dir, "template.manifest.json");
|
|
71174
71358
|
if (!fs38.existsSync(manifestPath)) return void 0;
|
|
71175
71359
|
try {
|
|
71176
71360
|
const raw = JSON.parse(fs38.readFileSync(manifestPath, "utf8"));
|
|
@@ -71191,24 +71375,24 @@ function looksLikeNpm(spec) {
|
|
|
71191
71375
|
return /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@.+)?$/i.test(spec);
|
|
71192
71376
|
}
|
|
71193
71377
|
function resolveBundledDir(pluginId) {
|
|
71194
|
-
const dir =
|
|
71378
|
+
const dir = path44.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
71195
71379
|
return hasManifest(dir) ? dir : null;
|
|
71196
71380
|
}
|
|
71197
71381
|
function expandHome(p) {
|
|
71198
|
-
if (p.startsWith("~/")) return
|
|
71382
|
+
if (p.startsWith("~/")) return path44.join(os17.homedir(), p.slice(2));
|
|
71199
71383
|
if (p === "~") return os17.homedir();
|
|
71200
71384
|
return p;
|
|
71201
71385
|
}
|
|
71202
71386
|
function resolvePathSpec(spec) {
|
|
71203
71387
|
const raw = spec.startsWith("file:") ? spec.slice("file:".length) : spec;
|
|
71204
|
-
const dir =
|
|
71388
|
+
const dir = path44.resolve(expandHome(raw));
|
|
71205
71389
|
if (!fs38.existsSync(dir) || !fs38.statSync(dir).isDirectory()) {
|
|
71206
71390
|
throw new Error(`Plugin path not found: ${spec}`);
|
|
71207
71391
|
}
|
|
71208
71392
|
if (!hasManifest(dir)) {
|
|
71209
71393
|
throw new Error(`No template.manifest.json in ${dir}`);
|
|
71210
71394
|
}
|
|
71211
|
-
const id = readManifestId(dir) ??
|
|
71395
|
+
const id = readManifestId(dir) ?? path44.basename(dir);
|
|
71212
71396
|
return {
|
|
71213
71397
|
id,
|
|
71214
71398
|
kind: "path",
|
|
@@ -71219,7 +71403,7 @@ function resolvePathSpec(spec) {
|
|
|
71219
71403
|
};
|
|
71220
71404
|
}
|
|
71221
71405
|
function makeTempDir(prefix) {
|
|
71222
|
-
return fs38.mkdtempSync(
|
|
71406
|
+
return fs38.mkdtempSync(path44.join(os17.tmpdir(), prefix));
|
|
71223
71407
|
}
|
|
71224
71408
|
function resolveNpmSpec(spec) {
|
|
71225
71409
|
const tmp = makeTempDir("har-plugin-npm-");
|
|
@@ -71234,16 +71418,16 @@ function resolveNpmSpec(spec) {
|
|
|
71234
71418
|
if (tarballs.length === 0) {
|
|
71235
71419
|
throw new Error(`npm pack produced no tarball for ${spec}`);
|
|
71236
71420
|
}
|
|
71237
|
-
const extractDir =
|
|
71421
|
+
const extractDir = path44.join(tmp, "extract");
|
|
71238
71422
|
fs38.mkdirSync(extractDir);
|
|
71239
|
-
(0, import_child_process11.execFileSync)("tar", ["-xzf",
|
|
71423
|
+
(0, import_child_process11.execFileSync)("tar", ["-xzf", path44.join(tmp, tarballs[0]), "-C", extractDir], {
|
|
71240
71424
|
encoding: "utf8",
|
|
71241
71425
|
stdio: ["ignore", "pipe", "pipe"]
|
|
71242
71426
|
});
|
|
71243
|
-
const packageDir =
|
|
71427
|
+
const packageDir = path44.join(extractDir, "package");
|
|
71244
71428
|
let dir = packageDir;
|
|
71245
71429
|
if (!hasManifest(dir)) {
|
|
71246
|
-
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));
|
|
71247
71431
|
if (!nested) {
|
|
71248
71432
|
throw new Error(
|
|
71249
71433
|
`npm package ${spec} has no template.manifest.json (not a HAR plugin bundle)`
|
|
@@ -71271,7 +71455,7 @@ function resolveNpmSpec(spec) {
|
|
|
71271
71455
|
function resolveGitSpec(spec) {
|
|
71272
71456
|
const tmp = makeTempDir("har-plugin-git-");
|
|
71273
71457
|
const cleanupDirs = [tmp];
|
|
71274
|
-
const cloneDir =
|
|
71458
|
+
const cloneDir = path44.join(tmp, "repo");
|
|
71275
71459
|
try {
|
|
71276
71460
|
let url = spec;
|
|
71277
71461
|
if (spec.startsWith("github:")) {
|
|
@@ -71290,16 +71474,16 @@ function resolveGitSpec(spec) {
|
|
|
71290
71474
|
});
|
|
71291
71475
|
let dir = cloneDir;
|
|
71292
71476
|
if (!hasManifest(dir)) {
|
|
71293
|
-
const pluginsRoot =
|
|
71477
|
+
const pluginsRoot = path44.join(cloneDir, "plugins");
|
|
71294
71478
|
if (fs38.existsSync(pluginsRoot)) {
|
|
71295
|
-
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));
|
|
71296
71480
|
if (child) dir = child;
|
|
71297
71481
|
}
|
|
71298
71482
|
}
|
|
71299
71483
|
if (!hasManifest(dir)) {
|
|
71300
71484
|
throw new Error(`Git repo ${spec} has no template.manifest.json (not a HAR plugin bundle)`);
|
|
71301
71485
|
}
|
|
71302
|
-
const id = readManifestId(dir) ??
|
|
71486
|
+
const id = readManifestId(dir) ?? path44.basename(url.replace(/\.git$/, ""));
|
|
71303
71487
|
return {
|
|
71304
71488
|
id,
|
|
71305
71489
|
kind: "git",
|
|
@@ -71358,9 +71542,9 @@ function resolvePluginSource(spec) {
|
|
|
71358
71542
|
);
|
|
71359
71543
|
}
|
|
71360
71544
|
function listBundledPluginIds() {
|
|
71361
|
-
const root =
|
|
71545
|
+
const root = path44.join(resolveTemplatesDir(), "plugins");
|
|
71362
71546
|
if (!fs38.existsSync(root)) return [];
|
|
71363
|
-
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();
|
|
71364
71548
|
}
|
|
71365
71549
|
function cleanupResolvedPlugin(source) {
|
|
71366
71550
|
for (const dir of source.cleanupDirs) {
|
|
@@ -71416,14 +71600,14 @@ function primaryStageId(manifest) {
|
|
|
71416
71600
|
return manifest.stageId ?? stages[0].id;
|
|
71417
71601
|
}
|
|
71418
71602
|
function resolveBundledPluginDir(pluginId) {
|
|
71419
|
-
const dir =
|
|
71603
|
+
const dir = path45.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
71420
71604
|
if (!fs39.existsSync(dir)) {
|
|
71421
71605
|
throw new Error(`Plugin not found: ${pluginId}. Run npm run build.`);
|
|
71422
71606
|
}
|
|
71423
71607
|
return dir;
|
|
71424
71608
|
}
|
|
71425
71609
|
function readPluginManifestFromDir(pluginDir, expectedId) {
|
|
71426
|
-
const manifestPath =
|
|
71610
|
+
const manifestPath = path45.join(pluginDir, "template.manifest.json");
|
|
71427
71611
|
if (!fs39.existsSync(manifestPath)) {
|
|
71428
71612
|
throw new Error(`No template.manifest.json in ${pluginDir}`);
|
|
71429
71613
|
}
|
|
@@ -71442,14 +71626,14 @@ function readPluginManifest(pluginId) {
|
|
|
71442
71626
|
return readPluginManifestFromDir(resolveBundledPluginDir(pluginId), pluginId);
|
|
71443
71627
|
}
|
|
71444
71628
|
function ensureParentDir(filePath) {
|
|
71445
|
-
const parent =
|
|
71629
|
+
const parent = path45.dirname(filePath);
|
|
71446
71630
|
if (!fs39.existsSync(parent)) {
|
|
71447
71631
|
fs39.mkdirSync(parent, { recursive: true });
|
|
71448
71632
|
}
|
|
71449
71633
|
}
|
|
71450
71634
|
function copyPluginFile(pluginDir, file, repoPath, force) {
|
|
71451
|
-
const srcPath =
|
|
71452
|
-
const destPath =
|
|
71635
|
+
const srcPath = path45.join(pluginDir, file.src);
|
|
71636
|
+
const destPath = path45.join(repoPath, file.dest);
|
|
71453
71637
|
if (!fs39.existsSync(srcPath)) {
|
|
71454
71638
|
throw new Error(`Plugin file missing: ${file.src}`);
|
|
71455
71639
|
}
|
|
@@ -71466,11 +71650,11 @@ function copyPluginFile(pluginDir, file, repoPath, force) {
|
|
|
71466
71650
|
return { written: true, path: file.dest };
|
|
71467
71651
|
}
|
|
71468
71652
|
function mergePackageJson(repoPath, pluginDir, fragmentRelPath, warnings) {
|
|
71469
|
-
const packagePath =
|
|
71653
|
+
const packagePath = path45.join(repoPath, "package.json");
|
|
71470
71654
|
if (!fs39.existsSync(packagePath)) {
|
|
71471
71655
|
throw new Error("No package.json in repo root. Add one before applying this plugin.");
|
|
71472
71656
|
}
|
|
71473
|
-
const fragmentPath =
|
|
71657
|
+
const fragmentPath = path45.join(pluginDir, fragmentRelPath);
|
|
71474
71658
|
if (!fs39.existsSync(fragmentPath)) {
|
|
71475
71659
|
throw new Error(`Package fragment missing: ${fragmentRelPath}`);
|
|
71476
71660
|
}
|
|
@@ -71532,7 +71716,7 @@ function assertStagesNotPresent(repoPath, stageIds, force) {
|
|
|
71532
71716
|
if (force) return;
|
|
71533
71717
|
const registry2 = readStageRegistry(repoPath);
|
|
71534
71718
|
for (const stageId of stageIds) {
|
|
71535
|
-
const scriptPath =
|
|
71719
|
+
const scriptPath = path45.join(repoPath, ".har", "stages", `${stageId}.sh`);
|
|
71536
71720
|
if (fs39.existsSync(scriptPath)) {
|
|
71537
71721
|
throw new Error(
|
|
71538
71722
|
`Stage script already exists: .har/stages/${stageId}.sh. Use --force to overwrite.`
|
|
@@ -71546,7 +71730,7 @@ function assertStagesNotPresent(repoPath, stageIds, force) {
|
|
|
71546
71730
|
}
|
|
71547
71731
|
}
|
|
71548
71732
|
function applyPluginFromDir(repoPath, pluginDir, options, meta) {
|
|
71549
|
-
const resolved =
|
|
71733
|
+
const resolved = path45.resolve(repoPath);
|
|
71550
71734
|
const force = options.force ?? false;
|
|
71551
71735
|
const warnings = [];
|
|
71552
71736
|
const filesWritten = [];
|
|
@@ -71566,7 +71750,7 @@ function applyPluginFromDir(repoPath, pluginDir, options, meta) {
|
|
|
71566
71750
|
if (file.skipFlag === "skipCi" && options.skipCi) {
|
|
71567
71751
|
continue;
|
|
71568
71752
|
}
|
|
71569
|
-
if (fs39.existsSync(
|
|
71753
|
+
if (fs39.existsSync(path45.join(resolved, file.dest)) && !force) {
|
|
71570
71754
|
warnings.push(`Skipped optional file (exists): ${file.dest}`);
|
|
71571
71755
|
continue;
|
|
71572
71756
|
}
|
|
@@ -71632,12 +71816,12 @@ function listPluginIds() {
|
|
|
71632
71816
|
init_stages();
|
|
71633
71817
|
var PACKAGE_SECTIONS = ["scripts", "devDependencies"];
|
|
71634
71818
|
function detectInstalledPlugins(repoPath) {
|
|
71635
|
-
const resolved =
|
|
71819
|
+
const resolved = path46.resolve(repoPath);
|
|
71636
71820
|
const ledger = readPluginLedger(resolved);
|
|
71637
71821
|
if (ledger && ledger.plugins.length > 0) {
|
|
71638
71822
|
return ledger.plugins.map((p) => p.id).sort();
|
|
71639
71823
|
}
|
|
71640
|
-
const registryPath =
|
|
71824
|
+
const registryPath = path46.join(resolved, ".har", "stages.json");
|
|
71641
71825
|
if (!fs40.existsSync(registryPath)) return [];
|
|
71642
71826
|
const registry2 = readStageRegistry(resolved);
|
|
71643
71827
|
const stageIds = new Set(registry2.stages.map((stage) => stage.id));
|
|
@@ -71655,7 +71839,7 @@ function detectInstalledPlugins(repoPath) {
|
|
|
71655
71839
|
return installed.sort();
|
|
71656
71840
|
}
|
|
71657
71841
|
function pluginTemplatePath(pluginId, srcRel) {
|
|
71658
|
-
return
|
|
71842
|
+
return path46.join(resolveTemplatesDir(), "plugins", pluginId, srcRel);
|
|
71659
71843
|
}
|
|
71660
71844
|
function resolvePluginTemplateDir(repoPath, pluginId) {
|
|
71661
71845
|
const ledger = readPluginLedger(repoPath);
|
|
@@ -71667,8 +71851,8 @@ function resolvePluginTemplateDir(repoPath, pluginId) {
|
|
|
71667
71851
|
} catch {
|
|
71668
71852
|
}
|
|
71669
71853
|
}
|
|
71670
|
-
const bundled =
|
|
71671
|
-
if (fs40.existsSync(
|
|
71854
|
+
const bundled = path46.join(resolveTemplatesDir(), "plugins", pluginId);
|
|
71855
|
+
if (fs40.existsSync(path46.join(bundled, "template.manifest.json"))) {
|
|
71672
71856
|
return bundled;
|
|
71673
71857
|
}
|
|
71674
71858
|
return null;
|
|
@@ -71682,7 +71866,7 @@ function listPluginDestPaths(pluginId, repoPath) {
|
|
|
71682
71866
|
const paths = manifest.files.map((file) => file.dest);
|
|
71683
71867
|
if (manifest.optionalFiles) {
|
|
71684
71868
|
for (const file of manifest.optionalFiles) {
|
|
71685
|
-
if (fs40.existsSync(
|
|
71869
|
+
if (fs40.existsSync(path46.join(repoPath, file.dest))) {
|
|
71686
71870
|
paths.push(file.dest);
|
|
71687
71871
|
}
|
|
71688
71872
|
}
|
|
@@ -71741,7 +71925,7 @@ function readTemplatePluginFile(pluginId, dest) {
|
|
|
71741
71925
|
return null;
|
|
71742
71926
|
}
|
|
71743
71927
|
function readInstalledPluginFile(repoPath, pluginId, dest) {
|
|
71744
|
-
const installedPath =
|
|
71928
|
+
const installedPath = path46.join(path46.resolve(repoPath), dest);
|
|
71745
71929
|
if (!fs40.existsSync(installedPath)) return null;
|
|
71746
71930
|
const content = fs40.readFileSync(installedPath, "utf8");
|
|
71747
71931
|
const manifest = readPluginManifest(pluginId);
|
|
@@ -71762,7 +71946,7 @@ function pluginActionHint(pluginId, dest, kind) {
|
|
|
71762
71946
|
}
|
|
71763
71947
|
function comparePluginToTemplate(repoPath, pluginId) {
|
|
71764
71948
|
const manifest = readPluginManifest(pluginId);
|
|
71765
|
-
const resolved =
|
|
71949
|
+
const resolved = path46.resolve(repoPath);
|
|
71766
71950
|
const destPaths = listPluginDestPaths(pluginId, resolved);
|
|
71767
71951
|
const missing = [];
|
|
71768
71952
|
const checksumMismatch = [];
|
|
@@ -71777,7 +71961,7 @@ function comparePluginToTemplate(repoPath, pluginId) {
|
|
|
71777
71961
|
}
|
|
71778
71962
|
if (dest === "package.json") {
|
|
71779
71963
|
const fragmentRel = manifest.merge?.[dest];
|
|
71780
|
-
const installedPath =
|
|
71964
|
+
const installedPath = path46.join(resolved, dest);
|
|
71781
71965
|
const installedRaw = fs40.readFileSync(installedPath, "utf8");
|
|
71782
71966
|
if (fragmentRel && pluginKeysMatch(installedRaw, readBundledPluginFile(pluginId, fragmentRel))) {
|
|
71783
71967
|
unchanged.push(dest);
|
|
@@ -71804,7 +71988,7 @@ function comparePluginToTemplate(repoPath, pluginId) {
|
|
|
71804
71988
|
}
|
|
71805
71989
|
function compareInstalledPluginsToTemplate(repoPath) {
|
|
71806
71990
|
return detectInstalledPlugins(repoPath).filter((pluginId) => {
|
|
71807
|
-
const bundled =
|
|
71991
|
+
const bundled = path46.join(resolveTemplatesDir(), "plugins", pluginId, "template.manifest.json");
|
|
71808
71992
|
return fs40.existsSync(bundled);
|
|
71809
71993
|
}).map((pluginId) => comparePluginToTemplate(repoPath, pluginId));
|
|
71810
71994
|
}
|
|
@@ -71843,13 +72027,13 @@ function substituteProjectName2(content, projectName) {
|
|
|
71843
72027
|
return content.replace(/__PROJECT_NAME__/g, projectName).replace(/template___PROJECT_NAME__/g, `template_${projectName}`);
|
|
71844
72028
|
}
|
|
71845
72029
|
function projectNameFromRepo(repoPath) {
|
|
71846
|
-
return
|
|
72030
|
+
return path47.basename(repoPath).toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
71847
72031
|
}
|
|
71848
72032
|
function boilerplateDirForProfile(profile) {
|
|
71849
|
-
return
|
|
72033
|
+
return path47.join(resolveTemplatesDir(), PROFILE_DIRS[profile]);
|
|
71850
72034
|
}
|
|
71851
72035
|
function readBundledTemplateContent(repoPath, profile, file) {
|
|
71852
|
-
const templatePath =
|
|
72036
|
+
const templatePath = path47.join(boilerplateDirForProfile(profile), templateFileForHarness(file));
|
|
71853
72037
|
let content = fs41.readFileSync(templatePath, "utf8");
|
|
71854
72038
|
if (file === "harness.env") {
|
|
71855
72039
|
content = substituteProjectName2(content, projectNameFromRepo(repoPath));
|
|
@@ -71881,10 +72065,10 @@ function actionHint(file, kind) {
|
|
|
71881
72065
|
return `Read maintain/diffs/${file}.diff and merge into .har/${file}.`;
|
|
71882
72066
|
}
|
|
71883
72067
|
function createUnifiedDiff(installedContent, templateContent, installedLabel, templateLabel) {
|
|
71884
|
-
const tmpDir = fs41.mkdtempSync(
|
|
72068
|
+
const tmpDir = fs41.mkdtempSync(path47.join(os18.tmpdir(), "har-maintain-diff-"));
|
|
71885
72069
|
try {
|
|
71886
|
-
const installedPath =
|
|
71887
|
-
const templatePath =
|
|
72070
|
+
const installedPath = path47.join(tmpDir, "installed");
|
|
72071
|
+
const templatePath = path47.join(tmpDir, "template");
|
|
71888
72072
|
fs41.writeFileSync(installedPath, installedContent);
|
|
71889
72073
|
fs41.writeFileSync(templatePath, templateContent);
|
|
71890
72074
|
const result = run(`diff -u "${installedPath}" "${templatePath}"`);
|
|
@@ -71910,7 +72094,7 @@ function buildActions(repoPath, profile, drift) {
|
|
|
71910
72094
|
});
|
|
71911
72095
|
}
|
|
71912
72096
|
for (const file of drift.checksumMismatch) {
|
|
71913
|
-
const installedPath =
|
|
72097
|
+
const installedPath = path47.join(harnessDir, file);
|
|
71914
72098
|
const installedRel = `maintain/installed/${file}`;
|
|
71915
72099
|
const templateRel = `maintain/templates/${file}`;
|
|
71916
72100
|
const diffRel = `maintain/diffs/${file}.diff`;
|
|
@@ -72070,16 +72254,16 @@ function buildReadme(report) {
|
|
|
72070
72254
|
}
|
|
72071
72255
|
function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
72072
72256
|
const harnessDir = getHarnessDir(repoPath);
|
|
72073
|
-
const bundleDir =
|
|
72257
|
+
const bundleDir = path47.join(harnessDir, MAINTAIN_DIR);
|
|
72074
72258
|
if (fs41.existsSync(bundleDir)) {
|
|
72075
72259
|
fs41.rmSync(bundleDir, { recursive: true, force: true });
|
|
72076
72260
|
}
|
|
72077
72261
|
const dirs = [
|
|
72078
72262
|
bundleDir,
|
|
72079
|
-
|
|
72080
|
-
|
|
72081
|
-
|
|
72082
|
-
|
|
72263
|
+
path47.join(bundleDir, "templates"),
|
|
72264
|
+
path47.join(bundleDir, "installed"),
|
|
72265
|
+
path47.join(bundleDir, "diffs"),
|
|
72266
|
+
path47.join(bundleDir, "stale")
|
|
72083
72267
|
];
|
|
72084
72268
|
for (const dir of dirs) {
|
|
72085
72269
|
fs41.mkdirSync(dir, { recursive: true });
|
|
@@ -72087,11 +72271,11 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
72087
72271
|
const affectedFiles = [...drift.missing, ...drift.checksumMismatch];
|
|
72088
72272
|
for (const file of affectedFiles) {
|
|
72089
72273
|
const templateContent = readBundledTemplateContent(repoPath, profile, file);
|
|
72090
|
-
writeFileSafe(
|
|
72091
|
-
const harnessPath =
|
|
72274
|
+
writeFileSafe(path47.join(bundleDir, "templates", file), templateContent);
|
|
72275
|
+
const harnessPath = path47.join(harnessDir, file);
|
|
72092
72276
|
if (fs41.existsSync(harnessPath)) {
|
|
72093
72277
|
const installedContent = fs41.readFileSync(harnessPath, "utf8");
|
|
72094
|
-
writeFileSafe(
|
|
72278
|
+
writeFileSafe(path47.join(bundleDir, "installed", file), installedContent);
|
|
72095
72279
|
const diff = createUnifiedDiff(
|
|
72096
72280
|
installedContent,
|
|
72097
72281
|
templateContent,
|
|
@@ -72099,14 +72283,14 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
72099
72283
|
`templates/${file}`
|
|
72100
72284
|
);
|
|
72101
72285
|
if (diff) {
|
|
72102
|
-
writeFileSafe(
|
|
72286
|
+
writeFileSafe(path47.join(bundleDir, "diffs", `${file}.diff`), diff);
|
|
72103
72287
|
}
|
|
72104
72288
|
}
|
|
72105
72289
|
}
|
|
72106
|
-
writeFileSafe(
|
|
72107
|
-
writeFileSafe(
|
|
72290
|
+
writeFileSafe(path47.join(bundleDir, "README.md"), buildReadme(report));
|
|
72291
|
+
writeFileSafe(path47.join(bundleDir, "drift-report.json"), JSON.stringify(report, null, 2) + "\n");
|
|
72108
72292
|
writeFileSafe(
|
|
72109
|
-
|
|
72293
|
+
path47.join(bundleDir, "validation.json"),
|
|
72110
72294
|
JSON.stringify(report.validation, null, 2) + "\n"
|
|
72111
72295
|
);
|
|
72112
72296
|
if (report.stale.length > 0) {
|
|
@@ -72118,12 +72302,12 @@ function writeBundleArtifacts(repoPath, profile, drift, report) {
|
|
|
72118
72302
|
...report.stale.map((s) => `- **${s.file}** \u2014 ${s.hint}`),
|
|
72119
72303
|
""
|
|
72120
72304
|
];
|
|
72121
|
-
writeFileSafe(
|
|
72305
|
+
writeFileSafe(path47.join(bundleDir, "stale", "MANIFEST.md"), staleLines.join("\n"));
|
|
72122
72306
|
}
|
|
72123
72307
|
return bundleDir;
|
|
72124
72308
|
}
|
|
72125
72309
|
function ensureParentDir2(filePath) {
|
|
72126
|
-
const parent =
|
|
72310
|
+
const parent = path47.dirname(filePath);
|
|
72127
72311
|
if (!fs41.existsSync(parent)) {
|
|
72128
72312
|
fs41.mkdirSync(parent, { recursive: true });
|
|
72129
72313
|
}
|
|
@@ -72131,21 +72315,21 @@ function ensureParentDir2(filePath) {
|
|
|
72131
72315
|
function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
72132
72316
|
if (report.pluginActions.length === 0) return;
|
|
72133
72317
|
for (const action of report.pluginActions) {
|
|
72134
|
-
const pluginRoot =
|
|
72135
|
-
const templatesDir =
|
|
72136
|
-
const installedDir =
|
|
72137
|
-
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");
|
|
72138
72322
|
for (const dir of [templatesDir, installedDir, diffsDir]) {
|
|
72139
72323
|
fs41.mkdirSync(dir, { recursive: true });
|
|
72140
72324
|
}
|
|
72141
72325
|
const templateContent = readTemplatePluginFile(action.pluginId, action.file);
|
|
72142
72326
|
if (templateContent === null) continue;
|
|
72143
|
-
const templatePath =
|
|
72327
|
+
const templatePath = path47.join(templatesDir, action.file);
|
|
72144
72328
|
ensureParentDir2(templatePath);
|
|
72145
72329
|
writeFileSafe(templatePath, templateContent);
|
|
72146
72330
|
const installedContent = readInstalledPluginFile(repoPath, action.pluginId, action.file);
|
|
72147
72331
|
if (installedContent !== null) {
|
|
72148
|
-
const installedPath =
|
|
72332
|
+
const installedPath = path47.join(installedDir, action.file);
|
|
72149
72333
|
ensureParentDir2(installedPath);
|
|
72150
72334
|
writeFileSafe(installedPath, installedContent);
|
|
72151
72335
|
const diff = createUnifiedDiff(
|
|
@@ -72155,7 +72339,7 @@ function writePluginBundleArtifacts(repoPath, bundleDir, report) {
|
|
|
72155
72339
|
`templates/${action.file}`
|
|
72156
72340
|
);
|
|
72157
72341
|
if (diff) {
|
|
72158
|
-
const diffPath =
|
|
72342
|
+
const diffPath = path47.join(diffsDir, `${action.file}.diff`);
|
|
72159
72343
|
ensureParentDir2(diffPath);
|
|
72160
72344
|
writeFileSafe(diffPath, diff);
|
|
72161
72345
|
}
|
|
@@ -72190,7 +72374,7 @@ function buildMaintainBundle(repoPath, validation2, drift) {
|
|
|
72190
72374
|
return { bundleDir, report };
|
|
72191
72375
|
}
|
|
72192
72376
|
function removeMaintainBundle(repoPath) {
|
|
72193
|
-
const bundleDir =
|
|
72377
|
+
const bundleDir = path47.join(getHarnessDir(repoPath), MAINTAIN_DIR);
|
|
72194
72378
|
if (fs41.existsSync(bundleDir)) {
|
|
72195
72379
|
fs41.rmSync(bundleDir, { recursive: true, force: true });
|
|
72196
72380
|
}
|
|
@@ -72285,7 +72469,7 @@ function listHarnessScripts(repoPath) {
|
|
|
72285
72469
|
return fs42.readdirSync(harnessDir).filter((name) => name.endsWith(".sh")).sort();
|
|
72286
72470
|
}
|
|
72287
72471
|
function describeProject(repoPath) {
|
|
72288
|
-
const resolved =
|
|
72472
|
+
const resolved = path48.resolve(repoPath);
|
|
72289
72473
|
const manifest = readManifest(resolved);
|
|
72290
72474
|
const present = harnessExists(resolved);
|
|
72291
72475
|
return {
|
|
@@ -72305,7 +72489,7 @@ function describeProject(repoPath) {
|
|
|
72305
72489
|
};
|
|
72306
72490
|
}
|
|
72307
72491
|
async function initHarness(options) {
|
|
72308
|
-
const repoPath =
|
|
72492
|
+
const repoPath = path48.resolve(options.repoPath);
|
|
72309
72493
|
if (!fs42.existsSync(repoPath)) {
|
|
72310
72494
|
throw new Error(`Path not found: ${repoPath}`);
|
|
72311
72495
|
}
|
|
@@ -72326,7 +72510,7 @@ async function initHarness(options) {
|
|
|
72326
72510
|
};
|
|
72327
72511
|
}
|
|
72328
72512
|
async function maintainHarness(options) {
|
|
72329
|
-
const repoPath =
|
|
72513
|
+
const repoPath = path48.resolve(options.repoPath);
|
|
72330
72514
|
const harnessDir = getHarnessDir(repoPath);
|
|
72331
72515
|
if (!fs42.existsSync(harnessDir)) {
|
|
72332
72516
|
throw new Error('No .har/ found. Run "har env init" first.');
|
|
@@ -72364,12 +72548,12 @@ function addPlugin(repoPath, pluginId, options = {}) {
|
|
|
72364
72548
|
|
|
72365
72549
|
// src/harness/custom-stage.ts
|
|
72366
72550
|
var fs43 = __toESM(require("fs"));
|
|
72367
|
-
var
|
|
72551
|
+
var path49 = __toESM(require("path"));
|
|
72368
72552
|
init_schema2();
|
|
72369
72553
|
init_stages();
|
|
72370
72554
|
var STAGE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
72371
72555
|
function addCustomStage(repoPath, options) {
|
|
72372
|
-
const resolved =
|
|
72556
|
+
const resolved = path49.resolve(repoPath);
|
|
72373
72557
|
if (!harnessExists(resolved)) {
|
|
72374
72558
|
throw new Error('No .har/ harness found. Run "har env init" first.');
|
|
72375
72559
|
}
|
|
@@ -72406,18 +72590,18 @@ function addCustomStage(repoPath, options) {
|
|
|
72406
72590
|
if (options.command) {
|
|
72407
72591
|
stage.command = options.command;
|
|
72408
72592
|
} else {
|
|
72409
|
-
const scriptRel =
|
|
72410
|
-
const scriptAbs =
|
|
72593
|
+
const scriptRel = path49.join("stages", `${id}.sh`);
|
|
72594
|
+
const scriptAbs = path49.join(resolved, ".har", scriptRel);
|
|
72411
72595
|
if (fs43.existsSync(scriptAbs) && !options.force) {
|
|
72412
72596
|
throw new Error(`Stage script already exists: .har/${scriptRel}. Use --force to overwrite.`);
|
|
72413
72597
|
}
|
|
72414
|
-
const skeletonPath =
|
|
72598
|
+
const skeletonPath = path49.join(
|
|
72415
72599
|
resolveTemplatesDir(),
|
|
72416
72600
|
"plugins",
|
|
72417
72601
|
"custom-stage-skeleton.sh"
|
|
72418
72602
|
);
|
|
72419
72603
|
const skeleton = fs43.readFileSync(skeletonPath, "utf8").replace(/__STAGE_ID__/g, id).replace(/__STAGE_KIND__/g, kind).replace(/__STAGE_DESCRIPTION__/g, stage.description);
|
|
72420
|
-
fs43.mkdirSync(
|
|
72604
|
+
fs43.mkdirSync(path49.dirname(scriptAbs), { recursive: true });
|
|
72421
72605
|
fs43.writeFileSync(scriptAbs, skeleton);
|
|
72422
72606
|
fs43.chmodSync(scriptAbs, 493);
|
|
72423
72607
|
filesWritten.push(`.har/${scriptRel}`);
|
|
@@ -72468,7 +72652,7 @@ function addCustomStage(repoPath, options) {
|
|
|
72468
72652
|
|
|
72469
72653
|
// src/harness/adaptation-prompt.ts
|
|
72470
72654
|
var fs44 = __toESM(require("fs"));
|
|
72471
|
-
var
|
|
72655
|
+
var path50 = __toESM(require("path"));
|
|
72472
72656
|
var readline5 = __toESM(require("readline"));
|
|
72473
72657
|
|
|
72474
72658
|
// src/utils/clipboard.ts
|
|
@@ -72580,7 +72764,7 @@ function buildMaintainAdaptationPrompt(_repoPath, bundleReport) {
|
|
|
72580
72764
|
}
|
|
72581
72765
|
function writeAdaptationPrompt(repoPath, content) {
|
|
72582
72766
|
const harnessDir = getHarnessDir(repoPath);
|
|
72583
|
-
const filePath =
|
|
72767
|
+
const filePath = path50.join(harnessDir, ADAPTATION_PROMPT_FILE);
|
|
72584
72768
|
writeFileSafe(filePath, content);
|
|
72585
72769
|
return filePath;
|
|
72586
72770
|
}
|
|
@@ -72599,12 +72783,12 @@ function printAdaptationPrompt(content) {
|
|
|
72599
72783
|
}
|
|
72600
72784
|
function askYesNo2(question) {
|
|
72601
72785
|
const rl = readline5.createInterface({ input: process.stdin, output: process.stderr });
|
|
72602
|
-
return new Promise((
|
|
72786
|
+
return new Promise((resolve52) => {
|
|
72603
72787
|
process.stderr.write(`${question} `);
|
|
72604
72788
|
rl.once("line", (answer) => {
|
|
72605
72789
|
rl.close();
|
|
72606
72790
|
const trimmed = answer.trim();
|
|
72607
|
-
|
|
72791
|
+
resolve52(trimmed === "" || /^y(es)?$/i.test(trimmed));
|
|
72608
72792
|
});
|
|
72609
72793
|
});
|
|
72610
72794
|
}
|
|
@@ -72636,16 +72820,16 @@ async function offerAdaptationPromptClipboard(content, options = {}) {
|
|
|
72636
72820
|
|
|
72637
72821
|
// src/harness/cursor-rule.ts
|
|
72638
72822
|
var fs45 = __toESM(require("fs"));
|
|
72639
|
-
var
|
|
72823
|
+
var path51 = __toESM(require("path"));
|
|
72640
72824
|
var readline6 = __toESM(require("readline"));
|
|
72641
72825
|
init_file_ops();
|
|
72642
72826
|
init_logging();
|
|
72643
72827
|
var CURSOR_RULE_RELATIVE_PATH = ".cursor/rules/har-workflow.mdc";
|
|
72644
72828
|
function getCursorRulePath(repoPath) {
|
|
72645
|
-
return
|
|
72829
|
+
return path51.join(repoPath, CURSOR_RULE_RELATIVE_PATH);
|
|
72646
72830
|
}
|
|
72647
72831
|
function isCursorWorkspace(repoPath) {
|
|
72648
|
-
return fs45.existsSync(
|
|
72832
|
+
return fs45.existsSync(path51.join(repoPath, ".cursor"));
|
|
72649
72833
|
}
|
|
72650
72834
|
function cursorRuleExists(repoPath) {
|
|
72651
72835
|
return fs45.existsSync(getCursorRulePath(repoPath));
|
|
@@ -72693,16 +72877,16 @@ async function promptScaffoldCursorRule(exists) {
|
|
|
72693
72877
|
}
|
|
72694
72878
|
async function askYesNo3(question) {
|
|
72695
72879
|
const rl = readline6.createInterface({ input: process.stdin, output: process.stderr });
|
|
72696
|
-
return new Promise((
|
|
72880
|
+
return new Promise((resolve52) => {
|
|
72697
72881
|
process.stderr.write(`${question} `);
|
|
72698
72882
|
rl.once("line", (answer) => {
|
|
72699
72883
|
rl.close();
|
|
72700
72884
|
const trimmed = answer.trim();
|
|
72701
72885
|
if (trimmed === "") {
|
|
72702
|
-
|
|
72886
|
+
resolve52(true);
|
|
72703
72887
|
return;
|
|
72704
72888
|
}
|
|
72705
|
-
|
|
72889
|
+
resolve52(/^y(es)?$/i.test(trimmed));
|
|
72706
72890
|
});
|
|
72707
72891
|
});
|
|
72708
72892
|
}
|
|
@@ -72745,7 +72929,7 @@ init_control_config();
|
|
|
72745
72929
|
|
|
72746
72930
|
// src/core/control-lifecycle.ts
|
|
72747
72931
|
var import_child_process13 = require("child_process");
|
|
72748
|
-
var
|
|
72932
|
+
var path52 = __toESM(require("path"));
|
|
72749
72933
|
|
|
72750
72934
|
// src/core/control-image.ts
|
|
72751
72935
|
init_package_version();
|
|
@@ -72772,10 +72956,10 @@ var CONTROL_DATA_VOLUME = "har_control_data";
|
|
|
72772
72956
|
var CONTROL_CONTAINER_PORT = 3847;
|
|
72773
72957
|
var CONTROL_DATA_DB_URL = "file:/data/har_control.db";
|
|
72774
72958
|
function resolveControlDir() {
|
|
72775
|
-
return
|
|
72959
|
+
return path52.resolve(__dirname, "..", "control");
|
|
72776
72960
|
}
|
|
72777
72961
|
function resolveControlBuildContext() {
|
|
72778
|
-
return
|
|
72962
|
+
return path52.resolve(resolveControlDir(), "..");
|
|
72779
72963
|
}
|
|
72780
72964
|
function buildDockerRunArgs(options) {
|
|
72781
72965
|
const name = options.containerName ?? CONTROL_CONTAINER_NAME;
|
|
@@ -72831,7 +73015,7 @@ async function startMissionControl(options) {
|
|
|
72831
73015
|
"-t",
|
|
72832
73016
|
imageRef,
|
|
72833
73017
|
"-f",
|
|
72834
|
-
|
|
73018
|
+
path52.join(resolveControlDir(), "Dockerfile"),
|
|
72835
73019
|
resolveControlBuildContext()
|
|
72836
73020
|
]);
|
|
72837
73021
|
if (buildCode !== 0) {
|
|
@@ -72978,7 +73162,7 @@ async function ensureTelemetryInfrastructure(options) {
|
|
|
72978
73162
|
// src/core/run-service.ts
|
|
72979
73163
|
init_telemetry_config();
|
|
72980
73164
|
init_telemetry_env();
|
|
72981
|
-
var
|
|
73165
|
+
var path54 = __toESM(require("path"));
|
|
72982
73166
|
init_local_executor();
|
|
72983
73167
|
function extractShellOutput(result) {
|
|
72984
73168
|
const stdout = result.logs?.find((log) => log.stream === "stdout")?.content ?? result.logs?.find((log) => !log.stream)?.content ?? "";
|
|
@@ -73184,12 +73368,12 @@ Usage from Cursor / Claude / Codex (@osfactory/otel-hook) will appear under Work
|
|
|
73184
73368
|
suffix: session.suffix,
|
|
73185
73369
|
createdAt: session.createdAt
|
|
73186
73370
|
});
|
|
73187
|
-
const envFile =
|
|
73371
|
+
const envFile = path54.join(session.workDir, `.env.agent.${options.agentId}`);
|
|
73188
73372
|
try {
|
|
73189
73373
|
appendTelemetryEnvToFile(envFile, {
|
|
73190
73374
|
sessionKey,
|
|
73191
73375
|
agentId: options.agentId,
|
|
73192
|
-
repoPath:
|
|
73376
|
+
repoPath: path54.resolve(options.repoPath),
|
|
73193
73377
|
workDir: session.workDir,
|
|
73194
73378
|
branch: session.branch,
|
|
73195
73379
|
suffix: session.suffix,
|
|
@@ -73428,7 +73612,7 @@ init_slot_status();
|
|
|
73428
73612
|
// src/core/cleanup-service.ts
|
|
73429
73613
|
var fs47 = __toESM(require("fs"));
|
|
73430
73614
|
var os20 = __toESM(require("os"));
|
|
73431
|
-
var
|
|
73615
|
+
var path55 = __toESM(require("path"));
|
|
73432
73616
|
var import_child_process15 = require("child_process");
|
|
73433
73617
|
init_control_sync();
|
|
73434
73618
|
init_control_repo_path();
|
|
@@ -73437,9 +73621,9 @@ init_manifest();
|
|
|
73437
73621
|
var DEFAULT_STALE_DAYS = 7;
|
|
73438
73622
|
function getWorktreesRoot() {
|
|
73439
73623
|
if (process.env.HAR_WORKTREES_ROOT) {
|
|
73440
|
-
return
|
|
73624
|
+
return path55.resolve(process.env.HAR_WORKTREES_ROOT);
|
|
73441
73625
|
}
|
|
73442
|
-
return
|
|
73626
|
+
return path55.join(process.env.HOME || os20.homedir(), "worktrees");
|
|
73443
73627
|
}
|
|
73444
73628
|
function runGit3(cwd, args) {
|
|
73445
73629
|
try {
|
|
@@ -73453,7 +73637,7 @@ function runGit3(cwd, args) {
|
|
|
73453
73637
|
}
|
|
73454
73638
|
}
|
|
73455
73639
|
function basenameRepo(repoPath) {
|
|
73456
|
-
return
|
|
73640
|
+
return path55.basename(canonicalizeControlRepoPath(repoPath));
|
|
73457
73641
|
}
|
|
73458
73642
|
function ageDaysFrom(iso) {
|
|
73459
73643
|
if (!iso) return void 0;
|
|
@@ -73465,12 +73649,12 @@ function matchesKeep(candidate, keep) {
|
|
|
73465
73649
|
if (!keep?.length) return false;
|
|
73466
73650
|
for (const pin of keep) {
|
|
73467
73651
|
if (pin.worktreePath && candidate.worktreePath) {
|
|
73468
|
-
if (
|
|
73652
|
+
if (path55.resolve(pin.worktreePath) === path55.resolve(candidate.worktreePath)) return true;
|
|
73469
73653
|
}
|
|
73470
73654
|
if (pin.repoPath && pin.agentId !== void 0 && candidate.agentId !== void 0) {
|
|
73471
73655
|
const repo = canonicalizeControlRepoPath(pin.repoPath);
|
|
73472
|
-
const candidateRepo =
|
|
73473
|
-
if ((repo === candidateRepo ||
|
|
73656
|
+
const candidateRepo = path55.resolve(candidate.repoPath);
|
|
73657
|
+
if ((repo === candidateRepo || path55.resolve(pin.repoPath) === candidateRepo) && pin.agentId === candidate.agentId) {
|
|
73474
73658
|
return true;
|
|
73475
73659
|
}
|
|
73476
73660
|
}
|
|
@@ -73528,7 +73712,7 @@ function resolveRepoForWorktree(worktreePath) {
|
|
|
73528
73712
|
if (!fs47.existsSync(worktreePath)) return void 0;
|
|
73529
73713
|
const commonDir = runGit3(worktreePath, "rev-parse --git-common-dir");
|
|
73530
73714
|
if (!commonDir) return void 0;
|
|
73531
|
-
const gitRoot =
|
|
73715
|
+
const gitRoot = path55.resolve(worktreePath, commonDir, "..");
|
|
73532
73716
|
if (!readManifest(gitRoot)) return void 0;
|
|
73533
73717
|
return canonicalizeControlRepoPath(gitRoot);
|
|
73534
73718
|
}
|
|
@@ -73538,7 +73722,7 @@ function discoverOrphanWorktrees(knownPaths) {
|
|
|
73538
73722
|
const orphans = [];
|
|
73539
73723
|
for (const entry of fs47.readdirSync(worktreesRoot, { withFileTypes: true })) {
|
|
73540
73724
|
if (!entry.isDirectory() || !entry.name.includes("-har-agent-")) continue;
|
|
73541
|
-
const worktreePath =
|
|
73725
|
+
const worktreePath = path55.resolve(path55.join(worktreesRoot, entry.name));
|
|
73542
73726
|
if (knownPaths.has(worktreePath)) continue;
|
|
73543
73727
|
const repoPath = resolveRepoForWorktree(worktreePath) ?? worktreesRoot;
|
|
73544
73728
|
const porcelain = runGit3(worktreePath, "status --porcelain");
|
|
@@ -73569,8 +73753,8 @@ async function discoverCleanupCandidates(options = {}) {
|
|
|
73569
73753
|
const status = collectEnvironmentStatus(harnessRoot);
|
|
73570
73754
|
const projectName = basenameRepo(harnessRoot);
|
|
73571
73755
|
for (const slot of status.slots) {
|
|
73572
|
-
if (slot.worktreePath) knownWorktreePaths.add(
|
|
73573
|
-
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));
|
|
73574
73758
|
const candidate = classifySlotCandidate(canonicalRepo, projectName, slot, {
|
|
73575
73759
|
staleDays: options.staleDays,
|
|
73576
73760
|
keep: options.keep
|
|
@@ -73630,8 +73814,8 @@ async function askYesNo4(question) {
|
|
|
73630
73814
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
73631
73815
|
const readline8 = await import("readline");
|
|
73632
73816
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
73633
|
-
const answer = await new Promise((
|
|
73634
|
-
rl.question(question,
|
|
73817
|
+
const answer = await new Promise((resolve52) => {
|
|
73818
|
+
rl.question(question, resolve52);
|
|
73635
73819
|
});
|
|
73636
73820
|
rl.close();
|
|
73637
73821
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -73714,7 +73898,7 @@ function parseCleanupKeepPins(values) {
|
|
|
73714
73898
|
}
|
|
73715
73899
|
if (raw.startsWith("/") || raw.startsWith("~")) {
|
|
73716
73900
|
return {
|
|
73717
|
-
worktreePath: raw.startsWith("~") ?
|
|
73901
|
+
worktreePath: raw.startsWith("~") ? path55.join(process.env.HOME || os20.homedir(), raw.slice(2)) : path55.resolve(raw)
|
|
73718
73902
|
};
|
|
73719
73903
|
}
|
|
73720
73904
|
return { repoPath: raw };
|
|
@@ -73728,12 +73912,12 @@ init_stages();
|
|
|
73728
73912
|
init_logging();
|
|
73729
73913
|
function askYesNo5(question) {
|
|
73730
73914
|
const rl = readline7.createInterface({ input: process.stdin, output: process.stderr });
|
|
73731
|
-
return new Promise((
|
|
73915
|
+
return new Promise((resolve52) => {
|
|
73732
73916
|
process.stderr.write(`${question} `);
|
|
73733
73917
|
rl.once("line", (answer) => {
|
|
73734
73918
|
rl.close();
|
|
73735
73919
|
const trimmed = answer.trim();
|
|
73736
|
-
|
|
73920
|
+
resolve52(trimmed === "" || /^y(es)?$/i.test(trimmed));
|
|
73737
73921
|
});
|
|
73738
73922
|
});
|
|
73739
73923
|
}
|
|
@@ -73836,13 +74020,13 @@ function warnIfDockerUnavailable(status = detectDockerStatus()) {
|
|
|
73836
74020
|
// src/core/onboarding-preferences.ts
|
|
73837
74021
|
var fs48 = __toESM(require("fs"));
|
|
73838
74022
|
var os21 = __toESM(require("os"));
|
|
73839
|
-
var
|
|
74023
|
+
var path56 = __toESM(require("path"));
|
|
73840
74024
|
init_schema2();
|
|
73841
74025
|
function getOnboardingPreferencesPath() {
|
|
73842
74026
|
if (process.env.HAR_PREFERENCES_PATH) {
|
|
73843
|
-
return
|
|
74027
|
+
return path56.resolve(process.env.HAR_PREFERENCES_PATH);
|
|
73844
74028
|
}
|
|
73845
|
-
return
|
|
74029
|
+
return path56.join(os21.homedir(), ".har", "preferences.json");
|
|
73846
74030
|
}
|
|
73847
74031
|
function readOnboardingPreferences() {
|
|
73848
74032
|
const preferencePath = getOnboardingPreferencesPath();
|
|
@@ -73873,7 +74057,7 @@ function writeOnboardingPreferences(overrides) {
|
|
|
73873
74057
|
};
|
|
73874
74058
|
const parsed = OnboardingPreferencesSchema.parse(preference);
|
|
73875
74059
|
const preferencePath = getOnboardingPreferencesPath();
|
|
73876
|
-
fs48.mkdirSync(
|
|
74060
|
+
fs48.mkdirSync(path56.dirname(preferencePath), { recursive: true });
|
|
73877
74061
|
fs48.writeFileSync(preferencePath, `${JSON.stringify(parsed, null, 2)}
|
|
73878
74062
|
`);
|
|
73879
74063
|
return parsed;
|
|
@@ -74219,7 +74403,7 @@ var envCommand = {
|
|
|
74219
74403
|
}
|
|
74220
74404
|
};
|
|
74221
74405
|
async function handleInit(argv) {
|
|
74222
|
-
const repoPath =
|
|
74406
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74223
74407
|
const onboarding = resolveOnboardingOptions(argv);
|
|
74224
74408
|
header("har env init");
|
|
74225
74409
|
info(`Repository: ${repoPath}`);
|
|
@@ -74266,7 +74450,7 @@ async function handleInit(argv) {
|
|
|
74266
74450
|
}
|
|
74267
74451
|
}
|
|
74268
74452
|
async function handleMaintain(argv) {
|
|
74269
|
-
const repoPath =
|
|
74453
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74270
74454
|
const onboarding = resolveOnboardingOptions(argv);
|
|
74271
74455
|
header("har env maintain");
|
|
74272
74456
|
info(`Repository: ${repoPath}`);
|
|
@@ -74397,7 +74581,7 @@ async function applyAgentIntegrations(options) {
|
|
|
74397
74581
|
}
|
|
74398
74582
|
}
|
|
74399
74583
|
async function handleAddPlugin(argv) {
|
|
74400
|
-
const repoPath =
|
|
74584
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74401
74585
|
const available = listPluginIds();
|
|
74402
74586
|
if (argv.list) {
|
|
74403
74587
|
for (const id of available) {
|
|
@@ -74437,7 +74621,7 @@ async function handleAddPlugin(argv) {
|
|
|
74437
74621
|
}
|
|
74438
74622
|
}
|
|
74439
74623
|
async function handleAddStage(argv) {
|
|
74440
|
-
const repoPath =
|
|
74624
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74441
74625
|
const available = listPluginIds();
|
|
74442
74626
|
if (argv.list) {
|
|
74443
74627
|
warn("har env add-stage --list is deprecated; prefer: har env add-plugin --list");
|
|
@@ -74503,7 +74687,7 @@ async function handleAddStage(argv) {
|
|
|
74503
74687
|
});
|
|
74504
74688
|
}
|
|
74505
74689
|
async function handlePreflight(argv) {
|
|
74506
|
-
const repo =
|
|
74690
|
+
const repo = path57.resolve(argv.repo);
|
|
74507
74691
|
const agentId = validateAgentId(argv.id, repo);
|
|
74508
74692
|
const result = await preflightEnvironment({
|
|
74509
74693
|
repoPath: repo,
|
|
@@ -74519,7 +74703,7 @@ async function handlePreflight(argv) {
|
|
|
74519
74703
|
return finishCommand(result.code);
|
|
74520
74704
|
}
|
|
74521
74705
|
async function handleLaunch(argv) {
|
|
74522
|
-
const repo =
|
|
74706
|
+
const repo = path57.resolve(argv.repo);
|
|
74523
74707
|
const agentId = validateAgentId(argv.id, repo);
|
|
74524
74708
|
if (!argv.resume) {
|
|
74525
74709
|
const guard = checkLaunchGuard2(repo, agentId, { worktree: argv.worktree });
|
|
@@ -74568,7 +74752,7 @@ async function handleWorkLink(argv) {
|
|
|
74568
74752
|
error("Provide --link or both --source and --url");
|
|
74569
74753
|
return finishCommand(1);
|
|
74570
74754
|
}
|
|
74571
|
-
const harnessRoot = resolveHarnessRoot(
|
|
74755
|
+
const harnessRoot = resolveHarnessRoot(path57.resolve(argv.repo));
|
|
74572
74756
|
const links = argv.link ? [parseWorkLinkSpec(argv.link)] : [{ source: argv.source, url: argv.url, label: argv.label }];
|
|
74573
74757
|
try {
|
|
74574
74758
|
const record2 = addWorkUnitLinks(harnessRoot, argv.workId, links);
|
|
@@ -74594,7 +74778,7 @@ async function handleRecover(argv) {
|
|
|
74594
74778
|
});
|
|
74595
74779
|
}
|
|
74596
74780
|
async function handleVerify(argv) {
|
|
74597
|
-
const repo =
|
|
74781
|
+
const repo = path57.resolve(argv.repo);
|
|
74598
74782
|
const agentId = validateAgentId(argv.id, repo);
|
|
74599
74783
|
const result = await runVerification({
|
|
74600
74784
|
repoPath: repo,
|
|
@@ -74623,7 +74807,7 @@ async function handleVerify(argv) {
|
|
|
74623
74807
|
return finishCommand(result.code);
|
|
74624
74808
|
}
|
|
74625
74809
|
async function handleTeardown(argv) {
|
|
74626
|
-
const repo =
|
|
74810
|
+
const repo = path57.resolve(argv.repo);
|
|
74627
74811
|
const agentId = validateAgentId(argv.id, repo);
|
|
74628
74812
|
const result = await teardownEnvironment({
|
|
74629
74813
|
repoPath: repo,
|
|
@@ -74634,7 +74818,7 @@ async function handleTeardown(argv) {
|
|
|
74634
74818
|
return finishCommand(result.code);
|
|
74635
74819
|
}
|
|
74636
74820
|
async function handleComplete(argv) {
|
|
74637
|
-
const repo =
|
|
74821
|
+
const repo = path57.resolve(argv.repo);
|
|
74638
74822
|
const agentId = validateAgentId(argv.id, repo);
|
|
74639
74823
|
const result = await completeEnvironment({
|
|
74640
74824
|
repoPath: repo,
|
|
@@ -74655,7 +74839,7 @@ async function handleComplete(argv) {
|
|
|
74655
74839
|
return finishCommand(result.code);
|
|
74656
74840
|
}
|
|
74657
74841
|
async function handleStatus(argv) {
|
|
74658
|
-
const repoPath =
|
|
74842
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74659
74843
|
if (argv.json) {
|
|
74660
74844
|
const status = collectEnvironmentStatus(repoPath);
|
|
74661
74845
|
const output = EnvironmentStatusSchema.parse(status);
|
|
@@ -74670,7 +74854,7 @@ async function handleStatus(argv) {
|
|
|
74670
74854
|
async function handleCleanup(argv) {
|
|
74671
74855
|
const keepValues = argv.keep?.split(",").map((value) => value.trim()).filter(Boolean);
|
|
74672
74856
|
const keep = parseCleanupKeepPins(keepValues);
|
|
74673
|
-
const repoPaths = argv.repo ? [
|
|
74857
|
+
const repoPaths = argv.repo ? [path57.resolve(argv.repo)] : void 0;
|
|
74674
74858
|
const plan = await discoverCleanupCandidates({
|
|
74675
74859
|
cwd: process.cwd(),
|
|
74676
74860
|
repoPaths,
|
|
@@ -74719,7 +74903,7 @@ async function handleCleanup(argv) {
|
|
|
74719
74903
|
return finishCommand(failed > 0 ? 1 : 0);
|
|
74720
74904
|
}
|
|
74721
74905
|
async function handleRunsList(argv) {
|
|
74722
|
-
const repoPath =
|
|
74906
|
+
const repoPath = path57.resolve(argv.repo);
|
|
74723
74907
|
const runs = listRuns(repoPath, { stageId: argv.stage, limit: argv.limit });
|
|
74724
74908
|
if (argv.json) {
|
|
74725
74909
|
process.stdout.write(JSON.stringify({ runs }, null, 2) + "\n");
|
|
@@ -74736,7 +74920,7 @@ async function handleRunsList(argv) {
|
|
|
74736
74920
|
}
|
|
74737
74921
|
}
|
|
74738
74922
|
async function handleRunsGet(argv) {
|
|
74739
|
-
const run2 = getRun(
|
|
74923
|
+
const run2 = getRun(path57.resolve(argv.repo), argv.runId);
|
|
74740
74924
|
if (!run2) {
|
|
74741
74925
|
error(`Run not found: ${argv.runId}`);
|
|
74742
74926
|
return finishCommand(1);
|
|
@@ -74813,7 +74997,7 @@ function printNextSteps() {
|
|
|
74813
74997
|
}
|
|
74814
74998
|
|
|
74815
74999
|
// src/cli/commands/control.ts
|
|
74816
|
-
var
|
|
75000
|
+
var path62 = __toESM(require("path"));
|
|
74817
75001
|
init_control_config();
|
|
74818
75002
|
init_portal_targets();
|
|
74819
75003
|
|
|
@@ -74822,7 +75006,7 @@ init_control_config();
|
|
|
74822
75006
|
|
|
74823
75007
|
// src/core/portal-connect.ts
|
|
74824
75008
|
var fs49 = __toESM(require("fs"));
|
|
74825
|
-
var
|
|
75009
|
+
var path58 = __toESM(require("path"));
|
|
74826
75010
|
var import_crypto2 = require("crypto");
|
|
74827
75011
|
init_control_repo_path();
|
|
74828
75012
|
init_control_registry();
|
|
@@ -74868,7 +75052,7 @@ async function loginViaBrowser(portalUrl, openUrlOrOptions = openBrowser) {
|
|
|
74868
75052
|
const options = typeof openUrlOrOptions === "function" ? { openUrl: openUrlOrOptions } : openUrlOrOptions;
|
|
74869
75053
|
const openUrl = options.openUrl ?? openBrowser;
|
|
74870
75054
|
const state = (0, import_crypto.randomUUID)();
|
|
74871
|
-
return new Promise((
|
|
75055
|
+
return new Promise((resolve52, reject) => {
|
|
74872
75056
|
let timer;
|
|
74873
75057
|
const server = http.createServer((req, res) => {
|
|
74874
75058
|
const requestUrl = new URL(req.url ?? "", "http://127.0.0.1");
|
|
@@ -74896,7 +75080,7 @@ async function loginViaBrowser(portalUrl, openUrlOrOptions = openBrowser) {
|
|
|
74896
75080
|
res.end("<h1>Logged in</h1><p>You can close this tab and return to the terminal.</p>");
|
|
74897
75081
|
cleanup();
|
|
74898
75082
|
const targets = parseCliTargetsParam(requestUrl.searchParams.get("targets"));
|
|
74899
|
-
|
|
75083
|
+
resolve52({
|
|
74900
75084
|
portalUrl,
|
|
74901
75085
|
token,
|
|
74902
75086
|
workspace: workspaceSlug ?? workspace,
|
|
@@ -74991,7 +75175,7 @@ function remainingConnections(connections, usedAliases) {
|
|
|
74991
75175
|
// src/core/portal-connect.ts
|
|
74992
75176
|
init_portal_targets();
|
|
74993
75177
|
function attachRepoIfPresent(alias, repoPath) {
|
|
74994
|
-
const resolved =
|
|
75178
|
+
const resolved = path58.resolve(repoPath ?? ".");
|
|
74995
75179
|
if (!fs49.existsSync(resolved)) return null;
|
|
74996
75180
|
const canonical = canonicalizeControlRepoPath(resolved);
|
|
74997
75181
|
attachRepoPortalTarget(canonical, alias);
|
|
@@ -75059,7 +75243,7 @@ async function runPortalConnect(input) {
|
|
|
75059
75243
|
return { record: record2, attachedRepo, extraAttached, mappedInBrowser: true };
|
|
75060
75244
|
}
|
|
75061
75245
|
function listRegisteredReposForConnect(repoPath) {
|
|
75062
|
-
const resolved = repoPath ?
|
|
75246
|
+
const resolved = repoPath ? path58.resolve(repoPath) : null;
|
|
75063
75247
|
const current = resolved && fs49.existsSync(resolved) ? canonicalizeControlRepoPath(resolved) : null;
|
|
75064
75248
|
return [.../* @__PURE__ */ new Set([...current ? [current] : [], ...listRegisteredRepos()])];
|
|
75065
75249
|
}
|
|
@@ -75378,13 +75562,13 @@ init_control_sync();
|
|
|
75378
75562
|
// src/core/control-sync-selection.ts
|
|
75379
75563
|
var fs50 = __toESM(require("fs"));
|
|
75380
75564
|
var os22 = __toESM(require("os"));
|
|
75381
|
-
var
|
|
75565
|
+
var path59 = __toESM(require("path"));
|
|
75382
75566
|
init_control_repo_path();
|
|
75383
75567
|
function getSelectionPath() {
|
|
75384
75568
|
if (process.env.HAR_CONTROL_SYNC_SELECTION_PATH) {
|
|
75385
|
-
return
|
|
75569
|
+
return path59.resolve(process.env.HAR_CONTROL_SYNC_SELECTION_PATH);
|
|
75386
75570
|
}
|
|
75387
|
-
return
|
|
75571
|
+
return path59.join(os22.homedir(), ".har", "sync-selection.json");
|
|
75388
75572
|
}
|
|
75389
75573
|
function readSyncSelection() {
|
|
75390
75574
|
const selectionPath = getSelectionPath();
|
|
@@ -75400,7 +75584,7 @@ function readSyncSelection() {
|
|
|
75400
75584
|
function writeSyncSelection(repos) {
|
|
75401
75585
|
const selectionPath = getSelectionPath();
|
|
75402
75586
|
const canonical = Array.from(new Set(repos.map((repoPath) => canonicalizeControlRepoPath(repoPath))));
|
|
75403
|
-
fs50.mkdirSync(
|
|
75587
|
+
fs50.mkdirSync(path59.dirname(selectionPath), { recursive: true });
|
|
75404
75588
|
fs50.writeFileSync(selectionPath, JSON.stringify({ repos: canonical }, null, 2) + "\n");
|
|
75405
75589
|
}
|
|
75406
75590
|
function resolveSyncSelection(input) {
|
|
@@ -75429,7 +75613,7 @@ function resolveSyncSelection(input) {
|
|
|
75429
75613
|
|
|
75430
75614
|
// src/core/control-unregister.ts
|
|
75431
75615
|
var fs51 = __toESM(require("fs"));
|
|
75432
|
-
var
|
|
75616
|
+
var path60 = __toESM(require("path"));
|
|
75433
75617
|
init_control_repo_path();
|
|
75434
75618
|
init_control_registry();
|
|
75435
75619
|
init_control_config();
|
|
@@ -75439,7 +75623,7 @@ function listUnregisterWorktreeCandidates(repoPath) {
|
|
|
75439
75623
|
const harnessRoot = canonicalizeControlRepoPath(repoPath);
|
|
75440
75624
|
const byPath = /* @__PURE__ */ new Map();
|
|
75441
75625
|
const add = (partial2) => {
|
|
75442
|
-
const resolved =
|
|
75626
|
+
const resolved = path60.resolve(partial2.worktreePath);
|
|
75443
75627
|
if (!resolved || resolved === harnessRoot) return;
|
|
75444
75628
|
const exists = partial2.exists ?? fs51.existsSync(resolved);
|
|
75445
75629
|
const prev = byPath.get(resolved);
|
|
@@ -75492,8 +75676,8 @@ async function askYesNo6(question) {
|
|
|
75492
75676
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
75493
75677
|
const readline8 = await import("readline");
|
|
75494
75678
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
75495
|
-
const answer = await new Promise((
|
|
75496
|
-
rl.question(question,
|
|
75679
|
+
const answer = await new Promise((resolve52) => {
|
|
75680
|
+
rl.question(question, resolve52);
|
|
75497
75681
|
});
|
|
75498
75682
|
rl.close();
|
|
75499
75683
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -75640,15 +75824,15 @@ init_control_registry();
|
|
|
75640
75824
|
|
|
75641
75825
|
// src/core/harness-scrub.ts
|
|
75642
75826
|
var fs52 = __toESM(require("fs"));
|
|
75643
|
-
var
|
|
75827
|
+
var path61 = __toESM(require("path"));
|
|
75644
75828
|
var HARNESS_SCRUB_DIRS = ["runs", "validations", "state", "slots"];
|
|
75645
75829
|
function scrubLocalHarnessDirs(repoPath) {
|
|
75646
75830
|
const results = [];
|
|
75647
|
-
const resolved =
|
|
75831
|
+
const resolved = path61.resolve(repoPath);
|
|
75648
75832
|
if (!fs52.existsSync(resolved)) {
|
|
75649
75833
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
75650
75834
|
results.push({
|
|
75651
|
-
path:
|
|
75835
|
+
path: path61.join(resolved, ".har", directory),
|
|
75652
75836
|
directory,
|
|
75653
75837
|
deleted: false,
|
|
75654
75838
|
error: "repository path does not exist"
|
|
@@ -75657,7 +75841,7 @@ function scrubLocalHarnessDirs(repoPath) {
|
|
|
75657
75841
|
return results;
|
|
75658
75842
|
}
|
|
75659
75843
|
for (const directory of HARNESS_SCRUB_DIRS) {
|
|
75660
|
-
const target =
|
|
75844
|
+
const target = path61.join(resolved, ".har", directory);
|
|
75661
75845
|
if (!fs52.existsSync(target)) {
|
|
75662
75846
|
results.push({ path: target, directory, deleted: true });
|
|
75663
75847
|
continue;
|
|
@@ -75685,7 +75869,7 @@ function scrubLocalHarnessForRepos(repoPaths) {
|
|
|
75685
75869
|
const results = [];
|
|
75686
75870
|
const seen = /* @__PURE__ */ new Set();
|
|
75687
75871
|
for (const repoPath of repoPaths) {
|
|
75688
|
-
const key =
|
|
75872
|
+
const key = path61.resolve(repoPath);
|
|
75689
75873
|
if (seen.has(key)) continue;
|
|
75690
75874
|
seen.add(key);
|
|
75691
75875
|
results.push(...scrubLocalHarnessDirs(key));
|
|
@@ -75698,8 +75882,8 @@ async function askYesNo7(question) {
|
|
|
75698
75882
|
if (!process.stdin.isTTY || !process.stdout.isTTY) return false;
|
|
75699
75883
|
const readline8 = await import("readline");
|
|
75700
75884
|
const rl = readline8.createInterface({ input: process.stdin, output: process.stderr });
|
|
75701
|
-
const answer = await new Promise((
|
|
75702
|
-
rl.question(question,
|
|
75885
|
+
const answer = await new Promise((resolve52) => {
|
|
75886
|
+
rl.question(question, resolve52);
|
|
75703
75887
|
});
|
|
75704
75888
|
rl.close();
|
|
75705
75889
|
return /^[Yy]$/.test(answer.trim());
|
|
@@ -75978,7 +76162,7 @@ async function handleDown() {
|
|
|
75978
76162
|
return finishCommand(code);
|
|
75979
76163
|
}
|
|
75980
76164
|
async function handleRegister(argv) {
|
|
75981
|
-
const repoPath =
|
|
76165
|
+
const repoPath = path62.resolve(argv.repo);
|
|
75982
76166
|
header("har control register");
|
|
75983
76167
|
info(`Repository: ${repoPath}`);
|
|
75984
76168
|
try {
|
|
@@ -76076,7 +76260,7 @@ async function handleReset(argv) {
|
|
|
76076
76260
|
}
|
|
76077
76261
|
}
|
|
76078
76262
|
async function handleUnregister(argv) {
|
|
76079
|
-
const repoPath =
|
|
76263
|
+
const repoPath = path62.resolve(argv.repo);
|
|
76080
76264
|
const worktrees = listUnregisterWorktreeCandidates(repoPath);
|
|
76081
76265
|
try {
|
|
76082
76266
|
let deleteWorktrees = argv.deleteWorktrees;
|
|
@@ -76214,7 +76398,7 @@ async function handleSync(argv) {
|
|
|
76214
76398
|
);
|
|
76215
76399
|
}
|
|
76216
76400
|
}
|
|
76217
|
-
const { synced, failed, results } = await syncReposWithControl({
|
|
76401
|
+
const { synced, failed, incomplete, results } = await syncReposWithControl({
|
|
76218
76402
|
repoPaths,
|
|
76219
76403
|
apiUrl: argv.apiUrl,
|
|
76220
76404
|
dryRun: argv.dryRun,
|
|
@@ -76223,7 +76407,9 @@ async function handleSync(argv) {
|
|
|
76223
76407
|
portalTargets
|
|
76224
76408
|
});
|
|
76225
76409
|
if (argv.json) {
|
|
76226
|
-
process.stdout.write(
|
|
76410
|
+
process.stdout.write(
|
|
76411
|
+
JSON.stringify({ ok: failed === 0, synced, failed, incomplete, results }, null, 2) + "\n"
|
|
76412
|
+
);
|
|
76227
76413
|
if (failed > 0) return finishCommand(1);
|
|
76228
76414
|
return;
|
|
76229
76415
|
}
|
|
@@ -76232,22 +76418,32 @@ async function handleSync(argv) {
|
|
|
76232
76418
|
for (const target of result.targets) {
|
|
76233
76419
|
const record2 = findPortalTargetRecord(target.alias);
|
|
76234
76420
|
const label = record2 ? displayPortalTargetLabel(record2) : target.alias;
|
|
76235
|
-
if (target.ok) {
|
|
76236
|
-
success(`Synced ${result.repoPath} \u2192 ${label}`);
|
|
76237
|
-
} else {
|
|
76421
|
+
if (!target.ok) {
|
|
76238
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}`);
|
|
76239
76427
|
}
|
|
76240
76428
|
}
|
|
76241
76429
|
continue;
|
|
76242
76430
|
}
|
|
76243
|
-
if (result.ok) {
|
|
76244
|
-
success(`Synced ${result.repoPath}`);
|
|
76245
|
-
} else {
|
|
76431
|
+
if (!result.ok) {
|
|
76246
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}`);
|
|
76247
76437
|
}
|
|
76248
76438
|
}
|
|
76249
|
-
if (synced >
|
|
76250
|
-
|
|
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
|
+
);
|
|
76251
76447
|
}
|
|
76252
76448
|
if (failed > 0) {
|
|
76253
76449
|
warn(`${failed} ${failed === 1 ? "repository" : "repositories"} could not be synced`);
|
|
@@ -76345,12 +76541,12 @@ async function handleTrajectory(argv) {
|
|
|
76345
76541
|
}
|
|
76346
76542
|
|
|
76347
76543
|
// src/cli/commands/hooks.ts
|
|
76348
|
-
var
|
|
76544
|
+
var path64 = __toESM(require("path"));
|
|
76349
76545
|
init_hooks();
|
|
76350
76546
|
|
|
76351
76547
|
// src/core/claude-hooks.ts
|
|
76352
76548
|
var fs53 = __toESM(require("fs"));
|
|
76353
|
-
var
|
|
76549
|
+
var path63 = __toESM(require("path"));
|
|
76354
76550
|
var CLAUDE_GUARD_RELATIVE_PATH = ".har/hooks/claude-worktree-guard.sh";
|
|
76355
76551
|
var CLAUDE_SETTINGS_RELATIVE_PATH = ".claude/settings.json";
|
|
76356
76552
|
var GUARD_MATCHER = "Edit|Write|MultiEdit|NotebookEdit";
|
|
@@ -76371,7 +76567,7 @@ function readSettings(settingsPath) {
|
|
|
76371
76567
|
return parsed;
|
|
76372
76568
|
}
|
|
76373
76569
|
function writeSettings(settingsPath, settings) {
|
|
76374
|
-
fs53.mkdirSync(
|
|
76570
|
+
fs53.mkdirSync(path63.dirname(settingsPath), { recursive: true });
|
|
76375
76571
|
fs53.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
76376
76572
|
}
|
|
76377
76573
|
function installClaudeGuard(repoPath) {
|
|
@@ -76379,11 +76575,11 @@ function installClaudeGuard(repoPath) {
|
|
|
76379
76575
|
if (!templatePath) {
|
|
76380
76576
|
throw new Error("Guard template not found (claude-worktree-guard.sh.template). Run npm run build.");
|
|
76381
76577
|
}
|
|
76382
|
-
const guardScript =
|
|
76383
|
-
fs53.mkdirSync(
|
|
76578
|
+
const guardScript = path63.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
76579
|
+
fs53.mkdirSync(path63.dirname(guardScript), { recursive: true });
|
|
76384
76580
|
fs53.copyFileSync(templatePath, guardScript);
|
|
76385
76581
|
fs53.chmodSync(guardScript, 493);
|
|
76386
|
-
const settingsPath =
|
|
76582
|
+
const settingsPath = path63.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
76387
76583
|
const settings = readSettings(settingsPath);
|
|
76388
76584
|
const hooks = settings.hooks ?? {};
|
|
76389
76585
|
const preToolUse = (hooks.PreToolUse ?? []).filter((entry) => !isHarGuardEntry(entry));
|
|
@@ -76397,14 +76593,14 @@ function installClaudeGuard(repoPath) {
|
|
|
76397
76593
|
}
|
|
76398
76594
|
function uninstallClaudeGuard(repoPath) {
|
|
76399
76595
|
let removed = false;
|
|
76400
|
-
const guardScript =
|
|
76596
|
+
const guardScript = path63.join(repoPath, CLAUDE_GUARD_RELATIVE_PATH);
|
|
76401
76597
|
if (fs53.existsSync(guardScript)) {
|
|
76402
76598
|
fs53.rmSync(guardScript);
|
|
76403
76599
|
removed = true;
|
|
76404
|
-
const parent =
|
|
76600
|
+
const parent = path63.dirname(guardScript);
|
|
76405
76601
|
if (fs53.existsSync(parent) && fs53.readdirSync(parent).length === 0) fs53.rmdirSync(parent);
|
|
76406
76602
|
}
|
|
76407
|
-
const settingsPath =
|
|
76603
|
+
const settingsPath = path63.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
76408
76604
|
if (fs53.existsSync(settingsPath)) {
|
|
76409
76605
|
const settings = readSettings(settingsPath);
|
|
76410
76606
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
@@ -76430,7 +76626,7 @@ function uninstallClaudeGuard(repoPath) {
|
|
|
76430
76626
|
return { removed };
|
|
76431
76627
|
}
|
|
76432
76628
|
function claudeGuardInstalled(repoPath) {
|
|
76433
|
-
const settingsPath =
|
|
76629
|
+
const settingsPath = path63.join(repoPath, CLAUDE_SETTINGS_RELATIVE_PATH);
|
|
76434
76630
|
if (!fs53.existsSync(settingsPath)) return false;
|
|
76435
76631
|
try {
|
|
76436
76632
|
const settings = readSettings(settingsPath);
|
|
@@ -76448,7 +76644,7 @@ function repoOption(y) {
|
|
|
76448
76644
|
function handleInstall2(argv) {
|
|
76449
76645
|
try {
|
|
76450
76646
|
if (argv.claude) {
|
|
76451
|
-
const result2 = installClaudeGuard(
|
|
76647
|
+
const result2 = installClaudeGuard(path64.resolve(argv.repo));
|
|
76452
76648
|
success("Claude Code worktree guard installed.");
|
|
76453
76649
|
info(`Guard script: ${result2.guardScript}`);
|
|
76454
76650
|
info(`Settings: ${result2.settingsPath} (PreToolUse: Edit|Write|MultiEdit|NotebookEdit)`);
|
|
@@ -76456,7 +76652,7 @@ function handleInstall2(argv) {
|
|
|
76456
76652
|
info("Commit both files so the guard travels with the repo.");
|
|
76457
76653
|
return;
|
|
76458
76654
|
}
|
|
76459
|
-
const result = installHooks({ repoPath:
|
|
76655
|
+
const result = installHooks({ repoPath: path64.resolve(argv.repo), force: argv.force });
|
|
76460
76656
|
success(`Commit gate installed in ${result.hooksDir}`);
|
|
76461
76657
|
info(`pre-commit: ${result.preCommit}, post-commit: ${result.postCommit}`);
|
|
76462
76658
|
info("Commits of unverified change batches will be blocked in agent worktrees.");
|
|
@@ -76469,7 +76665,7 @@ function handleInstall2(argv) {
|
|
|
76469
76665
|
function handleUninstall(argv) {
|
|
76470
76666
|
try {
|
|
76471
76667
|
if (argv.claude) {
|
|
76472
|
-
const result2 = uninstallClaudeGuard(
|
|
76668
|
+
const result2 = uninstallClaudeGuard(path64.resolve(argv.repo));
|
|
76473
76669
|
if (result2.removed) {
|
|
76474
76670
|
success("Claude Code worktree guard removed.");
|
|
76475
76671
|
} else {
|
|
@@ -76477,7 +76673,7 @@ function handleUninstall(argv) {
|
|
|
76477
76673
|
}
|
|
76478
76674
|
return;
|
|
76479
76675
|
}
|
|
76480
|
-
const result = uninstallHooks(
|
|
76676
|
+
const result = uninstallHooks(path64.resolve(argv.repo));
|
|
76481
76677
|
if (result.removed) {
|
|
76482
76678
|
success(`Commit gate removed from ${result.hooksDir}`);
|
|
76483
76679
|
} else {
|
|
@@ -76490,7 +76686,7 @@ function handleUninstall(argv) {
|
|
|
76490
76686
|
}
|
|
76491
76687
|
function handleStatus2(argv) {
|
|
76492
76688
|
try {
|
|
76493
|
-
const status = getHooksStatus(
|
|
76689
|
+
const status = getHooksStatus(path64.resolve(argv.repo));
|
|
76494
76690
|
if (argv.json) {
|
|
76495
76691
|
process.stdout.write(`${JSON.stringify(status, null, 2)}
|
|
76496
76692
|
`);
|
|
@@ -76508,7 +76704,7 @@ function handleStatus2(argv) {
|
|
|
76508
76704
|
);
|
|
76509
76705
|
info(`Effective: ${status.effectiveMode} (in this checkout)`);
|
|
76510
76706
|
info(
|
|
76511
|
-
`Claude guard: ${claudeGuardInstalled(
|
|
76707
|
+
`Claude guard: ${claudeGuardInstalled(path64.resolve(argv.repo)) ? `installed (${CLAUDE_GUARD_RELATIVE_PATH})` : "not installed"}`
|
|
76512
76708
|
);
|
|
76513
76709
|
} catch (err) {
|
|
76514
76710
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -76769,10 +76965,10 @@ function assignProp(target, prop, value) {
|
|
|
76769
76965
|
configurable: true
|
|
76770
76966
|
});
|
|
76771
76967
|
}
|
|
76772
|
-
function getElementAtPath(obj,
|
|
76773
|
-
if (!
|
|
76968
|
+
function getElementAtPath(obj, path69) {
|
|
76969
|
+
if (!path69)
|
|
76774
76970
|
return obj;
|
|
76775
|
-
return
|
|
76971
|
+
return path69.reduce((acc, key) => acc?.[key], obj);
|
|
76776
76972
|
}
|
|
76777
76973
|
function promiseAllObject(promisesObj) {
|
|
76778
76974
|
const keys = Object.keys(promisesObj);
|
|
@@ -77092,11 +77288,11 @@ function aborted(x, startIndex = 0) {
|
|
|
77092
77288
|
}
|
|
77093
77289
|
return false;
|
|
77094
77290
|
}
|
|
77095
|
-
function prefixIssues(
|
|
77291
|
+
function prefixIssues(path69, issues) {
|
|
77096
77292
|
return issues.map((iss) => {
|
|
77097
77293
|
var _a2;
|
|
77098
77294
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
77099
|
-
iss.path.unshift(
|
|
77295
|
+
iss.path.unshift(path69);
|
|
77100
77296
|
return iss;
|
|
77101
77297
|
});
|
|
77102
77298
|
}
|
|
@@ -82419,7 +82615,7 @@ var Protocol = class {
|
|
|
82419
82615
|
return;
|
|
82420
82616
|
}
|
|
82421
82617
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
82422
|
-
await new Promise((
|
|
82618
|
+
await new Promise((resolve52) => setTimeout(resolve52, pollInterval));
|
|
82423
82619
|
options?.signal?.throwIfAborted();
|
|
82424
82620
|
}
|
|
82425
82621
|
} catch (error3) {
|
|
@@ -82436,7 +82632,7 @@ var Protocol = class {
|
|
|
82436
82632
|
*/
|
|
82437
82633
|
request(request, resultSchema, options) {
|
|
82438
82634
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
82439
|
-
return new Promise((
|
|
82635
|
+
return new Promise((resolve52, reject) => {
|
|
82440
82636
|
const earlyReject = (error3) => {
|
|
82441
82637
|
reject(error3);
|
|
82442
82638
|
};
|
|
@@ -82514,7 +82710,7 @@ var Protocol = class {
|
|
|
82514
82710
|
if (!parseResult.success) {
|
|
82515
82711
|
reject(parseResult.error);
|
|
82516
82712
|
} else {
|
|
82517
|
-
|
|
82713
|
+
resolve52(parseResult.data);
|
|
82518
82714
|
}
|
|
82519
82715
|
} catch (error3) {
|
|
82520
82716
|
reject(error3);
|
|
@@ -82775,12 +82971,12 @@ var Protocol = class {
|
|
|
82775
82971
|
}
|
|
82776
82972
|
} catch {
|
|
82777
82973
|
}
|
|
82778
|
-
return new Promise((
|
|
82974
|
+
return new Promise((resolve52, reject) => {
|
|
82779
82975
|
if (signal.aborted) {
|
|
82780
82976
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
82781
82977
|
return;
|
|
82782
82978
|
}
|
|
82783
|
-
const timeoutId = setTimeout(
|
|
82979
|
+
const timeoutId = setTimeout(resolve52, interval);
|
|
82784
82980
|
signal.addEventListener("abort", () => {
|
|
82785
82981
|
clearTimeout(timeoutId);
|
|
82786
82982
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -83570,7 +83766,7 @@ var Server = class extends Protocol {
|
|
|
83570
83766
|
};
|
|
83571
83767
|
|
|
83572
83768
|
// src/mcp/server.ts
|
|
83573
|
-
var
|
|
83769
|
+
var path65 = __toESM(require("path"));
|
|
83574
83770
|
|
|
83575
83771
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
83576
83772
|
var import_node_process3 = __toESM(require("node:process"), 1);
|
|
@@ -83653,12 +83849,12 @@ var StdioServerTransport = class {
|
|
|
83653
83849
|
this.onclose?.();
|
|
83654
83850
|
}
|
|
83655
83851
|
send(message) {
|
|
83656
|
-
return new Promise((
|
|
83852
|
+
return new Promise((resolve52) => {
|
|
83657
83853
|
const json = serializeMessage(message);
|
|
83658
83854
|
if (this._stdout.write(json)) {
|
|
83659
|
-
|
|
83855
|
+
resolve52();
|
|
83660
83856
|
} else {
|
|
83661
|
-
this._stdout.once("drain",
|
|
83857
|
+
this._stdout.once("drain", resolve52);
|
|
83662
83858
|
}
|
|
83663
83859
|
});
|
|
83664
83860
|
}
|
|
@@ -84297,7 +84493,7 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
84297
84493
|
const input = ControlUpInputSchema.parse({ ...args, repo });
|
|
84298
84494
|
const result = await startControlAndSync({
|
|
84299
84495
|
detach: input.detach,
|
|
84300
|
-
cwd:
|
|
84496
|
+
cwd: path65.resolve(input.repo)
|
|
84301
84497
|
});
|
|
84302
84498
|
if (result.code !== 0) {
|
|
84303
84499
|
return {
|
|
@@ -84361,11 +84557,11 @@ var mcpCommand = {
|
|
|
84361
84557
|
};
|
|
84362
84558
|
|
|
84363
84559
|
// src/cli/commands/onboard.ts
|
|
84364
|
-
var
|
|
84560
|
+
var path67 = __toESM(require("path"));
|
|
84365
84561
|
init_stages();
|
|
84366
84562
|
|
|
84367
84563
|
// src/core/onboarding.ts
|
|
84368
|
-
var
|
|
84564
|
+
var path66 = __toESM(require("path"));
|
|
84369
84565
|
init_control_config();
|
|
84370
84566
|
init_control_sync();
|
|
84371
84567
|
init_otel_hooks();
|
|
@@ -84509,7 +84705,7 @@ async function defaultEnsureControl(options) {
|
|
|
84509
84705
|
return { started: true, apiUrl: result.apiUrl };
|
|
84510
84706
|
}
|
|
84511
84707
|
async function runOnboarding(options, deps = {}) {
|
|
84512
|
-
const repoPath =
|
|
84708
|
+
const repoPath = path66.resolve(options.repoPath);
|
|
84513
84709
|
const applyTelemetry = deps.applyTelemetry ?? applyOnboardingTelemetry;
|
|
84514
84710
|
const ensureControl = deps.ensureControl ?? defaultEnsureControl;
|
|
84515
84711
|
const init = deps.initHarness ?? initHarness;
|
|
@@ -84707,7 +84903,7 @@ async function promptChoices(args, docker) {
|
|
|
84707
84903
|
};
|
|
84708
84904
|
}
|
|
84709
84905
|
const pluginChoices = listPluginChoices();
|
|
84710
|
-
const repoPath =
|
|
84906
|
+
const repoPath = path67.resolve(args.repo);
|
|
84711
84907
|
const alreadyPresent = harnessExists(repoPath);
|
|
84712
84908
|
const needProfile = !alreadyPresent && !args.skipInit && args.profile === void 0;
|
|
84713
84909
|
const needAgentSlots = shouldConfigureSlots && flaggedSlots === void 0;
|
|
@@ -84828,7 +85024,7 @@ function printSummary(result) {
|
|
|
84828
85024
|
console.error("");
|
|
84829
85025
|
}
|
|
84830
85026
|
async function handleOnboard(argv) {
|
|
84831
|
-
const repoPath =
|
|
85027
|
+
const repoPath = path67.resolve(argv.repo);
|
|
84832
85028
|
header("har onboard");
|
|
84833
85029
|
info(`Repository: ${repoPath}`);
|
|
84834
85030
|
try {
|
|
@@ -85062,7 +85258,7 @@ var preferencesCommand = {
|
|
|
85062
85258
|
};
|
|
85063
85259
|
|
|
85064
85260
|
// src/cli/commands/telemetry.ts
|
|
85065
|
-
var
|
|
85261
|
+
var path68 = __toESM(require("path"));
|
|
85066
85262
|
init_control_config();
|
|
85067
85263
|
init_control_sync();
|
|
85068
85264
|
init_manifest();
|
|
@@ -85155,7 +85351,7 @@ async function handleOff() {
|
|
|
85155
85351
|
info("Mission Control will not auto-start. Existing usage rows are kept.");
|
|
85156
85352
|
}
|
|
85157
85353
|
async function handleWriteEnv(argv) {
|
|
85158
|
-
const repoPath =
|
|
85354
|
+
const repoPath = path68.resolve(argv.repo);
|
|
85159
85355
|
const harnessRoot = resolveHarnessRoot(repoPath);
|
|
85160
85356
|
const session = readSlotRegistry(harnessRoot, argv.agentId);
|
|
85161
85357
|
const workDir = argv.workDir ?? session?.workDir ?? repoPath;
|
|
@@ -85167,7 +85363,7 @@ async function handleWriteEnv(argv) {
|
|
|
85167
85363
|
suffix,
|
|
85168
85364
|
createdAt: session?.createdAt
|
|
85169
85365
|
});
|
|
85170
|
-
const envFile = argv.envFile ??
|
|
85366
|
+
const envFile = argv.envFile ?? path68.join(workDir, `.env.agent.${argv.agentId}`);
|
|
85171
85367
|
const attrs = {
|
|
85172
85368
|
sessionKey,
|
|
85173
85369
|
agentId: argv.agentId,
|
|
@@ -85183,7 +85379,7 @@ async function handleWriteEnv(argv) {
|
|
|
85183
85379
|
success(`Wrote session attribution to ${envFile}`);
|
|
85184
85380
|
}
|
|
85185
85381
|
function handlePrintEnv(argv) {
|
|
85186
|
-
const repoPath =
|
|
85382
|
+
const repoPath = path68.resolve(argv.repo);
|
|
85187
85383
|
const workDir = argv.workDir ?? repoPath;
|
|
85188
85384
|
const sessionKey = buildSessionKey({
|
|
85189
85385
|
branch: argv.branch,
|