@fro.bot/systematic 3.6.2 → 3.8.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 +96 -222
- 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 +3 -3
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 {
|
|
@@ -10958,16 +10832,16 @@ function canonicalFileTarget(filePath, realPath) {
|
|
|
10958
10832
|
const existing = canonicalExistingPath(filePath, realPath);
|
|
10959
10833
|
if (existing)
|
|
10960
10834
|
return existing;
|
|
10961
|
-
const parent = canonicalExistingPath(
|
|
10962
|
-
const basename =
|
|
10963
|
-
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;
|
|
10964
10838
|
}
|
|
10965
10839
|
function pathWithinOrEqual(root, candidate) {
|
|
10966
|
-
const relative =
|
|
10967
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
10840
|
+
const relative = path8.relative(root, candidate);
|
|
10841
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path8.sep}`) && !path8.isAbsolute(relative);
|
|
10968
10842
|
}
|
|
10969
10843
|
function targetIsGitAdminStorage(targetPath, validation) {
|
|
10970
|
-
return pathWithinOrEqual(
|
|
10844
|
+
return pathWithinOrEqual(path8.join(validation.targetRoot, ".git"), targetPath) || pathWithinOrEqual(validation.gitDir, targetPath) || pathWithinOrEqual(validation.commonDir, targetPath);
|
|
10971
10845
|
}
|
|
10972
10846
|
function targetResultFromValidation(candidatePath, validation) {
|
|
10973
10847
|
if (validation.status === "error")
|
|
@@ -10983,7 +10857,7 @@ function targetResultFromValidation(candidatePath, validation) {
|
|
|
10983
10857
|
function trustedParentTarget(parentTargetRoot, candidatePath) {
|
|
10984
10858
|
if (!pathWithinOrEqual(parentTargetRoot, candidatePath))
|
|
10985
10859
|
return;
|
|
10986
|
-
if (pathWithinOrEqual(
|
|
10860
|
+
if (pathWithinOrEqual(path8.join(parentTargetRoot, ".git"), candidatePath)) {
|
|
10987
10861
|
return unavailableOperationTarget();
|
|
10988
10862
|
}
|
|
10989
10863
|
return { status: "available", targetRoot: parentTargetRoot };
|
|
@@ -10996,14 +10870,14 @@ function validationForCandidate(candidatePath, options, targetPath = candidatePa
|
|
|
10996
10870
|
}
|
|
10997
10871
|
}
|
|
10998
10872
|
function deriveFileTarget(rawPath, baseDirectory, parentTargetRoot, options, realPath, allowParentFastPath = true) {
|
|
10999
|
-
const resolvedPath =
|
|
10873
|
+
const resolvedPath = path8.resolve(baseDirectory, rawPath);
|
|
11000
10874
|
const canonicalPath2 = canonicalFileTarget(resolvedPath, realPath);
|
|
11001
10875
|
if (!canonicalPath2)
|
|
11002
10876
|
return unavailableOperationTarget();
|
|
11003
|
-
const parentResult = allowParentFastPath && !
|
|
10877
|
+
const parentResult = allowParentFastPath && !path8.isAbsolute(rawPath) ? trustedParentTarget(parentTargetRoot, canonicalPath2) : undefined;
|
|
11004
10878
|
if (parentResult)
|
|
11005
10879
|
return parentResult;
|
|
11006
|
-
return validationForCandidate(
|
|
10880
|
+
return validationForCandidate(path8.dirname(canonicalPath2), options, canonicalPath2);
|
|
11007
10881
|
}
|
|
11008
10882
|
function sharedTargetRoot(targets, extraRoots = []) {
|
|
11009
10883
|
const roots = [...extraRoots];
|
|
@@ -11016,10 +10890,10 @@ function sharedTargetRoot(targets, extraRoots = []) {
|
|
|
11016
10890
|
return targetRoot && roots.every((root) => root === targetRoot) ? targetRoot : undefined;
|
|
11017
10891
|
}
|
|
11018
10892
|
function deriveDirectoryTarget(rawPath, baseDirectory, parentTargetRoot, options, realPath) {
|
|
11019
|
-
const resolvedPath = canonicalExistingPath(
|
|
10893
|
+
const resolvedPath = canonicalExistingPath(path8.resolve(baseDirectory, rawPath), realPath);
|
|
11020
10894
|
if (!resolvedPath)
|
|
11021
10895
|
return { status: "unavailable" };
|
|
11022
|
-
const parentResult =
|
|
10896
|
+
const parentResult = path8.isAbsolute(rawPath) ? undefined : trustedParentTarget(parentTargetRoot, resolvedPath);
|
|
11023
10897
|
if (parentResult?.status === "unavailable") {
|
|
11024
10898
|
return { status: "unavailable" };
|
|
11025
10899
|
}
|
|
@@ -11127,14 +11001,14 @@ function deriveBashTarget(args2, sessionLocation, parentTargetRoot, options, rea
|
|
|
11127
11001
|
if (typeof args2.workdir !== "string" || args2.workdir.length === 0) {
|
|
11128
11002
|
return unavailableOperationTarget();
|
|
11129
11003
|
}
|
|
11130
|
-
const candidatePath = canonicalExistingPath(
|
|
11004
|
+
const candidatePath = canonicalExistingPath(path8.resolve(sessionLocation, args2.workdir), realPath);
|
|
11131
11005
|
if (!candidatePath)
|
|
11132
11006
|
return unavailableOperationTarget();
|
|
11133
|
-
const parentResult =
|
|
11007
|
+
const parentResult = path8.isAbsolute(args2.workdir) ? undefined : trustedParentTarget(parentTargetRoot, candidatePath);
|
|
11134
11008
|
return parentResult ?? validationForCandidate(candidatePath, options);
|
|
11135
11009
|
}
|
|
11136
11010
|
function deriveOpencodeOperationTarget(tool, args2, options) {
|
|
11137
|
-
const realPath = options.realPath ??
|
|
11011
|
+
const realPath = options.realPath ?? fs9.realpathSync;
|
|
11138
11012
|
const parentTargetRoot = canonicalExistingPath(options.parentTargetRoot, realPath);
|
|
11139
11013
|
if (!parentTargetRoot)
|
|
11140
11014
|
return unavailableOperationTarget();
|
|
@@ -11211,7 +11085,7 @@ function canonicalPatchText(patchText, sessionLocation) {
|
|
|
11211
11085
|
const filePath = line.slice(prefix.length).trim();
|
|
11212
11086
|
if (!filePath)
|
|
11213
11087
|
return;
|
|
11214
|
-
segments[index] = `${prefix}${
|
|
11088
|
+
segments[index] = `${prefix}${path8.resolve(sessionLocation, filePath)}`;
|
|
11215
11089
|
}
|
|
11216
11090
|
return segments.join("");
|
|
11217
11091
|
}
|
|
@@ -11225,13 +11099,13 @@ function canonicalHunks(value, sessionLocation) {
|
|
|
11225
11099
|
}
|
|
11226
11100
|
const canonical = {
|
|
11227
11101
|
...hunk,
|
|
11228
|
-
path:
|
|
11102
|
+
path: path8.resolve(sessionLocation, hunk.path)
|
|
11229
11103
|
};
|
|
11230
11104
|
if (hunk.move_path !== undefined) {
|
|
11231
11105
|
if (typeof hunk.move_path !== "string" || !hunk.move_path) {
|
|
11232
11106
|
return;
|
|
11233
11107
|
}
|
|
11234
|
-
canonical.move_path =
|
|
11108
|
+
canonical.move_path = path8.resolve(sessionLocation, hunk.move_path);
|
|
11235
11109
|
}
|
|
11236
11110
|
hunks.push(canonical);
|
|
11237
11111
|
}
|
|
@@ -11520,7 +11394,7 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
|
|
|
11520
11394
|
function parentObserverRegistration() {
|
|
11521
11395
|
if (!options.observer)
|
|
11522
11396
|
return;
|
|
11523
|
-
const targetRoot = canonicalExistingPath(options.targetDirectory ?? process.cwd(),
|
|
11397
|
+
const targetRoot = canonicalExistingPath(options.targetDirectory ?? process.cwd(), fs9.realpathSync);
|
|
11524
11398
|
if (!targetRoot)
|
|
11525
11399
|
return;
|
|
11526
11400
|
let validation;
|
|
@@ -12469,7 +12343,7 @@ function createSessionRuntime(options, operationObservers, recoveredOperationCon
|
|
|
12469
12343
|
markUnavailable();
|
|
12470
12344
|
return;
|
|
12471
12345
|
}
|
|
12472
|
-
const canonicalParentTargetRoot = canonicalExistingPath(parentTargetRoot,
|
|
12346
|
+
const canonicalParentTargetRoot = canonicalExistingPath(parentTargetRoot, fs9.realpathSync);
|
|
12473
12347
|
if (!canonicalParentTargetRoot) {
|
|
12474
12348
|
markUnavailable();
|
|
12475
12349
|
return;
|
|
@@ -13505,8 +13379,8 @@ function createOpencodeWorkflowGuard(options) {
|
|
|
13505
13379
|
}
|
|
13506
13380
|
|
|
13507
13381
|
// src/lib/skill-resolver.ts
|
|
13508
|
-
import
|
|
13509
|
-
import
|
|
13382
|
+
import fs10 from "fs";
|
|
13383
|
+
import path9 from "path";
|
|
13510
13384
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
13511
13385
|
function getAllSkills(options) {
|
|
13512
13386
|
const { bundledSkillsDir, disabledSkills } = options;
|
|
@@ -13542,7 +13416,7 @@ function buildSkillToolParameterHint(options) {
|
|
|
13542
13416
|
}
|
|
13543
13417
|
function buildSkillContentOutput(matchedSkill) {
|
|
13544
13418
|
const body2 = extractSkillBody(matchedSkill.wrappedTemplate);
|
|
13545
|
-
const dir =
|
|
13419
|
+
const dir = path9.dirname(matchedSkill.skillFile);
|
|
13546
13420
|
const base = pathToFileURL2(dir).href;
|
|
13547
13421
|
const files = discoverSkillFiles(dir);
|
|
13548
13422
|
const lines = [
|
|
@@ -13573,17 +13447,17 @@ function discoverSkillFiles(dir, limit = 10) {
|
|
|
13573
13447
|
function handleEntry(entry, currentDir) {
|
|
13574
13448
|
if (entry.isDirectory()) {
|
|
13575
13449
|
if (!shouldSkipDirectory(entry.name)) {
|
|
13576
|
-
recurse(
|
|
13450
|
+
recurse(path9.resolve(currentDir, entry.name));
|
|
13577
13451
|
}
|
|
13578
13452
|
} else if (shouldIncludeFile(entry.name)) {
|
|
13579
|
-
files.push(
|
|
13453
|
+
files.push(path9.resolve(currentDir, entry.name));
|
|
13580
13454
|
}
|
|
13581
13455
|
}
|
|
13582
13456
|
function recurse(currentDir) {
|
|
13583
13457
|
if (files.length >= limit)
|
|
13584
13458
|
return;
|
|
13585
13459
|
try {
|
|
13586
|
-
const entries =
|
|
13460
|
+
const entries = fs10.readdirSync(currentDir, { withFileTypes: true });
|
|
13587
13461
|
for (const entry of entries) {
|
|
13588
13462
|
if (files.length >= limit)
|
|
13589
13463
|
break;
|
|
@@ -13640,19 +13514,19 @@ function createSkillTool(options) {
|
|
|
13640
13514
|
}
|
|
13641
13515
|
|
|
13642
13516
|
// src/index.ts
|
|
13643
|
-
var __dirname3 =
|
|
13644
|
-
var packageRoot2 =
|
|
13645
|
-
var bundledSkillsDir =
|
|
13646
|
-
var bundledAgentsDir2 =
|
|
13647
|
-
var bundledCommandsDir =
|
|
13648
|
-
var packageJsonPath =
|
|
13649
|
-
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;
|
|
13650
13524
|
var registrationSourceIdentity = createHash5("sha256").update(`systematic/opencode-registration-source/v1/${canonicalPackageSource}`).digest("hex");
|
|
13651
13525
|
var getPackageVersion = () => {
|
|
13652
13526
|
try {
|
|
13653
|
-
if (!
|
|
13527
|
+
if (!fs11.existsSync(packageJsonPath))
|
|
13654
13528
|
return "unknown";
|
|
13655
|
-
const content =
|
|
13529
|
+
const content = fs11.readFileSync(packageJsonPath, "utf8");
|
|
13656
13530
|
const parsed = JSON.parse(content);
|
|
13657
13531
|
return parsed.version ?? "unknown";
|
|
13658
13532
|
} catch {
|