omniagent 0.1.1 → 0.1.3
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/CLAUDE.md +29 -0
- package/README.md +49 -0
- package/dist/cli.js +1232 -163
- package/package.json +4 -1
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,131 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { constants, realpathSync } from "node:fs";
|
|
3
|
-
import { pathToFileURL } from "node:url";
|
|
2
|
+
import { constants, realpathSync, existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
4
4
|
import yargs from "yargs";
|
|
5
5
|
import { hideBin } from "yargs/helpers";
|
|
6
|
-
import { stat, access, readFile, mkdir, writeFile,
|
|
6
|
+
import { stat, rm, readdir, access, readFile, mkdir, writeFile, rename } from "node:fs/promises";
|
|
7
7
|
import path from "node:path";
|
|
8
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
9
|
+
import os from "node:os";
|
|
8
10
|
import { createInterface } from "node:readline/promises";
|
|
9
11
|
import { TextDecoder } from "node:util";
|
|
10
|
-
import { createHash } from "node:crypto";
|
|
11
|
-
import os from "node:os";
|
|
12
12
|
import { spawn } from "node:child_process";
|
|
13
|
+
async function pathExists$2(candidate) {
|
|
14
|
+
try {
|
|
15
|
+
await stat(candidate);
|
|
16
|
+
return true;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function findUp(startDir, markerRelativePath) {
|
|
22
|
+
let current = path.resolve(startDir);
|
|
23
|
+
let previous = "";
|
|
24
|
+
while (current !== previous) {
|
|
25
|
+
if (await pathExists$2(path.join(current, markerRelativePath))) {
|
|
26
|
+
return current;
|
|
27
|
+
}
|
|
28
|
+
previous = current;
|
|
29
|
+
current = path.dirname(current);
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
async function findRepoRoot(startDir) {
|
|
34
|
+
const gitRoot = await findUp(startDir, ".git");
|
|
35
|
+
if (gitRoot) {
|
|
36
|
+
return gitRoot;
|
|
37
|
+
}
|
|
38
|
+
return await findUp(startDir, "package.json");
|
|
39
|
+
}
|
|
40
|
+
function hashIdentifier$3(value) {
|
|
41
|
+
return createHash("sha256").update(value).digest("hex");
|
|
42
|
+
}
|
|
43
|
+
async function pathExists$1(candidate) {
|
|
44
|
+
try {
|
|
45
|
+
await stat(candidate);
|
|
46
|
+
return true;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function listRepoSlashCommandManifestPaths(repoRoot) {
|
|
52
|
+
const matches = [];
|
|
53
|
+
const stack = [repoRoot];
|
|
54
|
+
while (stack.length > 0) {
|
|
55
|
+
const current = stack.pop();
|
|
56
|
+
if (!current) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const entries = await readdir(current, { withFileTypes: true });
|
|
60
|
+
for (const entry2 of entries) {
|
|
61
|
+
const childPath = path.join(current, entry2.name);
|
|
62
|
+
if (entry2.isDirectory()) {
|
|
63
|
+
stack.push(childPath);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (entry2.isFile() && entry2.name === ".omniagent-slash-commands.toml") {
|
|
67
|
+
matches.push(childPath);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return matches;
|
|
72
|
+
}
|
|
73
|
+
function resolveRepoScopedStatePaths(repoRoot, homeDir) {
|
|
74
|
+
const repoHash = hashIdentifier$3(repoRoot);
|
|
75
|
+
return [
|
|
76
|
+
path.join(homeDir, ".omniagent", "state", "managed-outputs", "projects", repoHash),
|
|
77
|
+
path.join(homeDir, ".omniagent", "state", "instructions", "projects", repoHash),
|
|
78
|
+
path.join(homeDir, ".omniagent", "state", "subagents", "projects", repoHash),
|
|
79
|
+
path.join(homeDir, ".omniagent", "state", "slash-commands", "projects", repoHash),
|
|
80
|
+
path.join(homeDir, ".omniagent", "state", "ignore-rules", "projects", `${repoHash}.json`),
|
|
81
|
+
path.join(homeDir, ".omniagent", "slash-commands", "projects", repoHash),
|
|
82
|
+
path.join(homeDir, ".omniagent", "slash-commands", "skills", "projects", repoHash),
|
|
83
|
+
path.join(repoRoot, ".omniagent", "slash-commands")
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
async function resetProjectState(repoRoot, homeDir = os.homedir()) {
|
|
87
|
+
const candidates = [
|
|
88
|
+
...resolveRepoScopedStatePaths(repoRoot, homeDir),
|
|
89
|
+
...await listRepoSlashCommandManifestPaths(repoRoot)
|
|
90
|
+
];
|
|
91
|
+
const uniqueCandidates = Array.from(new Set(candidates));
|
|
92
|
+
const removedPaths = [];
|
|
93
|
+
for (const candidate of uniqueCandidates) {
|
|
94
|
+
if (!await pathExists$1(candidate)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
await rm(candidate, { recursive: true, force: true });
|
|
98
|
+
removedPaths.push(candidate);
|
|
99
|
+
}
|
|
100
|
+
return { removedPaths };
|
|
101
|
+
}
|
|
102
|
+
const resetStateCommand = {
|
|
103
|
+
command: "reset-state",
|
|
104
|
+
describe: "Reset omniagent project state for the current repository",
|
|
105
|
+
handler: async () => {
|
|
106
|
+
const startDir = process.cwd();
|
|
107
|
+
const repoRoot = await findRepoRoot(startDir);
|
|
108
|
+
if (!repoRoot) {
|
|
109
|
+
console.error("Error: Could not find a project root from the current directory.");
|
|
110
|
+
process.exit(1);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const result = await resetProjectState(repoRoot);
|
|
114
|
+
if (result.removedPaths.length === 0) {
|
|
115
|
+
console.log(`No project state found for: ${repoRoot}`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
console.log(`Reset project state for: ${repoRoot}`);
|
|
119
|
+
console.log(`Removed ${result.removedPaths.length} path(s).`);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const devCommand = {
|
|
123
|
+
command: "dev <command>",
|
|
124
|
+
describe: "Developer utilities",
|
|
125
|
+
builder: (yargs2) => yargs2.command(resetStateCommand).demandCommand(1, "Specify a dev command.").strictCommands(),
|
|
126
|
+
handler: () => {
|
|
127
|
+
}
|
|
128
|
+
};
|
|
13
129
|
const echoCommand = {
|
|
14
130
|
command: "echo [message]",
|
|
15
131
|
describe: "Echo a message with optional repetition and prefix",
|
|
@@ -718,6 +834,74 @@ const codexTarget = {
|
|
|
718
834
|
}
|
|
719
835
|
}
|
|
720
836
|
};
|
|
837
|
+
const FRONTMATTER_MARKER$2 = "---";
|
|
838
|
+
function stripFrontmatterFields(contents, keysToRemove) {
|
|
839
|
+
const lines = contents.split(/\r?\n/);
|
|
840
|
+
if (lines[0]?.trim() !== FRONTMATTER_MARKER$2) {
|
|
841
|
+
return contents;
|
|
842
|
+
}
|
|
843
|
+
let endIndex = -1;
|
|
844
|
+
for (let i = 1; i < lines.length; i += 1) {
|
|
845
|
+
if (lines[i].trim() === FRONTMATTER_MARKER$2) {
|
|
846
|
+
endIndex = i;
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
if (endIndex === -1) {
|
|
851
|
+
return contents;
|
|
852
|
+
}
|
|
853
|
+
const normalizedKeys = new Set(Array.from(keysToRemove).map((key) => key.toLowerCase()));
|
|
854
|
+
const frontmatterLines = lines.slice(1, endIndex);
|
|
855
|
+
const filtered = [];
|
|
856
|
+
let skippingList = false;
|
|
857
|
+
for (const line of frontmatterLines) {
|
|
858
|
+
const trimmed = line.trim();
|
|
859
|
+
const match = trimmed.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
860
|
+
if (skippingList) {
|
|
861
|
+
if (match && !normalizedKeys.has(match[1].toLowerCase())) {
|
|
862
|
+
skippingList = false;
|
|
863
|
+
} else if (!match) {
|
|
864
|
+
const shouldSkip = trimmed === "" || trimmed.startsWith("-") || trimmed.startsWith("#");
|
|
865
|
+
if (shouldSkip) {
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
868
|
+
skippingList = false;
|
|
869
|
+
} else {
|
|
870
|
+
continue;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (match) {
|
|
874
|
+
const [, key, rawValue] = match;
|
|
875
|
+
if (normalizedKeys.has(key.toLowerCase())) {
|
|
876
|
+
const rest = rawValue.trim();
|
|
877
|
+
if (!rest || rest.startsWith("#")) {
|
|
878
|
+
skippingList = true;
|
|
879
|
+
}
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
if (!skippingList) {
|
|
884
|
+
filtered.push(line);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
const eol = contents.includes("\r\n") ? "\r\n" : "\n";
|
|
888
|
+
const outputLines = [lines[0], ...filtered, ...lines.slice(endIndex)];
|
|
889
|
+
return outputLines.join(eol);
|
|
890
|
+
}
|
|
891
|
+
const TARGET_FRONTMATTER_KEYS$3 = /* @__PURE__ */ new Set(["targets", "targetagents"]);
|
|
892
|
+
function isSlashCommandLike(value) {
|
|
893
|
+
if (!value || typeof value !== "object") {
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
const command = value;
|
|
897
|
+
return typeof command.name === "string" && typeof command.rawContents === "string";
|
|
898
|
+
}
|
|
899
|
+
function renderPromptReference(agentName) {
|
|
900
|
+
return `---
|
|
901
|
+
agent: ${JSON.stringify(agentName)}
|
|
902
|
+
---
|
|
903
|
+
`;
|
|
904
|
+
}
|
|
721
905
|
const copilotTarget = {
|
|
722
906
|
id: "copilot",
|
|
723
907
|
displayName: "GitHub Copilot CLI",
|
|
@@ -740,13 +924,41 @@ const copilotTarget = {
|
|
|
740
924
|
},
|
|
741
925
|
outputs: {
|
|
742
926
|
skills: "{repoRoot}/.github/skills/{itemName}",
|
|
743
|
-
subagents: {
|
|
744
|
-
path: "{repoRoot}/.github/skills/{itemName}",
|
|
745
|
-
fallback: { mode: "convert", targetType: "skills" }
|
|
746
|
-
},
|
|
927
|
+
subagents: "{repoRoot}/.github/agents/{itemName}.agent.md",
|
|
747
928
|
commands: {
|
|
748
|
-
projectPath: "{repoRoot}/.github/
|
|
749
|
-
|
|
929
|
+
projectPath: "{repoRoot}/.github/agents/{itemName}.agent.md",
|
|
930
|
+
converter: {
|
|
931
|
+
id: "copilot-command-to-agent-and-prompt",
|
|
932
|
+
convert: (item, context) => {
|
|
933
|
+
if (!isSlashCommandLike(item)) {
|
|
934
|
+
return { error: "Invalid slash command payload for Copilot conversion." };
|
|
935
|
+
}
|
|
936
|
+
const agentPath = path.join(
|
|
937
|
+
context.repoRoot,
|
|
938
|
+
".github",
|
|
939
|
+
"agents",
|
|
940
|
+
`${item.name}.agent.md`
|
|
941
|
+
);
|
|
942
|
+
const promptPath = path.join(
|
|
943
|
+
context.repoRoot,
|
|
944
|
+
".github",
|
|
945
|
+
"prompts",
|
|
946
|
+
`${item.name}.prompt.md`
|
|
947
|
+
);
|
|
948
|
+
return {
|
|
949
|
+
outputs: [
|
|
950
|
+
{
|
|
951
|
+
outputPath: agentPath,
|
|
952
|
+
content: stripFrontmatterFields(item.rawContents, TARGET_FRONTMATTER_KEYS$3)
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
outputPath: promptPath,
|
|
956
|
+
content: renderPromptReference(item.name)
|
|
957
|
+
}
|
|
958
|
+
]
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
}
|
|
750
962
|
},
|
|
751
963
|
instructions: {
|
|
752
964
|
filename: "AGENTS.md",
|
|
@@ -812,7 +1024,7 @@ const BUILTIN_TARGETS = [
|
|
|
812
1024
|
copilotTarget
|
|
813
1025
|
];
|
|
814
1026
|
Object.freeze(BUILTIN_TARGETS.map((target) => target.id));
|
|
815
|
-
const FRONTMATTER_MARKER$
|
|
1027
|
+
const FRONTMATTER_MARKER$1 = "---";
|
|
816
1028
|
function parseScalar$1(rawValue) {
|
|
817
1029
|
const trimmed = rawValue.trim();
|
|
818
1030
|
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
@@ -864,12 +1076,12 @@ function parseFrontmatter(lines) {
|
|
|
864
1076
|
}
|
|
865
1077
|
function extractFrontmatter$1(contents) {
|
|
866
1078
|
const lines = contents.split(/\r?\n/);
|
|
867
|
-
if (lines[0]?.trim() !== FRONTMATTER_MARKER$
|
|
1079
|
+
if (lines[0]?.trim() !== FRONTMATTER_MARKER$1) {
|
|
868
1080
|
return { frontmatter: {}, body: contents.trimEnd() };
|
|
869
1081
|
}
|
|
870
1082
|
let endIndex = -1;
|
|
871
1083
|
for (let i = 1; i < lines.length; i += 1) {
|
|
872
|
-
if (lines[i].trim() === FRONTMATTER_MARKER$
|
|
1084
|
+
if (lines[i].trim() === FRONTMATTER_MARKER$1) {
|
|
873
1085
|
endIndex = i;
|
|
874
1086
|
break;
|
|
875
1087
|
}
|
|
@@ -933,6 +1145,7 @@ function parseInstructionFrontmatter(options) {
|
|
|
933
1145
|
resolvedOutputDir
|
|
934
1146
|
};
|
|
935
1147
|
}
|
|
1148
|
+
const RESERVED_MANAGED_SOURCE_DIRS = /* @__PURE__ */ new Set(["skills", "commands", "agents", "instructions"]);
|
|
936
1149
|
function isTemplateFile(fileName) {
|
|
937
1150
|
if (!fileName.toLowerCase().endsWith(".md")) {
|
|
938
1151
|
return false;
|
|
@@ -962,6 +1175,19 @@ async function listTemplateFiles(root) {
|
|
|
962
1175
|
}
|
|
963
1176
|
return files;
|
|
964
1177
|
}
|
|
1178
|
+
function isInReservedManagedSourceDir(filePath, repoRoot, agentsDir) {
|
|
1179
|
+
const templatesRoot = resolveAgentsDirPath(repoRoot, agentsDir);
|
|
1180
|
+
const relative = path.relative(templatesRoot, filePath);
|
|
1181
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
1182
|
+
return false;
|
|
1183
|
+
}
|
|
1184
|
+
const segments = relative.split(path.sep).filter(Boolean);
|
|
1185
|
+
if (segments.length < 2) {
|
|
1186
|
+
return false;
|
|
1187
|
+
}
|
|
1188
|
+
const first = segments[0] === ".local" ? segments[1] : segments[0];
|
|
1189
|
+
return first ? RESERVED_MANAGED_SOURCE_DIRS.has(first) : false;
|
|
1190
|
+
}
|
|
965
1191
|
async function scanInstructionTemplateSources(options) {
|
|
966
1192
|
const includeLocal = options.includeLocal ?? true;
|
|
967
1193
|
const templatesRoot = resolveAgentsDirPath(options.repoRoot, options.agentsDir);
|
|
@@ -973,6 +1199,9 @@ async function scanInstructionTemplateSources(options) {
|
|
|
973
1199
|
}
|
|
974
1200
|
const entries = [];
|
|
975
1201
|
for (const filePath of templateFiles) {
|
|
1202
|
+
if (isInReservedManagedSourceDir(filePath, options.repoRoot, options.agentsDir)) {
|
|
1203
|
+
continue;
|
|
1204
|
+
}
|
|
976
1205
|
const markerType = detectLocalMarker$1(filePath);
|
|
977
1206
|
const sourceType = markerType ? "local" : "shared";
|
|
978
1207
|
if (!includeLocal && sourceType === "local") {
|
|
@@ -1630,59 +1859,456 @@ async function writeManagedOutputs(repoRoot, manifest, homeDir) {
|
|
|
1630
1859
|
await writeFile(manifestPath, `${JSON.stringify({ entries: sorted }, null, 2)}
|
|
1631
1860
|
`, "utf8");
|
|
1632
1861
|
}
|
|
1633
|
-
const
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1862
|
+
const SCRIPT_TAG_DEFINITIONS = [
|
|
1863
|
+
{ kind: "nodejs", openTag: "<nodejs>", closeTag: "</nodejs>" },
|
|
1864
|
+
{ kind: "shell", openTag: "<shell>", closeTag: "</shell>" }
|
|
1865
|
+
];
|
|
1866
|
+
const SCRIPT_HEARTBEAT_INTERVAL_MS = 3e4;
|
|
1867
|
+
const PREVIEW_LIMIT = 200;
|
|
1868
|
+
const WINDOWS_DEFAULT_SHELL = "cmd.exe";
|
|
1869
|
+
const POSIX_DEFAULT_SHELL = "/bin/sh";
|
|
1870
|
+
const RUNNER_SOURCE = String.raw`
|
|
1871
|
+
import path from "node:path";
|
|
1872
|
+
import { writeFileSync } from "node:fs";
|
|
1873
|
+
import { createRequire } from "node:module";
|
|
1874
|
+
|
|
1875
|
+
const encoded = process.env.OMNIAGENT_SCRIPT_B64 ?? "";
|
|
1876
|
+
const sourceLabel = process.env.OMNIAGENT_SCRIPT_SOURCE ?? "template";
|
|
1877
|
+
const sourcePathValue = process.env.OMNIAGENT_SCRIPT_TEMPLATE_PATH ?? sourceLabel;
|
|
1878
|
+
const script = Buffer.from(encoded, "base64").toString("utf8");
|
|
1879
|
+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
1880
|
+
const sourcePath = path.isAbsolute(sourcePathValue)
|
|
1881
|
+
? sourcePathValue
|
|
1882
|
+
: path.resolve(process.cwd(), sourcePathValue);
|
|
1883
|
+
const __filename = sourcePath;
|
|
1884
|
+
const __dirname = path.dirname(__filename);
|
|
1885
|
+
const require = createRequire(__filename);
|
|
1886
|
+
|
|
1887
|
+
function encodeResult(value) {
|
|
1888
|
+
if (value === undefined) {
|
|
1889
|
+
return { kind: "undefined" };
|
|
1890
|
+
}
|
|
1891
|
+
if (value === null) {
|
|
1892
|
+
return { kind: "null" };
|
|
1893
|
+
}
|
|
1894
|
+
const valueType = typeof value;
|
|
1895
|
+
if (valueType === "string") {
|
|
1896
|
+
return { kind: "string", value };
|
|
1897
|
+
}
|
|
1898
|
+
if (valueType === "number") {
|
|
1899
|
+
return { kind: "number", value };
|
|
1900
|
+
}
|
|
1901
|
+
if (valueType === "boolean") {
|
|
1902
|
+
return { kind: "boolean", value };
|
|
1903
|
+
}
|
|
1904
|
+
if (valueType === "bigint") {
|
|
1905
|
+
return { kind: "bigint", value: value.toString() };
|
|
1906
|
+
}
|
|
1907
|
+
if (valueType === "symbol") {
|
|
1908
|
+
return { kind: "symbol", value: String(value) };
|
|
1909
|
+
}
|
|
1910
|
+
if (valueType === "function") {
|
|
1911
|
+
return { kind: "function", value: String(value) };
|
|
1912
|
+
}
|
|
1913
|
+
try {
|
|
1914
|
+
return { kind: "json", value: JSON.stringify(value) };
|
|
1915
|
+
} catch {
|
|
1916
|
+
return { kind: "coerced", value: String(value) };
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
async function main() {
|
|
1921
|
+
try {
|
|
1922
|
+
const wrapped = script + "\n//# sourceURL=" + sourceLabel;
|
|
1923
|
+
const fn = new AsyncFunction("require", "__dirname", "__filename", wrapped);
|
|
1924
|
+
const result = await fn(require, __dirname, __filename);
|
|
1925
|
+
writeFileSync(3, JSON.stringify({ ok: true, payload: encodeResult(result) }), "utf8");
|
|
1926
|
+
} catch (error) {
|
|
1927
|
+
const message =
|
|
1928
|
+
error instanceof Error
|
|
1929
|
+
? (error.stack ?? error.message)
|
|
1930
|
+
: String(error);
|
|
1931
|
+
writeFileSync(3, JSON.stringify({ ok: false, error: message }), "utf8");
|
|
1932
|
+
process.exitCode = 1;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
await main();
|
|
1937
|
+
`;
|
|
1938
|
+
class TemplateScriptExecutionError extends Error {
|
|
1939
|
+
templatePath;
|
|
1940
|
+
blockId;
|
|
1941
|
+
constructor(message, options) {
|
|
1942
|
+
super(message);
|
|
1943
|
+
this.name = "TemplateScriptExecutionError";
|
|
1944
|
+
this.templatePath = options.templatePath;
|
|
1945
|
+
this.blockId = options.blockId ?? null;
|
|
1638
1946
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1947
|
+
}
|
|
1948
|
+
function formatParseError(templatePath, message) {
|
|
1949
|
+
return new TemplateScriptExecutionError(
|
|
1950
|
+
`Invalid template script markup in ${templatePath}: ${message}`,
|
|
1951
|
+
{ templatePath }
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
function createStillRunningWarning(options) {
|
|
1955
|
+
return {
|
|
1956
|
+
code: "still_running",
|
|
1957
|
+
message: `Template script is still running for ${options.templatePath} (${options.blockId}).`,
|
|
1958
|
+
templatePath: options.templatePath,
|
|
1959
|
+
blockId: options.blockId
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
function appendWarning(runtime, warning) {
|
|
1963
|
+
runtime.warnings.push(warning);
|
|
1964
|
+
runtime.onWarning?.(warning);
|
|
1965
|
+
}
|
|
1966
|
+
function emitVerbose(runtime, message) {
|
|
1967
|
+
if (!runtime.verbose) {
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
runtime.onVerbose?.(message);
|
|
1971
|
+
}
|
|
1972
|
+
function hasTemplateScriptMarkup(content) {
|
|
1973
|
+
return SCRIPT_TAG_DEFINITIONS.some((definition) => content.includes(definition.openTag));
|
|
1974
|
+
}
|
|
1975
|
+
function findNextScriptToken(content, cursor) {
|
|
1976
|
+
let nextToken = null;
|
|
1977
|
+
for (const definition of SCRIPT_TAG_DEFINITIONS) {
|
|
1978
|
+
const openIndex = content.indexOf(definition.openTag, cursor);
|
|
1979
|
+
if (openIndex !== -1 && (!nextToken || openIndex < nextToken.index)) {
|
|
1980
|
+
nextToken = {
|
|
1981
|
+
index: openIndex,
|
|
1982
|
+
kind: "open",
|
|
1983
|
+
definition
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
const closeIndex = content.indexOf(definition.closeTag, cursor);
|
|
1987
|
+
if (closeIndex !== -1 && (!nextToken || closeIndex < nextToken.index)) {
|
|
1988
|
+
nextToken = {
|
|
1989
|
+
index: closeIndex,
|
|
1990
|
+
kind: "close",
|
|
1991
|
+
definition
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
return nextToken;
|
|
1996
|
+
}
|
|
1997
|
+
function resolveShellInvocation() {
|
|
1998
|
+
if (process.platform === "win32") {
|
|
1999
|
+
const command2 = process.env.ComSpec?.trim() || WINDOWS_DEFAULT_SHELL;
|
|
2000
|
+
return { command: command2, args: ["/d", "/s", "/c"] };
|
|
2001
|
+
}
|
|
2002
|
+
const command = process.env.SHELL?.trim() || POSIX_DEFAULT_SHELL;
|
|
2003
|
+
return { command, args: ["-c"] };
|
|
2004
|
+
}
|
|
2005
|
+
function normalizeScriptResult(payload) {
|
|
2006
|
+
if (payload.kind === "undefined" || payload.kind === "null") {
|
|
2007
|
+
return { renderedText: "", resultKind: "empty" };
|
|
2008
|
+
}
|
|
2009
|
+
if (payload.kind === "string") {
|
|
2010
|
+
return { renderedText: payload.value, resultKind: "string" };
|
|
2011
|
+
}
|
|
2012
|
+
if (payload.kind === "json") {
|
|
2013
|
+
return { renderedText: payload.value, resultKind: "json" };
|
|
2014
|
+
}
|
|
2015
|
+
if (payload.kind === "coerced") {
|
|
2016
|
+
return { renderedText: payload.value, resultKind: "coerced" };
|
|
2017
|
+
}
|
|
2018
|
+
return {
|
|
2019
|
+
renderedText: String(payload.value ?? ""),
|
|
2020
|
+
resultKind: "coerced"
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
function markReusedExecutions(runtime, blockIds) {
|
|
2024
|
+
for (const blockId of blockIds) {
|
|
2025
|
+
const existing = runtime.scriptExecutions.get(blockId);
|
|
2026
|
+
if (!existing) {
|
|
2027
|
+
continue;
|
|
2028
|
+
}
|
|
2029
|
+
runtime.scriptExecutions.set(blockId, {
|
|
2030
|
+
...existing,
|
|
2031
|
+
reusedAcrossTargets: true
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
function parseTemplateScripts(templatePath, content) {
|
|
2036
|
+
const blocks = [];
|
|
2037
|
+
let cursor = 0;
|
|
2038
|
+
let index = 0;
|
|
2039
|
+
while (cursor < content.length) {
|
|
2040
|
+
const nextToken = findNextScriptToken(content, cursor);
|
|
2041
|
+
if (!nextToken) {
|
|
1643
2042
|
break;
|
|
1644
2043
|
}
|
|
2044
|
+
if (nextToken.kind === "close") {
|
|
2045
|
+
throw formatParseError(
|
|
2046
|
+
templatePath,
|
|
2047
|
+
`closing ${nextToken.definition.closeTag} appears before an opening tag`
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
2050
|
+
const { definition } = nextToken;
|
|
2051
|
+
const scriptStart = nextToken.index + definition.openTag.length;
|
|
2052
|
+
const closeIndex = content.indexOf(definition.closeTag, scriptStart);
|
|
2053
|
+
if (closeIndex === -1) {
|
|
2054
|
+
throw formatParseError(templatePath, `missing closing ${definition.closeTag} tag`);
|
|
2055
|
+
}
|
|
2056
|
+
const scriptBody = content.slice(scriptStart, closeIndex);
|
|
2057
|
+
if (hasTemplateScriptMarkup(scriptBody)) {
|
|
2058
|
+
throw formatParseError(templatePath, "nested template script blocks are not supported");
|
|
2059
|
+
}
|
|
2060
|
+
blocks.push({
|
|
2061
|
+
blockId: `${templatePath}#${index}`,
|
|
2062
|
+
templatePath,
|
|
2063
|
+
index,
|
|
2064
|
+
evaluator: definition.kind,
|
|
2065
|
+
scriptBody,
|
|
2066
|
+
startOffset: nextToken.index,
|
|
2067
|
+
endOffset: closeIndex + definition.closeTag.length
|
|
2068
|
+
});
|
|
2069
|
+
index += 1;
|
|
2070
|
+
cursor = closeIndex + definition.closeTag.length;
|
|
2071
|
+
}
|
|
2072
|
+
return { blocks };
|
|
2073
|
+
}
|
|
2074
|
+
async function executeNodeJsScriptBlock(options) {
|
|
2075
|
+
const { block, runtime } = options;
|
|
2076
|
+
const child = spawn(process.execPath, ["--input-type=module", "--eval", RUNNER_SOURCE], {
|
|
2077
|
+
cwd: runtime.cwd,
|
|
2078
|
+
env: {
|
|
2079
|
+
...process.env,
|
|
2080
|
+
OMNIAGENT_SCRIPT_B64: Buffer.from(block.scriptBody, "utf8").toString("base64"),
|
|
2081
|
+
OMNIAGENT_SCRIPT_SOURCE: options.blockLabel,
|
|
2082
|
+
OMNIAGENT_SCRIPT_TEMPLATE_PATH: block.templatePath
|
|
2083
|
+
},
|
|
2084
|
+
// Ignore child stdout to prevent scripts with heavy console output from deadlocking on pipe backpressure.
|
|
2085
|
+
stdio: ["ignore", "ignore", "pipe", "pipe"]
|
|
2086
|
+
});
|
|
2087
|
+
let stderr = "";
|
|
2088
|
+
let responseRaw = "";
|
|
2089
|
+
const stderrPipe = child.stderr;
|
|
2090
|
+
if (stderrPipe) {
|
|
2091
|
+
stderrPipe.setEncoding("utf8");
|
|
2092
|
+
stderrPipe.on("data", (chunk) => {
|
|
2093
|
+
stderr += chunk;
|
|
2094
|
+
});
|
|
1645
2095
|
}
|
|
1646
|
-
|
|
1647
|
-
|
|
2096
|
+
const resultPipe = child.stdio[3];
|
|
2097
|
+
if (resultPipe) {
|
|
2098
|
+
resultPipe.setEncoding("utf8");
|
|
2099
|
+
resultPipe.on("data", (chunk) => {
|
|
2100
|
+
responseRaw += chunk;
|
|
2101
|
+
});
|
|
1648
2102
|
}
|
|
1649
|
-
const
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
const shouldSkip = trimmed === "" || trimmed.startsWith("-") || trimmed.startsWith("#");
|
|
1661
|
-
if (shouldSkip) {
|
|
1662
|
-
continue;
|
|
1663
|
-
}
|
|
1664
|
-
skippingList = false;
|
|
1665
|
-
} else {
|
|
1666
|
-
continue;
|
|
1667
|
-
}
|
|
2103
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
2104
|
+
child.once("error", reject);
|
|
2105
|
+
child.once("exit", (code) => resolve(code ?? 1));
|
|
2106
|
+
});
|
|
2107
|
+
const parsed = responseRaw.trim();
|
|
2108
|
+
let response = null;
|
|
2109
|
+
if (parsed.length > 0) {
|
|
2110
|
+
try {
|
|
2111
|
+
response = JSON.parse(parsed);
|
|
2112
|
+
} catch {
|
|
2113
|
+
response = null;
|
|
1668
2114
|
}
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
2115
|
+
}
|
|
2116
|
+
if (exitCode !== 0) {
|
|
2117
|
+
const message = response && !response.ok ? response.error : stderr.trim() || `Script process exited with code ${exitCode}.`;
|
|
2118
|
+
throw new TemplateScriptExecutionError(
|
|
2119
|
+
`Template script failed in ${block.templatePath} (${block.blockId}): ${message}`,
|
|
2120
|
+
{ templatePath: block.templatePath, blockId: block.blockId }
|
|
2121
|
+
);
|
|
2122
|
+
}
|
|
2123
|
+
if (!response || !response.ok) {
|
|
2124
|
+
throw new TemplateScriptExecutionError(
|
|
2125
|
+
`Template script failed in ${block.templatePath} (${block.blockId}): invalid runner response`,
|
|
2126
|
+
{ templatePath: block.templatePath, blockId: block.blockId }
|
|
2127
|
+
);
|
|
2128
|
+
}
|
|
2129
|
+
const normalized = normalizeScriptResult(response.payload);
|
|
2130
|
+
return normalized;
|
|
2131
|
+
}
|
|
2132
|
+
async function executeShellScriptBlock(options) {
|
|
2133
|
+
const { block, runtime } = options;
|
|
2134
|
+
const shell = resolveShellInvocation();
|
|
2135
|
+
const child = spawn(shell.command, [...shell.args, block.scriptBody], {
|
|
2136
|
+
cwd: runtime.cwd,
|
|
2137
|
+
env: {
|
|
2138
|
+
...process.env
|
|
2139
|
+
},
|
|
2140
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2141
|
+
});
|
|
2142
|
+
let stdout = "";
|
|
2143
|
+
let stderr = "";
|
|
2144
|
+
const stdoutPipe = child.stdout;
|
|
2145
|
+
if (stdoutPipe) {
|
|
2146
|
+
stdoutPipe.setEncoding("utf8");
|
|
2147
|
+
stdoutPipe.on("data", (chunk) => {
|
|
2148
|
+
stdout += chunk;
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
const stderrPipe = child.stderr;
|
|
2152
|
+
if (stderrPipe) {
|
|
2153
|
+
stderrPipe.setEncoding("utf8");
|
|
2154
|
+
stderrPipe.on("data", (chunk) => {
|
|
2155
|
+
stderr += chunk;
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
2159
|
+
child.once("error", reject);
|
|
2160
|
+
child.once("exit", (code) => resolve(code ?? 1));
|
|
2161
|
+
});
|
|
2162
|
+
if (exitCode !== 0) {
|
|
2163
|
+
const message = stderr.trim() || `Script process exited with code ${exitCode}.`;
|
|
2164
|
+
throw new TemplateScriptExecutionError(
|
|
2165
|
+
`Template script failed in ${block.templatePath} (${block.blockId}): ${message}`,
|
|
2166
|
+
{ templatePath: block.templatePath, blockId: block.blockId }
|
|
2167
|
+
);
|
|
2168
|
+
}
|
|
2169
|
+
return {
|
|
2170
|
+
renderedText: stdout,
|
|
2171
|
+
resultKind: stdout.length > 0 ? "string" : "empty"
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2174
|
+
async function executeScriptBlock(options) {
|
|
2175
|
+
const { block, runtime } = options;
|
|
2176
|
+
const startTime = Date.now();
|
|
2177
|
+
const blockLabel = `${block.templatePath}#${block.index}`;
|
|
2178
|
+
emitVerbose(runtime, `Evaluating template script ${blockLabel} (${block.evaluator}).`);
|
|
2179
|
+
let warningTimer = null;
|
|
2180
|
+
if (runtime.heartbeatIntervalMs > 0) {
|
|
2181
|
+
warningTimer = setInterval(() => {
|
|
2182
|
+
appendWarning(
|
|
2183
|
+
runtime,
|
|
2184
|
+
createStillRunningWarning({
|
|
2185
|
+
templatePath: block.templatePath,
|
|
2186
|
+
blockId: block.blockId
|
|
2187
|
+
})
|
|
2188
|
+
);
|
|
2189
|
+
}, runtime.heartbeatIntervalMs);
|
|
2190
|
+
warningTimer.unref();
|
|
2191
|
+
}
|
|
2192
|
+
try {
|
|
2193
|
+
const executed = block.evaluator === "shell" ? await executeShellScriptBlock({ block, runtime }) : await executeNodeJsScriptBlock({ block, runtime, blockLabel });
|
|
2194
|
+
const durationMs = Date.now() - startTime;
|
|
2195
|
+
emitVerbose(
|
|
2196
|
+
runtime,
|
|
2197
|
+
`Finished template script ${blockLabel} (${block.evaluator}) in ${durationMs}ms.`
|
|
2198
|
+
);
|
|
2199
|
+
return { ...executed, durationMs };
|
|
2200
|
+
} finally {
|
|
2201
|
+
if (warningTimer) {
|
|
2202
|
+
clearInterval(warningTimer);
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
async function evaluateTemplateScriptsUncached(request) {
|
|
2207
|
+
const { content, templatePath, runtime } = request;
|
|
2208
|
+
const parsed = parseTemplateScripts(templatePath, content);
|
|
2209
|
+
if (parsed.blocks.length === 0) {
|
|
2210
|
+
return {
|
|
2211
|
+
renderedContent: content,
|
|
2212
|
+
blockIds: []
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
let output = "";
|
|
2216
|
+
let cursor = 0;
|
|
2217
|
+
const blockIds = [];
|
|
2218
|
+
for (const block of parsed.blocks) {
|
|
2219
|
+
output += content.slice(cursor, block.startOffset);
|
|
2220
|
+
cursor = block.endOffset;
|
|
2221
|
+
blockIds.push(block.blockId);
|
|
2222
|
+
runtime.scriptExecutions.set(block.blockId, {
|
|
2223
|
+
blockId: block.blockId,
|
|
2224
|
+
templatePath,
|
|
2225
|
+
status: "running",
|
|
2226
|
+
reusedAcrossTargets: false
|
|
2227
|
+
});
|
|
2228
|
+
try {
|
|
2229
|
+
const executed = await executeScriptBlock({ block, runtime });
|
|
2230
|
+
output += executed.renderedText;
|
|
2231
|
+
runtime.scriptExecutions.set(block.blockId, {
|
|
2232
|
+
blockId: block.blockId,
|
|
2233
|
+
templatePath,
|
|
2234
|
+
status: "succeeded",
|
|
2235
|
+
resultKind: executed.resultKind,
|
|
2236
|
+
renderedPreview: executed.renderedText.slice(0, PREVIEW_LIMIT),
|
|
2237
|
+
durationMs: executed.durationMs,
|
|
2238
|
+
reusedAcrossTargets: false
|
|
2239
|
+
});
|
|
2240
|
+
} catch (error) {
|
|
2241
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2242
|
+
runtime.scriptExecutions.set(block.blockId, {
|
|
2243
|
+
blockId: block.blockId,
|
|
2244
|
+
templatePath,
|
|
2245
|
+
status: "failed",
|
|
2246
|
+
errorMessage: message,
|
|
2247
|
+
reusedAcrossTargets: false
|
|
2248
|
+
});
|
|
2249
|
+
if (!runtime.failedTemplatePath) {
|
|
2250
|
+
runtime.failedTemplatePath = templatePath;
|
|
2251
|
+
runtime.failedBlockId = block.blockId;
|
|
2252
|
+
}
|
|
2253
|
+
if (error instanceof TemplateScriptExecutionError) {
|
|
2254
|
+
throw error;
|
|
1677
2255
|
}
|
|
2256
|
+
throw new TemplateScriptExecutionError(message, {
|
|
2257
|
+
templatePath,
|
|
2258
|
+
blockId: block.blockId
|
|
2259
|
+
});
|
|
1678
2260
|
}
|
|
1679
|
-
|
|
1680
|
-
|
|
2261
|
+
}
|
|
2262
|
+
output += content.slice(cursor);
|
|
2263
|
+
return {
|
|
2264
|
+
renderedContent: output,
|
|
2265
|
+
blockIds
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
function createTemplateScriptRuntime(options = {}) {
|
|
2269
|
+
return {
|
|
2270
|
+
runId: options.runId ?? randomUUID(),
|
|
2271
|
+
verbose: options.verbose ?? false,
|
|
2272
|
+
heartbeatIntervalMs: options.heartbeatIntervalMs ?? SCRIPT_HEARTBEAT_INTERVAL_MS,
|
|
2273
|
+
cwd: options.cwd ?? process.cwd(),
|
|
2274
|
+
cache: /* @__PURE__ */ new Map(),
|
|
2275
|
+
usageCounts: /* @__PURE__ */ new Map(),
|
|
2276
|
+
scriptExecutions: /* @__PURE__ */ new Map(),
|
|
2277
|
+
warnings: [],
|
|
2278
|
+
failedTemplatePath: null,
|
|
2279
|
+
failedBlockId: null,
|
|
2280
|
+
onWarning: options.onWarning,
|
|
2281
|
+
onVerbose: options.onVerbose
|
|
2282
|
+
};
|
|
2283
|
+
}
|
|
2284
|
+
async function evaluateTemplateScripts(request) {
|
|
2285
|
+
const usageCount = (request.runtime.usageCounts.get(request.templatePath) ?? 0) + 1;
|
|
2286
|
+
request.runtime.usageCounts.set(request.templatePath, usageCount);
|
|
2287
|
+
const existing = request.runtime.cache.get(request.templatePath);
|
|
2288
|
+
if (existing) {
|
|
2289
|
+
const cached = await existing;
|
|
2290
|
+
if (usageCount > 1 && cached.blockIds.length > 0) {
|
|
2291
|
+
markReusedExecutions(request.runtime, cached.blockIds);
|
|
1681
2292
|
}
|
|
2293
|
+
return cached.renderedContent;
|
|
2294
|
+
}
|
|
2295
|
+
const evaluationPromise = evaluateTemplateScriptsUncached(request);
|
|
2296
|
+
request.runtime.cache.set(request.templatePath, evaluationPromise);
|
|
2297
|
+
try {
|
|
2298
|
+
const evaluated = await evaluationPromise;
|
|
2299
|
+
if (usageCount > 1 && evaluated.blockIds.length > 0) {
|
|
2300
|
+
markReusedExecutions(request.runtime, evaluated.blockIds);
|
|
2301
|
+
}
|
|
2302
|
+
return evaluated.renderedContent;
|
|
2303
|
+
} catch (error) {
|
|
2304
|
+
request.runtime.cache.delete(request.templatePath);
|
|
2305
|
+
throw error;
|
|
1682
2306
|
}
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
return
|
|
2307
|
+
}
|
|
2308
|
+
function listTemplateScriptExecutions(runtime) {
|
|
2309
|
+
return [...runtime.scriptExecutions.values()].sort(
|
|
2310
|
+
(left, right) => left.blockId.localeCompare(right.blockId)
|
|
2311
|
+
);
|
|
1686
2312
|
}
|
|
1687
2313
|
const utf8Decoder$1 = new TextDecoder("utf-8", { fatal: true });
|
|
1688
2314
|
const TARGET_FRONTMATTER_KEYS$2 = /* @__PURE__ */ new Set(["targets", "targetagents"]);
|
|
@@ -1736,46 +2362,152 @@ async function writeOutputFile(outputPath, content) {
|
|
|
1736
2362
|
await writeFile(outputPath, buffer);
|
|
1737
2363
|
return { status: existing ? "updated" : "created", contentHash };
|
|
1738
2364
|
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
2365
|
+
function markerRank(markerType) {
|
|
2366
|
+
if (markerType === "path") {
|
|
2367
|
+
return 2;
|
|
2368
|
+
}
|
|
2369
|
+
if (markerType === "suffix") {
|
|
2370
|
+
return 1;
|
|
2371
|
+
}
|
|
2372
|
+
return 0;
|
|
2373
|
+
}
|
|
2374
|
+
function normalizeLocalRelativeFilePath(relativePath) {
|
|
2375
|
+
const parts = relativePath.split(path.sep).filter(Boolean);
|
|
2376
|
+
if (parts.length === 0) {
|
|
2377
|
+
return { normalizedPath: relativePath, markerType: null };
|
|
2378
|
+
}
|
|
2379
|
+
const directoryParts = parts.slice(0, -1);
|
|
2380
|
+
const fileName = parts[parts.length - 1];
|
|
2381
|
+
let hasPathMarker = false;
|
|
2382
|
+
const normalizedDirectories = [];
|
|
2383
|
+
for (const part of directoryParts) {
|
|
2384
|
+
if (part === ".local") {
|
|
2385
|
+
hasPathMarker = true;
|
|
1749
2386
|
continue;
|
|
1750
2387
|
}
|
|
1751
|
-
const
|
|
1752
|
-
if (
|
|
1753
|
-
|
|
1754
|
-
...options,
|
|
1755
|
-
source: sourcePath,
|
|
1756
|
-
destination: path.join(options.destination, entry2.name)
|
|
1757
|
-
});
|
|
1758
|
-
continue;
|
|
2388
|
+
const { baseName, hadLocalSuffix } = stripLocalPathSuffix(part);
|
|
2389
|
+
if (hadLocalSuffix) {
|
|
2390
|
+
hasPathMarker = true;
|
|
1759
2391
|
}
|
|
1760
|
-
if (!
|
|
2392
|
+
if (!baseName) {
|
|
1761
2393
|
continue;
|
|
1762
2394
|
}
|
|
1763
|
-
|
|
2395
|
+
normalizedDirectories.push(baseName);
|
|
2396
|
+
}
|
|
2397
|
+
let normalizedFileName = fileName;
|
|
2398
|
+
const isEnvPrefixedFile = fileName.toLowerCase().startsWith(".env");
|
|
2399
|
+
const extension = path.extname(fileName);
|
|
2400
|
+
let strippedSuffix = {
|
|
2401
|
+
outputFileName: fileName,
|
|
2402
|
+
hadLocalSuffix: false
|
|
2403
|
+
};
|
|
2404
|
+
if (!isEnvPrefixedFile) {
|
|
2405
|
+
strippedSuffix = stripLocalSuffix(fileName, extension);
|
|
2406
|
+
if (strippedSuffix.hadLocalSuffix) {
|
|
2407
|
+
normalizedFileName = strippedSuffix.outputFileName;
|
|
2408
|
+
}
|
|
2409
|
+
const strippedPath = stripLocalPathSuffix(normalizedFileName);
|
|
2410
|
+
if (strippedPath.hadLocalSuffix) {
|
|
2411
|
+
hasPathMarker = true;
|
|
2412
|
+
normalizedFileName = strippedPath.baseName;
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
const normalizedParts = [...normalizedDirectories, normalizedFileName].filter(Boolean);
|
|
2416
|
+
const markerType = hasPathMarker ? "path" : strippedSuffix.hadLocalSuffix ? "suffix" : null;
|
|
2417
|
+
return {
|
|
2418
|
+
normalizedPath: normalizedParts.join(path.sep),
|
|
2419
|
+
markerType
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
async function collectSkillCopyCandidates(options) {
|
|
2423
|
+
const selectedSkillFile = options.skillFileName.toLowerCase();
|
|
2424
|
+
const candidates = [];
|
|
2425
|
+
const walk = async (currentSource, relativePrefix = "") => {
|
|
2426
|
+
const entries = await readdir(currentSource, { withFileTypes: true });
|
|
2427
|
+
for (const entry2 of entries) {
|
|
2428
|
+
const sourcePath = path.join(currentSource, entry2.name);
|
|
2429
|
+
const relativePath = relativePrefix ? path.join(relativePrefix, entry2.name) : entry2.name;
|
|
2430
|
+
if (entry2.isDirectory()) {
|
|
2431
|
+
await walk(sourcePath, relativePath);
|
|
2432
|
+
continue;
|
|
2433
|
+
}
|
|
2434
|
+
if (!entry2.isFile()) {
|
|
2435
|
+
continue;
|
|
2436
|
+
}
|
|
2437
|
+
const entryLowerName = entry2.name.toLowerCase();
|
|
2438
|
+
const isSkillFile = entryLowerName === "skill.md" || entryLowerName === "skill.local.md";
|
|
2439
|
+
if (isSkillFile && entryLowerName !== selectedSkillFile) {
|
|
2440
|
+
continue;
|
|
2441
|
+
}
|
|
2442
|
+
const detectedMarker = detectLocalMarkerFromPath(relativePath) ?? (options.sourceType === "local" && options.markerType === "path" ? "path" : null);
|
|
2443
|
+
if (isSkillFile) {
|
|
2444
|
+
candidates.push({
|
|
2445
|
+
sourcePath,
|
|
2446
|
+
destinationPath: path.join(options.destination, options.outputFileName),
|
|
2447
|
+
isSkillFile: true,
|
|
2448
|
+
markerRank: markerRank(detectedMarker)
|
|
2449
|
+
});
|
|
2450
|
+
continue;
|
|
2451
|
+
}
|
|
2452
|
+
const normalized = normalizeLocalRelativeFilePath(relativePath);
|
|
2453
|
+
if (!normalized.normalizedPath) {
|
|
2454
|
+
continue;
|
|
2455
|
+
}
|
|
2456
|
+
const marker = normalized.markerType ?? detectedMarker;
|
|
2457
|
+
candidates.push({
|
|
2458
|
+
sourcePath,
|
|
2459
|
+
destinationPath: path.join(options.destination, normalized.normalizedPath),
|
|
2460
|
+
isSkillFile: false,
|
|
2461
|
+
markerRank: markerRank(marker)
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
};
|
|
2465
|
+
await walk(options.source);
|
|
2466
|
+
return candidates;
|
|
2467
|
+
}
|
|
2468
|
+
async function copySkillDirectory(options) {
|
|
2469
|
+
await mkdir(options.destination, { recursive: true });
|
|
2470
|
+
const candidates = await collectSkillCopyCandidates({
|
|
2471
|
+
source: options.source,
|
|
2472
|
+
destination: options.destination,
|
|
2473
|
+
skillFileName: options.skillFileName,
|
|
2474
|
+
outputFileName: options.outputFileName,
|
|
2475
|
+
sourceType: options.sourceType,
|
|
2476
|
+
markerType: options.markerType
|
|
2477
|
+
});
|
|
2478
|
+
const winnerByOutputPath = /* @__PURE__ */ new Map();
|
|
2479
|
+
for (const candidate of candidates) {
|
|
2480
|
+
const key = path.normalize(candidate.destinationPath).replace(/\\/g, "/").toLowerCase();
|
|
2481
|
+
const existing = winnerByOutputPath.get(key);
|
|
2482
|
+
if (!existing || candidate.markerRank > existing.markerRank || candidate.markerRank === existing.markerRank && candidate.sourcePath.localeCompare(existing.sourcePath) > 0) {
|
|
2483
|
+
winnerByOutputPath.set(key, candidate);
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
const winners = [...winnerByOutputPath.values()].sort(
|
|
2487
|
+
(left, right) => left.destinationPath.localeCompare(right.destinationPath)
|
|
2488
|
+
);
|
|
2489
|
+
for (const winner of winners) {
|
|
2490
|
+
const buffer = await readFile(winner.sourcePath);
|
|
1764
2491
|
const decoded = decodeUtf8$1(buffer);
|
|
1765
2492
|
if (decoded === null) {
|
|
1766
|
-
await mkdir(path.dirname(destinationPath), { recursive: true });
|
|
1767
|
-
await writeFile(destinationPath, buffer);
|
|
2493
|
+
await mkdir(path.dirname(winner.destinationPath), { recursive: true });
|
|
2494
|
+
await writeFile(winner.destinationPath, buffer);
|
|
1768
2495
|
continue;
|
|
1769
2496
|
}
|
|
1770
|
-
const
|
|
2497
|
+
const withScripts = options.templateScriptRuntime ? await evaluateTemplateScripts({
|
|
2498
|
+
templatePath: winner.sourcePath,
|
|
1771
2499
|
content: decoded,
|
|
2500
|
+
runtime: options.templateScriptRuntime
|
|
2501
|
+
}) : decoded;
|
|
2502
|
+
const templated = applyAgentTemplating({
|
|
2503
|
+
content: withScripts,
|
|
1772
2504
|
target: options.targetId,
|
|
1773
2505
|
validAgents: options.validAgents,
|
|
1774
|
-
sourcePath
|
|
2506
|
+
sourcePath: winner.sourcePath
|
|
1775
2507
|
});
|
|
1776
|
-
const output = isSkillFile ? stripFrontmatterFields(templated, TARGET_FRONTMATTER_KEYS$2) : templated;
|
|
1777
|
-
await mkdir(path.dirname(destinationPath), { recursive: true });
|
|
1778
|
-
await writeFile(destinationPath, output, "utf8");
|
|
2508
|
+
const output = winner.isSkillFile ? stripFrontmatterFields(templated, TARGET_FRONTMATTER_KEYS$2) : templated;
|
|
2509
|
+
await mkdir(path.dirname(winner.destinationPath), { recursive: true });
|
|
2510
|
+
await writeFile(winner.destinationPath, output, "utf8");
|
|
1779
2511
|
}
|
|
1780
2512
|
}
|
|
1781
2513
|
const defaultSkillWriter = {
|
|
@@ -1791,7 +2523,10 @@ const defaultSkillWriter = {
|
|
|
1791
2523
|
targetId: options.context.targetId,
|
|
1792
2524
|
validAgents: options.context.validAgents,
|
|
1793
2525
|
skillFileName: item.skillFileName,
|
|
1794
|
-
outputFileName: item.outputFileName
|
|
2526
|
+
outputFileName: item.outputFileName,
|
|
2527
|
+
sourceType: item.sourceType,
|
|
2528
|
+
markerType: item.markerType,
|
|
2529
|
+
templateScriptRuntime: options.context.templateScriptRuntime
|
|
1795
2530
|
});
|
|
1796
2531
|
return { status: "created" };
|
|
1797
2532
|
}
|
|
@@ -1803,8 +2538,13 @@ const defaultSubagentWriter = {
|
|
|
1803
2538
|
if (!item) {
|
|
1804
2539
|
return writeOutputFile(options.outputPath, options.content);
|
|
1805
2540
|
}
|
|
1806
|
-
const
|
|
2541
|
+
const withScripts = options.context.templateScriptRuntime ? await evaluateTemplateScripts({
|
|
2542
|
+
templatePath: item.sourcePath,
|
|
1807
2543
|
content: item.rawContents,
|
|
2544
|
+
runtime: options.context.templateScriptRuntime
|
|
2545
|
+
}) : item.rawContents;
|
|
2546
|
+
const templated = applyAgentTemplating({
|
|
2547
|
+
content: withScripts,
|
|
1808
2548
|
target: options.context.targetId,
|
|
1809
2549
|
validAgents: options.context.validAgents,
|
|
1810
2550
|
sourcePath: item.sourcePath
|
|
@@ -1888,6 +2628,10 @@ function formatDisplayPath$4(repoRoot, absolutePath) {
|
|
|
1888
2628
|
const isWithinRepo = relative && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
1889
2629
|
return isWithinRepo ? relative : absolutePath;
|
|
1890
2630
|
}
|
|
2631
|
+
function isWithinDirectory(root, candidate) {
|
|
2632
|
+
const relative = path.relative(root, candidate);
|
|
2633
|
+
return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
2634
|
+
}
|
|
1891
2635
|
function sortCandidates(candidates) {
|
|
1892
2636
|
return [...candidates].sort(
|
|
1893
2637
|
(left, right) => left.source.sourcePath.localeCompare(right.source.sourcePath)
|
|
@@ -2023,6 +2767,7 @@ function normalizeInstructionTargets(targets) {
|
|
|
2023
2767
|
return resolved;
|
|
2024
2768
|
}
|
|
2025
2769
|
async function syncInstructions(request) {
|
|
2770
|
+
const templateScriptRuntime = request.templateScriptRuntime ?? createTemplateScriptRuntime({ cwd: request.repoRoot });
|
|
2026
2771
|
const targets = normalizeInstructionTargets(request.targets);
|
|
2027
2772
|
const includeLocal = !(request.excludeLocal ?? false);
|
|
2028
2773
|
const summarySourcePath = request.repoRoot;
|
|
@@ -2134,8 +2879,13 @@ async function syncInstructions(request) {
|
|
|
2134
2879
|
});
|
|
2135
2880
|
const outputPath = resolveInstructionOutputPath(resolvedOutputDir, filename);
|
|
2136
2881
|
const key = buildOutputKey(outputPath, selection.group);
|
|
2137
|
-
const
|
|
2882
|
+
const withScripts = templateScriptRuntime ? await evaluateTemplateScripts({
|
|
2883
|
+
templatePath: template.sourcePath,
|
|
2138
2884
|
content: template.body,
|
|
2885
|
+
runtime: templateScriptRuntime
|
|
2886
|
+
}) : template.body;
|
|
2887
|
+
const content = applyAgentTemplating({
|
|
2888
|
+
content: withScripts,
|
|
2139
2889
|
target: targetName,
|
|
2140
2890
|
validAgents: request.validAgents,
|
|
2141
2891
|
sourcePath: template.sourcePath
|
|
@@ -2391,7 +3141,8 @@ async function syncInstructions(request) {
|
|
|
2391
3141
|
homeDir,
|
|
2392
3142
|
targetId: candidate.targetName,
|
|
2393
3143
|
outputType: "instructions",
|
|
2394
|
-
validAgents: request.validAgents
|
|
3144
|
+
validAgents: request.validAgents,
|
|
3145
|
+
templateScriptRuntime
|
|
2395
3146
|
}
|
|
2396
3147
|
});
|
|
2397
3148
|
recordCount(groupResult.counts, writeResult.status);
|
|
@@ -2433,8 +3184,12 @@ async function syncInstructions(request) {
|
|
|
2433
3184
|
};
|
|
2434
3185
|
for (const [key, entry2] of previousEntries) {
|
|
2435
3186
|
const group = resolveInstructionTargetGroup(entry2.targetName);
|
|
3187
|
+
if (isWithinDirectory(agentsRoot, entry2.outputPath)) {
|
|
3188
|
+
mergedEntries.set(key, entry2);
|
|
3189
|
+
continue;
|
|
3190
|
+
}
|
|
2436
3191
|
const groupSelected = activeGroups.has(group);
|
|
2437
|
-
if (!groupSelected) {
|
|
3192
|
+
if (!groupSelected && !removeMissing) {
|
|
2438
3193
|
mergedEntries.set(key, entry2);
|
|
2439
3194
|
continue;
|
|
2440
3195
|
}
|
|
@@ -2533,17 +3288,26 @@ async function syncInstructions(request) {
|
|
|
2533
3288
|
if (managedManifest.entries.length > 0 || nextManaged.size > 0) {
|
|
2534
3289
|
const updatedEntries = [];
|
|
2535
3290
|
for (const entry2 of managedManifest.entries) {
|
|
2536
|
-
if (entry2.sourceType !== "instruction"
|
|
3291
|
+
if (entry2.sourceType !== "instruction") {
|
|
2537
3292
|
updatedEntries.push(entry2);
|
|
2538
3293
|
continue;
|
|
2539
3294
|
}
|
|
3295
|
+
if (isWithinDirectory(agentsRoot, entry2.outputPath)) {
|
|
3296
|
+
updatedEntries.push(entry2);
|
|
3297
|
+
continue;
|
|
3298
|
+
}
|
|
3299
|
+
const targetSelected = selectedTargetIds.has(entry2.targetId);
|
|
2540
3300
|
const key = buildManagedOutputKey(entry2);
|
|
2541
3301
|
if (nextManaged.has(key)) {
|
|
2542
3302
|
continue;
|
|
2543
3303
|
}
|
|
3304
|
+
if (!targetSelected && !removeMissing) {
|
|
3305
|
+
updatedEntries.push(entry2);
|
|
3306
|
+
continue;
|
|
3307
|
+
}
|
|
2544
3308
|
const activeSources = activeSourcesByTarget.get(entry2.targetId);
|
|
2545
3309
|
const sourceStillActive = activeSources?.has(entry2.sourceId) ?? false;
|
|
2546
|
-
if (!removeMissing || sourceStillActive) {
|
|
3310
|
+
if (targetSelected && (!removeMissing || sourceStillActive)) {
|
|
2547
3311
|
updatedEntries.push(entry2);
|
|
2548
3312
|
continue;
|
|
2549
3313
|
}
|
|
@@ -2623,33 +3387,6 @@ async function syncInstructions(request) {
|
|
|
2623
3387
|
sourceCounts
|
|
2624
3388
|
};
|
|
2625
3389
|
}
|
|
2626
|
-
async function pathExists$1(candidate) {
|
|
2627
|
-
try {
|
|
2628
|
-
await stat(candidate);
|
|
2629
|
-
return true;
|
|
2630
|
-
} catch {
|
|
2631
|
-
return false;
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
async function findUp(startDir, markerRelativePath) {
|
|
2635
|
-
let current = path.resolve(startDir);
|
|
2636
|
-
let previous = "";
|
|
2637
|
-
while (current !== previous) {
|
|
2638
|
-
if (await pathExists$1(path.join(current, markerRelativePath))) {
|
|
2639
|
-
return current;
|
|
2640
|
-
}
|
|
2641
|
-
previous = current;
|
|
2642
|
-
current = path.dirname(current);
|
|
2643
|
-
}
|
|
2644
|
-
return null;
|
|
2645
|
-
}
|
|
2646
|
-
async function findRepoRoot(startDir) {
|
|
2647
|
-
const gitRoot = await findUp(startDir, ".git");
|
|
2648
|
-
if (gitRoot) {
|
|
2649
|
-
return gitRoot;
|
|
2650
|
-
}
|
|
2651
|
-
return await findUp(startDir, "package.json");
|
|
2652
|
-
}
|
|
2653
3390
|
async function readDirectoryStats(directory) {
|
|
2654
3391
|
try {
|
|
2655
3392
|
return await stat(directory);
|
|
@@ -2704,8 +3441,8 @@ function resolveSkillName(frontmatter, fallback) {
|
|
|
2704
3441
|
}
|
|
2705
3442
|
return fallback;
|
|
2706
3443
|
}
|
|
2707
|
-
function normalizeSkillKey$1(
|
|
2708
|
-
return
|
|
3444
|
+
function normalizeSkillKey$1(relativePath) {
|
|
3445
|
+
return path.normalize(relativePath).replace(/\\/g, "/").toLowerCase();
|
|
2709
3446
|
}
|
|
2710
3447
|
function resolveSkillRelativePath(skillsRoot, directoryPath) {
|
|
2711
3448
|
const relativePath = path.relative(skillsRoot, directoryPath);
|
|
@@ -2868,7 +3605,7 @@ async function loadSkillCatalog(repoRoot, options = {}) {
|
|
|
2868
3605
|
shared: sharedSkills,
|
|
2869
3606
|
localPath: localPathSkills,
|
|
2870
3607
|
localSuffix: localSuffixSkills,
|
|
2871
|
-
key: (skill) => normalizeSkillKey$1(skill.
|
|
3608
|
+
key: (skill) => normalizeSkillKey$1(skill.relativePath)
|
|
2872
3609
|
});
|
|
2873
3610
|
const skills = includeLocal ? [...sharedEffectiveSkills, ...localEffectiveSkills] : sharedSkills;
|
|
2874
3611
|
return {
|
|
@@ -2921,6 +3658,7 @@ function buildInvalidTargetWarnings$2(skills) {
|
|
|
2921
3658
|
return warnings;
|
|
2922
3659
|
}
|
|
2923
3660
|
async function syncSkills(request) {
|
|
3661
|
+
const templateScriptRuntime = request.templateScriptRuntime ?? createTemplateScriptRuntime({ cwd: request.repoRoot });
|
|
2924
3662
|
const sourcePath = resolveSharedCategoryRoot(request.repoRoot, "skills", request.agentsDir);
|
|
2925
3663
|
const skillTargets = request.targets.filter(
|
|
2926
3664
|
(target) => normalizeOutputDefinition(target.outputs.skills) !== null
|
|
@@ -3143,7 +3881,9 @@ async function syncSkills(request) {
|
|
|
3143
3881
|
directoryPath: selected.skill.directoryPath,
|
|
3144
3882
|
skillFileName: selected.skill.skillFileName,
|
|
3145
3883
|
outputFileName: selected.skill.outputFileName,
|
|
3146
|
-
sourcePath: selected.skill.sourcePath
|
|
3884
|
+
sourcePath: selected.skill.sourcePath,
|
|
3885
|
+
sourceType: selected.skill.sourceType,
|
|
3886
|
+
markerType: selected.skill.markerType
|
|
3147
3887
|
};
|
|
3148
3888
|
await writer.write({
|
|
3149
3889
|
outputPath: selected.outputPath,
|
|
@@ -3155,7 +3895,8 @@ async function syncSkills(request) {
|
|
|
3155
3895
|
homeDir,
|
|
3156
3896
|
targetId: target.id,
|
|
3157
3897
|
outputType: "skills",
|
|
3158
|
-
validAgents: request.validAgents
|
|
3898
|
+
validAgents: request.validAgents,
|
|
3899
|
+
templateScriptRuntime
|
|
3159
3900
|
}
|
|
3160
3901
|
});
|
|
3161
3902
|
const checksum = await hashOutputPath(selected.outputPath);
|
|
@@ -3787,9 +4528,14 @@ function buildInvalidTargetWarnings$1(commands) {
|
|
|
3787
4528
|
}
|
|
3788
4529
|
return warnings;
|
|
3789
4530
|
}
|
|
3790
|
-
function applyTemplatingToCommand(command, targetName, validAgents) {
|
|
3791
|
-
const
|
|
4531
|
+
async function applyTemplatingToCommand(command, targetName, validAgents, runtime) {
|
|
4532
|
+
const withScripts = runtime ? await evaluateTemplateScripts({
|
|
4533
|
+
templatePath: command.sourcePath,
|
|
3792
4534
|
content: command.rawContents,
|
|
4535
|
+
runtime
|
|
4536
|
+
}) : command.rawContents;
|
|
4537
|
+
const templatedContents = applyAgentTemplating({
|
|
4538
|
+
content: withScripts,
|
|
3793
4539
|
target: targetName,
|
|
3794
4540
|
validAgents,
|
|
3795
4541
|
sourcePath: command.sourcePath
|
|
@@ -3847,6 +4593,7 @@ async function ensureBackupPath(outputPath) {
|
|
|
3847
4593
|
}
|
|
3848
4594
|
}
|
|
3849
4595
|
async function syncSlashCommands(request) {
|
|
4596
|
+
const templateScriptRuntime = request.templateScriptRuntime ?? createTemplateScriptRuntime({ cwd: request.repoRoot });
|
|
3850
4597
|
const catalog = await loadCommandCatalog(request.repoRoot, {
|
|
3851
4598
|
includeLocal: !request.excludeLocal,
|
|
3852
4599
|
agentsDir: request.agentsDir,
|
|
@@ -3989,40 +4736,32 @@ async function syncSlashCommands(request) {
|
|
|
3989
4736
|
});
|
|
3990
4737
|
commandPaths = [{ location: "project", path: path.join(basePath, "SKILL.md") }];
|
|
3991
4738
|
} else {
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
repoRoot: request.repoRoot,
|
|
3997
|
-
agentsDir: agentsDirPath,
|
|
3998
|
-
homeDir,
|
|
3999
|
-
targetId: target.id,
|
|
4000
|
-
itemName: command.name,
|
|
4001
|
-
commandLocation: "project"
|
|
4002
|
-
},
|
|
4003
|
-
item: command,
|
|
4004
|
-
baseDir: request.repoRoot
|
|
4005
|
-
});
|
|
4006
|
-
commandPaths.push({ location: "project", path: resolved });
|
|
4007
|
-
}
|
|
4008
|
-
if (commandDef.userPath) {
|
|
4739
|
+
const preferredLocation = commandDef.projectPath ? "project" : "user";
|
|
4740
|
+
const preferredTemplate = preferredLocation === "project" ? commandDef.projectPath : commandDef.userPath;
|
|
4741
|
+
const baseDir = preferredLocation === "project" ? request.repoRoot : homeDir;
|
|
4742
|
+
if (preferredTemplate) {
|
|
4009
4743
|
const resolved = resolveCommandOutputPath({
|
|
4010
|
-
template:
|
|
4744
|
+
template: preferredTemplate,
|
|
4011
4745
|
context: {
|
|
4012
4746
|
repoRoot: request.repoRoot,
|
|
4013
4747
|
agentsDir: agentsDirPath,
|
|
4014
4748
|
homeDir,
|
|
4015
4749
|
targetId: target.id,
|
|
4016
4750
|
itemName: command.name,
|
|
4017
|
-
commandLocation:
|
|
4751
|
+
commandLocation: preferredLocation
|
|
4018
4752
|
},
|
|
4019
4753
|
item: command,
|
|
4020
|
-
baseDir
|
|
4754
|
+
baseDir
|
|
4021
4755
|
});
|
|
4022
|
-
commandPaths.push({ location:
|
|
4756
|
+
commandPaths.push({ location: preferredLocation, path: resolved });
|
|
4023
4757
|
}
|
|
4024
4758
|
}
|
|
4025
|
-
const templated = applyTemplatingToCommand(
|
|
4759
|
+
const templated = await applyTemplatingToCommand(
|
|
4760
|
+
command,
|
|
4761
|
+
target.id,
|
|
4762
|
+
validAgents,
|
|
4763
|
+
templateScriptRuntime
|
|
4764
|
+
);
|
|
4026
4765
|
const writer = resolveWriter(commandDef.writer, writerRegistry);
|
|
4027
4766
|
const converter = resolveConverter(commandDef.converter, converterRegistry);
|
|
4028
4767
|
for (const entry2 of commandPaths) {
|
|
@@ -4159,7 +4898,8 @@ async function syncSlashCommands(request) {
|
|
|
4159
4898
|
targetId: target.id,
|
|
4160
4899
|
outputType: "commands",
|
|
4161
4900
|
commandLocation: selected.location,
|
|
4162
|
-
validAgents
|
|
4901
|
+
validAgents,
|
|
4902
|
+
templateScriptRuntime
|
|
4163
4903
|
}
|
|
4164
4904
|
});
|
|
4165
4905
|
const checksum = writeResult.contentHash ?? await hashOutputPath(selected.outputPath);
|
|
@@ -4764,6 +5504,7 @@ function formatSubagentSummary(summary, jsonOutput) {
|
|
|
4764
5504
|
return lines.join("\n");
|
|
4765
5505
|
}
|
|
4766
5506
|
async function syncSubagents(request) {
|
|
5507
|
+
const templateScriptRuntime = request.templateScriptRuntime ?? createTemplateScriptRuntime({ cwd: request.repoRoot });
|
|
4767
5508
|
const catalog = await loadSubagentCatalog(request.repoRoot, {
|
|
4768
5509
|
includeLocal: !request.excludeLocal,
|
|
4769
5510
|
agentsDir: request.agentsDir,
|
|
@@ -5044,7 +5785,8 @@ async function syncSubagents(request) {
|
|
|
5044
5785
|
homeDir,
|
|
5045
5786
|
targetId: target.id,
|
|
5046
5787
|
outputType: "subagents",
|
|
5047
|
-
validAgents
|
|
5788
|
+
validAgents,
|
|
5789
|
+
templateScriptRuntime
|
|
5048
5790
|
}
|
|
5049
5791
|
});
|
|
5050
5792
|
const checksum = selected.outputKind === "skill" ? await hashOutputPath(selected.outputPath) : writeResult.contentHash ?? await hashOutputPath(selected.outputPath);
|
|
@@ -6007,6 +6749,147 @@ function formatLocalItemsOutput(items, repoRoot, jsonOutput) {
|
|
|
6007
6749
|
}
|
|
6008
6750
|
return lines.join("\n");
|
|
6009
6751
|
}
|
|
6752
|
+
function hasTemplateScripts(content) {
|
|
6753
|
+
return hasTemplateScriptMarkup(content);
|
|
6754
|
+
}
|
|
6755
|
+
function addTemplateScriptSource(sources, templatePath, content) {
|
|
6756
|
+
if (!hasTemplateScripts(content)) {
|
|
6757
|
+
return;
|
|
6758
|
+
}
|
|
6759
|
+
if (sources.has(templatePath)) {
|
|
6760
|
+
return;
|
|
6761
|
+
}
|
|
6762
|
+
sources.set(templatePath, content);
|
|
6763
|
+
}
|
|
6764
|
+
function intersectsTargets(targets, selectedTargetIds) {
|
|
6765
|
+
return targets.some((target) => selectedTargetIds.has(target));
|
|
6766
|
+
}
|
|
6767
|
+
async function listAllFiles(root) {
|
|
6768
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
6769
|
+
const files = [];
|
|
6770
|
+
for (const entry2 of entries) {
|
|
6771
|
+
const entryPath = path.join(root, entry2.name);
|
|
6772
|
+
if (entry2.isDirectory()) {
|
|
6773
|
+
files.push(...await listAllFiles(entryPath));
|
|
6774
|
+
continue;
|
|
6775
|
+
}
|
|
6776
|
+
if (entry2.isFile()) {
|
|
6777
|
+
files.push(entryPath);
|
|
6778
|
+
}
|
|
6779
|
+
}
|
|
6780
|
+
return files;
|
|
6781
|
+
}
|
|
6782
|
+
async function gatherTemplateScriptSources(options) {
|
|
6783
|
+
const selectedSkillTargetIds = new Set(options.selectedSkillTargets.map((target) => target.id));
|
|
6784
|
+
const selectedCommandTargetIds = new Set(
|
|
6785
|
+
options.selectedCommandTargets.map((target) => target.id)
|
|
6786
|
+
);
|
|
6787
|
+
const selectedSubagentTargetIds = new Set(
|
|
6788
|
+
options.selectedSubagentTargets.map((target) => target.id)
|
|
6789
|
+
);
|
|
6790
|
+
const selectedInstructionTargetIds = new Set(
|
|
6791
|
+
options.selectedInstructionTargets.map((target) => target.id)
|
|
6792
|
+
);
|
|
6793
|
+
const sources = /* @__PURE__ */ new Map();
|
|
6794
|
+
if (options.commandsAvailable && options.selectedCommandTargets.length > 0) {
|
|
6795
|
+
const commandCatalog = await loadCommandCatalog(options.repoRoot, {
|
|
6796
|
+
includeLocal: !options.excludeLocalCommands,
|
|
6797
|
+
agentsDir: options.agentsDir,
|
|
6798
|
+
resolveTargetName: options.resolveTargetName
|
|
6799
|
+
});
|
|
6800
|
+
for (const command of commandCatalog.commands) {
|
|
6801
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
6802
|
+
defaultTargets: command.targetAgents,
|
|
6803
|
+
overrideOnly: options.overrideOnly,
|
|
6804
|
+
overrideSkip: options.overrideSkip,
|
|
6805
|
+
allTargets: options.allTargetIds
|
|
6806
|
+
});
|
|
6807
|
+
if (!intersectsTargets(effectiveTargets, selectedCommandTargetIds)) {
|
|
6808
|
+
continue;
|
|
6809
|
+
}
|
|
6810
|
+
addTemplateScriptSource(sources, command.sourcePath, command.rawContents);
|
|
6811
|
+
}
|
|
6812
|
+
}
|
|
6813
|
+
if (options.selectedSubagentTargets.length > 0) {
|
|
6814
|
+
const subagentCatalog = await loadSubagentCatalog(options.repoRoot, {
|
|
6815
|
+
includeLocal: !options.excludeLocalAgents,
|
|
6816
|
+
agentsDir: options.agentsDir,
|
|
6817
|
+
resolveTargetName: options.resolveTargetName
|
|
6818
|
+
});
|
|
6819
|
+
for (const subagent of subagentCatalog.subagents) {
|
|
6820
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
6821
|
+
defaultTargets: subagent.targetAgents,
|
|
6822
|
+
overrideOnly: options.overrideOnly,
|
|
6823
|
+
overrideSkip: options.overrideSkip,
|
|
6824
|
+
allTargets: options.allTargetIds
|
|
6825
|
+
});
|
|
6826
|
+
if (!intersectsTargets(effectiveTargets, selectedSubagentTargetIds)) {
|
|
6827
|
+
continue;
|
|
6828
|
+
}
|
|
6829
|
+
addTemplateScriptSource(sources, subagent.sourcePath, subagent.rawContents);
|
|
6830
|
+
}
|
|
6831
|
+
}
|
|
6832
|
+
if (options.selectedInstructionTargets.length > 0) {
|
|
6833
|
+
const templateCatalog = await loadInstructionTemplateCatalog({
|
|
6834
|
+
repoRoot: options.repoRoot,
|
|
6835
|
+
includeLocal: !options.excludeLocalInstructions,
|
|
6836
|
+
agentsDir: options.agentsDir,
|
|
6837
|
+
resolveTargetName: options.resolveTargetName
|
|
6838
|
+
});
|
|
6839
|
+
for (const template of templateCatalog.templates) {
|
|
6840
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
6841
|
+
defaultTargets: template.targets,
|
|
6842
|
+
overrideOnly: options.overrideOnly,
|
|
6843
|
+
overrideSkip: options.overrideSkip,
|
|
6844
|
+
allTargets: options.allTargetIds
|
|
6845
|
+
});
|
|
6846
|
+
if (!intersectsTargets(effectiveTargets, selectedInstructionTargetIds)) {
|
|
6847
|
+
continue;
|
|
6848
|
+
}
|
|
6849
|
+
addTemplateScriptSource(sources, template.sourcePath, template.body);
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6852
|
+
if (options.skillsAvailable && options.selectedSkillTargets.length > 0) {
|
|
6853
|
+
const skillCatalog = await loadSkillCatalog(options.repoRoot, {
|
|
6854
|
+
includeLocal: !options.excludeLocalSkills,
|
|
6855
|
+
agentsDir: options.agentsDir,
|
|
6856
|
+
resolveTargetName: options.resolveTargetName
|
|
6857
|
+
});
|
|
6858
|
+
for (const skill of skillCatalog.skills) {
|
|
6859
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
6860
|
+
defaultTargets: skill.targetAgents,
|
|
6861
|
+
overrideOnly: options.overrideOnly,
|
|
6862
|
+
overrideSkip: options.overrideSkip,
|
|
6863
|
+
allTargets: options.allTargetIds
|
|
6864
|
+
});
|
|
6865
|
+
if (!intersectsTargets(effectiveTargets, selectedSkillTargetIds)) {
|
|
6866
|
+
continue;
|
|
6867
|
+
}
|
|
6868
|
+
const files = await listAllFiles(skill.directoryPath);
|
|
6869
|
+
for (const filePath of files) {
|
|
6870
|
+
const buffer = await readFile(filePath);
|
|
6871
|
+
const decoded = decodeUtf8(buffer);
|
|
6872
|
+
if (decoded === null) {
|
|
6873
|
+
continue;
|
|
6874
|
+
}
|
|
6875
|
+
addTemplateScriptSource(sources, filePath, decoded);
|
|
6876
|
+
}
|
|
6877
|
+
}
|
|
6878
|
+
}
|
|
6879
|
+
return [...sources.entries()].map(([templatePath, content]) => ({ templatePath, content })).sort((left, right) => left.templatePath.localeCompare(right.templatePath));
|
|
6880
|
+
}
|
|
6881
|
+
function buildSyncRunMetadata(options) {
|
|
6882
|
+
const warnings = [...options.runtime.warnings];
|
|
6883
|
+
return {
|
|
6884
|
+
runId: options.runtime.runId,
|
|
6885
|
+
status: options.status,
|
|
6886
|
+
failedTemplatePath: options.runtime.failedTemplatePath,
|
|
6887
|
+
failedBlockId: options.runtime.failedBlockId,
|
|
6888
|
+
partialOutputsWritten: options.partialOutputsWritten,
|
|
6889
|
+
scriptExecutions: listTemplateScriptExecutions(options.runtime),
|
|
6890
|
+
warnings
|
|
6891
|
+
};
|
|
6892
|
+
}
|
|
6010
6893
|
async function assertSourceDirectory(sourcePath) {
|
|
6011
6894
|
try {
|
|
6012
6895
|
const stats = await stat(sourcePath);
|
|
@@ -6284,7 +7167,7 @@ function logNonInteractiveNotices(options) {
|
|
|
6284
7167
|
logWithChannel(`${target.displayName} commands are user-only.`, options.jsonOutput);
|
|
6285
7168
|
} else if (hasUser && hasProject) {
|
|
6286
7169
|
logWithChannel(
|
|
6287
|
-
`${target.displayName} commands
|
|
7170
|
+
`${target.displayName} commands prefer the project location (user path is fallback-only).`,
|
|
6288
7171
|
options.jsonOutput
|
|
6289
7172
|
);
|
|
6290
7173
|
}
|
|
@@ -6344,7 +7227,7 @@ function buildCommandSummary(sourcePath, targets, status, message, excludedLocal
|
|
|
6344
7227
|
return {
|
|
6345
7228
|
sourcePath,
|
|
6346
7229
|
results: normalizedTargets.map((target) => {
|
|
6347
|
-
const verb = "Skipped";
|
|
7230
|
+
const verb = status === "failed" ? "Failed" : "Skipped";
|
|
6348
7231
|
return {
|
|
6349
7232
|
targetName: target.id,
|
|
6350
7233
|
status,
|
|
@@ -6367,7 +7250,7 @@ function buildSkillsSummary(repoRoot, sourcePath, targets, status, reason, exclu
|
|
|
6367
7250
|
const results = normalizeTargets(targets).map((target) => ({
|
|
6368
7251
|
targetName: target.id,
|
|
6369
7252
|
status,
|
|
6370
|
-
message: `${"Skipped"} ${sourceDisplay} for ${target.displayName}: ${reason}`,
|
|
7253
|
+
message: `${status === "failed" ? "Failed" : "Skipped"} ${sourceDisplay} for ${target.displayName}: ${reason}`,
|
|
6371
7254
|
error: reason
|
|
6372
7255
|
}));
|
|
6373
7256
|
return buildSummary(sourcePath, results, [], {
|
|
@@ -6405,6 +7288,27 @@ function buildInstructionsSummary(repoRoot, targets, status, message, excludedLo
|
|
|
6405
7288
|
}
|
|
6406
7289
|
};
|
|
6407
7290
|
}
|
|
7291
|
+
function buildSubagentSummary(targets, status, message, excludedLocal, sourcePath) {
|
|
7292
|
+
const results = normalizeTargets(targets).map((target) => ({
|
|
7293
|
+
targetName: target.id,
|
|
7294
|
+
status,
|
|
7295
|
+
message: `${"Failed"} ${target.displayName}: ${message}`,
|
|
7296
|
+
error: message,
|
|
7297
|
+
counts: { created: 0, updated: 0, removed: 0, converted: 0, skipped: 0 },
|
|
7298
|
+
warnings: []
|
|
7299
|
+
}));
|
|
7300
|
+
return {
|
|
7301
|
+
sourcePath,
|
|
7302
|
+
results,
|
|
7303
|
+
warnings: [],
|
|
7304
|
+
hadFailures: status === "failed",
|
|
7305
|
+
sourceCounts: {
|
|
7306
|
+
shared: 0,
|
|
7307
|
+
local: 0,
|
|
7308
|
+
excludedLocal
|
|
7309
|
+
}
|
|
7310
|
+
};
|
|
7311
|
+
}
|
|
6408
7312
|
function mergeWarnings(existing, additions) {
|
|
6409
7313
|
if (additions.length === 0) {
|
|
6410
7314
|
return existing;
|
|
@@ -6473,9 +7377,29 @@ function buildAvailabilitySubagentWarnings(skips) {
|
|
|
6473
7377
|
function emitSyncSummary(options) {
|
|
6474
7378
|
const { combined, jsonOutput, repoRoot, agentsDir, ignoreRules } = options;
|
|
6475
7379
|
if (jsonOutput) {
|
|
6476
|
-
console.log(
|
|
7380
|
+
console.log(
|
|
7381
|
+
JSON.stringify(
|
|
7382
|
+
{
|
|
7383
|
+
...combined,
|
|
7384
|
+
runId: combined.syncRun.runId,
|
|
7385
|
+
status: combined.syncRun.status,
|
|
7386
|
+
failedTemplatePath: combined.syncRun.failedTemplatePath,
|
|
7387
|
+
failedBlockId: combined.syncRun.failedBlockId,
|
|
7388
|
+
partialOutputsWritten: combined.syncRun.partialOutputsWritten,
|
|
7389
|
+
scriptExecutions: combined.syncRun.scriptExecutions,
|
|
7390
|
+
warnings: combined.syncRun.warnings
|
|
7391
|
+
},
|
|
7392
|
+
null,
|
|
7393
|
+
2
|
|
7394
|
+
)
|
|
7395
|
+
);
|
|
6477
7396
|
} else {
|
|
6478
7397
|
const outputs = [];
|
|
7398
|
+
if (combined.syncRun.status === "failed" && combined.syncRun.failedTemplatePath && combined.syncRun.failedBlockId) {
|
|
7399
|
+
outputs.push(
|
|
7400
|
+
`Failed template script: ${combined.syncRun.failedTemplatePath} (${combined.syncRun.failedBlockId})`
|
|
7401
|
+
);
|
|
7402
|
+
}
|
|
6479
7403
|
const instructionOutput = formatInstructionSummary(combined.instructions);
|
|
6480
7404
|
if (instructionOutput.length > 0) {
|
|
6481
7405
|
outputs.push(instructionOutput);
|
|
@@ -6496,6 +7420,9 @@ function emitSyncSummary(options) {
|
|
|
6496
7420
|
const warningRules = ignoreRules ?? buildAgentsIgnoreRules(repoRoot, agentsDir);
|
|
6497
7421
|
outputs.push(`Warning: Missing ignore rules for local sources (${warningRules.join(", ")}).`);
|
|
6498
7422
|
}
|
|
7423
|
+
for (const warning of combined.syncRun.warnings) {
|
|
7424
|
+
outputs.push(`Warning: ${warning.message}`);
|
|
7425
|
+
}
|
|
6499
7426
|
if (outputs.length > 0) {
|
|
6500
7427
|
console.log(outputs.join("\n"));
|
|
6501
7428
|
}
|
|
@@ -6543,6 +7470,10 @@ const syncCommand = {
|
|
|
6543
7470
|
type: "string",
|
|
6544
7471
|
choices: ["overwrite", "rename", "skip"],
|
|
6545
7472
|
describe: "Conflict resolution strategy for slash commands"
|
|
7473
|
+
}).option("verbose", {
|
|
7474
|
+
type: "boolean",
|
|
7475
|
+
default: false,
|
|
7476
|
+
describe: "Show per-script execution telemetry during sync"
|
|
6546
7477
|
}).option("json", {
|
|
6547
7478
|
type: "boolean",
|
|
6548
7479
|
default: false,
|
|
@@ -6553,7 +7484,7 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
6553
7484
|
).example("omniagent sync", "Sync available targets (auto-detects agent CLIs on PATH)").example("omniagent sync --skip <target>", "Skip a target").example("omniagent sync --only <target>", "Sync only one target").example("omniagent sync --agentsDir ./my-custom-agents", "Use a custom agents directory").example("omniagent sync --exclude-local", "Sync shared sources only").example(
|
|
6554
7485
|
"omniagent sync --exclude-local=skills,commands",
|
|
6555
7486
|
"Exclude local skills and commands"
|
|
6556
|
-
).example("omniagent sync --list-local", "List detected local items").example("omniagent sync --yes", "Accept defaults and apply changes").example("omniagent sync --json", "Output a JSON summary"),
|
|
7487
|
+
).example("omniagent sync --list-local", "List detected local items").example("omniagent sync --yes", "Accept defaults and apply changes").example("omniagent sync --verbose", "Show per-script execution telemetry").example("omniagent sync --json", "Output a JSON summary"),
|
|
6557
7488
|
handler: async (argv) => {
|
|
6558
7489
|
try {
|
|
6559
7490
|
const skipList = parseList(argv.skip);
|
|
@@ -6573,9 +7504,21 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
6573
7504
|
const excludeLocalAgents = excludeLocalCategories.has("agents");
|
|
6574
7505
|
const excludeLocalInstructions = excludeLocalCategories.has("instructions");
|
|
6575
7506
|
const jsonOutput = argv.json ?? false;
|
|
7507
|
+
const verboseOutput = argv.verbose ?? false;
|
|
6576
7508
|
const yes = argv.yes ?? false;
|
|
6577
7509
|
const removeMissing = argv.removeMissing ?? true;
|
|
6578
7510
|
const listLocal = argv.listLocal ?? false;
|
|
7511
|
+
let partialOutputsWritten = false;
|
|
7512
|
+
const scriptRuntime = createTemplateScriptRuntime({
|
|
7513
|
+
verbose: verboseOutput,
|
|
7514
|
+
cwd: process.cwd(),
|
|
7515
|
+
onWarning: (warning) => {
|
|
7516
|
+
logWithChannel(`Warning: ${warning.message}`, jsonOutput);
|
|
7517
|
+
},
|
|
7518
|
+
onVerbose: (message) => {
|
|
7519
|
+
logWithChannel(message, jsonOutput);
|
|
7520
|
+
}
|
|
7521
|
+
});
|
|
6579
7522
|
const startDir = process.cwd();
|
|
6580
7523
|
const repoRoot = await findRepoRoot(startDir);
|
|
6581
7524
|
if (!repoRoot) {
|
|
@@ -6585,6 +7528,7 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
6585
7528
|
process.exit(1);
|
|
6586
7529
|
return;
|
|
6587
7530
|
}
|
|
7531
|
+
scriptRuntime.cwd = repoRoot;
|
|
6588
7532
|
const agentsDirResolution = resolveAgentsDir(repoRoot, argv.agentsDir);
|
|
6589
7533
|
if (agentsDirResolution.source === "override") {
|
|
6590
7534
|
const validation2 = await validateAgentsDir(repoRoot, argv.agentsDir);
|
|
@@ -6802,7 +7746,12 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
6802
7746
|
subagents: subagentSummary2,
|
|
6803
7747
|
commands: commandsSummary2,
|
|
6804
7748
|
hadFailures: false,
|
|
6805
|
-
missingIgnoreRules: false
|
|
7749
|
+
missingIgnoreRules: false,
|
|
7750
|
+
syncRun: buildSyncRunMetadata({
|
|
7751
|
+
runtime: scriptRuntime,
|
|
7752
|
+
status: "completed",
|
|
7753
|
+
partialOutputsWritten
|
|
7754
|
+
})
|
|
6806
7755
|
};
|
|
6807
7756
|
emitSyncSummary({
|
|
6808
7757
|
combined: combined2,
|
|
@@ -6860,6 +7809,90 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
6860
7809
|
process.exit(1);
|
|
6861
7810
|
return;
|
|
6862
7811
|
}
|
|
7812
|
+
try {
|
|
7813
|
+
const scriptSources = await gatherTemplateScriptSources({
|
|
7814
|
+
repoRoot,
|
|
7815
|
+
agentsDir,
|
|
7816
|
+
allTargetIds: resolved.targets.map((target) => target.id),
|
|
7817
|
+
resolveTargetName,
|
|
7818
|
+
overrideOnly,
|
|
7819
|
+
overrideSkip,
|
|
7820
|
+
excludeLocalSkills,
|
|
7821
|
+
excludeLocalCommands,
|
|
7822
|
+
excludeLocalAgents,
|
|
7823
|
+
excludeLocalInstructions,
|
|
7824
|
+
selectedSkillTargets,
|
|
7825
|
+
selectedCommandTargets,
|
|
7826
|
+
selectedSubagentTargets,
|
|
7827
|
+
selectedInstructionTargets,
|
|
7828
|
+
skillsAvailable: hasSkillsToSync,
|
|
7829
|
+
commandsAvailable: hasCommandsToSync
|
|
7830
|
+
});
|
|
7831
|
+
for (const source of scriptSources) {
|
|
7832
|
+
await evaluateTemplateScripts({
|
|
7833
|
+
templatePath: source.templatePath,
|
|
7834
|
+
content: source.content,
|
|
7835
|
+
runtime: scriptRuntime
|
|
7836
|
+
});
|
|
7837
|
+
}
|
|
7838
|
+
} catch (error) {
|
|
7839
|
+
if (error instanceof TemplateScriptExecutionError) {
|
|
7840
|
+
const warning = {
|
|
7841
|
+
code: "sync_warning",
|
|
7842
|
+
message: error.message,
|
|
7843
|
+
templatePath: error.templatePath,
|
|
7844
|
+
blockId: error.blockId
|
|
7845
|
+
};
|
|
7846
|
+
scriptRuntime.warnings.push(warning);
|
|
7847
|
+
const combined2 = {
|
|
7848
|
+
instructions: buildInstructionsSummary(
|
|
7849
|
+
repoRoot,
|
|
7850
|
+
selectedInstructionTargets,
|
|
7851
|
+
"failed",
|
|
7852
|
+
error.message,
|
|
7853
|
+
excludeLocalInstructions
|
|
7854
|
+
),
|
|
7855
|
+
skills: buildSkillsSummary(
|
|
7856
|
+
repoRoot,
|
|
7857
|
+
skillsSourcePath,
|
|
7858
|
+
selectedSkillTargets,
|
|
7859
|
+
"failed",
|
|
7860
|
+
error.message,
|
|
7861
|
+
excludeLocalSkills
|
|
7862
|
+
),
|
|
7863
|
+
subagents: buildSubagentSummary(
|
|
7864
|
+
selectedSubagentTargets,
|
|
7865
|
+
"failed",
|
|
7866
|
+
error.message,
|
|
7867
|
+
excludeLocalAgents,
|
|
7868
|
+
subagentsSourcePath
|
|
7869
|
+
),
|
|
7870
|
+
commands: buildCommandSummary(
|
|
7871
|
+
commandsSourcePath,
|
|
7872
|
+
selectedCommandTargets,
|
|
7873
|
+
"failed",
|
|
7874
|
+
error.message,
|
|
7875
|
+
excludeLocalCommands
|
|
7876
|
+
),
|
|
7877
|
+
hadFailures: true,
|
|
7878
|
+
missingIgnoreRules: false,
|
|
7879
|
+
syncRun: buildSyncRunMetadata({
|
|
7880
|
+
runtime: scriptRuntime,
|
|
7881
|
+
status: "failed",
|
|
7882
|
+
partialOutputsWritten
|
|
7883
|
+
})
|
|
7884
|
+
};
|
|
7885
|
+
emitSyncSummary({
|
|
7886
|
+
combined: combined2,
|
|
7887
|
+
jsonOutput,
|
|
7888
|
+
repoRoot,
|
|
7889
|
+
agentsDir,
|
|
7890
|
+
ignoreRules: null
|
|
7891
|
+
});
|
|
7892
|
+
return;
|
|
7893
|
+
}
|
|
7894
|
+
throw error;
|
|
7895
|
+
}
|
|
6863
7896
|
let missingIgnoreRules = false;
|
|
6864
7897
|
let ignoreRules = null;
|
|
6865
7898
|
if (hasLocalItems) {
|
|
@@ -6892,6 +7925,7 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
6892
7925
|
}
|
|
6893
7926
|
}
|
|
6894
7927
|
}
|
|
7928
|
+
partialOutputsWritten = true;
|
|
6895
7929
|
let commandsSummary;
|
|
6896
7930
|
if (selectedCommandTargets.length === 0) {
|
|
6897
7931
|
commandsSummary = {
|
|
@@ -6930,7 +7964,8 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
6930
7964
|
validAgents,
|
|
6931
7965
|
excludeLocal: excludeLocalCommands,
|
|
6932
7966
|
resolveTargetName,
|
|
6933
|
-
hooks: globalHooks
|
|
7967
|
+
hooks: globalHooks,
|
|
7968
|
+
templateScriptRuntime: scriptRuntime
|
|
6934
7969
|
});
|
|
6935
7970
|
}
|
|
6936
7971
|
if (availabilityCommandSkips.length > 0) {
|
|
@@ -6951,7 +7986,8 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
6951
7986
|
excludeLocal: excludeLocalAgents,
|
|
6952
7987
|
includeLocalSkills,
|
|
6953
7988
|
resolveTargetName,
|
|
6954
|
-
hooks: globalHooks
|
|
7989
|
+
hooks: globalHooks,
|
|
7990
|
+
templateScriptRuntime: scriptRuntime
|
|
6955
7991
|
});
|
|
6956
7992
|
if (availabilitySubagentSkips.length > 0) {
|
|
6957
7993
|
const subagentWarnings = mergeWarnings(
|
|
@@ -7000,6 +8036,7 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
7000
8036
|
validAgents,
|
|
7001
8037
|
resolveTargetName,
|
|
7002
8038
|
hooks: globalHooks,
|
|
8039
|
+
templateScriptRuntime: scriptRuntime,
|
|
7003
8040
|
confirmRemoval
|
|
7004
8041
|
});
|
|
7005
8042
|
} catch (error) {
|
|
@@ -7057,7 +8094,8 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
7057
8094
|
excludeLocal: excludeLocalSkills,
|
|
7058
8095
|
removeMissing,
|
|
7059
8096
|
resolveTargetName,
|
|
7060
|
-
hooks: globalHooks
|
|
8097
|
+
hooks: globalHooks,
|
|
8098
|
+
templateScriptRuntime: scriptRuntime
|
|
7061
8099
|
});
|
|
7062
8100
|
}
|
|
7063
8101
|
if (availabilitySkillSkips.length > 0) {
|
|
@@ -7071,13 +8109,19 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
7071
8109
|
results: [...skillsSummary.results, ...availabilitySkillResults]
|
|
7072
8110
|
};
|
|
7073
8111
|
}
|
|
8112
|
+
const hadFailures = instructionsSummary.hadFailures || skillsSummary.hadFailures || subagentSummary.hadFailures || commandsSummary.hadFailures;
|
|
7074
8113
|
const combined = {
|
|
7075
8114
|
instructions: instructionsSummary,
|
|
7076
8115
|
skills: skillsSummary,
|
|
7077
8116
|
subagents: subagentSummary,
|
|
7078
8117
|
commands: commandsSummary,
|
|
7079
|
-
hadFailures
|
|
7080
|
-
missingIgnoreRules
|
|
8118
|
+
hadFailures,
|
|
8119
|
+
missingIgnoreRules,
|
|
8120
|
+
syncRun: buildSyncRunMetadata({
|
|
8121
|
+
runtime: scriptRuntime,
|
|
8122
|
+
status: hadFailures ? "failed" : "completed",
|
|
8123
|
+
partialOutputsWritten
|
|
8124
|
+
})
|
|
7081
8125
|
};
|
|
7082
8126
|
emitSyncSummary({
|
|
7083
8127
|
combined,
|
|
@@ -7092,6 +8136,11 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
7092
8136
|
process.exit(1);
|
|
7093
8137
|
return;
|
|
7094
8138
|
}
|
|
8139
|
+
if (error instanceof TemplateScriptExecutionError) {
|
|
8140
|
+
console.error(`Error: ${error.message}`);
|
|
8141
|
+
process.exit(1);
|
|
8142
|
+
return;
|
|
8143
|
+
}
|
|
7095
8144
|
throw error;
|
|
7096
8145
|
}
|
|
7097
8146
|
}
|
|
@@ -7745,8 +8794,28 @@ async function runShim(argv, runtime = {}) {
|
|
|
7745
8794
|
return exitCodeFor("execution-error");
|
|
7746
8795
|
}
|
|
7747
8796
|
}
|
|
7748
|
-
|
|
7749
|
-
const
|
|
8797
|
+
function resolveVersion() {
|
|
8798
|
+
const packageJsonPaths = [
|
|
8799
|
+
fileURLToPath(new URL("../package.json", import.meta.url)),
|
|
8800
|
+
fileURLToPath(new URL("../../package.json", import.meta.url))
|
|
8801
|
+
];
|
|
8802
|
+
for (const packageJsonPath of packageJsonPaths) {
|
|
8803
|
+
if (!existsSync(packageJsonPath)) {
|
|
8804
|
+
continue;
|
|
8805
|
+
}
|
|
8806
|
+
try {
|
|
8807
|
+
const contents = readFileSync(packageJsonPath, "utf8");
|
|
8808
|
+
const parsed = JSON.parse(contents);
|
|
8809
|
+
if (typeof parsed.version === "string" && parsed.version.trim().length > 0) {
|
|
8810
|
+
return parsed.version;
|
|
8811
|
+
}
|
|
8812
|
+
} catch {
|
|
8813
|
+
}
|
|
8814
|
+
}
|
|
8815
|
+
return "0.0.0";
|
|
8816
|
+
}
|
|
8817
|
+
const VERSION = resolveVersion();
|
|
8818
|
+
const KNOWN_COMMANDS = /* @__PURE__ */ new Set(["hello", "greet", "echo", "sync", "dev"]);
|
|
7750
8819
|
const SHIM_CAPABILITIES = [
|
|
7751
8820
|
"Capabilities by agent:",
|
|
7752
8821
|
" codex: approval, sandbox, output, model, web",
|
|
@@ -7796,7 +8865,7 @@ function runCli(argv = process.argv, options = {}) {
|
|
|
7796
8865
|
console.error(formatError(message, args));
|
|
7797
8866
|
const exitCode = isCommandInvocation(args) ? 1 : 2;
|
|
7798
8867
|
process.exit(exitCode);
|
|
7799
|
-
}).command(helloCommand).command(greetCommand).command(echoCommand).command(syncCommand).command(
|
|
8868
|
+
}).command(helloCommand).command(greetCommand).command(echoCommand).command(syncCommand).command(devCommand).command(
|
|
7800
8869
|
"$0",
|
|
7801
8870
|
"omniagent CLI",
|
|
7802
8871
|
(yargsInstance) => yargsInstance.usage("omniagent [flags] --agent <target-id> [-- <agent flags>]").example("omniagent --agent codex", "Start an interactive session (default mode).").example('omniagent -p "Summarize the repo" --agent codex', "Run a one-shot prompt.").example("omniagent --agent codex -- --some-flag", "Pass through agent-specific flags.").option("prompt", {
|