@fro.bot/systematic 3.6.1 → 3.7.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.
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +1071 -127
- package/dist/{index-1mb4baxr.js → index-hjbt4p5s.js} +335 -27
- package/dist/index.js +99 -223
- package/dist/lib/capability-snapshot.d.ts +195 -0
- package/dist/lib/config-schema.d.ts +1 -1
- package/dist/lib/config.d.ts +40 -2
- package/dist/lib/discovered-skills.d.ts +3 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3,24 +3,23 @@ import {
|
|
|
3
3
|
AgentOverlaySchema,
|
|
4
4
|
CategoryOverlaySchema,
|
|
5
5
|
__require,
|
|
6
|
+
discoverSkills,
|
|
6
7
|
exports_external,
|
|
7
8
|
extractAgentFrontmatter,
|
|
8
9
|
extractCommandFrontmatter,
|
|
9
|
-
extractFrontmatterFromContent,
|
|
10
10
|
findAgentsInDir,
|
|
11
11
|
findCommandsInDir,
|
|
12
12
|
findSkillsInDir,
|
|
13
13
|
isRecord,
|
|
14
14
|
loadConfig,
|
|
15
15
|
loadConfigWithSources,
|
|
16
|
-
parseFrontmatter
|
|
17
|
-
|
|
18
|
-
} from "./index-1mb4baxr.js";
|
|
16
|
+
parseFrontmatter
|
|
17
|
+
} from "./index-hjbt4p5s.js";
|
|
19
18
|
|
|
20
19
|
// src/index.ts
|
|
21
20
|
import { createHash as createHash5 } from "crypto";
|
|
22
|
-
import
|
|
23
|
-
import
|
|
21
|
+
import fs11 from "fs";
|
|
22
|
+
import path10 from "path";
|
|
24
23
|
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL3 } from "url";
|
|
25
24
|
|
|
26
25
|
// src/lib/bootstrap.ts
|
|
@@ -251,9 +250,9 @@ ${skillUsage}${profileSection}${catalogSection}
|
|
|
251
250
|
}
|
|
252
251
|
|
|
253
252
|
// src/lib/config-handler.ts
|
|
254
|
-
import
|
|
253
|
+
import fs6 from "fs";
|
|
255
254
|
import os3 from "os";
|
|
256
|
-
import
|
|
255
|
+
import path6 from "path";
|
|
257
256
|
|
|
258
257
|
// src/lib/agent-overlays.ts
|
|
259
258
|
import fs4 from "fs";
|
|
@@ -605,136 +604,11 @@ function throwConfigError(sourcePath, keyPath, message) {
|
|
|
605
604
|
throw new Error(`Invalid Systematic config in ${sourcePath}: ${keyPath} ${message}`);
|
|
606
605
|
}
|
|
607
606
|
|
|
608
|
-
// src/lib/discovered-skills.ts
|
|
609
|
-
import fs5 from "fs";
|
|
610
|
-
import path5 from "path";
|
|
611
|
-
var SKILL_NAME_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
612
|
-
function isValidSkillName(name2) {
|
|
613
|
-
return name2.length >= 1 && name2.length <= 64 && SKILL_NAME_REGEX.test(name2);
|
|
614
|
-
}
|
|
615
|
-
function findGitWorktreeRoot(startDir) {
|
|
616
|
-
let current = path5.resolve(startDir);
|
|
617
|
-
while (true) {
|
|
618
|
-
try {
|
|
619
|
-
if (fs5.existsSync(path5.join(current, ".git"))) {
|
|
620
|
-
return current;
|
|
621
|
-
}
|
|
622
|
-
} catch {
|
|
623
|
-
return null;
|
|
624
|
-
}
|
|
625
|
-
const parent = path5.dirname(current);
|
|
626
|
-
if (parent === current)
|
|
627
|
-
return null;
|
|
628
|
-
current = parent;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
function upWalk(targets, start2, stop2) {
|
|
632
|
-
const results = [];
|
|
633
|
-
let current = path5.resolve(start2);
|
|
634
|
-
const resolvedStop = stop2 === undefined ? undefined : path5.resolve(stop2);
|
|
635
|
-
while (true) {
|
|
636
|
-
for (const target of targets) {
|
|
637
|
-
const candidate = path5.join(current, target);
|
|
638
|
-
try {
|
|
639
|
-
if (fs5.existsSync(candidate)) {
|
|
640
|
-
results.push(candidate);
|
|
641
|
-
}
|
|
642
|
-
} catch {}
|
|
643
|
-
}
|
|
644
|
-
if (resolvedStop !== undefined && current === resolvedStop)
|
|
645
|
-
break;
|
|
646
|
-
const parent = path5.dirname(current);
|
|
647
|
-
if (parent === current)
|
|
648
|
-
break;
|
|
649
|
-
current = parent;
|
|
650
|
-
}
|
|
651
|
-
return results;
|
|
652
|
-
}
|
|
653
|
-
function uniqueStrings(values) {
|
|
654
|
-
return Array.from(new Set(values));
|
|
655
|
-
}
|
|
656
|
-
function buildOpencodeConfigDirs(startDir, homeDir, gitRoot, globalConfigDir, opencodeConfigDirOverride) {
|
|
657
|
-
const dirs = [globalConfigDir];
|
|
658
|
-
dirs.push(...upWalk([".opencode"], startDir, gitRoot ?? startDir));
|
|
659
|
-
dirs.push(...upWalk([".opencode"], homeDir, homeDir));
|
|
660
|
-
if (opencodeConfigDirOverride !== undefined) {
|
|
661
|
-
dirs.push(opencodeConfigDirOverride);
|
|
662
|
-
}
|
|
663
|
-
return uniqueStrings(dirs);
|
|
664
|
-
}
|
|
665
|
-
function globSkillFiles(rootDir, subdirNames) {
|
|
666
|
-
const results = [];
|
|
667
|
-
for (const subdirName of subdirNames) {
|
|
668
|
-
const scanRoot = path5.join(rootDir, subdirName);
|
|
669
|
-
try {
|
|
670
|
-
if (!fs5.existsSync(scanRoot))
|
|
671
|
-
continue;
|
|
672
|
-
const entries = walkDir(scanRoot, {
|
|
673
|
-
maxDepth: 10,
|
|
674
|
-
filter: (entry) => !entry.isDirectory && entry.name === "SKILL.md"
|
|
675
|
-
});
|
|
676
|
-
for (const entry of entries) {
|
|
677
|
-
results.push(entry.path);
|
|
678
|
-
}
|
|
679
|
-
} catch {}
|
|
680
|
-
}
|
|
681
|
-
return results;
|
|
682
|
-
}
|
|
683
|
-
function toDiscoveredSkill(skillPath, rootId) {
|
|
684
|
-
let content;
|
|
685
|
-
try {
|
|
686
|
-
content = fs5.readFileSync(skillPath, "utf8");
|
|
687
|
-
} catch {
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
const frontmatter = extractFrontmatterFromContent(content);
|
|
691
|
-
const name2 = frontmatter.name;
|
|
692
|
-
if (!name2 || !isValidSkillName(name2))
|
|
693
|
-
return;
|
|
694
|
-
return {
|
|
695
|
-
name: name2,
|
|
696
|
-
description: frontmatter.description,
|
|
697
|
-
frontmatter,
|
|
698
|
-
body: parseFrontmatter(content).body,
|
|
699
|
-
skillPath,
|
|
700
|
-
root: rootId
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
function discoverSkills(options) {
|
|
704
|
-
const { startDir, homeDir, configDir, opencodeConfigDirOverride } = options;
|
|
705
|
-
const globalConfigDir = configDir ?? path5.join(homeDir, ".config/opencode");
|
|
706
|
-
const gitRoot = findGitWorktreeRoot(startDir);
|
|
707
|
-
const byName = new Map;
|
|
708
|
-
function upsertAll(skillPaths, rootId) {
|
|
709
|
-
for (const skillPath of skillPaths) {
|
|
710
|
-
const skill = toDiscoveredSkill(skillPath, rootId);
|
|
711
|
-
if (skill)
|
|
712
|
-
byName.set(skill.name, skill);
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
upsertAll(globSkillFiles(homeDir, [".claude/skills"]), "global-claude");
|
|
716
|
-
upsertAll(globSkillFiles(homeDir, [".agents/skills"]), "global-agents");
|
|
717
|
-
const externalLevels = upWalk([".claude", ".agents"], startDir, gitRoot ?? startDir);
|
|
718
|
-
for (const levelDir of externalLevels) {
|
|
719
|
-
const isClaudeDir = path5.basename(levelDir) === ".claude";
|
|
720
|
-
const parentDir = path5.dirname(levelDir);
|
|
721
|
-
const subdirGlob = isClaudeDir ? ".claude/skills" : ".agents/skills";
|
|
722
|
-
const rootId = isClaudeDir ? "project-claude" : "project-agents";
|
|
723
|
-
upsertAll(globSkillFiles(parentDir, [subdirGlob]), rootId);
|
|
724
|
-
}
|
|
725
|
-
const configDirs = buildOpencodeConfigDirs(startDir, homeDir, gitRoot, globalConfigDir, opencodeConfigDirOverride);
|
|
726
|
-
for (const dir of configDirs) {
|
|
727
|
-
const rootId = dir === globalConfigDir ? "global-opencode-config" : "project-opencode";
|
|
728
|
-
upsertAll(globSkillFiles(dir, ["skill", "skills"]), rootId);
|
|
729
|
-
}
|
|
730
|
-
return Array.from(byName.values());
|
|
731
|
-
}
|
|
732
|
-
|
|
733
607
|
// src/lib/model-availability.ts
|
|
734
608
|
import { createHash } from "crypto";
|
|
735
|
-
import
|
|
609
|
+
import fs5 from "fs";
|
|
736
610
|
import os2 from "os";
|
|
737
|
-
import
|
|
611
|
+
import path5 from "path";
|
|
738
612
|
function emptyAvailability() {
|
|
739
613
|
return { status: "unknown", models: new Set };
|
|
740
614
|
}
|
|
@@ -744,8 +618,8 @@ var MODELS_JSON_FILENAME = "models.json";
|
|
|
744
618
|
var availabilityCache = new WeakMap;
|
|
745
619
|
function resolveCacheDir() {
|
|
746
620
|
const xdgCacheHome = process.env.XDG_CACHE_HOME?.trim();
|
|
747
|
-
const cacheBase = xdgCacheHome &&
|
|
748
|
-
return
|
|
621
|
+
const cacheBase = xdgCacheHome && path5.isAbsolute(xdgCacheHome) ? xdgCacheHome : path5.join(os2.homedir(), ".cache");
|
|
622
|
+
return path5.join(cacheBase, "opencode");
|
|
749
623
|
}
|
|
750
624
|
function fastHash(input) {
|
|
751
625
|
return createHash("sha1").update(input).digest("hex");
|
|
@@ -764,7 +638,7 @@ function isProviderRecord(value) {
|
|
|
764
638
|
function readModelsFromCache(filePath) {
|
|
765
639
|
let fd;
|
|
766
640
|
try {
|
|
767
|
-
fd =
|
|
641
|
+
fd = fs5.openSync(filePath, "r");
|
|
768
642
|
} catch {
|
|
769
643
|
return null;
|
|
770
644
|
}
|
|
@@ -772,7 +646,7 @@ function readModelsFromCache(filePath) {
|
|
|
772
646
|
try {
|
|
773
647
|
let stat;
|
|
774
648
|
try {
|
|
775
|
-
stat =
|
|
649
|
+
stat = fs5.fstatSync(fd);
|
|
776
650
|
} catch {
|
|
777
651
|
return null;
|
|
778
652
|
}
|
|
@@ -787,7 +661,7 @@ function readModelsFromCache(filePath) {
|
|
|
787
661
|
const buffer = Buffer.alloc(stat.size);
|
|
788
662
|
let bytesRead;
|
|
789
663
|
try {
|
|
790
|
-
bytesRead =
|
|
664
|
+
bytesRead = fs5.readSync(fd, buffer, 0, stat.size, 0);
|
|
791
665
|
} catch {
|
|
792
666
|
return null;
|
|
793
667
|
}
|
|
@@ -796,7 +670,7 @@ function readModelsFromCache(filePath) {
|
|
|
796
670
|
raw = buffer.toString("utf8");
|
|
797
671
|
} finally {
|
|
798
672
|
try {
|
|
799
|
-
|
|
673
|
+
fs5.closeSync(fd);
|
|
800
674
|
} catch {}
|
|
801
675
|
}
|
|
802
676
|
if (raw.trim().length === 0)
|
|
@@ -823,14 +697,14 @@ function readFallbackCache() {
|
|
|
823
697
|
const cacheDir = resolveCacheDir();
|
|
824
698
|
const openCodeModelsUrl = process.env.OPENCODE_MODELS_URL?.trim();
|
|
825
699
|
if (openCodeModelsUrl) {
|
|
826
|
-
const urlDerivedPath =
|
|
700
|
+
const urlDerivedPath = path5.join(cacheDir, `models-${fastHash(openCodeModelsUrl)}.json`);
|
|
827
701
|
const urlResult = readModelsFromCache(urlDerivedPath);
|
|
828
702
|
if (urlResult !== null && urlResult.size > 0) {
|
|
829
703
|
return { status: "cache", models: urlResult };
|
|
830
704
|
}
|
|
831
705
|
return emptyAvailability();
|
|
832
706
|
}
|
|
833
|
-
const defaultPath =
|
|
707
|
+
const defaultPath = path5.join(cacheDir, MODELS_JSON_FILENAME);
|
|
834
708
|
const defaultResult = readModelsFromCache(defaultPath);
|
|
835
709
|
if (defaultResult !== null && defaultResult.size > 0) {
|
|
836
710
|
return { status: "cache", models: defaultResult };
|
|
@@ -931,7 +805,7 @@ function formatAgentDescription(name2, description) {
|
|
|
931
805
|
}
|
|
932
806
|
function loadAgentAsConfig(agentInfo) {
|
|
933
807
|
try {
|
|
934
|
-
const content =
|
|
808
|
+
const content = fs6.readFileSync(agentInfo.file, "utf8");
|
|
935
809
|
const {
|
|
936
810
|
description,
|
|
937
811
|
prompt,
|
|
@@ -980,7 +854,7 @@ function loadAgentAsConfig(agentInfo) {
|
|
|
980
854
|
}
|
|
981
855
|
function loadCommandAsConfig(commandInfo) {
|
|
982
856
|
try {
|
|
983
|
-
const content =
|
|
857
|
+
const content = fs6.readFileSync(commandInfo.file, "utf8");
|
|
984
858
|
const { name: name2, description, agent, model, subtask } = extractCommandFrontmatter(content);
|
|
985
859
|
const { body: body2 } = parseFrontmatter(content);
|
|
986
860
|
const cleanName = commandInfo.name.replace(/^\//, "");
|
|
@@ -1241,7 +1115,7 @@ function collectEnabledSkillNames(dir, disabledSkills) {
|
|
|
1241
1115
|
function createConfigHandler(deps) {
|
|
1242
1116
|
const { directory, bundledSkillsDir, bundledAgentsDir: bundledAgentsDir2, bundledCommandsDir } = deps;
|
|
1243
1117
|
const homeDir = deps.homeDir ?? os3.homedir();
|
|
1244
|
-
const opencodeConfigDir = deps.opencodeConfigDir ??
|
|
1118
|
+
const opencodeConfigDir = deps.opencodeConfigDir ?? path6.join(homeDir, ".config/opencode");
|
|
1245
1119
|
const opencodeConfigDirOverride = process.env.OPENCODE_CONFIG_DIR?.trim() ? process.env.OPENCODE_CONFIG_DIR : undefined;
|
|
1246
1120
|
return async (config) => {
|
|
1247
1121
|
const { config: systematicConfig, overlays } = loadConfigWithSources(directory);
|
|
@@ -1287,21 +1161,21 @@ function registerSkillsPaths(config, skillsDir) {
|
|
|
1287
1161
|
};
|
|
1288
1162
|
}
|
|
1289
1163
|
function removeSystematicSkillPaths(paths) {
|
|
1290
|
-
return paths.filter((
|
|
1164
|
+
return paths.filter((path7) => !isSystematicSkillPath(path7));
|
|
1291
1165
|
}
|
|
1292
|
-
function isSystematicSkillPath(
|
|
1293
|
-
const normalizedPath = normalizePath(
|
|
1166
|
+
function isSystematicSkillPath(path7) {
|
|
1167
|
+
const normalizedPath = normalizePath(path7);
|
|
1294
1168
|
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);
|
|
1295
1169
|
}
|
|
1296
|
-
function normalizePath(
|
|
1297
|
-
return
|
|
1170
|
+
function normalizePath(path7) {
|
|
1171
|
+
return path7.replaceAll("\\", "/").replace(/\/+$/u, "");
|
|
1298
1172
|
}
|
|
1299
1173
|
|
|
1300
1174
|
// src/lib/opencode-operation-observer.ts
|
|
1301
1175
|
import { spawnSync } from "child_process";
|
|
1302
1176
|
import { createHash as createHash2 } from "crypto";
|
|
1303
|
-
import
|
|
1304
|
-
import
|
|
1177
|
+
import fs7 from "fs";
|
|
1178
|
+
import path7 from "path";
|
|
1305
1179
|
var DEFAULT_LIMITS = {
|
|
1306
1180
|
maxCommandOutputBytes: 1048576,
|
|
1307
1181
|
maxCommandTimeoutMs: 5000,
|
|
@@ -1413,11 +1287,11 @@ function parseStageEntries(output, maxPathBytes) {
|
|
|
1413
1287
|
return entries.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
1414
1288
|
}
|
|
1415
1289
|
function safePath(root, relativePath) {
|
|
1416
|
-
if (
|
|
1290
|
+
if (path7.isAbsolute(relativePath))
|
|
1417
1291
|
return;
|
|
1418
|
-
const absolutePath =
|
|
1419
|
-
const relative =
|
|
1420
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
1292
|
+
const absolutePath = path7.resolve(root, relativePath);
|
|
1293
|
+
const relative = path7.relative(root, absolutePath);
|
|
1294
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path7.sep}`)) {
|
|
1421
1295
|
return;
|
|
1422
1296
|
}
|
|
1423
1297
|
return absolutePath;
|
|
@@ -1440,25 +1314,25 @@ function runCommand(runner, args2, cwd, limits) {
|
|
|
1440
1314
|
}
|
|
1441
1315
|
return { status: "ok", output: { stdout: result.stdout } };
|
|
1442
1316
|
}
|
|
1443
|
-
function canonicalPath(filePath, realPath =
|
|
1317
|
+
function canonicalPath(filePath, realPath = fs7.realpathSync) {
|
|
1444
1318
|
try {
|
|
1445
1319
|
return realPath(filePath);
|
|
1446
1320
|
} catch {
|
|
1447
1321
|
return;
|
|
1448
1322
|
}
|
|
1449
1323
|
}
|
|
1450
|
-
function requiredGitPath(runner, args2, cwd, limits, realPath =
|
|
1324
|
+
function requiredGitPath(runner, args2, cwd, limits, realPath = fs7.realpathSync) {
|
|
1451
1325
|
const result = runCommand(runner, args2, cwd, limits);
|
|
1452
1326
|
if (result.status === "error")
|
|
1453
1327
|
return result;
|
|
1454
1328
|
const rawValue = result.output.stdout.trim();
|
|
1455
|
-
if (!
|
|
1329
|
+
if (!path7.isAbsolute(rawValue)) {
|
|
1456
1330
|
return { status: "error", reasonCode: "target-unavailable" };
|
|
1457
1331
|
}
|
|
1458
1332
|
const value = canonicalPath(rawValue, realPath);
|
|
1459
1333
|
return value === undefined ? { status: "error", reasonCode: "target-unavailable" } : { status: "ok", value };
|
|
1460
1334
|
}
|
|
1461
|
-
function captureParentIdentity(targetDirectory, runner, limits, realPath =
|
|
1335
|
+
function captureParentIdentity(targetDirectory, runner, limits, realPath = fs7.realpathSync) {
|
|
1462
1336
|
const targetRoot = requiredGitPath(runner, ["rev-parse", "--show-toplevel"], targetDirectory, limits, realPath);
|
|
1463
1337
|
if (targetRoot.status === "error")
|
|
1464
1338
|
return targetRoot;
|
|
@@ -1486,53 +1360,53 @@ function captureParentIdentity(targetDirectory, runner, limits, realPath = fs8.r
|
|
|
1486
1360
|
}
|
|
1487
1361
|
} : { status: "error", reasonCode: "target-unavailable" };
|
|
1488
1362
|
}
|
|
1489
|
-
function readGitfileTarget(gitfilePath, realPath =
|
|
1363
|
+
function readGitfileTarget(gitfilePath, realPath = fs7.realpathSync) {
|
|
1490
1364
|
let contents;
|
|
1491
1365
|
try {
|
|
1492
|
-
contents =
|
|
1366
|
+
contents = fs7.readFileSync(gitfilePath, "utf8");
|
|
1493
1367
|
} catch {
|
|
1494
1368
|
return;
|
|
1495
1369
|
}
|
|
1496
1370
|
const match = /^gitdir:\s*(.+?)\s*$/im.exec(contents);
|
|
1497
1371
|
if (!match)
|
|
1498
1372
|
return;
|
|
1499
|
-
const target =
|
|
1373
|
+
const target = path7.isAbsolute(match[1]) ? match[1] : path7.resolve(path7.dirname(gitfilePath), match[1]);
|
|
1500
1374
|
return canonicalPath(target, realPath);
|
|
1501
1375
|
}
|
|
1502
1376
|
function readGitdirBacklink(backlinkPath, realPath) {
|
|
1503
1377
|
let contents;
|
|
1504
1378
|
try {
|
|
1505
|
-
contents =
|
|
1379
|
+
contents = fs7.readFileSync(backlinkPath, "utf8").trim();
|
|
1506
1380
|
} catch {
|
|
1507
1381
|
return;
|
|
1508
1382
|
}
|
|
1509
1383
|
if (contents.length === 0)
|
|
1510
1384
|
return;
|
|
1511
|
-
const target =
|
|
1385
|
+
const target = path7.isAbsolute(contents) ? contents : path7.resolve(path7.dirname(backlinkPath), contents);
|
|
1512
1386
|
return canonicalPath(target, realPath);
|
|
1513
1387
|
}
|
|
1514
1388
|
function isPathWithin(root, candidate) {
|
|
1515
|
-
const relative =
|
|
1516
|
-
return relative !== "" && relative !== ".." && !relative.startsWith(`..${
|
|
1389
|
+
const relative = path7.relative(root, candidate);
|
|
1390
|
+
return relative !== "" && relative !== ".." && !relative.startsWith(`..${path7.sep}`) && !path7.isAbsolute(relative);
|
|
1517
1391
|
}
|
|
1518
1392
|
function validateDotGitLinkage(targetRoot, gitDir, commonDir, realPath) {
|
|
1519
|
-
const dotGit =
|
|
1393
|
+
const dotGit = path7.join(targetRoot, ".git");
|
|
1520
1394
|
let dotGitStat;
|
|
1521
1395
|
try {
|
|
1522
|
-
dotGitStat =
|
|
1396
|
+
dotGitStat = fs7.lstatSync(dotGit);
|
|
1523
1397
|
} catch {
|
|
1524
1398
|
return false;
|
|
1525
1399
|
}
|
|
1526
1400
|
if (dotGitStat.isDirectory()) {
|
|
1527
1401
|
return gitDir === commonDir && canonicalPath(dotGit, realPath) === commonDir;
|
|
1528
1402
|
}
|
|
1529
|
-
if (!dotGitStat.isFile() || dotGitStat.isSymbolicLink() || !isPathWithin(
|
|
1403
|
+
if (!dotGitStat.isFile() || dotGitStat.isSymbolicLink() || !isPathWithin(path7.join(commonDir, "worktrees"), gitDir) || readGitfileTarget(dotGit, realPath) !== gitDir) {
|
|
1530
1404
|
return false;
|
|
1531
1405
|
}
|
|
1532
|
-
const backlinkPath =
|
|
1406
|
+
const backlinkPath = path7.join(gitDir, "gitdir");
|
|
1533
1407
|
let backlinkStat;
|
|
1534
1408
|
try {
|
|
1535
|
-
backlinkStat =
|
|
1409
|
+
backlinkStat = fs7.lstatSync(backlinkPath);
|
|
1536
1410
|
} catch {
|
|
1537
1411
|
return false;
|
|
1538
1412
|
}
|
|
@@ -1541,7 +1415,7 @@ function validateDotGitLinkage(targetRoot, gitDir, commonDir, realPath) {
|
|
|
1541
1415
|
function validateRegisteredWorktree(candidateDirectory, parentIdentity, options = {}) {
|
|
1542
1416
|
const runner = options.commandRunner ?? defaultCommandRunner;
|
|
1543
1417
|
const limits = mergeLimits(options.limits);
|
|
1544
|
-
const realPath = options.realPath ??
|
|
1418
|
+
const realPath = options.realPath ?? fs7.realpathSync;
|
|
1545
1419
|
const candidateRoot = canonicalPath(candidateDirectory, realPath);
|
|
1546
1420
|
if (candidateRoot === undefined) {
|
|
1547
1421
|
return { status: "error", reasonCode: "target-unavailable" };
|
|
@@ -1926,19 +1800,19 @@ function createOpencodeOperationObserver(options) {
|
|
|
1926
1800
|
const limits = mergeLimits(options.limits);
|
|
1927
1801
|
let targetDirectory;
|
|
1928
1802
|
try {
|
|
1929
|
-
targetDirectory = (options.realPath ??
|
|
1803
|
+
targetDirectory = (options.realPath ?? fs7.realpathSync)(options.targetDirectory);
|
|
1930
1804
|
} catch {
|
|
1931
|
-
targetDirectory =
|
|
1805
|
+
targetDirectory = path7.resolve(options.targetDirectory);
|
|
1932
1806
|
}
|
|
1933
1807
|
const runner = options.commandRunner ?? defaultCommandRunner;
|
|
1934
1808
|
const remoteRunner = options.remoteCommandRunner ?? defaultRemoteCommandRunner;
|
|
1935
|
-
const realPath = options.realPath ??
|
|
1809
|
+
const realPath = options.realPath ?? fs7.realpathSync;
|
|
1936
1810
|
const parentIdentityResult = captureParentIdentity(targetDirectory, runner, limits, realPath);
|
|
1937
1811
|
const targetDigest = digest("target", [targetDirectory]);
|
|
1938
|
-
const fileReader = options.fileReader ??
|
|
1939
|
-
const symlinkReader = options.symlinkReader ??
|
|
1812
|
+
const fileReader = options.fileReader ?? fs7.readFileSync;
|
|
1813
|
+
const symlinkReader = options.symlinkReader ?? fs7.readlinkSync;
|
|
1940
1814
|
const statReader = options.statReader ?? ((filePath) => {
|
|
1941
|
-
const stat =
|
|
1815
|
+
const stat = fs7.lstatSync(filePath);
|
|
1942
1816
|
return {
|
|
1943
1817
|
isFile: stat.isFile(),
|
|
1944
1818
|
isSymbolicLink: stat.isSymbolicLink(),
|
|
@@ -2001,8 +1875,8 @@ function createOpencodeOperationObserver(options) {
|
|
|
2001
1875
|
|
|
2002
1876
|
// src/lib/opencode-workflow-guard.ts
|
|
2003
1877
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
2004
|
-
import
|
|
2005
|
-
import
|
|
1878
|
+
import fs9 from "fs";
|
|
1879
|
+
import path8 from "path";
|
|
2006
1880
|
|
|
2007
1881
|
// src/lib/question-attestation.ts
|
|
2008
1882
|
import { createHash as createHash3, randomBytes } from "crypto";
|
|
@@ -4542,7 +4416,7 @@ function normalizeCapabilities(input) {
|
|
|
4542
4416
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
4543
4417
|
|
|
4544
4418
|
// src/lib/receipt-classifier.ts
|
|
4545
|
-
import
|
|
4419
|
+
import fs8 from "fs";
|
|
4546
4420
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4547
4421
|
|
|
4548
4422
|
// node_modules/.bun/web-tree-sitter@0.25.10/node_modules/web-tree-sitter/tree-sitter.js
|
|
@@ -6002,11 +5876,11 @@ var Module2 = (() => {
|
|
|
6002
5876
|
throw toThrow;
|
|
6003
5877
|
}, "quit_");
|
|
6004
5878
|
var scriptDirectory = "";
|
|
6005
|
-
function locateFile(
|
|
5879
|
+
function locateFile(path8) {
|
|
6006
5880
|
if (Module["locateFile"]) {
|
|
6007
|
-
return Module["locateFile"](
|
|
5881
|
+
return Module["locateFile"](path8, scriptDirectory);
|
|
6008
5882
|
}
|
|
6009
|
-
return scriptDirectory +
|
|
5883
|
+
return scriptDirectory + path8;
|
|
6010
5884
|
}
|
|
6011
5885
|
__name(locateFile, "locateFile");
|
|
6012
5886
|
var readAsync, readBinary;
|
|
@@ -8080,7 +7954,7 @@ function matchesToolIdentity(tool, executable) {
|
|
|
8080
7954
|
async function initializeParserAssets(options) {
|
|
8081
7955
|
const treeSitterWasmPath = options.treeSitterWasmPath ?? resolveAsset("web-tree-sitter/tree-sitter.wasm");
|
|
8082
7956
|
const bashWasmPath = options.bashWasmPath ?? resolveAsset("tree-sitter-bash/tree-sitter-bash.wasm");
|
|
8083
|
-
if (!
|
|
7957
|
+
if (!fs8.existsSync(treeSitterWasmPath) || !fs8.existsSync(bashWasmPath)) {
|
|
8084
7958
|
throw new Error("parser-asset-unavailable");
|
|
8085
7959
|
}
|
|
8086
7960
|
try {
|
|
@@ -10734,6 +10608,7 @@ function createWorkflowGuard(options) {
|
|
|
10734
10608
|
var MARKER_OPEN = "<SYSTEMATIC_WORKFLOW_GUARD>";
|
|
10735
10609
|
var MARKER_CLOSE = "</SYSTEMATIC_WORKFLOW_GUARD>";
|
|
10736
10610
|
var MARKER_PROTOCOL_VERSION = 2;
|
|
10611
|
+
var LEGACY_MARKER_PROTOCOL_VERSION = 1;
|
|
10737
10612
|
var MAX_MARKER_LENGTH = 4096;
|
|
10738
10613
|
var MAX_MARKER_SOURCES = 8;
|
|
10739
10614
|
var MAX_CALL_ID_LENGTH = 256;
|
|
@@ -10957,16 +10832,16 @@ function canonicalFileTarget(filePath, realPath) {
|
|
|
10957
10832
|
const existing = canonicalExistingPath(filePath, realPath);
|
|
10958
10833
|
if (existing)
|
|
10959
10834
|
return existing;
|
|
10960
|
-
const parent = canonicalExistingPath(
|
|
10961
|
-
const basename =
|
|
10962
|
-
return parent && basename && basename !== "." && basename !== ".." ?
|
|
10835
|
+
const parent = canonicalExistingPath(path8.dirname(filePath), realPath);
|
|
10836
|
+
const basename = path8.basename(filePath);
|
|
10837
|
+
return parent && basename && basename !== "." && basename !== ".." ? path8.join(parent, basename) : undefined;
|
|
10963
10838
|
}
|
|
10964
10839
|
function pathWithinOrEqual(root, candidate) {
|
|
10965
|
-
const relative =
|
|
10966
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
10840
|
+
const relative = path8.relative(root, candidate);
|
|
10841
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path8.sep}`) && !path8.isAbsolute(relative);
|
|
10967
10842
|
}
|
|
10968
10843
|
function targetIsGitAdminStorage(targetPath, validation) {
|
|
10969
|
-
return pathWithinOrEqual(
|
|
10844
|
+
return pathWithinOrEqual(path8.join(validation.targetRoot, ".git"), targetPath) || pathWithinOrEqual(validation.gitDir, targetPath) || pathWithinOrEqual(validation.commonDir, targetPath);
|
|
10970
10845
|
}
|
|
10971
10846
|
function targetResultFromValidation(candidatePath, validation) {
|
|
10972
10847
|
if (validation.status === "error")
|
|
@@ -10982,7 +10857,7 @@ function targetResultFromValidation(candidatePath, validation) {
|
|
|
10982
10857
|
function trustedParentTarget(parentTargetRoot, candidatePath) {
|
|
10983
10858
|
if (!pathWithinOrEqual(parentTargetRoot, candidatePath))
|
|
10984
10859
|
return;
|
|
10985
|
-
if (pathWithinOrEqual(
|
|
10860
|
+
if (pathWithinOrEqual(path8.join(parentTargetRoot, ".git"), candidatePath)) {
|
|
10986
10861
|
return unavailableOperationTarget();
|
|
10987
10862
|
}
|
|
10988
10863
|
return { status: "available", targetRoot: parentTargetRoot };
|
|
@@ -10995,14 +10870,14 @@ function validationForCandidate(candidatePath, options, targetPath = candidatePa
|
|
|
10995
10870
|
}
|
|
10996
10871
|
}
|
|
10997
10872
|
function deriveFileTarget(rawPath, baseDirectory, parentTargetRoot, options, realPath, allowParentFastPath = true) {
|
|
10998
|
-
const resolvedPath =
|
|
10873
|
+
const resolvedPath = path8.resolve(baseDirectory, rawPath);
|
|
10999
10874
|
const canonicalPath2 = canonicalFileTarget(resolvedPath, realPath);
|
|
11000
10875
|
if (!canonicalPath2)
|
|
11001
10876
|
return unavailableOperationTarget();
|
|
11002
|
-
const parentResult = allowParentFastPath && !
|
|
10877
|
+
const parentResult = allowParentFastPath && !path8.isAbsolute(rawPath) ? trustedParentTarget(parentTargetRoot, canonicalPath2) : undefined;
|
|
11003
10878
|
if (parentResult)
|
|
11004
10879
|
return parentResult;
|
|
11005
|
-
return validationForCandidate(
|
|
10880
|
+
return validationForCandidate(path8.dirname(canonicalPath2), options, canonicalPath2);
|
|
11006
10881
|
}
|
|
11007
10882
|
function sharedTargetRoot(targets, extraRoots = []) {
|
|
11008
10883
|
const roots = [...extraRoots];
|
|
@@ -11015,10 +10890,10 @@ function sharedTargetRoot(targets, extraRoots = []) {
|
|
|
11015
10890
|
return targetRoot && roots.every((root) => root === targetRoot) ? targetRoot : undefined;
|
|
11016
10891
|
}
|
|
11017
10892
|
function deriveDirectoryTarget(rawPath, baseDirectory, parentTargetRoot, options, realPath) {
|
|
11018
|
-
const resolvedPath = canonicalExistingPath(
|
|
10893
|
+
const resolvedPath = canonicalExistingPath(path8.resolve(baseDirectory, rawPath), realPath);
|
|
11019
10894
|
if (!resolvedPath)
|
|
11020
10895
|
return { status: "unavailable" };
|
|
11021
|
-
const parentResult =
|
|
10896
|
+
const parentResult = path8.isAbsolute(rawPath) ? undefined : trustedParentTarget(parentTargetRoot, resolvedPath);
|
|
11022
10897
|
if (parentResult?.status === "unavailable") {
|
|
11023
10898
|
return { status: "unavailable" };
|
|
11024
10899
|
}
|
|
@@ -11126,14 +11001,14 @@ function deriveBashTarget(args2, sessionLocation, parentTargetRoot, options, rea
|
|
|
11126
11001
|
if (typeof args2.workdir !== "string" || args2.workdir.length === 0) {
|
|
11127
11002
|
return unavailableOperationTarget();
|
|
11128
11003
|
}
|
|
11129
|
-
const candidatePath = canonicalExistingPath(
|
|
11004
|
+
const candidatePath = canonicalExistingPath(path8.resolve(sessionLocation, args2.workdir), realPath);
|
|
11130
11005
|
if (!candidatePath)
|
|
11131
11006
|
return unavailableOperationTarget();
|
|
11132
|
-
const parentResult =
|
|
11007
|
+
const parentResult = path8.isAbsolute(args2.workdir) ? undefined : trustedParentTarget(parentTargetRoot, candidatePath);
|
|
11133
11008
|
return parentResult ?? validationForCandidate(candidatePath, options);
|
|
11134
11009
|
}
|
|
11135
11010
|
function deriveOpencodeOperationTarget(tool, args2, options) {
|
|
11136
|
-
const realPath = options.realPath ??
|
|
11011
|
+
const realPath = options.realPath ?? fs9.realpathSync;
|
|
11137
11012
|
const parentTargetRoot = canonicalExistingPath(options.parentTargetRoot, realPath);
|
|
11138
11013
|
if (!parentTargetRoot)
|
|
11139
11014
|
return unavailableOperationTarget();
|
|
@@ -11210,7 +11085,7 @@ function canonicalPatchText(patchText, sessionLocation) {
|
|
|
11210
11085
|
const filePath = line.slice(prefix.length).trim();
|
|
11211
11086
|
if (!filePath)
|
|
11212
11087
|
return;
|
|
11213
|
-
segments[index] = `${prefix}${
|
|
11088
|
+
segments[index] = `${prefix}${path8.resolve(sessionLocation, filePath)}`;
|
|
11214
11089
|
}
|
|
11215
11090
|
return segments.join("");
|
|
11216
11091
|
}
|
|
@@ -11224,13 +11099,13 @@ function canonicalHunks(value, sessionLocation) {
|
|
|
11224
11099
|
}
|
|
11225
11100
|
const canonical = {
|
|
11226
11101
|
...hunk,
|
|
11227
|
-
path:
|
|
11102
|
+
path: path8.resolve(sessionLocation, hunk.path)
|
|
11228
11103
|
};
|
|
11229
11104
|
if (hunk.move_path !== undefined) {
|
|
11230
11105
|
if (typeof hunk.move_path !== "string" || !hunk.move_path) {
|
|
11231
11106
|
return;
|
|
11232
11107
|
}
|
|
11233
|
-
canonical.move_path =
|
|
11108
|
+
canonical.move_path = path8.resolve(sessionLocation, hunk.move_path);
|
|
11234
11109
|
}
|
|
11235
11110
|
hunks.push(canonical);
|
|
11236
11111
|
}
|
|
@@ -11384,8 +11259,9 @@ function parseMarkerBody(body2) {
|
|
|
11384
11259
|
return;
|
|
11385
11260
|
try {
|
|
11386
11261
|
const parsed = JSON.parse(body2);
|
|
11387
|
-
if (parsed.protocolVersion !== MARKER_PROTOCOL_VERSION)
|
|
11262
|
+
if (parsed.protocolVersion !== MARKER_PROTOCOL_VERSION && parsed.protocolVersion !== LEGACY_MARKER_PROTOCOL_VERSION) {
|
|
11388
11263
|
return;
|
|
11264
|
+
}
|
|
11389
11265
|
if (!Array.isArray(parsed.sources) || parsed.sources.length > MAX_MARKER_SOURCES) {
|
|
11390
11266
|
return;
|
|
11391
11267
|
}
|
|
@@ -11518,7 +11394,7 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
|
|
|
11518
11394
|
function parentObserverRegistration() {
|
|
11519
11395
|
if (!options.observer)
|
|
11520
11396
|
return;
|
|
11521
|
-
const targetRoot = canonicalExistingPath(options.targetDirectory ?? process.cwd(),
|
|
11397
|
+
const targetRoot = canonicalExistingPath(options.targetDirectory ?? process.cwd(), fs9.realpathSync);
|
|
11522
11398
|
if (!targetRoot)
|
|
11523
11399
|
return;
|
|
11524
11400
|
let validation;
|
|
@@ -12467,7 +12343,7 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
|
|
|
12467
12343
|
markUnavailable();
|
|
12468
12344
|
return;
|
|
12469
12345
|
}
|
|
12470
|
-
const canonicalParentTargetRoot = canonicalExistingPath(parentTargetRoot,
|
|
12346
|
+
const canonicalParentTargetRoot = canonicalExistingPath(parentTargetRoot, fs9.realpathSync);
|
|
12471
12347
|
if (!canonicalParentTargetRoot) {
|
|
12472
12348
|
markUnavailable();
|
|
12473
12349
|
return;
|
|
@@ -13503,8 +13379,8 @@ function createOpencodeWorkflowGuard(options) {
|
|
|
13503
13379
|
}
|
|
13504
13380
|
|
|
13505
13381
|
// src/lib/skill-resolver.ts
|
|
13506
|
-
import
|
|
13507
|
-
import
|
|
13382
|
+
import fs10 from "fs";
|
|
13383
|
+
import path9 from "path";
|
|
13508
13384
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
13509
13385
|
function getAllSkills(options) {
|
|
13510
13386
|
const { bundledSkillsDir, disabledSkills } = options;
|
|
@@ -13540,7 +13416,7 @@ function buildSkillToolParameterHint(options) {
|
|
|
13540
13416
|
}
|
|
13541
13417
|
function buildSkillContentOutput(matchedSkill) {
|
|
13542
13418
|
const body2 = extractSkillBody(matchedSkill.wrappedTemplate);
|
|
13543
|
-
const dir =
|
|
13419
|
+
const dir = path9.dirname(matchedSkill.skillFile);
|
|
13544
13420
|
const base = pathToFileURL2(dir).href;
|
|
13545
13421
|
const files = discoverSkillFiles(dir);
|
|
13546
13422
|
const lines = [
|
|
@@ -13571,17 +13447,17 @@ function discoverSkillFiles(dir, limit = 10) {
|
|
|
13571
13447
|
function handleEntry(entry, currentDir) {
|
|
13572
13448
|
if (entry.isDirectory()) {
|
|
13573
13449
|
if (!shouldSkipDirectory(entry.name)) {
|
|
13574
|
-
recurse(
|
|
13450
|
+
recurse(path9.resolve(currentDir, entry.name));
|
|
13575
13451
|
}
|
|
13576
13452
|
} else if (shouldIncludeFile(entry.name)) {
|
|
13577
|
-
files.push(
|
|
13453
|
+
files.push(path9.resolve(currentDir, entry.name));
|
|
13578
13454
|
}
|
|
13579
13455
|
}
|
|
13580
13456
|
function recurse(currentDir) {
|
|
13581
13457
|
if (files.length >= limit)
|
|
13582
13458
|
return;
|
|
13583
13459
|
try {
|
|
13584
|
-
const entries =
|
|
13460
|
+
const entries = fs10.readdirSync(currentDir, { withFileTypes: true });
|
|
13585
13461
|
for (const entry of entries) {
|
|
13586
13462
|
if (files.length >= limit)
|
|
13587
13463
|
break;
|
|
@@ -13638,19 +13514,19 @@ function createSkillTool(options) {
|
|
|
13638
13514
|
}
|
|
13639
13515
|
|
|
13640
13516
|
// src/index.ts
|
|
13641
|
-
var __dirname3 =
|
|
13642
|
-
var packageRoot2 =
|
|
13643
|
-
var bundledSkillsDir =
|
|
13644
|
-
var bundledAgentsDir2 =
|
|
13645
|
-
var bundledCommandsDir =
|
|
13646
|
-
var packageJsonPath =
|
|
13647
|
-
var canonicalPackageSource = pathToFileURL3(
|
|
13517
|
+
var __dirname3 = path10.dirname(fileURLToPath3(import.meta.url));
|
|
13518
|
+
var packageRoot2 = path10.resolve(__dirname3, "..");
|
|
13519
|
+
var bundledSkillsDir = path10.join(packageRoot2, "skills");
|
|
13520
|
+
var bundledAgentsDir2 = path10.join(packageRoot2, "agents");
|
|
13521
|
+
var bundledCommandsDir = path10.join(packageRoot2, "commands");
|
|
13522
|
+
var packageJsonPath = path10.join(packageRoot2, "package.json");
|
|
13523
|
+
var canonicalPackageSource = pathToFileURL3(fs11.realpathSync(packageRoot2)).href;
|
|
13648
13524
|
var registrationSourceIdentity = createHash5("sha256").update(`systematic/opencode-registration-source/v1/${canonicalPackageSource}`).digest("hex");
|
|
13649
13525
|
var getPackageVersion = () => {
|
|
13650
13526
|
try {
|
|
13651
|
-
if (!
|
|
13527
|
+
if (!fs11.existsSync(packageJsonPath))
|
|
13652
13528
|
return "unknown";
|
|
13653
|
-
const content =
|
|
13529
|
+
const content = fs11.readFileSync(packageJsonPath, "utf8");
|
|
13654
13530
|
const parsed = JSON.parse(content);
|
|
13655
13531
|
return parsed.version ?? "unknown";
|
|
13656
13532
|
} catch {
|