@fro.bot/systematic 3.14.5 → 3.15.1

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 CHANGED
@@ -1,21 +1,24 @@
1
1
  // @bun
2
2
  import {
3
+ parseFrontmatter,
4
+ string,
5
+ array,
6
+ object,
7
+ record,
8
+ _enum,
3
9
  AgentOverlaySchema,
4
10
  CategoryOverlaySchema,
5
- __require,
6
- discoverSkills,
7
- exports_external,
8
- extractAgentFrontmatter,
9
- extractCommandFrontmatter,
11
+ loadConfig,
12
+ loadConfigWithSources,
13
+ isRecord,
14
+ isDiscoverableMarkdown,
10
15
  findAgentsInDir,
16
+ extractAgentFrontmatter,
11
17
  findCommandsInDir,
18
+ extractCommandFrontmatter,
12
19
  findSkillsInDir,
13
- isDiscoverableMarkdown,
14
- isRecord,
15
- loadConfig,
16
- loadConfigWithSources,
17
- parseFrontmatter
18
- } from "./index-0stf3ag0.js";
20
+ discoverSkills
21
+ } from "./index-7cyxcwf5.js";
19
22
 
20
23
  // src/index.ts
21
24
  import { createHash as createHash4 } from "crypto";
@@ -731,14 +734,14 @@ function registerSkillsPaths(config, skillsDir) {
731
734
  };
732
735
  }
733
736
  function removeSystematicSkillPaths(paths) {
734
- return paths.filter((path5) => !isSystematicSkillPath(path5));
737
+ return paths.filter((path) => !isSystematicSkillPath(path));
735
738
  }
736
- function isSystematicSkillPath(path5) {
737
- const normalizedPath = normalizePath(path5);
739
+ function isSystematicSkillPath(path) {
740
+ const normalizedPath = normalizePath(path);
738
741
  return normalizedPath.endsWith("/.config/opencode/systematic/skills") || normalizedPath.endsWith("/.cache/opencode/systematic/skills") || normalizedPath.endsWith("/.local/share/opencode/systematic/skills") || normalizedPath.endsWith("/.opencode/systematic/skills") || /(?:^|\/)\.cache\/opencode\/packages\/@fro\.bot\/systematic@[^/]+\/node_modules\/@fro\.bot\/systematic\/skills(?:$|\/)/u.test(normalizedPath);
739
742
  }
740
- function normalizePath(path5) {
741
- return path5.replaceAll("\\", "/").replace(/\/+$/u, "");
743
+ function normalizePath(path) {
744
+ return path.replaceAll("\\", "/").replace(/\/+$/u, "");
742
745
  }
743
746
 
744
747
  // src/lib/opencode-operation-observer.ts
@@ -1655,10 +1658,10 @@ function createQuestionAttestation(options = {}) {
1655
1658
  const disabledSessions = new Set;
1656
1659
  let challengeCounter = 0;
1657
1660
  function expireChallenges(now) {
1658
- for (const [challengeId, challenge2] of challenges) {
1659
- if ((challenge2.state === "pending" || challenge2.state === "bound") && now - challenge2.createdAt > maxChallengeAgeMs) {
1660
- challenge2.state = "expired";
1661
- const key = bindingKey(challenge2, challenge2.resourceDigest);
1661
+ for (const [challengeId, challenge] of challenges) {
1662
+ if ((challenge.state === "pending" || challenge.state === "bound") && now - challenge.createdAt > maxChallengeAgeMs) {
1663
+ challenge.state = "expired";
1664
+ const key = bindingKey(challenge, challenge.resourceDigest);
1662
1665
  if (activeByBinding.get(key) === challengeId)
1663
1666
  activeByBinding.delete(key);
1664
1667
  }
@@ -1675,17 +1678,17 @@ function createQuestionAttestation(options = {}) {
1675
1678
  function findBindChallenge(input) {
1676
1679
  return "challengeId" in input ? findChallengeById(input.challengeId) : findChallengeByScope(input);
1677
1680
  }
1678
- function bindStateRejection(challenge2, input) {
1679
- if (challenge2.state === "expired")
1681
+ function bindStateRejection(challenge, input) {
1682
+ if (challenge.state === "expired")
1680
1683
  return "challenge-expired";
1681
- if (challenge2.state === "denied" || challenge2.state === "consumed") {
1684
+ if (challenge.state === "denied" || challenge.state === "consumed") {
1682
1685
  return "challenge-consumed";
1683
1686
  }
1684
- if ("sessionId" in input && input.sessionId !== undefined && input.sessionId !== challenge2.sessionId) {
1687
+ if ("sessionId" in input && input.sessionId !== undefined && input.sessionId !== challenge.sessionId) {
1685
1688
  return "call-session-mismatch";
1686
1689
  }
1687
- if (challenge2.state === "bound") {
1688
- return challenge2.requestId === input.requestId ? "already-bound" : "substitution";
1690
+ if (challenge.state === "bound") {
1691
+ return challenge.requestId === input.requestId ? "already-bound" : "substitution";
1689
1692
  }
1690
1693
  return seenRequestIds.has(input.requestId) ? "replay" : null;
1691
1694
  }
@@ -1693,23 +1696,23 @@ function createQuestionAttestation(options = {}) {
1693
1696
  const challengeId = challengeByRequest.get(requestId);
1694
1697
  return challengeId === undefined ? null : challenges.get(challengeId) ?? null;
1695
1698
  }
1696
- function replyStateRejection(challenge2, input) {
1697
- if (challenge2.sessionId !== input.sessionId)
1699
+ function replyStateRejection(challenge, input) {
1700
+ if (challenge.sessionId !== input.sessionId)
1698
1701
  return "substitution";
1699
- if (challenge2.state === "expired")
1702
+ if (challenge.state === "expired")
1700
1703
  return "challenge-expired";
1701
- if (challenge2.state !== "bound" || challenge2.requestId !== input.requestId) {
1704
+ if (challenge.state !== "bound" || challenge.requestId !== input.requestId) {
1702
1705
  return "replay";
1703
1706
  }
1704
1707
  return null;
1705
1708
  }
1706
- function rejectStateRejection(challenge2, input) {
1707
- if (challenge2.sessionId !== input.sessionId)
1709
+ function rejectStateRejection(challenge, input) {
1710
+ if (challenge.sessionId !== input.sessionId)
1708
1711
  return "substitution";
1709
- if (challenge2.state === "denied" || challenge2.state === "consumed") {
1712
+ if (challenge.state === "denied" || challenge.state === "consumed") {
1710
1713
  return "already-consumed";
1711
1714
  }
1712
- if (challenge2.state === "expired")
1715
+ if (challenge.state === "expired")
1713
1716
  return "challenge-expired";
1714
1717
  return null;
1715
1718
  }
@@ -1721,37 +1724,37 @@ function createQuestionAttestation(options = {}) {
1721
1724
  const parsed = parseBinding(input);
1722
1725
  return parsed === null ? null : findChallengeByScope(parsed);
1723
1726
  }
1724
- function projectionBase(challenge2, status2) {
1727
+ function projectionBase(challenge, status) {
1725
1728
  return {
1726
- status: status2,
1727
- challengeId: challenge2.challengeId,
1728
- purpose: challenge2.purpose,
1729
- sessionId: challenge2.sessionId,
1730
- resourceDigest: challenge2.resourceDigest,
1731
- transitionKey: challenge2.transition,
1732
- ...challenge2.requestId === undefined ? {} : { requestId: challenge2.requestId }
1729
+ status,
1730
+ challengeId: challenge.challengeId,
1731
+ purpose: challenge.purpose,
1732
+ sessionId: challenge.sessionId,
1733
+ resourceDigest: challenge.resourceDigest,
1734
+ transitionKey: challenge.transition,
1735
+ ...challenge.requestId === undefined ? {} : { requestId: challenge.requestId }
1733
1736
  };
1734
1737
  }
1735
- function projectChallenge(challenge2) {
1736
- const attestation = challenge2.requestId === undefined ? undefined : attestations.get(challenge2.requestId);
1738
+ function projectChallenge(challenge) {
1739
+ const attestation = challenge.requestId === undefined ? undefined : attestations.get(challenge.requestId);
1737
1740
  if (attestation !== undefined) {
1738
- const status2 = attestation.purpose === "session-disablement" && attestation.consumption === "consumed" ? "disabled" : "attested";
1741
+ const status = attestation.purpose === "session-disablement" && attestation.consumption === "consumed" ? "disabled" : "attested";
1739
1742
  return {
1740
- ...projectionBase(challenge2, status2),
1743
+ ...projectionBase(challenge, status),
1741
1744
  consumption: attestation.consumption
1742
1745
  };
1743
1746
  }
1744
- if (challenge2.state === "pending" || challenge2.state === "bound") {
1745
- return projectionBase(challenge2, challenge2.state);
1747
+ if (challenge.state === "pending" || challenge.state === "bound") {
1748
+ return projectionBase(challenge, challenge.state);
1746
1749
  }
1747
- if (challenge2.state === "denied") {
1748
- return projectionBase(challenge2, "denied");
1750
+ if (challenge.state === "denied") {
1751
+ return projectionBase(challenge, "denied");
1749
1752
  }
1750
1753
  return { status: "unknown", reasonCode: "challenge-expired" };
1751
1754
  }
1752
- function removeActiveChallenge(challenge2) {
1753
- const key = bindingKey(challenge2, challenge2.resourceDigest);
1754
- if (activeByBinding.get(key) === challenge2.challengeId) {
1755
+ function removeActiveChallenge(challenge) {
1756
+ const key = bindingKey(challenge, challenge.resourceDigest);
1757
+ if (activeByBinding.get(key) === challenge.challengeId) {
1755
1758
  activeByBinding.delete(key);
1756
1759
  }
1757
1760
  }
@@ -1800,20 +1803,20 @@ function createQuestionAttestation(options = {}) {
1800
1803
  if (parsed === null)
1801
1804
  return rejected("invalid-input");
1802
1805
  expireChallenges(readNow(clock));
1803
- const challenge2 = findBindChallenge(parsed);
1804
- if (challenge2 === null)
1806
+ const challenge = findBindChallenge(parsed);
1807
+ if (challenge === null)
1805
1808
  return rejected("unknown-challenge");
1806
- const stateRejection = bindStateRejection(challenge2, parsed);
1809
+ const stateRejection = bindStateRejection(challenge, parsed);
1807
1810
  if (stateRejection !== null)
1808
1811
  return rejected(stateRejection);
1809
- challenge2.state = "bound";
1810
- challenge2.callId = parsed.callId;
1811
- challenge2.requestId = parsed.requestId;
1812
- challengeByRequest.set(parsed.requestId, challenge2.challengeId);
1812
+ challenge.state = "bound";
1813
+ challenge.callId = parsed.callId;
1814
+ challenge.requestId = parsed.requestId;
1815
+ challengeByRequest.set(parsed.requestId, challenge.challengeId);
1813
1816
  seenRequestIds.add(parsed.requestId);
1814
1817
  return {
1815
1818
  status: "bound",
1816
- challengeId: challenge2.challengeId,
1819
+ challengeId: challenge.challengeId,
1817
1820
  requestId: parsed.requestId
1818
1821
  };
1819
1822
  } catch {
@@ -1826,32 +1829,32 @@ function createQuestionAttestation(options = {}) {
1826
1829
  if (parsed === null)
1827
1830
  return rejected("invalid-input");
1828
1831
  expireChallenges(readNow(clock));
1829
- const challenge2 = requestChallenge(parsed.requestId);
1830
- if (challenge2 === null) {
1832
+ const challenge = requestChallenge(parsed.requestId);
1833
+ if (challenge === null) {
1831
1834
  const replay = seenRequestIds.has(parsed.requestId);
1832
1835
  seenRequestIds.add(parsed.requestId);
1833
1836
  return rejected(replay ? "replay" : "unknown-request");
1834
1837
  }
1835
- const stateRejection = replyStateRejection(challenge2, parsed);
1838
+ const stateRejection = replyStateRejection(challenge, parsed);
1836
1839
  if (stateRejection !== null)
1837
1840
  return rejected(stateRejection);
1838
1841
  if (classifyQuestionAnswer(parsed.answer) !== "affirmative") {
1839
- challenge2.state = "denied";
1840
- removeActiveChallenge(challenge2);
1842
+ challenge.state = "denied";
1843
+ removeActiveChallenge(challenge);
1841
1844
  return rejected("non-affirmative");
1842
1845
  }
1843
1846
  const attestation = {
1844
- purpose: challenge2.purpose,
1845
- sessionId: challenge2.sessionId,
1846
- resourceDigest: challenge2.resourceDigest,
1847
- transitionKey: challenge2.transition,
1847
+ purpose: challenge.purpose,
1848
+ sessionId: challenge.sessionId,
1849
+ resourceDigest: challenge.resourceDigest,
1850
+ transitionKey: challenge.transition,
1848
1851
  requestId: parsed.requestId,
1849
1852
  answer: "affirmed",
1850
1853
  timestamp: readNow(clock),
1851
1854
  consumption: "available"
1852
1855
  };
1853
- challenge2.state = "consumed";
1854
- removeActiveChallenge(challenge2);
1856
+ challenge.state = "consumed";
1857
+ removeActiveChallenge(challenge);
1855
1858
  attestations.set(parsed.requestId, attestation);
1856
1859
  return { status: "accepted", attestation: cloneAttestation(attestation) };
1857
1860
  } catch {
@@ -1864,17 +1867,17 @@ function createQuestionAttestation(options = {}) {
1864
1867
  if (parsed === null)
1865
1868
  return rejected("invalid-input");
1866
1869
  expireChallenges(readNow(clock));
1867
- const challenge2 = requestChallenge(parsed.requestId);
1868
- if (challenge2 === null) {
1870
+ const challenge = requestChallenge(parsed.requestId);
1871
+ if (challenge === null) {
1869
1872
  const replay = seenRequestIds.has(parsed.requestId);
1870
1873
  seenRequestIds.add(parsed.requestId);
1871
1874
  return rejected(replay ? "replay" : "unknown-request");
1872
1875
  }
1873
- const stateRejection = rejectStateRejection(challenge2, parsed);
1876
+ const stateRejection = rejectStateRejection(challenge, parsed);
1874
1877
  if (stateRejection !== null)
1875
1878
  return rejected(stateRejection);
1876
- challenge2.state = "denied";
1877
- removeActiveChallenge(challenge2);
1879
+ challenge.state = "denied";
1880
+ removeActiveChallenge(challenge);
1878
1881
  return { status: "rejected", reasonCode: "rejected" };
1879
1882
  } catch {
1880
1883
  return rejected("invalid-input");
@@ -1924,10 +1927,10 @@ function createQuestionAttestation(options = {}) {
1924
1927
  ])) {
1925
1928
  return { status: "unknown", reasonCode: "invalid-input" };
1926
1929
  }
1927
- const challenge2 = statusChallenge(input);
1928
- if (challenge2 === null)
1930
+ const challenge = statusChallenge(input);
1931
+ if (challenge === null)
1929
1932
  return { status: "unknown", reasonCode: "unknown-challenge" };
1930
- return projectChallenge(challenge2);
1933
+ return projectChallenge(challenge);
1931
1934
  } catch {
1932
1935
  return { status: "unknown", reasonCode: "invalid-input" };
1933
1936
  }
@@ -1941,9 +1944,9 @@ function createQuestionAttestation(options = {}) {
1941
1944
  const sessionId = input.sessionId;
1942
1945
  if (disabledSessions.has(sessionId))
1943
1946
  return { status: "disabled", sessionId };
1944
- for (const challenge2 of challenges.values()) {
1945
- if (challenge2.sessionId === sessionId && challenge2.purpose === "session-disablement" && (challenge2.state === "pending" || challenge2.state === "bound")) {
1946
- return { status: challenge2.state, sessionId };
1947
+ for (const challenge of challenges.values()) {
1948
+ if (challenge.sessionId === sessionId && challenge.purpose === "session-disablement" && (challenge.state === "pending" || challenge.state === "bound")) {
1949
+ return { status: challenge.state, sessionId };
1947
1950
  }
1948
1951
  }
1949
1952
  return { status: "enabled", sessionId };
@@ -3862,10 +3865,10 @@ function createReceiptLedger(options = {}) {
3862
3865
  return { status: "consumed", receipt: cloneEnvelope2(stored.envelope) };
3863
3866
  }
3864
3867
  function recoverReceipt(input, operationTargetIdentity) {
3865
- const markerResult2 = getMintMarker(input);
3866
- if (markerResult2.status !== "valid")
3867
- return markerResult2;
3868
- const marker = markerResult2.marker;
3868
+ const markerResult = getMintMarker(input);
3869
+ if (markerResult.status !== "valid")
3870
+ return markerResult;
3871
+ const marker = markerResult.marker;
3869
3872
  if (marker.sessionSalt !== sessionSalt)
3870
3873
  return { status: "rejected", category: "salt-mismatch" };
3871
3874
  if (marker.envelope.schemaVersion === 1 && operationTargetIdentity !== undefined) {
@@ -4990,8 +4993,8 @@ var Language = class _Language {
4990
4993
  if (input instanceof Uint8Array) {
4991
4994
  binary2 = input;
4992
4995
  } else if (globalThis.process?.versions.node) {
4993
- const fs22 = await import("fs/promises");
4994
- binary2 = await fs22.readFile(input);
4996
+ const fs2 = await import("fs/promises");
4997
+ binary2 = await fs2.readFile(input);
4995
4998
  } else {
4996
4999
  const response = await fetch(input);
4997
5000
  if (!response.ok) {
@@ -5042,11 +5045,11 @@ async function Module2(moduleArg = {}) {
5042
5045
  }, "quit_");
5043
5046
  var _scriptName = import.meta.url;
5044
5047
  var scriptDirectory = "";
5045
- function locateFile(path6) {
5048
+ function locateFile(path) {
5046
5049
  if (Module["locateFile"]) {
5047
- return Module["locateFile"](path6, scriptDirectory);
5050
+ return Module["locateFile"](path, scriptDirectory);
5048
5051
  }
5049
- return scriptDirectory + path6;
5052
+ return scriptDirectory + path;
5050
5053
  }
5051
5054
  __name(locateFile, "locateFile");
5052
5055
  var readAsync, readBinary;
@@ -9744,23 +9747,23 @@ function createWorkflowGuard(options) {
9744
9747
  return recoveryUnitProgressionReason(progression);
9745
9748
  }
9746
9749
  function recoveryUnitProgressionReason(progression) {
9747
- const epoch2 = progression.epoch;
9750
+ const epoch = progression.epoch;
9748
9751
  const unit = progression.unit;
9749
- if (!epoch2)
9752
+ if (!epoch)
9750
9753
  return "invalid-recovery";
9751
9754
  if (!unit) {
9752
- return epoch2.state === "completed" ? "invalid-recovery" : undefined;
9755
+ return epoch.state === "completed" ? "invalid-recovery" : undefined;
9753
9756
  }
9754
- const declarationFailure = recoveryUnitDeclarationReason(epoch2, unit);
9757
+ const declarationFailure = recoveryUnitDeclarationReason(epoch, unit);
9755
9758
  if (declarationFailure)
9756
9759
  return declarationFailure;
9757
- return unit.resourceScopes.some((scope) => !unit.requiredOperations.includes(scope.operation)) ? "invalid-recovery" : recoveryCompletedPairReason(epoch2, unit);
9760
+ return unit.resourceScopes.some((scope) => !unit.requiredOperations.includes(scope.operation)) ? "invalid-recovery" : recoveryCompletedPairReason(epoch, unit);
9758
9761
  }
9759
- function recoveryUnitDeclarationReason(epoch2, unit) {
9760
- return unit.epochId === epoch2.epochId && unit.epochDigest === epoch2.epochDigest && unit.unitDigest === options.ledger.digestIdentity("unit", unit.unitId) && unit.family === epoch2.family ? undefined : "invalid-recovery";
9762
+ function recoveryUnitDeclarationReason(epoch, unit) {
9763
+ return unit.epochId === epoch.epochId && unit.epochDigest === epoch.epochDigest && unit.unitDigest === options.ledger.digestIdentity("unit", unit.unitId) && unit.family === epoch.family ? undefined : "invalid-recovery";
9761
9764
  }
9762
- function recoveryCompletedPairReason(epoch2, unit) {
9763
- return epoch2.state === "completed" && unit.state !== "completed" ? "invalid-recovery" : undefined;
9765
+ function recoveryCompletedPairReason(epoch, unit) {
9766
+ return epoch.state === "completed" && unit.state !== "completed" ? "invalid-recovery" : undefined;
9764
9767
  }
9765
9768
  function recoveryBoundaryReason(envelope) {
9766
9769
  if (envelope.canonical.workspaceDigest !== options.ledger.digestIdentity("workspace", currentWorkspaceIdentity)) {
@@ -9857,8 +9860,8 @@ function createWorkflowGuard(options) {
9857
9860
  }
9858
9861
  return;
9859
9862
  }
9860
- function recoveryEpochCompletionReason(epoch2, matching) {
9861
- if (epoch2?.state !== "completed")
9863
+ function recoveryEpochCompletionReason(epoch, matching) {
9864
+ if (epoch?.state !== "completed")
9862
9865
  return;
9863
9866
  return matching.length > 0 && matching.every((envelope) => envelope.canonical.consumption === "consumed") ? undefined : "invalid-recovery";
9864
9867
  }
@@ -10291,18 +10294,18 @@ function isWorkflowGuardBlockedError(value) {
10291
10294
  return typeof candidate.reasonCode === "string" && REASON_CODES.has(candidate.reasonCode);
10292
10295
  }
10293
10296
  var startToolShape = {
10294
- expected_operations: exports_external.array(exports_external.enum(OPERATIONS)).optional(),
10295
- resource_scopes: exports_external.record(exports_external.string(), exports_external.string()).optional()
10297
+ expected_operations: array(_enum(OPERATIONS)).optional(),
10298
+ resource_scopes: record(string(), string()).optional()
10296
10299
  };
10297
- var completeToolShape = { target: exports_external.enum(["unit", "epoch"]) };
10300
+ var completeToolShape = { target: _enum(["unit", "epoch"]) };
10298
10301
  var controlToolShape = {
10299
- mode: exports_external.enum(["protected", "disabled", "unavailable"])
10302
+ mode: _enum(["protected", "disabled", "unavailable"])
10300
10303
  };
10301
10304
  var statusToolShape = {};
10302
- var startToolSchema = exports_external.object(startToolShape).strict();
10303
- var completeToolSchema = exports_external.object(completeToolShape).strict();
10304
- var controlToolSchema = exports_external.object(controlToolShape).strict();
10305
- var statusToolSchema = exports_external.object(statusToolShape).strict();
10305
+ var startToolSchema = object(startToolShape).strict();
10306
+ var completeToolSchema = object(completeToolShape).strict();
10307
+ var controlToolSchema = object(controlToolShape).strict();
10308
+ var statusToolSchema = object(statusToolShape).strict();
10306
10309
  function isRecord7(value) {
10307
10310
  return typeof value === "object" && value !== null && !Array.isArray(value);
10308
10311
  }
@@ -10453,13 +10456,13 @@ function validationForCandidate(candidatePath, options, targetPath = candidatePa
10453
10456
  }
10454
10457
  function deriveFileTarget(rawPath, baseDirectory, parentTargetRoot, options, realPath, allowParentFastPath = true) {
10455
10458
  const resolvedPath = path6.resolve(baseDirectory, rawPath);
10456
- const canonicalPath2 = canonicalFileTarget(resolvedPath, realPath);
10457
- if (!canonicalPath2)
10459
+ const canonicalPath = canonicalFileTarget(resolvedPath, realPath);
10460
+ if (!canonicalPath)
10458
10461
  return unavailableOperationTarget();
10459
- const parentResult = allowParentFastPath && !path6.isAbsolute(rawPath) ? trustedParentTarget(parentTargetRoot, canonicalPath2) : undefined;
10462
+ const parentResult = allowParentFastPath && !path6.isAbsolute(rawPath) ? trustedParentTarget(parentTargetRoot, canonicalPath) : undefined;
10460
10463
  if (parentResult)
10461
10464
  return parentResult;
10462
- return validationForCandidate(path6.dirname(canonicalPath2), options, canonicalPath2);
10465
+ return validationForCandidate(path6.dirname(canonicalPath), options, canonicalPath);
10463
10466
  }
10464
10467
  function sharedTargetRoot(targets, extraRoots = []) {
10465
10468
  const roots = [...extraRoots];
@@ -11057,7 +11060,7 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
11057
11060
  return classifyQuestionAnswer(answer) === "affirmative" ? answer : "no";
11058
11061
  }
11059
11062
  function challengeForTransition(sessionID, target) {
11060
- const existing = [...pendingQuestionChallenges.values()].find((pending2) => pending2.purpose === "transition" && pending2.transition === target);
11063
+ const existing = [...pendingQuestionChallenges.values()].find((pending) => pending.purpose === "transition" && pending.transition === target);
11061
11064
  if (existing)
11062
11065
  return existing;
11063
11066
  const resource = questionResource(target);
@@ -11079,7 +11082,7 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
11079
11082
  return pending;
11080
11083
  }
11081
11084
  function challengeForDisablement(sessionID) {
11082
- const existing = [...pendingQuestionChallenges.values()].find((pending2) => pending2.purpose === "session-disablement");
11085
+ const existing = [...pendingQuestionChallenges.values()].find((pending) => pending.purpose === "session-disablement");
11083
11086
  if (existing)
11084
11087
  return existing;
11085
11088
  const resource = `session/${sessionID}`;
@@ -11253,14 +11256,14 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
11253
11256
  }
11254
11257
  return;
11255
11258
  }
11256
- function candidateAgreesWithOwnIdentity(salt, digest2) {
11259
+ function candidateAgreesWithOwnIdentity(salt, digest) {
11257
11260
  try {
11258
11261
  const probe = createReceiptLedger({
11259
11262
  capabilityFlags: ["workflow-guard"],
11260
11263
  registrationIdentity: options.registrationIdentity,
11261
11264
  sessionSalt: salt
11262
11265
  });
11263
- return probe.metadata.registrationDigest === digest2;
11266
+ return probe.metadata.registrationDigest === digest;
11264
11267
  } catch {
11265
11268
  return false;
11266
11269
  }
@@ -12465,7 +12468,7 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
12465
12468
  return;
12466
12469
  }
12467
12470
  }
12468
- function buildOperationObservation(host, pending, after2, current, output, operation = operationCandidate(host.tool), remoteAfter) {
12471
+ function buildOperationObservation(host, pending, after, current, output, operation = operationCandidate(host.tool), remoteAfter) {
12469
12472
  if (!current.epoch || !current.unit || !isLocalOperationTool(host.tool)) {
12470
12473
  return;
12471
12474
  }
@@ -12489,10 +12492,10 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
12489
12492
  },
12490
12493
  after: {
12491
12494
  workspaceIdentity: options.workspaceIdentity,
12492
- repositoryIdentity: after2.repositoryRevisionDigest,
12493
- worktreeIdentity: after2.worktreeRevisionDigest,
12495
+ repositoryIdentity: after.repositoryRevisionDigest,
12496
+ worktreeIdentity: after.worktreeRevisionDigest,
12494
12497
  ...localOperation(operation) ? { operationTargetIdentity: pending.targetIdentity } : {},
12495
- commitClosure: after2.commitClosure,
12498
+ commitClosure: after.commitClosure,
12496
12499
  ...remoteAfter ? {
12497
12500
  resourceIdentity: remoteAfter.resourceIdentity,
12498
12501
  resourceRevisionIdentity: remoteAfter.resourceRevisionIdentity,
@@ -13093,7 +13096,7 @@ function createSkillTool(options) {
13093
13096
  return cachedDescription;
13094
13097
  },
13095
13098
  args: {
13096
- name: exports_external.string().describe((() => {
13099
+ name: string().describe((() => {
13097
13100
  if (cachedParameterHint == null) {
13098
13101
  cachedParameterHint = buildParameterHint();
13099
13102
  }
@@ -0,0 +1,20 @@
1
+ export type ArtifactPathResult = {
2
+ readonly ok: true;
3
+ readonly path: string;
4
+ } | {
5
+ readonly ok: false;
6
+ readonly message: string;
7
+ };
8
+ export type ReadArtifactResult = {
9
+ readonly ok: true;
10
+ readonly value: unknown;
11
+ } | {
12
+ readonly ok: false;
13
+ readonly message: string;
14
+ };
15
+ export declare function formatReviewArtifactIssuePath(issuePath: readonly PropertyKey[]): string;
16
+ export declare function readReviewArtifact(filePath: string): ReadArtifactResult;
17
+ export declare function isLegacyReviewArtifact(value: unknown): boolean;
18
+ export declare function hasParentDirectoryTraversal(input: string): boolean;
19
+ export declare function pathContainsSymlink(candidate: string): boolean;
20
+ export declare function resolveReviewArtifactPath(input: string, cwd: string): ArtifactPathResult;
package/dist/pi.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/pi.ts
2
2
  import path6 from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { Type as Type2 } from "typebox";
4
+ import { Type as Type3 } from "typebox";
5
5
 
6
6
  // src/lib/agent-resolver.ts
7
7
  import fs2 from "node:fs";
@@ -3114,6 +3114,22 @@ function requireJsYaml() {
3114
3114
  }
3115
3115
  var jsYamlExports = requireJsYaml();
3116
3116
  var yaml = /* @__PURE__ */ getDefaultExportFromCjs(jsYamlExports);
3117
+ var {
3118
+ Type,
3119
+ Schema,
3120
+ FAILSAFE_SCHEMA,
3121
+ JSON_SCHEMA,
3122
+ CORE_SCHEMA,
3123
+ DEFAULT_SCHEMA,
3124
+ load,
3125
+ loadAll,
3126
+ dump,
3127
+ YAMLException,
3128
+ types,
3129
+ safeLoad,
3130
+ safeLoadAll,
3131
+ safeDump
3132
+ } = yaml;
3117
3133
 
3118
3134
  // src/lib/frontmatter.ts
3119
3135
  function parseFrontmatter(content) {
@@ -3412,7 +3428,7 @@ import {
3412
3428
  } from "@earendil-works/pi-coding-agent";
3413
3429
 
3414
3430
  // src/lib/pi-delegate-tool.ts
3415
- import { Type } from "typebox";
3431
+ import { Type as Type2 } from "typebox";
3416
3432
  var MAX_DELEGATE_TURNS = 20;
3417
3433
  var DELEGATE_TOOL_NAME = "systematic_delegate";
3418
3434
  var DELEGATE_EXECUTION_MODE = "sequential";
@@ -3486,9 +3502,9 @@ function createPiDelegateTool(deps) {
3486
3502
  };
3487
3503
  }
3488
3504
  function buildDelegateParametersSchema(catalog) {
3489
- return Type.Object({
3490
- agent: Type.String({ description: buildAgentParameterHint(catalog) }),
3491
- task: Type.String({
3505
+ return Type2.Object({
3506
+ agent: Type2.String({ description: buildAgentParameterHint(catalog) }),
3507
+ task: Type2.String({
3492
3508
  description: "The task to delegate to the persona."
3493
3509
  })
3494
3510
  });
@@ -4023,8 +4039,8 @@ async function systematicPiExtension(pi, deps = defaultPiExtensionDependencies)
4023
4039
  label: "Systematic Skill",
4024
4040
  description: buildSkillToolDescription(resolverOptions),
4025
4041
  promptSnippet: "Use `systematic_skill` to load Systematic skills.",
4026
- parameters: Type2.Object({
4027
- name: Type2.String({
4042
+ parameters: Type3.Object({
4043
+ name: Type3.String({
4028
4044
  description: buildSkillToolParameterHint(resolverOptions)
4029
4045
  })
4030
4046
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fro.bot/systematic",
3
- "version": "3.14.5",
3
+ "version": "3.15.1",
4
4
  "description": "Compound-engineering loops for OpenCode, Pi, and Claude Code",
5
5
  "type": "module",
6
6
  "homepage": "https://fro.bot/systematic",
@@ -57,7 +57,7 @@
57
57
  "registry:drift": "bun scripts/generate-registry.ts --check",
58
58
  "registry:validate": "bun scripts/build-registry.ts --validate-only",
59
59
  "claude-code:build": "bun scripts/build-claude-code-plugin.ts",
60
- "postupgrade": "bun run build && bun run agent-browser:build",
60
+ "postupgrade": "bun run build && bun run agent-browser:build && bun run schema:generate && bun run review-schema:generate && bun scripts/generate-registry.ts",
61
61
  "prepublishOnly": "bun run build && bun run schema:generate"
62
62
  },
63
63
  "keywords": [
@@ -93,7 +93,7 @@
93
93
  }
94
94
  },
95
95
  "devDependencies": {
96
- "@biomejs/biome": "2.5.10",
96
+ "@biomejs/biome": "2.5.11",
97
97
  "@earendil-works/pi-coding-agent": "0.83.0",
98
98
  "@opencode-ai/plugin": "1.18.21",
99
99
  "@opencode-ai/sdk": "1.18.21",
@@ -101,7 +101,7 @@
101
101
  "@tintinweb/pi-subagents": "0.14.3",
102
102
  "@types/bun": "latest",
103
103
  "@types/js-yaml": "4.0.9",
104
- "@types/node": "26.2.0",
104
+ "@types/node": "26.4.0",
105
105
  "agent-browser": "0.34.0",
106
106
  "ajv": "8.20.0",
107
107
  "ajv-formats": "3.0.1",
@@ -110,7 +110,7 @@
110
110
  "rimraf": "6.1.3",
111
111
  "semantic-release": "25.0.9",
112
112
  "semantic-release-export-data": "1.2.0",
113
- "typebox": "1.3.16",
113
+ "typebox": "1.3.24",
114
114
  "typescript": "7.0.2"
115
115
  },
116
116
  "dependencies": {
@@ -118,7 +118,7 @@
118
118
  "jsonc-parser": "^3.3.0",
119
119
  "tree-sitter-bash": "0.25.1",
120
120
  "web-tree-sitter": "0.26.12",
121
- "zod": "4.4.3"
121
+ "zod": "4.5.4"
122
122
  },
123
123
  "overrides": {
124
124
  "@earendil-works/pi-ai": "0.83.0",
@@ -41,7 +41,7 @@
41
41
  "completed_at": {
42
42
  "type": "string",
43
43
  "format": "date-time",
44
- "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
44
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
45
45
  },
46
46
  "dispatches": {
47
47
  "maxItems": 64,