skill-harness 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +108 -31
  2. package/package.json +5 -3
package/dist/index.js CHANGED
@@ -1295,16 +1295,21 @@ function requireLoader() {
1295
1295
  state.result += _result;
1296
1296
  }
1297
1297
  }
1298
+ function chargeMergeWork(state) {
1299
+ state.totalMergeKeys++;
1300
+ if (state.maxTotalMergeKeys !== -1 && state.totalMergeKeys > state.maxTotalMergeKeys) {
1301
+ throwError(state, "merge keys exceeded maxTotalMergeKeys (" + state.maxTotalMergeKeys + ")");
1302
+ }
1303
+ }
1298
1304
  function mergeMappings(state, destination, source, overridableKeys) {
1299
1305
  if (!common2.isObject(source)) {
1300
1306
  throwError(state, "cannot merge mappings; the provided source object is unacceptable");
1301
1307
  }
1308
+ chargeMergeWork(state);
1302
1309
  const sourceKeys = Object.keys(source);
1303
1310
  for (let index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {
1304
1311
  const key3 = sourceKeys[index];
1305
- if (state.maxTotalMergeKeys !== -1 && ++state.totalMergeKeys > state.maxTotalMergeKeys) {
1306
- throwError(state, "merge keys exceeded maxTotalMergeKeys (" + state.maxTotalMergeKeys + ")");
1307
- }
1312
+ chargeMergeWork(state);
1308
1313
  if (!_hasOwnProperty.call(destination, key3)) {
1309
1314
  setProperty(destination, key3, source[key3]);
1310
1315
  overridableKeys[key3] = true;
@@ -1332,6 +1337,9 @@ function requireLoader() {
1332
1337
  }
1333
1338
  if (keyTag === "tag:yaml.org,2002:merge") {
1334
1339
  if (Array.isArray(valueNode)) {
1340
+ if (valueNode.length > 100) {
1341
+ throwError(state, "abnormal merge sequence size");
1342
+ }
1335
1343
  for (let index = 0, quantity = valueNode.length; index < quantity; index += 1) {
1336
1344
  mergeMappings(state, _result, valueNode[index], overridableKeys);
1337
1345
  }
@@ -6076,11 +6084,11 @@ function vitestTally(out) {
6076
6084
  const line = /^\s*Tests\s+(.+)$/m.exec(out);
6077
6085
  if (!line)
6078
6086
  return null;
6079
- const read2 = (word) => {
6087
+ const read3 = (word) => {
6080
6088
  const m = new RegExp(`(\\d+)\\s+${word}`).exec(line[1]);
6081
6089
  return m ? Number(m[1]) : 0;
6082
6090
  };
6083
- return { passed: read2("passed"), failed: read2("failed"), skipped: read2("skipped"), todo: read2("todo") };
6091
+ return { passed: read3("passed"), failed: read3("failed"), skipped: read3("skipped"), todo: read3("todo") };
6084
6092
  }
6085
6093
 
6086
6094
  // packages/core/dist/execution-trace.js
@@ -12289,14 +12297,14 @@ function optionalV2EnumMap(value, field, allowed, event, line) {
12289
12297
  }
12290
12298
  return Object.fromEntries(entries);
12291
12299
  }
12292
- function optionalV2StringMap(value, field, event, line, validate5 = () => true) {
12300
+ function optionalV2StringMap(value, field, event, line, validate6 = () => true) {
12293
12301
  if (value === void 0)
12294
12302
  return void 0;
12295
12303
  const parsed = object2(value);
12296
12304
  if (!parsed)
12297
12305
  throw new Error(`invalid pi-daddy v2 ${event} at line ${line}: ${field} must be an object`);
12298
12306
  const entries = Object.entries(parsed);
12299
- if (entries.some(([key3, entry]) => !key3 || typeof entry !== "string" || !validate5(entry))) {
12307
+ if (entries.some(([key3, entry]) => !key3 || typeof entry !== "string" || !validate6(entry))) {
12300
12308
  throw new Error(`invalid pi-daddy v2 ${event} at line ${line}: ${field} must map capabilities to valid strings`);
12301
12309
  }
12302
12310
  return Object.fromEntries(entries);
@@ -14259,7 +14267,7 @@ function learningJournal2(path, initial) {
14259
14267
  const s = lstatSync12(path);
14260
14268
  if (s.dev !== identity2.dev || s.ino !== identity2.ino) throw Error("learning directory identity changed");
14261
14269
  };
14262
- const read2 = () => {
14270
+ const read3 = () => {
14263
14271
  check();
14264
14272
  const stat = lstatSync12(file);
14265
14273
  if (stat.mode & 63 || process.getuid && stat.uid !== process.getuid()) throw Error("private learning journal required");
@@ -14275,8 +14283,8 @@ function learningJournal2(path, initial) {
14275
14283
  return r;
14276
14284
  });
14277
14285
  };
14278
- read2();
14279
- return { read: read2, append(prior, value) {
14286
+ read3();
14287
+ return { read: read3, append(prior, value) {
14280
14288
  check();
14281
14289
  const lock = join43(path, "writer.lock"), token = randomUUID6();
14282
14290
  const fd = openSync13(lock, constants14.O_RDWR | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384), owned = fstatSync12(fd);
@@ -14284,7 +14292,7 @@ function learningJournal2(path, initial) {
14284
14292
  try {
14285
14293
  writeAll(fd, Buffer.from(token));
14286
14294
  fsyncSync9(fd);
14287
- const history = read2();
14295
+ const history = read3();
14288
14296
  if (history.at(-1).id !== prior) throw Error("stale learning CAS");
14289
14297
  if (history.length >= 4096) throw Error("learning history bound");
14290
14298
  const body = { prior, value: learningCopy2(value) }, event = { ...body, id: learningHash2(body) }, line = Buffer.from(learningJson(event) + "\n");
@@ -15764,9 +15772,9 @@ function metadata(context, checkpointId, projection) {
15764
15772
  };
15765
15773
  }
15766
15774
  function inspectNativePolicy2(context, checkpointId) {
15767
- const read2 = readRetainedExecution2(context.policy.archiveRoot, checkpointId);
15768
- if (read2.sourceId !== context.archiveSourceId || Object.values(read2.manifest.content).some((ref) => ref.bytes !== null && ref.bytes > context.policy.maxBytes)) throw new Error("native snapshot outside policy");
15769
- return metadata(context, checkpointId, read2.projection);
15775
+ const read3 = readRetainedExecution2(context.policy.archiveRoot, checkpointId);
15776
+ if (read3.sourceId !== context.archiveSourceId || Object.values(read3.manifest.content).some((ref) => ref.bytes !== null && ref.bytes > context.policy.maxBytes)) throw new Error("native snapshot outside policy");
15777
+ return metadata(context, checkpointId, read3.projection);
15770
15778
  }
15771
15779
  function ingestNativePolicy2(context, previous, readBytes) {
15772
15780
  if (previous) inspectNativePolicy2(context, previous);
@@ -16170,8 +16178,8 @@ function integer3(value) {
16170
16178
  function member(value, values) {
16171
16179
  require3(typeof value === "string" && values.includes(value));
16172
16180
  }
16173
- function nullable5(value, validate5) {
16174
- if (value !== null) validate5(value);
16181
+ function nullable5(value, validate6) {
16182
+ if (value !== null) validate6(value);
16175
16183
  }
16176
16184
  function reference(value, allowed = kinds) {
16177
16185
  const ref = closed11(value, ["kind", "id", "revision", "digest"]);
@@ -16200,9 +16208,9 @@ function timestamp2(value) {
16200
16208
  require3(typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value));
16201
16209
  require3(!value.startsWith("0000") && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value);
16202
16210
  }
16203
- function set2(value, validate5, building, key3 = canonicalWorkJson2) {
16211
+ function set2(value, validate6, building, key3 = canonicalWorkJson2) {
16204
16212
  require3(Array.isArray(value));
16205
- value.forEach(validate5);
16213
+ value.forEach(validate6);
16206
16214
  const keyed = value.map((item) => ({ item, key: key3(item) }));
16207
16215
  const sorted2 = [...keyed].sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
16208
16216
  for (let i = 1; i < sorted2.length; i++) require3(sorted2[i - 1].key !== sorted2[i].key);
@@ -16491,7 +16499,7 @@ function projectWorkAcceptance2(index, structure, authority, runtime) {
16491
16499
  const receiptIndex = indexWorkReceipts2(authority), { receipts } = receiptIndex;
16492
16500
  conflicts.push(...receiptIndex.conflicts);
16493
16501
  const decisions = [...receipts.values()].filter((g) => g.size === 1).flatMap((g) => [...g.values()]);
16494
- function available(kind, id3, digest4) {
16502
+ function available2(kind, id3, digest4) {
16495
16503
  const values = sortWorkResults2((authority?.availability ?? []).filter((row) => row.kind === kind && row.id === id3 && row.digest === digest4).map((row) => row.available));
16496
16504
  const state = values.length > 1 ? "conflicted" : values.length === 0 ? "unknown" : values[0] ? "available" : "unavailable";
16497
16505
  return { kind, identity: { id: id3, digest: digest4 }, state };
@@ -16533,9 +16541,9 @@ function projectWorkAcceptance2(index, structure, authority, runtime) {
16533
16541
  conflicts.push({ kind: "receipt", id: id3, digests: sortWorkResults2(group.keys()), affectedObligations: affected });
16534
16542
  blockers.push(problem("RECEIPT_CONFLICT", { type: "authority", ref: authority.snapshot }));
16535
16543
  }
16536
- const artifactItems = row.artifact ? [available("artifact", row.artifact.id, row.artifact.contentDigest)] : [];
16544
+ const artifactItems = row.artifact ? [available2("artifact", row.artifact.id, row.artifact.contentDigest)] : [];
16537
16545
  const artifactCoverage = binding.artifact === null ? { state: "unselected", items: [] } : coverage(artifactItems);
16538
- const evidenceCoverage = coverage(sortWorkResults2(current.flatMap((e) => e.payload.binding.evidence.map((ref) => available("evidence", ref.id, ref.digest)))));
16546
+ const evidenceCoverage = coverage(sortWorkResults2(current.flatMap((e) => e.payload.binding.evidence.map((ref) => available2("evidence", ref.id, ref.digest)))));
16539
16547
  const rowClaims = [];
16540
16548
  const trustedDecisions = /* @__PURE__ */ new Set();
16541
16549
  for (const claim of selectedClaims) {
@@ -16560,7 +16568,7 @@ function projectWorkAcceptance2(index, structure, authority, runtime) {
16560
16568
  if (!authority) local.push(problem("AUTHORITY_MISSING", null));
16561
16569
  else if (!matching2.length) local.push(problem(decisions.some((d) => d.claim.eventId === claim.eventId) ? "RECEIPT_MISMATCH" : "RECEIPT_MISSING", eventReference(claim)));
16562
16570
  const support = b.evidence.flatMap((ref) => ref.event ? sourceProblems(ref.event, affected) : []);
16563
- const availabilityProblems = coverageProblems2([...artifactItems, ...b.evidence.map((ref) => available("evidence", ref.id, ref.digest))]);
16571
+ const availabilityProblems = coverageProblems2([...artifactItems, ...b.evidence.map((ref) => available2("evidence", ref.id, ref.digest))]);
16564
16572
  local.push(...support, ...availabilityProblems);
16565
16573
  if (matching2.length) blockers.push(...support.filter(isConflict), ...availabilityProblems.filter(isConflict));
16566
16574
  const rejection = matching2.some((d) => d.decision === "reject");
@@ -17035,9 +17043,9 @@ function readArchivedWork(root, manifestId, context = { selectedSnapshot: null,
17035
17043
  }
17036
17044
  }
17037
17045
  function captureArchivedWorkSignals(root, manifestId, context, suppliedFacts) {
17038
- const read2 = readArchivedWork(root, manifestId, context);
17039
- if (read2.state !== "available" || read2.projection.errors.length || read2.projection.scopeState !== "valid" || !read2.projection.selectedSnapshot || !read2.projection.runtime) throw new Error("work source/selection incomplete; cannot capture signals");
17040
- const work = read2.projection, snapshotDigest = read2.projection.selectedSnapshot.digest;
17046
+ const read3 = readArchivedWork(root, manifestId, context);
17047
+ if (read3.state !== "available" || read3.projection.errors.length || read3.projection.scopeState !== "valid" || !read3.projection.selectedSnapshot || !read3.projection.runtime) throw new Error("work source/selection incomplete; cannot capture signals");
17048
+ const work = read3.projection, runtime = read3.projection.runtime, snapshotDigest = read3.projection.selectedSnapshot.digest;
17041
17049
  const snapshot2 = {
17042
17050
  snapshotDigest,
17043
17051
  scopeValid: true,
@@ -17060,23 +17068,41 @@ function captureArchivedWorkSignals(root, manifestId, context, suppliedFacts) {
17060
17068
  violations: [],
17061
17069
  priorAccepted: []
17062
17070
  };
17071
+ const runtimeFacts = {
17072
+ version: "observed-work-runtime-v1",
17073
+ snapshotDigest,
17074
+ sourceManifestId: manifestId,
17075
+ attempts: runtime.attempts.map((attempt) => {
17076
+ const eventDigests = runtime.occurrences.filter((occurrence2) => occurrence2.payload.executionId === attempt.executionId && occurrence2.payload.provenance === "observed" && ["completed", "failed", "cancelled"].includes(occurrence2.payload.state)).map((occurrence2) => occurrence2.event.digest).sort();
17077
+ return {
17078
+ executionId: attempt.executionId,
17079
+ state: attempt.state,
17080
+ resolution: attempt.resolution,
17081
+ completionEvidence: { state: eventDigests.length ? "available" : "unavailable", eventDigests }
17082
+ };
17083
+ }).sort((a, b) => a.executionId < b.executionId ? -1 : a.executionId > b.executionId ? 1 : 0),
17084
+ obligations: snapshot2.obligations.map((obligation) => ({ obligationDigest: obligation.digest, acceptance: obligation.acceptance, coverage: obligation.coverage })).sort((a, b) => a.obligationDigest < b.obligationDigest ? -1 : a.obligationDigest > b.obligationDigest ? 1 : 0),
17085
+ unavailable: ["checkpoint-evidence", "expected-wait-evidence", "prior-acceptance-history"]
17086
+ };
17087
+ const retainedRuntimeFacts = retainArchiveSource2(root, { sourceId: `observed-runtime-${read3.sourceSha256}`, parser: { id: "observed-work-runtime-facts", version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(runtimeFacts)) });
17063
17088
  const observation = retainWorkSignalObservation2(root, snapshot2, facts);
17064
- const projection = retainArchiveSource2(root, { sourceId: `work-signal-projection-${read2.sourceSha256}`, parser: { id: "pi-daddy-work-projection", version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(work)) });
17089
+ const projection = retainArchiveSource2(root, { sourceId: `work-signal-projection-${read3.sourceSha256}`, parser: { id: "pi-daddy-work-projection", version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(work)) });
17065
17090
  const cases = captureWorkSignalCases2(root, observation.manifestId);
17066
17091
  const linkage = {
17067
17092
  version: "archived-work-signals-v1",
17068
17093
  bindingProfile: "work-v4-revision-digests-v1",
17069
17094
  workManifestId: manifestId,
17070
- workSha256: read2.sourceSha256,
17071
- producerCommit: read2.producerCommit,
17095
+ workSha256: read3.sourceSha256,
17096
+ producerCommit: read3.producerCommit,
17072
17097
  projectionManifestId: projection.manifestId,
17098
+ runtimeFactsManifestId: retainedRuntimeFacts.manifestId,
17073
17099
  observationId: observation.manifestId,
17074
17100
  caseBatchId: cases.batchId,
17075
17101
  candidateIds: cases.candidateIds,
17076
17102
  authorityBasis: "independently-supplied-host-context",
17077
17103
  acceptance: "not-assessed"
17078
17104
  };
17079
- const stored = retainArchiveSource2(root, { sourceId: `work-signal-link-${read2.sourceSha256}`, parser: { id: "archived-work-signals", version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(linkage)) });
17105
+ const stored = retainArchiveSource2(root, { sourceId: `work-signal-link-${read3.sourceSha256}`, parser: { id: "archived-work-signals", version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(linkage)) });
17080
17106
  return { ...linkage, linkageManifestId: stored.manifestId };
17081
17107
  }
17082
17108
 
@@ -17262,8 +17288,57 @@ function openBlindIntervention2(root, id3, author) {
17262
17288
  });
17263
17289
  }
17264
17290
 
17291
+ // packages/adapters/src/learning-lifecycle.ts
17292
+ var SHA7 = /^[a-f0-9]{64}$/;
17293
+ var closed12 = (value, names) => !!value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).sort().join() === names.sort().join();
17294
+ function available(root, id3, parser) {
17295
+ if (!SHA7.test(id3)) throw Error("invalid retained learning link");
17296
+ const source = readArchiveSource2(root, id3);
17297
+ if (source.status !== "available" || source.reference.retention !== "exact" || parser && source.reference.parser.id !== parser) throw Error("retained learning link unavailable");
17298
+ return source;
17299
+ }
17300
+ function validate5(root, input, depth = 0) {
17301
+ if (depth > 64) throw Error("learning lifecycle predecessor bound exceeded");
17302
+ if (!closed12(input, ["caseManifestId", "hypothesisManifestId", "comparisonManifestId", "choiceManifestId", "adoptionManifestId", "rollbackManifestId", "outcomeManifestIds", "predecessorManifestId"]) || !Array.isArray(input.outcomeManifestIds) || input.outcomeManifestIds.length > 64 || new Set(input.outcomeManifestIds).size !== input.outcomeManifestIds.length) throw Error("invalid bounded learning lifecycle");
17303
+ for (const id3 of [input.caseManifestId, input.hypothesisManifestId, input.comparisonManifestId]) available(root, id3);
17304
+ for (const id3 of [input.choiceManifestId, input.adoptionManifestId, input.rollbackManifestId, ...input.outcomeManifestIds]) if (id3 !== null) available(root, id3);
17305
+ if (input.adoptionManifestId && !input.choiceManifestId) throw Error("quality choice required before adoption");
17306
+ if (input.rollbackManifestId && !input.adoptionManifestId) throw Error("adoption required before rollback");
17307
+ if (input.outcomeManifestIds.length && !input.adoptionManifestId) throw Error("adoption required before outcomes");
17308
+ if (input.predecessorManifestId) {
17309
+ const prior = read2(root, input.predecessorManifestId, depth + 1);
17310
+ if (prior.links.case !== input.caseManifestId || prior.links.hypothesis !== input.hypothesisManifestId || prior.links.comparison !== input.comparisonManifestId) throw Error("learning lifecycle identity changed");
17311
+ for (const key3 of ["choice", "adoption", "rollback"]) if (prior.links[key3] !== null && prior.links[key3] !== { choice: input.choiceManifestId, adoption: input.adoptionManifestId, rollback: input.rollbackManifestId }[key3]) throw Error("learning lifecycle cannot regress or replace decisions");
17312
+ if (prior.links.outcomes.some((id3, index) => input.outcomeManifestIds[index] !== id3)) throw Error("learning lifecycle cannot regress or replace outcomes");
17313
+ }
17314
+ const state = input.outcomeManifestIds.length ? "outcome-observed" : input.rollbackManifestId ? "rolled-back" : input.adoptionManifestId ? "adopted-awaiting-outcome" : input.choiceManifestId ? "decision-recorded" : "awaiting-human-choice";
17315
+ return { version: "retained-learning-lifecycle-v1", state, predecessorManifestId: input.predecessorManifestId, links: { case: input.caseManifestId, hypothesis: input.hypothesisManifestId, comparison: input.comparisonManifestId, choice: input.choiceManifestId, adoption: input.adoptionManifestId, rollback: input.rollbackManifestId, outcomes: [...input.outcomeManifestIds] } };
17316
+ }
17317
+ function retainLearningLifecycle(root, input) {
17318
+ const view = validate5(root, input);
17319
+ return retainArchiveSource2(root, { sourceId: `learning-${view.links.comparison.slice(0, 24)}`, parser: { id: "learning-lifecycle", version: "1" }, retention: "exact", bytes: Buffer.from(JSON.stringify(view)) }).manifestId;
17320
+ }
17321
+ function read2(root, manifestId, depth) {
17322
+ if (depth > 64) throw Error("learning lifecycle predecessor bound exceeded");
17323
+ const source = available(root, manifestId, "learning-lifecycle");
17324
+ let value;
17325
+ try {
17326
+ value = JSON.parse(source.bytes.toString("utf8"));
17327
+ } catch {
17328
+ throw Error("invalid retained learning lifecycle");
17329
+ }
17330
+ if (!closed12(value, ["version", "state", "predecessorManifestId", "links"]) || value.version !== "retained-learning-lifecycle-v1" || !closed12(value.links, ["case", "hypothesis", "comparison", "choice", "adoption", "rollback", "outcomes"])) throw Error("invalid retained learning lifecycle");
17331
+ const links = value.links;
17332
+ const rebuilt = validate5(root, { caseManifestId: links.case, hypothesisManifestId: links.hypothesis, comparisonManifestId: links.comparison, choiceManifestId: links.choice, adoptionManifestId: links.adoption, rollbackManifestId: links.rollback, outcomeManifestIds: links.outcomes, predecessorManifestId: value.predecessorManifestId }, depth);
17333
+ if (rebuilt.state !== value.state || JSON.stringify(rebuilt) !== source.bytes.toString("utf8")) throw Error("retained learning lifecycle changed");
17334
+ return Object.freeze({ ...rebuilt, links: Object.freeze({ ...rebuilt.links, outcomes: Object.freeze(rebuilt.links.outcomes) }) });
17335
+ }
17336
+ function readLearningLifecycle(root, manifestId) {
17337
+ return read2(root, manifestId, 0);
17338
+ }
17339
+
17265
17340
  // packages/pi-extension/src/dashboard-bridge.ts
17266
- var DASHBOARD_HARNESS_SOURCE = "127b349310dd8f28e5d6b12148a063fce66a77dd";
17341
+ var DASHBOARD_HARNESS_SOURCE = "d123257e53d48a2cad6919708976b5371dc7590e";
17267
17342
  var DASHBOARD_HARNESS_BRIDGE = /* @__PURE__ */ Symbol.for("skill-harness.dashboard-host.v1");
17268
17343
  var functions = {
17269
17344
  learningJournal: learningJournal2,
@@ -17281,7 +17356,9 @@ var functions = {
17281
17356
  createWorkCaseReviewer: createWorkCaseReviewer2,
17282
17357
  createWorkSignalReviewer: createWorkSignalReviewer2,
17283
17358
  retainBlindIntervention: retainBlindIntervention2,
17284
- openBlindIntervention: openBlindIntervention2
17359
+ openBlindIntervention: openBlindIntervention2,
17360
+ retainLearningLifecycle,
17361
+ readLearningLifecycle
17285
17362
  };
17286
17363
  function publishDashboardHarnessBridge(target = globalThis) {
17287
17364
  const old = target[DASHBOARD_HARNESS_BRIDGE];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skill-harness",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Test/optimize loop for agent skills — run spec'd scenarios on pi, LLM-judge, score, review, re-run",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -18,7 +18,9 @@
18
18
  "skill-harness": "bin.js"
19
19
  },
20
20
  "pi": {
21
- "extensions": ["./dist/index.js"]
21
+ "extensions": [
22
+ "./dist/index.js"
23
+ ]
22
24
  },
23
25
  "files": [
24
26
  "bin.js",
@@ -30,7 +32,7 @@
30
32
  "README.md"
31
33
  ],
32
34
  "dependencies": {
33
- "@skill-harness/cli": "0.14.0",
35
+ "@skill-harness/cli": "0.15.0",
34
36
  "typebox": "^1.1.38"
35
37
  },
36
38
  "repository": {