hunter-harness 0.2.19 → 0.2.21

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.
Files changed (2) hide show
  1. package/dist/bin.js +424 -128
  2. package/package.json +36 -36
package/dist/bin.js CHANGED
@@ -164,7 +164,15 @@ var requestMetadataSchema = z2.object({
164
164
  }).strict();
165
165
 
166
166
  // ../contracts/dist/registry.js
167
- var registryAgentSchema = z3.enum(["claude-code", "codex", "cursor", "generic", "mcp"]);
167
+ var skillTargetAgentSchema = z3.enum(["claude-code", "codex", "cursor", "codebuddy"]);
168
+ var registryAgentSchema = z3.enum([
169
+ "claude-code",
170
+ "codex",
171
+ "cursor",
172
+ "codebuddy",
173
+ "generic",
174
+ "mcp"
175
+ ]);
168
176
  var registrySkillStatusSchema = z3.enum([
169
177
  "draft",
170
178
  "pending_review",
@@ -180,6 +188,7 @@ var registrySkillProposalStatusSchema = z3.enum([
180
188
  var registrySemverSchema = z3.string().regex(/^\d+\.\d+\.\d+$/);
181
189
  var registrySlugSchema = z3.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
182
190
  var checkStatusSchema = z3.enum(["green", "yellow", "red"]);
191
+ var skillVariantStatusSchema = z3.enum(["ready", "degraded", "unsupported"]);
183
192
  var sourceFileSchema = z3.object({
184
193
  path: z3.string(),
185
194
  content: z3.string()
@@ -204,6 +213,39 @@ var skillUsageExampleSchema = z3.object({
204
213
  result: z3.string(),
205
214
  files: z3.array(z3.string()).default([])
206
215
  }).strict();
216
+ var sensitiveFindingViewSchema = z3.object({
217
+ rule_id: z3.string().min(1),
218
+ severity: z3.enum(["high", "medium", "low"]),
219
+ path: z3.string().min(1),
220
+ line: z3.number().int().positive(),
221
+ column: z3.number().int().positive(),
222
+ fingerprint: sha256Schema,
223
+ redacted_preview: z3.string(),
224
+ overridable: z3.boolean()
225
+ }).strict();
226
+ var sensitiveReviewSubmissionSchema = z3.object({
227
+ scanner_version: z3.string().min(1),
228
+ finding_fingerprints: z3.array(sha256Schema).min(1),
229
+ reason: z3.string().trim().min(3).max(500)
230
+ }).strict();
231
+ var sensitiveReviewEvidenceSchema = sensitiveReviewSubmissionSchema.extend({
232
+ actor: z3.string().min(1),
233
+ accepted_at: z3.iso.datetime()
234
+ }).strict();
235
+ var skillVariantSchema = z3.object({
236
+ agent: skillTargetAgentSchema,
237
+ status: skillVariantStatusSchema,
238
+ buildHash: sha256Schema.nullable(),
239
+ adapterVersion: z3.string().min(1),
240
+ components: z3.array(z3.string().min(1))
241
+ }).strict();
242
+ var skillReleaseSchema = z3.object({
243
+ version: registrySemverSchema,
244
+ packageName: z3.string().min(1),
245
+ packageDigest: z3.string().min(1),
246
+ variants: z3.partialRecord(skillTargetAgentSchema, skillVariantSchema),
247
+ created_at: z3.iso.datetime()
248
+ }).strict();
207
249
  var agentSkillConfigSchema = z3.object({
208
250
  agent: registryAgentSchema,
209
251
  enabled: z3.boolean(),
@@ -250,6 +292,24 @@ var publishSkillRequestSchema = z3.object({
250
292
  version: registrySemverSchema,
251
293
  releaseNote: z3.string().optional()
252
294
  }).strict();
295
+ var publishUnifiedSkillRequestSchema = z3.object({
296
+ version: registrySemverSchema,
297
+ sourceAgent: skillTargetAgentSchema,
298
+ draftRevision: z3.number().int().positive(),
299
+ releaseNote: z3.string().trim().min(1).max(2e3).optional()
300
+ }).strict();
301
+ var publishSkillResponseSchema = z3.object({
302
+ release: z3.object({
303
+ slug: registrySlugSchema,
304
+ version: registrySemverSchema
305
+ }).strict(),
306
+ npmRelease: z3.object({
307
+ status: z3.enum(["published", "idempotent"]),
308
+ packageName: z3.string().min(1),
309
+ version: registrySemverSchema,
310
+ tarballHash: z3.string().min(1)
311
+ }).strict()
312
+ }).strict();
253
313
  var setDefaultAgentRequestSchema = z3.object({
254
314
  defaultAgent: registryAgentSchema,
255
315
  revision: z3.number().int().positive()
@@ -931,94 +991,148 @@ var semanticSearchHitSchema = z12.object({
931
991
  project_id: z12.string()
932
992
  }).strict();
933
993
 
934
- // ../contracts/dist/workflow-family.js
994
+ // ../contracts/dist/skill-package.js
935
995
  import { z as z13 } from "zod";
936
- var workflowBundleManifestSchema = z13.object({
937
- schema_version: z13.literal(1),
996
+ var skillComponentRoleSchema = z13.enum(["skill", "subagent"]);
997
+ var skillBundlePathSchema = z13.string().min(1).refine((value) => {
998
+ if (value === ".")
999
+ return true;
1000
+ return !value.includes("\0") && !value.includes("\\") && !value.startsWith("/") && !/^[A-Za-z]:/.test(value) && value.split("/").every((part) => part !== "" && part !== "." && part !== "..");
1001
+ }, "path must be a normalized relative POSIX path");
1002
+ var skillBundleComponentSchema = z13.object({
1003
+ role: skillComponentRoleSchema,
1004
+ source: skillBundlePathSchema,
1005
+ name: registrySlugSchema.optional(),
1006
+ variants: z13.partialRecord(skillTargetAgentSchema, skillBundlePathSchema).optional()
1007
+ }).strict().superRefine((component, context) => {
1008
+ if (component.role === "skill" && component.variants !== void 0) {
1009
+ context.addIssue({ code: "custom", message: "skill components cannot define agent variants" });
1010
+ }
1011
+ if (component.role === "subagent" && (component.name === void 0 || component.variants === void 0 || Object.keys(component.variants).length === 0)) {
1012
+ context.addIssue({ code: "custom", message: "subagent components require a name and variants" });
1013
+ }
1014
+ }).superRefine((component, context) => {
1015
+ if (component.role === "subagent" && component.source !== ".") {
1016
+ context.addIssue({ code: "custom", message: "subagent source must be '.'; variants select native files" });
1017
+ }
1018
+ });
1019
+ var authorSkillBundleManifestSchema = z13.object({
1020
+ apiVersion: z13.literal("hunter-harness/v1"),
1021
+ kind: z13.literal("SkillBundle"),
1022
+ components: z13.array(skillBundleComponentSchema).min(1)
1023
+ }).strict().superRefine((manifest, context) => {
1024
+ if (!manifest.components.some((component) => component.role === "skill")) {
1025
+ context.addIssue({ code: "custom", message: "bundle requires a skill component" });
1026
+ }
1027
+ });
1028
+ var skillPackageFileSchema = z13.object({
1029
+ path: skillBundlePathSchema,
1030
+ sha256: sha256Schema,
1031
+ size: z13.number().int().nonnegative()
1032
+ }).strict();
1033
+ var skillPackageVariantSchema = z13.object({
1034
+ status: skillVariantStatusSchema,
1035
+ adapterVersion: z13.string().min(1),
1036
+ buildHash: sha256Schema.nullable(),
1037
+ components: z13.array(z13.string().min(1))
1038
+ }).strict();
1039
+ var skillPackageManifestV3Schema = z13.object({
1040
+ schema_version: z13.literal(3),
1041
+ slug: registrySlugSchema,
1042
+ version: registrySemverSchema,
1043
+ files: z13.array(skillPackageFileSchema),
1044
+ components: z13.array(skillBundleComponentSchema).min(1),
1045
+ variants: z13.record(skillTargetAgentSchema, skillPackageVariantSchema)
1046
+ }).strict();
1047
+
1048
+ // ../contracts/dist/workflow-family.js
1049
+ import { z as z14 } from "zod";
1050
+ var workflowBundleManifestSchema = z14.object({
1051
+ schema_version: z14.literal(1),
938
1052
  profile: registrySlugSchema,
939
- files: z13.array(z13.object({
940
- path: z13.string().min(1),
1053
+ files: z14.array(z14.object({
1054
+ path: z14.string().min(1),
941
1055
  sha256: sha256Schema
942
1056
  }).strict()).min(1)
943
1057
  }).strict();
944
- var workflowFamilyBundleArtifactSchema = z13.object({
945
- artifact_id: z13.string().regex(/^wfb_/),
1058
+ var workflowFamilyBundleArtifactSchema = z14.object({
1059
+ artifact_id: z14.string().regex(/^wfb_/),
946
1060
  family_slug: registrySlugSchema,
947
1061
  profile: registrySlugSchema,
948
1062
  version: registrySemverSchema,
949
1063
  content_sha256: sha256Schema,
950
- size_bytes: z13.number().int().nonnegative(),
1064
+ size_bytes: z14.number().int().nonnegative(),
951
1065
  bundle_manifest: workflowBundleManifestSchema,
952
- created_at: z13.iso.datetime()
1066
+ created_at: z14.iso.datetime()
953
1067
  }).strict();
954
- var workflowFamilyVersionProfileSchema = z13.object({
1068
+ var workflowFamilyVersionProfileSchema = z14.object({
955
1069
  profile: registrySlugSchema,
956
1070
  bundle_manifest: workflowBundleManifestSchema,
957
- artifact_id: z13.string().regex(/^wfb_/),
958
- sourceFiles: z13.array(sourceFileSchema).default([])
1071
+ artifact_id: z14.string().regex(/^wfb_/),
1072
+ sourceFiles: z14.array(sourceFileSchema).default([])
959
1073
  }).strict();
960
- var workflowFamilyVersionSchema = z13.object({
1074
+ var workflowFamilyVersionSchema = z14.object({
961
1075
  family_slug: registrySlugSchema,
962
1076
  version: registrySemverSchema,
963
- profiles: z13.array(workflowFamilyVersionProfileSchema).min(1),
964
- artifacts: z13.array(workflowFamilyBundleArtifactSchema),
965
- changeNote: z13.string().nullable(),
966
- created_at: z13.iso.datetime()
1077
+ profiles: z14.array(workflowFamilyVersionProfileSchema).min(1),
1078
+ artifacts: z14.array(workflowFamilyBundleArtifactSchema),
1079
+ changeNote: z14.string().nullable(),
1080
+ created_at: z14.iso.datetime()
967
1081
  }).strict();
968
- var workflowFamilyDraftProfileSchema = z13.object({
1082
+ var workflowFamilyDraftProfileSchema = z14.object({
969
1083
  profile: registrySlugSchema,
970
- sourceFiles: z13.array(sourceFileSchema),
1084
+ sourceFiles: z14.array(sourceFileSchema),
971
1085
  bundle_manifest: workflowBundleManifestSchema
972
1086
  }).strict();
973
- var workflowFamilyDraftStateSchema = z13.object({
1087
+ var workflowFamilyDraftStateSchema = z14.object({
974
1088
  family_slug: registrySlugSchema,
975
- profiles: z13.array(workflowFamilyDraftProfileSchema),
976
- required_profiles: z13.array(registrySlugSchema),
1089
+ profiles: z14.array(workflowFamilyDraftProfileSchema),
1090
+ required_profiles: z14.array(registrySlugSchema),
977
1091
  draftVersion: registrySemverSchema.nullable(),
978
1092
  checks: skillCheckResultSchema.nullable(),
979
- releaseNote: z13.string().nullable(),
980
- revision: z13.number().int(),
981
- created_at: z13.string(),
982
- updated_at: z13.string()
1093
+ releaseNote: z14.string().nullable(),
1094
+ revision: z14.number().int(),
1095
+ created_at: z14.string(),
1096
+ updated_at: z14.string()
983
1097
  }).strict();
984
- var workflowFamilySchema = z13.object({
985
- family_id: z13.string().regex(/^wff_/),
1098
+ var workflowFamilySchema = z14.object({
1099
+ family_id: z14.string().regex(/^wff_/),
986
1100
  slug: registrySlugSchema,
987
- displayName: z13.string().min(1).max(120),
988
- description: z13.string().min(1).max(1e3),
989
- tags: z13.array(registrySlugSchema).default([]),
1101
+ displayName: z14.string().min(1).max(120),
1102
+ description: z14.string().min(1).max(1e3),
1103
+ tags: z14.array(registrySlugSchema).default([]),
990
1104
  latest_version: registrySemverSchema.nullable(),
991
- required_profiles: z13.array(registrySlugSchema).min(1),
992
- revision: z13.number().int().positive(),
993
- npmReleases: z13.array(npmReleaseRecordSchema).optional().default([]),
994
- created_at: z13.iso.datetime(),
995
- updated_at: z13.iso.datetime()
1105
+ required_profiles: z14.array(registrySlugSchema).min(1),
1106
+ revision: z14.number().int().positive(),
1107
+ npmReleases: z14.array(npmReleaseRecordSchema).optional().default([]),
1108
+ created_at: z14.iso.datetime(),
1109
+ updated_at: z14.iso.datetime()
996
1110
  }).strict();
997
- var workflowFamilyMutationSchema = z13.object({
1111
+ var workflowFamilyMutationSchema = z14.object({
998
1112
  slug: registrySlugSchema,
999
- displayName: z13.string().min(1).max(120),
1000
- description: z13.string().min(1).max(1e3),
1001
- tags: z13.array(registrySlugSchema).default([]),
1002
- required_profiles: z13.array(registrySlugSchema).min(1)
1113
+ displayName: z14.string().min(1).max(120),
1114
+ description: z14.string().min(1).max(1e3),
1115
+ tags: z14.array(registrySlugSchema).default([]),
1116
+ required_profiles: z14.array(registrySlugSchema).min(1)
1003
1117
  }).strict();
1004
- var publishWorkflowFamilyRequestSchema = z13.object({
1118
+ var publishWorkflowFamilyRequestSchema = z14.object({
1005
1119
  version: registrySemverSchema,
1006
- releaseNote: z13.string().optional()
1120
+ releaseNote: z14.string().optional()
1007
1121
  }).strict();
1008
- var registryProjectWorkflowBindingSchema = z13.object({
1009
- project_id: z13.string().regex(/^prj_/),
1122
+ var registryProjectWorkflowBindingSchema = z14.object({
1123
+ project_id: z14.string().regex(/^prj_/),
1010
1124
  family_slug: registrySlugSchema,
1011
1125
  profile: registrySlugSchema,
1012
1126
  version: registrySemverSchema.nullable().optional(),
1013
- revision: z13.number().int().positive(),
1014
- updated_at: z13.iso.datetime()
1127
+ revision: z14.number().int().positive(),
1128
+ updated_at: z14.iso.datetime()
1015
1129
  }).strict();
1016
- var bindProjectWorkflowFamilyRequestSchema = z13.object({
1017
- schema_version: z13.literal(1),
1130
+ var bindProjectWorkflowFamilyRequestSchema = z14.object({
1131
+ schema_version: z14.literal(1),
1018
1132
  family_slug: registrySlugSchema,
1019
1133
  profile: registrySlugSchema,
1020
1134
  version: registrySemverSchema.nullable().optional(),
1021
- revision: z13.number().int().nullable()
1135
+ revision: z14.number().int().nullable()
1022
1136
  }).strict();
1023
1137
 
1024
1138
  // ../core/dist/fs/hash.js
@@ -1030,6 +1144,10 @@ function sha256Bytes(content) {
1030
1144
  async function sha256File(path) {
1031
1145
  return sha256Bytes(await readFile(path));
1032
1146
  }
1147
+ function aggregateInstalledContentHash(files) {
1148
+ const lines = [...files].sort((a, b) => a.relpath.localeCompare(b.relpath)).map((entry) => `${entry.relpath}:${entry.sha256}`);
1149
+ return createHash("sha256").update(lines.join("\n"), "utf8").digest("hex");
1150
+ }
1033
1151
 
1034
1152
  // ../core/dist/fs/path-safety.js
1035
1153
  import { lstat } from "node:fs/promises";
@@ -1115,7 +1233,7 @@ async function assertNoSymlinks(root, relativePath) {
1115
1233
  async function withRetry(action, options) {
1116
1234
  const attempts = options.attempts ?? 3;
1117
1235
  const sleep = options.sleep ?? (async (milliseconds) => {
1118
- await new Promise((resolve8) => setTimeout(resolve8, milliseconds));
1236
+ await new Promise((resolve9) => setTimeout(resolve9, milliseconds));
1119
1237
  });
1120
1238
  let lastError;
1121
1239
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
@@ -1613,8 +1731,8 @@ function decideUpdate(policy, dirty) {
1613
1731
 
1614
1732
  // ../core/dist/project/initialize.js
1615
1733
  import { createHash as createHash4 } from "node:crypto";
1616
- import { readFile as readFile4, stat as stat2 } from "node:fs/promises";
1617
- import { basename, join as join5, resolve as resolve3 } from "node:path";
1734
+ import { readFile as readFile4, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
1735
+ import { basename, join as join5, resolve as resolve4 } from "node:path";
1618
1736
  import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
1619
1737
 
1620
1738
  // ../core/dist/transaction/transaction.js
@@ -2132,7 +2250,7 @@ function managedTargetsFor(adapter, bundle, context) {
2132
2250
  // ../core/dist/project/profile-bundle.js
2133
2251
  import { createHash as createHash3 } from "node:crypto";
2134
2252
  import { readFile as readFile3, readdir as readdir2 } from "node:fs/promises";
2135
- import { join as join4 } from "node:path";
2253
+ import { join as join4, resolve as resolve3 } from "node:path";
2136
2254
  var AdapterBundleError = class extends Error {
2137
2255
  code;
2138
2256
  exitCode = 7;
@@ -2156,7 +2274,13 @@ function validateRelativeBundlePath2(path) {
2156
2274
  throw new Error("invalid Harness Bundle path");
2157
2275
  }
2158
2276
  }
2277
+ var bundleCache = /* @__PURE__ */ new Map();
2159
2278
  async function loadAgentBundle(resourcesRoot, profile, agent) {
2279
+ const cacheKey = `${resolve3(resourcesRoot)}:${profile}:${agent}`;
2280
+ const cached = bundleCache.get(cacheKey);
2281
+ if (cached) {
2282
+ return { manifest: cached.manifest, files: new Map(cached.files) };
2283
+ }
2160
2284
  const manifestPath = join4(resourcesRoot, "harness", "manifests", profile, `${agent}.json`);
2161
2285
  let manifestText;
2162
2286
  try {
@@ -2200,7 +2324,9 @@ async function loadAgentBundle(resourcesRoot, profile, agent) {
2200
2324
  }
2201
2325
  files.set(item2.path, bytes);
2202
2326
  }
2203
- return { manifest: raw, files };
2327
+ const result = { manifest: raw, files };
2328
+ bundleCache.set(cacheKey, result);
2329
+ return { manifest: result.manifest, files: new Map(result.files) };
2204
2330
  }
2205
2331
  async function managedBundleTargets(resourcesRoot, profile, agent = "claude-code") {
2206
2332
  const bundle = await loadAgentBundle(resourcesRoot, profile, agent);
@@ -2311,6 +2437,27 @@ function uuidV7(now = Date.now()) {
2311
2437
  }
2312
2438
 
2313
2439
  // ../core/dist/project/initialize.js
2440
+ var CONTEXT_INDEX_PATH = ".harness/context-index.json";
2441
+ async function fileHex(path) {
2442
+ try {
2443
+ const data = await readFile4(path);
2444
+ return createHash4("sha256").update(data).digest("hex");
2445
+ } catch {
2446
+ return null;
2447
+ }
2448
+ }
2449
+ async function readExistingSkillBundles(root) {
2450
+ const text = await readOptional(join5(root, CONTEXT_INDEX_PATH));
2451
+ if (text === "")
2452
+ return /* @__PURE__ */ new Map();
2453
+ try {
2454
+ const parsed = JSON.parse(text);
2455
+ const bundles = parsed.skill_bundles ?? {};
2456
+ return new Map(Object.entries(bundles));
2457
+ } catch {
2458
+ return /* @__PURE__ */ new Map();
2459
+ }
2460
+ }
2314
2461
  var TargetCollisionError = class extends Error {
2315
2462
  code = "TARGET_COLLISION";
2316
2463
  exitCode = 7;
@@ -2394,7 +2541,7 @@ function mergeOwnedTargets(owned) {
2394
2541
  });
2395
2542
  }
2396
2543
  async function initializeProject(options) {
2397
- const root = resolve3(options.projectRoot);
2544
+ const root = resolve4(options.projectRoot);
2398
2545
  const config = initConfigSchema.parse(options.config);
2399
2546
  const existing = await existingProjectConfig(root);
2400
2547
  const profile = config.profile;
@@ -2405,6 +2552,7 @@ async function initializeProject(options) {
2405
2552
  const manifests = [];
2406
2553
  const adaptersIndex = {};
2407
2554
  const skillBundles = {};
2555
+ const existingContextBundles = await readExistingSkillBundles(root);
2408
2556
  let primaryBundleHash = "";
2409
2557
  let primaryRegistryVersion = "";
2410
2558
  for (const agent of enabledAgents) {
@@ -2424,7 +2572,8 @@ async function initializeProject(options) {
2424
2572
  });
2425
2573
  skillBundles[agent] = {
2426
2574
  registry_version: bundle.manifest.bundle_version,
2427
- bundle_hash: bundleHash
2575
+ bundle_hash: bundleHash,
2576
+ ...existingContextBundles.get(agent) ?? {}
2428
2577
  };
2429
2578
  adaptersIndex[agent] = adapter.contextIndex(adapterContext);
2430
2579
  for (const target of targets) {
@@ -2541,6 +2690,7 @@ async function initializeProject(options) {
2541
2690
  if (!options.dryRun) {
2542
2691
  const writeOperations = await Promise.all([...files.entries()].map(async ([path, content]) => operationFor(root, path, content)));
2543
2692
  await runTransaction(root, writeOperations, { kind: "init" });
2693
+ await enrichContextIndexWithVerification(root, enabledAgents, profile, options.resourcesRoot, adapterContext);
2544
2694
  }
2545
2695
  return {
2546
2696
  projectConfig,
@@ -2549,15 +2699,61 @@ async function initializeProject(options) {
2549
2699
  registryVersion: primaryRegistryVersion
2550
2700
  };
2551
2701
  }
2702
+ async function enrichContextIndexWithVerification(root, agents, profile, resourcesRoot, adapterContext) {
2703
+ const contextPath = join5(root, CONTEXT_INDEX_PATH);
2704
+ const existing = await readOptional(join5(contextPath));
2705
+ if (existing === "")
2706
+ return;
2707
+ let parsed;
2708
+ try {
2709
+ parsed = JSON.parse(existing);
2710
+ } catch {
2711
+ return;
2712
+ }
2713
+ const bundles = parsed.skill_bundles ?? {};
2714
+ for (const agent of agents) {
2715
+ const entry = bundles[agent];
2716
+ if (!entry)
2717
+ continue;
2718
+ let loadedBundle;
2719
+ try {
2720
+ loadedBundle = await loadAgentBundle(resourcesRoot, profile, agent);
2721
+ } catch {
2722
+ continue;
2723
+ }
2724
+ const targets = managedTargetsFor(getAdapter(agent), loadedBundle, adapterContext);
2725
+ const mismatches = [];
2726
+ const entries = [];
2727
+ for (const target of targets) {
2728
+ const rel = target.target_path.replace(/\\/g, "/");
2729
+ const actual = await fileHex(join5(root, target.target_path));
2730
+ entries.push({ relpath: rel, sha256: actual ?? "" });
2731
+ if (actual === null) {
2732
+ mismatches.push({ relpath: rel, expected: target.sha256, actual: "<missing>" });
2733
+ } else if (actual !== target.sha256) {
2734
+ mismatches.push({ relpath: rel, expected: target.sha256, actual });
2735
+ }
2736
+ }
2737
+ entry.installedContentHash = aggregateInstalledContentHash(entries);
2738
+ const newStatus = mismatches.length === 0 ? "verified" : "degraded";
2739
+ if (newStatus === "verified" && typeof entry.verifiedAt === "string" && entry.verifiedAt !== "") {
2740
+ } else {
2741
+ entry.verifiedAt = (/* @__PURE__ */ new Date()).toISOString();
2742
+ }
2743
+ entry.verificationStatus = newStatus;
2744
+ entry.mismatchDetails = mismatches;
2745
+ }
2746
+ await writeFile3(contextPath, JSON.stringify(parsed, null, 2) + "\n", "utf8");
2747
+ }
2552
2748
 
2553
2749
  // ../core/dist/project/refresh.js
2554
2750
  import { createHash as createHash5 } from "node:crypto";
2555
2751
  import { readFile as readFile5, readdir as readdir3, rmdir } from "node:fs/promises";
2556
- import { dirname as dirname3, join as join6, resolve as resolve4 } from "node:path";
2752
+ import { dirname as dirname3, join as join6, resolve as resolve5 } from "node:path";
2557
2753
  import { parse as parseYaml3, stringify as stringifyYaml2 } from "yaml";
2558
2754
  var INSTALLED_STATE_PATH = ".harness/state/local/installed-harness-bundle.json";
2559
- var CONTEXT_INDEX_PATH = ".harness/context-index.json";
2560
- async function fileHex(path) {
2755
+ var CONTEXT_INDEX_PATH2 = ".harness/context-index.json";
2756
+ async function fileHex2(path) {
2561
2757
  try {
2562
2758
  return createHash5("sha256").update(await readFile5(path)).digest("hex");
2563
2759
  } catch (error) {
@@ -2648,7 +2844,7 @@ async function readInstalledState(root) {
2648
2844
  };
2649
2845
  }
2650
2846
  async function readInstalledAgentConfiguration(projectRoot) {
2651
- const installed = await readInstalledState(resolve4(projectRoot));
2847
+ const installed = await readInstalledState(resolve5(projectRoot));
2652
2848
  return {
2653
2849
  agents: installed.adapters,
2654
2850
  profiles: Object.fromEntries(installed.adapters.map((agent) => [
@@ -2658,7 +2854,7 @@ async function readInstalledAgentConfiguration(projectRoot) {
2658
2854
  };
2659
2855
  }
2660
2856
  async function readContextIndexBundleHash(root) {
2661
- const content = await readOptionalText(join6(root, CONTEXT_INDEX_PATH));
2857
+ const content = await readOptionalText(join6(root, CONTEXT_INDEX_PATH2));
2662
2858
  if (content === "")
2663
2859
  return null;
2664
2860
  try {
@@ -2713,8 +2909,8 @@ function conflict(target, reason, oldSha, incomingSha) {
2713
2909
  function sortByTarget(items) {
2714
2910
  return [...items].sort((left, right) => left.target_path.localeCompare(right.target_path));
2715
2911
  }
2716
- async function reconcileContextIndex(root, agents, profiles, manifests, codebuddySurface2) {
2717
- const existing = await readOptionalText(join6(root, CONTEXT_INDEX_PATH));
2912
+ async function reconcileContextIndex(root, agents, profiles, manifests, codebuddySurface2, verifications) {
2913
+ const existing = await readOptionalText(join6(root, CONTEXT_INDEX_PATH2));
2718
2914
  let codebase = {
2719
2915
  map: ".harness/codebase/map",
2720
2916
  status: "missing"
@@ -2741,17 +2937,27 @@ async function reconcileContextIndex(root, agents, profiles, manifests, codebudd
2741
2937
  },
2742
2938
  knowledge: { index: ".harness/knowledge/index.json" },
2743
2939
  codebase,
2744
- skill_bundles: Object.fromEntries(manifests.map((manifest) => [
2745
- manifest.adapter,
2746
- { registry_version: manifest.bundle_version, bundle_hash: manifest.bundle_manifest_hash }
2747
- ]))
2940
+ skill_bundles: Object.fromEntries(manifests.map((manifest) => {
2941
+ const ver = verifications.get(manifest.adapter);
2942
+ return [
2943
+ manifest.adapter,
2944
+ {
2945
+ registry_version: manifest.bundle_version,
2946
+ bundle_hash: manifest.bundle_manifest_hash,
2947
+ installedContentHash: ver?.installedContentHash ?? null,
2948
+ verifiedAt: ver?.verifiedAt ?? null,
2949
+ verificationStatus: ver?.verificationStatus ?? "unknown",
2950
+ mismatchDetails: ver?.mismatchDetails ?? []
2951
+ }
2952
+ ];
2953
+ }))
2748
2954
  };
2749
2955
  const next = JSON.stringify(record, null, 2) + "\n";
2750
2956
  if (existing === next)
2751
2957
  return null;
2752
2958
  return {
2753
2959
  operation: existing === "" ? "add" : "modify",
2754
- path: CONTEXT_INDEX_PATH,
2960
+ path: CONTEXT_INDEX_PATH2,
2755
2961
  content: next
2756
2962
  };
2757
2963
  }
@@ -2831,7 +3037,7 @@ function stateWithoutInstalledAt(value) {
2831
3037
  return copy;
2832
3038
  }
2833
3039
  async function refreshProject(options) {
2834
- const root = resolve4(options.projectRoot);
3040
+ const root = resolve5(options.projectRoot);
2835
3041
  const installed = await readInstalledState(root);
2836
3042
  const oldAgents = installed.adapters.length > 0 ? installed.adapters : ["claude-code"];
2837
3043
  const selectedAgents = sortHarnessAgents(options.agents);
@@ -2915,7 +3121,7 @@ async function refreshProject(options) {
2915
3121
  const newStateFiles = installed.files.filter((entry) => entry.owner === "shared" || !selectedSet.has(entry.owner));
2916
3122
  for (const target of newManaged) {
2917
3123
  const incoming = target.sha256;
2918
- const current = await fileHex(join6(root, target.target_path));
3124
+ const current = await fileHex2(join6(root, target.target_path));
2919
3125
  if (current === null) {
2920
3126
  applied.push(item(target, "add", "MISSING_TARGET", null, incoming));
2921
3127
  ops.push({ operation: "add", path: target.target_path, content: target.bytes });
@@ -2943,7 +3149,7 @@ async function refreshProject(options) {
2943
3149
  }
2944
3150
  }
2945
3151
  for (const target of oldOnly) {
2946
- const current = await fileHex(join6(root, target.target_path));
3152
+ const current = await fileHex2(join6(root, target.target_path));
2947
3153
  if (current === null) {
2948
3154
  continue;
2949
3155
  }
@@ -2969,7 +3175,48 @@ async function refreshProject(options) {
2969
3175
  const projectOperation = await projectTransitionOperation(root, agents, profiles, codebuddySurface2);
2970
3176
  if (projectOperation !== null)
2971
3177
  ops.push(projectOperation);
2972
- const contextOperation = await reconcileContextIndex(root, agents, profiles, manifests, codebuddySurface2);
3178
+ const verifications = /* @__PURE__ */ new Map();
3179
+ for (const agent of selectedAgents) {
3180
+ const agentProfile = profiles.get(agent) ?? profile;
3181
+ let bundleForVerify;
3182
+ try {
3183
+ bundleForVerify = await loadAgentBundle(options.resourcesRoot, agentProfile, agent);
3184
+ } catch {
3185
+ continue;
3186
+ }
3187
+ const verifyTargets = managedTargetsFor(getAdapter(agent), bundleForVerify, {
3188
+ profile: agentProfile,
3189
+ codebuddySurface: codebuddySurface2
3190
+ });
3191
+ const verifyMismatches = [];
3192
+ const verifyEntries = [];
3193
+ for (const target of verifyTargets) {
3194
+ const rel = target.target_path.replace(/\\/g, "/");
3195
+ const actual = await fileHex2(join6(root, target.target_path));
3196
+ verifyEntries.push({ relpath: rel, sha256: actual ?? "" });
3197
+ if (actual === null) {
3198
+ verifyMismatches.push({ relpath: rel, expected: target.sha256, actual: "<missing>" });
3199
+ } else if (actual !== target.sha256) {
3200
+ verifyMismatches.push({ relpath: rel, expected: target.sha256, actual });
3201
+ }
3202
+ }
3203
+ verifications.set(agent, {
3204
+ adapter: agent,
3205
+ bundleVersion: bundleForVerify.manifest.bundle_version,
3206
+ installedBundleVersion: null,
3207
+ manifestHash: null,
3208
+ installedManifestHash: null,
3209
+ coreHash: null,
3210
+ installedCoreHash: null,
3211
+ adapterHash: null,
3212
+ installedAdapterHash: null,
3213
+ installedContentHash: aggregateInstalledContentHash(verifyEntries),
3214
+ verifiedAt: (/* @__PURE__ */ new Date()).toISOString(),
3215
+ verificationStatus: verifyMismatches.length === 0 ? "verified" : "degraded",
3216
+ mismatchDetails: verifyMismatches
3217
+ });
3218
+ }
3219
+ const contextOperation = await reconcileContextIndex(root, agents, profiles, manifests, codebuddySurface2, verifications);
2973
3220
  if (contextOperation !== null)
2974
3221
  ops.push(contextOperation);
2975
3222
  const managedBlocks = [
@@ -3040,6 +3287,14 @@ async function refreshProject(options) {
3040
3287
  function freshnessEntry(agent, profile, status, identity) {
3041
3288
  return { agent, profile, status, identity, driftedFiles: [], missingFiles: [] };
3042
3289
  }
3290
+ function emptyVerification() {
3291
+ return {
3292
+ installedContentHash: null,
3293
+ verifiedAt: null,
3294
+ verificationStatus: "unknown",
3295
+ mismatchDetails: []
3296
+ };
3297
+ }
3043
3298
  var BUILD_MARKER_BUNDLE_PATH = ".harness-build.json";
3044
3299
  function buildMarkerCoreHash(text) {
3045
3300
  if (text === null || text === "")
@@ -3052,7 +3307,7 @@ function buildMarkerCoreHash(text) {
3052
3307
  }
3053
3308
  }
3054
3309
  async function collectFreshness(options) {
3055
- const root = resolve4(options.projectRoot);
3310
+ const root = resolve5(options.projectRoot);
3056
3311
  const installed = await readInstalledState(root);
3057
3312
  const codebuddySurface2 = options.codebuddySurface ?? "both";
3058
3313
  const agents = [];
@@ -3069,7 +3324,8 @@ async function collectFreshness(options) {
3069
3324
  coreHash: null,
3070
3325
  installedCoreHash: null,
3071
3326
  adapterHash: null,
3072
- installedAdapterHash: null
3327
+ installedAdapterHash: null,
3328
+ ...emptyVerification()
3073
3329
  };
3074
3330
  let officialHash = null;
3075
3331
  let officialVersion = null;
@@ -3096,13 +3352,29 @@ async function collectFreshness(options) {
3096
3352
  identity.adapterHash = sha256Bytes(canonicalJson(targets.map((target) => ({ path: target.target_path.replace(/\\/g, "/"), sha256: target.sha256 })).sort((a, b) => a.path.localeCompare(b.path))));
3097
3353
  const installedProjection = await Promise.all(targets.map(async (target) => ({
3098
3354
  path: target.target_path.replace(/\\/g, "/"),
3099
- sha256: await fileHex(join6(root, target.target_path))
3355
+ sha256: await fileHex2(join6(root, target.target_path))
3100
3356
  })));
3101
3357
  identity.installedAdapterHash = sha256Bytes(canonicalJson(installedProjection.sort((a, b) => a.path.localeCompare(b.path))));
3102
3358
  const markerTarget = targets.find((target) => target.target_path.replace(/\\/g, "/").endsWith(`/${BUILD_MARKER_BUNDLE_PATH}`) || target.target_path === BUILD_MARKER_BUNDLE_PATH);
3103
3359
  if (markerTarget !== void 0) {
3104
3360
  identity.installedCoreHash = buildMarkerCoreHash(await readOptionalText(join6(root, markerTarget.target_path)));
3105
3361
  }
3362
+ const mismatchDetails = [];
3363
+ const contentEntries = [];
3364
+ for (const target of targets) {
3365
+ const rel = target.target_path.replace(/\\/g, "/");
3366
+ const actual = await fileHex2(join6(root, target.target_path));
3367
+ contentEntries.push({ relpath: rel, sha256: actual ?? "" });
3368
+ if (actual === null) {
3369
+ mismatchDetails.push({ relpath: rel, expected: target.sha256, actual: "<missing>" });
3370
+ } else if (actual !== target.sha256) {
3371
+ mismatchDetails.push({ relpath: rel, expected: target.sha256, actual });
3372
+ }
3373
+ }
3374
+ identity.installedContentHash = aggregateInstalledContentHash(contentEntries);
3375
+ identity.verifiedAt = (/* @__PURE__ */ new Date()).toISOString();
3376
+ identity.verificationStatus = mismatchDetails.length === 0 ? "verified" : "degraded";
3377
+ identity.mismatchDetails = mismatchDetails;
3106
3378
  if (requestedProfile !== installedProfile) {
3107
3379
  agents.push(freshnessEntry(agent, installedProfile, "PROFILE_MISMATCH", identity));
3108
3380
  continue;
@@ -3114,7 +3386,7 @@ async function collectFreshness(options) {
3114
3386
  const drifted = [];
3115
3387
  const missing = [];
3116
3388
  for (const target of targets) {
3117
- const current = await fileHex(join6(root, target.target_path));
3389
+ const current = await fileHex2(join6(root, target.target_path));
3118
3390
  if (current === null) {
3119
3391
  missing.push(target.target_path);
3120
3392
  } else if (current !== target.sha256) {
@@ -3304,7 +3576,7 @@ function highEntropyCandidates(content) {
3304
3576
  }
3305
3577
 
3306
3578
  // ../core/dist/security/scanner.js
3307
- var SENSITIVE_SCANNER_VERSION = "1.0.0";
3579
+ var SENSITIVE_SCANNER_VERSION = "1.1.0";
3308
3580
  var RULES = [
3309
3581
  {
3310
3582
  id: "HH_PRIVATE_KEY",
@@ -3359,6 +3631,9 @@ function rawFindings(content) {
3359
3631
  for (const rule of RULES) {
3360
3632
  for (const match of content.matchAll(rule.pattern)) {
3361
3633
  const value = match[rule.valueGroup ?? 0] ?? match[0];
3634
+ if (rule.id === "HH_PASSWORD_VALUE" && isObviousPlaceholder(value)) {
3635
+ continue;
3636
+ }
3362
3637
  const relative3 = match[0].indexOf(value);
3363
3638
  findings.push({
3364
3639
  ruleId: rule.id,
@@ -3369,6 +3644,8 @@ function rawFindings(content) {
3369
3644
  }
3370
3645
  }
3371
3646
  for (const candidate of highEntropyCandidates(content)) {
3647
+ if (!hasSensitiveLexicalContext(content, candidate.offset))
3648
+ continue;
3372
3649
  findings.push({
3373
3650
  ruleId: "HH_HIGH_ENTROPY",
3374
3651
  severity: "high",
@@ -3378,6 +3655,17 @@ function rawFindings(content) {
3378
3655
  }
3379
3656
  return findings;
3380
3657
  }
3658
+ function isObviousPlaceholder(value) {
3659
+ const trimmed = value.trim();
3660
+ return /^\$\([^)]+\)$/.test(trimmed) || /^\$\{[A-Za-z_][A-Za-z0-9_]*\}$/.test(trimmed) || /^\{\{[^{}]+\}\}$/.test(trimmed) || /^<[^<>]+>$/.test(trimmed) || /^(?:example|placeholder|your[-_][a-z0-9_-]+)$/i.test(trimmed);
3661
+ }
3662
+ function hasSensitiveLexicalContext(content, offset) {
3663
+ const lineStart = content.lastIndexOf("\n", Math.max(0, offset - 1)) + 1;
3664
+ const nextLineBreak = content.indexOf("\n", offset);
3665
+ const lineEnd = nextLineBreak === -1 ? content.length : nextLineBreak;
3666
+ const line = content.slice(lineStart, lineEnd);
3667
+ return /(?:secret|token|password|passwd|pwd|api[_-]?key|credential|authorization|bearer)\s*[:=]\s*["']?[A-Za-z0-9._~+/-]{8,}/i.test(line);
3668
+ }
3381
3669
  function scanSensitiveFiles(files, options = {}) {
3382
3670
  const findings = [];
3383
3671
  const evidence = [];
@@ -3436,6 +3724,8 @@ function scanSensitiveFiles(files, options = {}) {
3436
3724
  return {
3437
3725
  scanner_version: SENSITIVE_SCANNER_VERSION,
3438
3726
  blocked: findings.some((finding) => finding.disposition === "blocked"),
3727
+ hard_blocked: findings.some((finding) => finding.disposition === "blocked" && finding.severity === "high"),
3728
+ review_required: findings.some((finding) => finding.disposition === "blocked" && finding.severity !== "high"),
3439
3729
  findings,
3440
3730
  override_evidence: Object.freeze(evidence)
3441
3731
  };
@@ -3460,7 +3750,7 @@ function generateProposalPreview(input, scanOptions = {}) {
3460
3750
  }
3461
3751
 
3462
3752
  // ../core/dist/push/credentials.js
3463
- import { readFile as readFile6, writeFile as writeFile3 } from "node:fs/promises";
3753
+ import { readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
3464
3754
  import { join as join7 } from "node:path";
3465
3755
  import { parse as parseYaml4, stringify as stringifyYaml3 } from "yaml";
3466
3756
  var CREDENTIALS_LOCAL_RELATIVE = ".harness/credentials.local.yaml";
@@ -3542,7 +3832,7 @@ async function readLocalCredentials(projectRoot) {
3542
3832
  }
3543
3833
  async function writeLocalCredentials(projectRoot, credentials) {
3544
3834
  const normalized = validateLocalCredentials(credentials);
3545
- await writeFile3(join7(projectRoot, CREDENTIALS_LOCAL_RELATIVE), stringifyYaml3(normalized, { sortMapEntries: true }) + "\n", "utf8");
3835
+ await writeFile4(join7(projectRoot, CREDENTIALS_LOCAL_RELATIVE), stringifyYaml3(normalized, { sortMapEntries: true }) + "\n", "utf8");
3546
3836
  }
3547
3837
  async function ensureCredentialsGitignore(projectRoot) {
3548
3838
  const gitignorePath = join7(projectRoot, ".gitignore");
@@ -3571,7 +3861,7 @@ async function ensureCredentialsGitignore(projectRoot) {
3571
3861
  return;
3572
3862
  }
3573
3863
  const suffix = content.length === 0 || content.endsWith("\n") ? "" : "\n";
3574
- await writeFile3(gitignorePath, content + suffix + missing.join("\n") + "\n", "utf8");
3864
+ await writeFile4(gitignorePath, content + suffix + missing.join("\n") + "\n", "utf8");
3575
3865
  }
3576
3866
  function resolvePushAuth(input) {
3577
3867
  const tokenEnv = input.tokenEnv ?? input.projectTokenEnv;
@@ -3600,7 +3890,7 @@ function resolvePushAuth(input) {
3600
3890
 
3601
3891
  // ../core/dist/push/push.js
3602
3892
  import { lstat as lstat3, readFile as readFile10, readdir as readdir4, rm as rm5 } from "node:fs/promises";
3603
- import { join as join11, relative, resolve as resolve6 } from "node:path";
3893
+ import { join as join11, relative, resolve as resolve7 } from "node:path";
3604
3894
  import { parse as parseYaml5, stringify as stringifyYaml4 } from "yaml";
3605
3895
 
3606
3896
  // ../core/dist/state/baseline.js
@@ -3613,7 +3903,7 @@ async function readBaseline(projectRoot) {
3613
3903
 
3614
3904
  // ../core/dist/state/locks.js
3615
3905
  import { randomUUID as randomUUID3 } from "node:crypto";
3616
- import { readFile as readFile8, rename as rename3, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
3906
+ import { readFile as readFile8, rename as rename3, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
3617
3907
  import { join as join9 } from "node:path";
3618
3908
  async function readLock(path) {
3619
3909
  return JSON.parse(await readFile8(path, "utf8"));
@@ -3633,7 +3923,7 @@ async function acquireProtocolLock(projectRoot, operation, options = {}) {
3633
3923
  };
3634
3924
  for (let attempt = 0; attempt < 2; attempt += 1) {
3635
3925
  try {
3636
- await writeFile4(lockPath, JSON.stringify(record, null, 2), { flag: "wx" });
3926
+ await writeFile5(lockPath, JSON.stringify(record, null, 2), { flag: "wx" });
3637
3927
  return {
3638
3928
  path: lockPath,
3639
3929
  operation,
@@ -3663,7 +3953,7 @@ async function acquireProtocolLock(projectRoot, operation, options = {}) {
3663
3953
 
3664
3954
  // ../core/dist/sync/synchronize.js
3665
3955
  import { lstat as lstat2, readFile as readFile9, rm as rm4 } from "node:fs/promises";
3666
- import { join as join10, resolve as resolve5 } from "node:path";
3956
+ import { join as join10, resolve as resolve6 } from "node:path";
3667
3957
 
3668
3958
  // ../core/dist/update/conflicts.js
3669
3959
  function operationTargetPath(operation) {
@@ -4077,7 +4367,7 @@ async function saveConflictReport(root, requestId, manifest, plan) {
4077
4367
  });
4078
4368
  }
4079
4369
  async function synchronizeArtifacts(options, initialBaseline) {
4080
- const root = resolve5(options.projectRoot);
4370
+ const root = resolve6(options.projectRoot);
4081
4371
  const projectId = options.project.project.project_id;
4082
4372
  if (projectId === null) {
4083
4373
  throw new Error("PROJECT_NOT_BOUND");
@@ -4254,7 +4544,7 @@ function baselineEntryFromOperation(manifest, operation, localContent) {
4254
4544
  };
4255
4545
  }
4256
4546
  async function advanceBaselineFromArtifact(options, baseline) {
4257
- const root = resolve5(options.projectRoot);
4547
+ const root = resolve6(options.projectRoot);
4258
4548
  if (options.manifest.project_version === null) {
4259
4549
  throw new Error("artifact manifest missing project_version");
4260
4550
  }
@@ -4416,7 +4706,7 @@ async function walkHarnessEntries(root, directory, output) {
4416
4706
  }
4417
4707
  }
4418
4708
  async function managedFiles(projectRoot, project) {
4419
- const root = resolve6(projectRoot);
4709
+ const root = resolve7(projectRoot);
4420
4710
  const paths = [];
4421
4711
  const adapters = getAdapters(enabledHarnessAgents(project));
4422
4712
  const managedFiles2 = [
@@ -4668,7 +4958,7 @@ async function bindProject(root, project, baseline, projectId) {
4668
4958
  return { project: nextProject, baseline: nextBaseline };
4669
4959
  }
4670
4960
  async function pushProject(options) {
4671
- const root = resolve6(options.projectRoot);
4961
+ const root = resolve7(options.projectRoot);
4672
4962
  let project = await readProject(root);
4673
4963
  let baseline = await readBaseline(root);
4674
4964
  const profile = parseHarnessProfile(project.project.profiles[0]);
@@ -4998,46 +5288,52 @@ async function cleanupProject(options) {
4998
5288
 
4999
5289
  // ../core/dist/skill/frontmatter.js
5000
5290
  import { parse as parseYaml6 } from "yaml";
5001
- import { z as z14 } from "zod";
5291
+ import { z as z15 } from "zod";
5002
5292
 
5003
5293
  // ../core/dist/skill/fixer.js
5004
5294
  import { parse as parseYaml7, stringify as stringifyYaml5 } from "yaml";
5005
5295
 
5006
- // ../core/dist/skill/agents.js
5007
- var AGENT_DESCRIPTORS = {
5008
- "claude-code": {
5296
+ // ../core/dist/skill/agent-surfaces.js
5297
+ var SURFACES = Object.freeze({
5298
+ "claude-code": Object.freeze({
5009
5299
  agent: "claude-code",
5010
- installable: true,
5011
- installTarget: (slug) => `.claude/skills/${slug}/`,
5012
- installMode: "folder"
5013
- },
5014
- codex: {
5300
+ skillRoots: Object.freeze({ project: ".claude/skills", user: ".claude/skills" }),
5301
+ subagentRoots: Object.freeze({ project: ".claude/agents", user: ".claude/agents" }),
5302
+ subagentFormat: "markdown",
5303
+ subagentExtension: ".md",
5304
+ nativeSkillAliases: Object.freeze([])
5305
+ }),
5306
+ codex: Object.freeze({
5015
5307
  agent: "codex",
5016
- installable: true,
5017
- installTarget: () => "AGENTS.md",
5018
- installMode: "managed_block",
5019
- blockId: (slug) => `harness-skill-${slug}`
5020
- },
5021
- cursor: {
5308
+ skillRoots: Object.freeze({ project: ".agents/skills", user: ".agents/skills" }),
5309
+ subagentRoots: Object.freeze({ project: ".codex/agents", user: ".codex/agents" }),
5310
+ subagentFormat: "toml",
5311
+ subagentExtension: ".toml",
5312
+ nativeSkillAliases: Object.freeze([])
5313
+ }),
5314
+ cursor: Object.freeze({
5022
5315
  agent: "cursor",
5023
- installable: true,
5024
- installTarget: (slug) => `.cursor/rules/${slug}.mdc`,
5025
- installMode: "file"
5026
- },
5027
- generic: {
5028
- agent: "generic",
5029
- installable: true,
5030
- installTarget: (slug) => `.agent-skills/${slug}.md`,
5031
- installMode: "file"
5032
- },
5033
- mcp: {
5034
- agent: "mcp",
5035
- installable: false,
5036
- installTarget: () => "",
5037
- installMode: "file"
5038
- }
5039
- };
5040
- var INSTALLABLE_AGENTS = Object.keys(AGENT_DESCRIPTORS).filter((agent) => AGENT_DESCRIPTORS[agent]?.installable === true);
5316
+ skillRoots: Object.freeze({ project: ".cursor/skills", user: ".cursor/skills" }),
5317
+ subagentRoots: Object.freeze({ project: ".cursor/agents", user: ".cursor/agents" }),
5318
+ subagentFormat: "markdown",
5319
+ subagentExtension: ".md",
5320
+ nativeSkillAliases: Object.freeze([".agents/skills"])
5321
+ }),
5322
+ codebuddy: Object.freeze({
5323
+ agent: "codebuddy",
5324
+ skillRoots: Object.freeze({ project: ".codebuddy/skills", user: ".codebuddy/skills" }),
5325
+ subagentRoots: Object.freeze({ project: ".codebuddy/agents", user: ".codebuddy/agents" }),
5326
+ subagentFormat: "markdown",
5327
+ subagentExtension: ".md",
5328
+ nativeSkillAliases: Object.freeze([])
5329
+ })
5330
+ });
5331
+ var SKILL_TARGET_AGENTS = Object.freeze([
5332
+ "claude-code",
5333
+ "codex",
5334
+ "cursor",
5335
+ "codebuddy"
5336
+ ]);
5041
5337
 
5042
5338
  // ../core/dist/transaction/recovery.js
5043
5339
  import { readFile as readFile12, readdir as readdir6, rm as rm7, stat as stat3 } from "node:fs/promises";
@@ -5161,7 +5457,7 @@ async function cleanupOldTransactions(projectRoot, now = /* @__PURE__ */ new Dat
5161
5457
 
5162
5458
  // ../core/dist/update/update.js
5163
5459
  import { readFile as readFile13 } from "node:fs/promises";
5164
- import { join as join14, resolve as resolve7 } from "node:path";
5460
+ import { join as join14, resolve as resolve8 } from "node:path";
5165
5461
  import { parse as parseYaml8 } from "yaml";
5166
5462
  var UpdateWorkflowError = class extends Error {
5167
5463
  exitCode;
@@ -5174,7 +5470,7 @@ var UpdateWorkflowError = class extends Error {
5174
5470
  }
5175
5471
  };
5176
5472
  async function updateProject(options) {
5177
- const root = resolve7(options.projectRoot);
5473
+ const root = resolve8(options.projectRoot);
5178
5474
  let project;
5179
5475
  try {
5180
5476
  project = projectConfigSchema.parse(parseYaml8(await readFile13(join14(root, ".harness", "project.yaml"), "utf8")));
@@ -5420,7 +5716,7 @@ function serializeCliResult(result) {
5420
5716
  }
5421
5717
 
5422
5718
  // src/config/codebuddy-setup.ts
5423
- import { mkdir as mkdir4, readFile as readFile15, readdir as readdir7, stat as stat4, writeFile as writeFile5 } from "node:fs/promises";
5719
+ import { mkdir as mkdir4, readFile as readFile15, readdir as readdir7, stat as stat4, writeFile as writeFile6 } from "node:fs/promises";
5424
5720
  import { basename as basename2, dirname as dirname4, extname, join as join16 } from "node:path";
5425
5721
  var MANAGED_RULE_NAMES = /* @__PURE__ */ new Set([
5426
5722
  "harness-general.md",
@@ -5494,7 +5790,7 @@ async function applyCodeBuddySetup(options) {
5494
5790
  continue;
5495
5791
  }
5496
5792
  await mkdir4(dirname4(target), { recursive: true });
5497
- await writeFile5(target, content, { encoding: "utf8", flag: "wx" });
5793
+ await writeFile6(target, content, { encoding: "utf8", flag: "wx" });
5498
5794
  result.copied.push(target);
5499
5795
  }
5500
5796
  }
@@ -5515,7 +5811,7 @@ async function applyCodeBuddySetup(options) {
5515
5811
  codegraph: { command: "codegraph", args: ["serve", "--mcp"] }
5516
5812
  }
5517
5813
  };
5518
- await writeFile5(path, JSON.stringify(next, null, 2) + "\n", "utf8");
5814
+ await writeFile6(path, JSON.stringify(next, null, 2) + "\n", "utf8");
5519
5815
  result.mcpUpdated = true;
5520
5816
  }
5521
5817
  }
package/package.json CHANGED
@@ -1,36 +1,36 @@
1
- {
2
- "name": "hunter-harness",
3
- "version": "0.2.19",
4
- "description": "Local-first, server-governed agent harness",
5
- "license": "MIT",
6
- "type": "module",
7
- "engines": {
8
- "node": ">=22.12.0"
9
- },
10
- "bin": {
11
- "hunter-harness": "dist/bin.js"
12
- },
13
- "files": [
14
- "dist/bin.js"
15
- ],
16
- "scripts": {
17
- "build": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json && npm run bundle",
18
- "bundle": "node ../../scripts/bundle-cli.mjs",
19
- "typecheck": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json --noEmit",
20
- "prepack": "npm run build"
21
- },
22
- "dependencies": {
23
- "commander": "15.0.0",
24
- "yaml": "2.9.0",
25
- "zod": "4.4.3"
26
- },
27
- "optionalDependencies": {
28
- "pacote": "21.4.0"
29
- },
30
- "devDependencies": {
31
- "@hunter-harness/contracts": "*",
32
- "@hunter-harness/core": "*",
33
- "@types/pacote": "^11.1.8",
34
- "esbuild": "^0.25.12"
35
- }
36
- }
1
+ {
2
+ "name": "hunter-harness",
3
+ "version": "0.2.21",
4
+ "description": "Local-first, server-governed agent harness",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=22.12.0"
9
+ },
10
+ "bin": {
11
+ "hunter-harness": "dist/bin.js"
12
+ },
13
+ "files": [
14
+ "dist/bin.js"
15
+ ],
16
+ "scripts": {
17
+ "build": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json && npm run bundle",
18
+ "bundle": "node ../../scripts/bundle-cli.mjs",
19
+ "typecheck": "node ../../node_modules/typescript/bin/tsc -p tsconfig.json --noEmit",
20
+ "prepack": "npm run build"
21
+ },
22
+ "dependencies": {
23
+ "commander": "15.0.0",
24
+ "yaml": "2.9.0",
25
+ "zod": "4.4.3"
26
+ },
27
+ "optionalDependencies": {
28
+ "pacote": "21.4.0"
29
+ },
30
+ "devDependencies": {
31
+ "@hunter-harness/contracts": "*",
32
+ "@hunter-harness/core": "*",
33
+ "@types/pacote": "^11.1.8",
34
+ "esbuild": "^0.25.12"
35
+ }
36
+ }