@kody-ade/kody-engine 0.4.263 → 0.4.265
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/bin/kody.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_package = __esm({
|
|
|
15
15
|
"package.json"() {
|
|
16
16
|
package_default = {
|
|
17
17
|
name: "@kody-ade/kody-engine",
|
|
18
|
-
version: "0.4.
|
|
18
|
+
version: "0.4.265",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -32,7 +32,8 @@ var init_package = __esm({
|
|
|
32
32
|
serve: "tsx bin/kody.ts serve",
|
|
33
33
|
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
34
34
|
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
35
|
-
|
|
35
|
+
"clean:dist": "node scripts/clean-dist.cjs",
|
|
36
|
+
build: "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
36
37
|
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
37
38
|
pretest: "pnpm check:modularity",
|
|
38
39
|
test: "vitest run tests/unit tests/int --coverage",
|
|
@@ -762,6 +763,8 @@ function parseReleaseConfig(raw) {
|
|
|
762
763
|
if (typeof r.publishCommand === "string") out.publishCommand = r.publishCommand;
|
|
763
764
|
if (typeof r.notifyCommand === "string") out.notifyCommand = r.notifyCommand;
|
|
764
765
|
if (typeof r.e2eCommand === "string") out.e2eCommand = r.e2eCommand;
|
|
766
|
+
if (typeof r.productionUrl === "string") out.productionUrl = r.productionUrl;
|
|
767
|
+
if (typeof r.smokeCommand === "string") out.smokeCommand = r.smokeCommand;
|
|
765
768
|
if (typeof r.draftRelease === "boolean") out.draftRelease = r.draftRelease;
|
|
766
769
|
if (typeof r.releaseBranch === "string") out.releaseBranch = r.releaseBranch;
|
|
767
770
|
if (typeof r.timeoutMs === "number" && r.timeoutMs > 0) out.timeoutMs = Math.floor(r.timeoutMs);
|
|
@@ -1406,12 +1409,12 @@ function parseCapabilityConfig(raw) {
|
|
|
1406
1409
|
capabilityTools: tools,
|
|
1407
1410
|
implementations,
|
|
1408
1411
|
executables: stringList(raw.executables),
|
|
1409
|
-
capabilityKind: capabilityKindField(raw.capabilityKind),
|
|
1410
1412
|
role: stringField(raw.role),
|
|
1411
1413
|
describe: stringField(raw.describe),
|
|
1412
1414
|
stage: stringField(raw.stage),
|
|
1413
1415
|
readsFrom: stringList(raw.readsFrom ?? raw.reads_from),
|
|
1414
|
-
writesTo: stringList(raw.writesTo ?? raw.writes_to)
|
|
1416
|
+
writesTo: stringList(raw.writesTo ?? raw.writes_to),
|
|
1417
|
+
workflow: parseWorkflow(raw.workflow)
|
|
1415
1418
|
};
|
|
1416
1419
|
}
|
|
1417
1420
|
function parseCapabilityBody(raw, slug2) {
|
|
@@ -1447,9 +1450,44 @@ function stringList(value) {
|
|
|
1447
1450
|
}
|
|
1448
1451
|
return [];
|
|
1449
1452
|
}
|
|
1450
|
-
function
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
+
function parseWorkflow(value) {
|
|
1454
|
+
const stepsRaw = Array.isArray(value) ? value : value && typeof value === "object" && Array.isArray(value.steps) ? value.steps : [];
|
|
1455
|
+
const steps = stepsRaw.map(parseWorkflowStep).filter((step) => step !== null);
|
|
1456
|
+
return steps.length > 0 ? { steps } : void 0;
|
|
1457
|
+
}
|
|
1458
|
+
function parseWorkflowStep(value) {
|
|
1459
|
+
if (typeof value === "string") {
|
|
1460
|
+
const capability2 = value.trim();
|
|
1461
|
+
return isSafeSlug(capability2) ? { capability: capability2 } : null;
|
|
1462
|
+
}
|
|
1463
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
1464
|
+
const raw = value;
|
|
1465
|
+
const capability = stringField(raw.capability ?? raw.action);
|
|
1466
|
+
if (!capability || !isSafeSlug(capability)) return null;
|
|
1467
|
+
const executable = stringField(raw.executable ?? raw.implementation);
|
|
1468
|
+
const action = stringField(raw.action);
|
|
1469
|
+
const agent = stringField(raw.agent);
|
|
1470
|
+
const reason = stringField(raw.reason);
|
|
1471
|
+
const target = stringField(raw.target);
|
|
1472
|
+
const cliArgs = raw.cliArgs;
|
|
1473
|
+
return {
|
|
1474
|
+
capability,
|
|
1475
|
+
...action && isSafeSlug(action) ? { action } : {},
|
|
1476
|
+
...executable && isSafeSlug(executable) ? { executable } : {},
|
|
1477
|
+
...target === "issue" || target === "pr" ? { target } : {},
|
|
1478
|
+
...agent && isSafeSlug(agent) ? { agent } : {},
|
|
1479
|
+
...reason ? { reason } : {},
|
|
1480
|
+
...cliArgs && typeof cliArgs === "object" && !Array.isArray(cliArgs) ? { cliArgs } : {},
|
|
1481
|
+
...isPlainObject(raw.runWhen) ? { runWhen: raw.runWhen } : {},
|
|
1482
|
+
...stringList(raw.continueOn ?? raw.continue_on).length > 0 ? { continueOn: stringList(raw.continueOn ?? raw.continue_on) } : {},
|
|
1483
|
+
...raw.saveReport === true ? { saveReport: true } : {}
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
function isPlainObject(value) {
|
|
1487
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1488
|
+
}
|
|
1489
|
+
function isSafeSlug(value) {
|
|
1490
|
+
return /^[a-z][a-z0-9-]*$/.test(value) && !value.includes("..");
|
|
1453
1491
|
}
|
|
1454
1492
|
var CAPABILITY_PROFILE_FILE, CAPABILITY_BODY_FILE;
|
|
1455
1493
|
var init_capabilityFolders = __esm({
|
|
@@ -1482,7 +1520,8 @@ function getCompanyStoreAssetRoot(kind) {
|
|
|
1482
1520
|
capabilities: "capabilities",
|
|
1483
1521
|
executables: "executables",
|
|
1484
1522
|
goals: "goals",
|
|
1485
|
-
agents: "agents"
|
|
1523
|
+
agents: "agents",
|
|
1524
|
+
workflows: "workflows"
|
|
1486
1525
|
};
|
|
1487
1526
|
return path7.join(root, ".kody", folderByKind[kind]);
|
|
1488
1527
|
}
|
|
@@ -1677,13 +1716,13 @@ function listCapabilityActions(projectCapabilitiesRoot = getProjectCapabilitiesR
|
|
|
1677
1716
|
const projectExecutableRoots = [getProjectExecutablesRoot()];
|
|
1678
1717
|
const storeExecutableRoot = getCompanyStoreExecutablesRoot();
|
|
1679
1718
|
const storeExecutableRoots = storeExecutableRoot ? [storeExecutableRoot] : [];
|
|
1680
|
-
for (const action of listFolderCapabilityActions(projectCapabilitiesRoot, "project-folder"
|
|
1719
|
+
for (const action of listFolderCapabilityActions(projectCapabilitiesRoot, "project-folder"))
|
|
1681
1720
|
add(action);
|
|
1682
1721
|
for (const root of projectExecutableRoots) {
|
|
1683
1722
|
for (const action of listExecutableCapabilityActions(root, "project-executable")) add(action);
|
|
1684
1723
|
}
|
|
1685
1724
|
if (storeCapabilitiesRoot) {
|
|
1686
|
-
for (const action of listFolderCapabilityActions(storeCapabilitiesRoot, "company-store"
|
|
1725
|
+
for (const action of listFolderCapabilityActions(storeCapabilitiesRoot, "company-store")) add(action);
|
|
1687
1726
|
}
|
|
1688
1727
|
for (const root of storeExecutableRoots) {
|
|
1689
1728
|
for (const action of listExecutableCapabilityActions(root, "company-store-executable")) add(action);
|
|
@@ -1706,7 +1745,16 @@ function resolveCapabilityFolder(slug2, projectCapabilitiesRoot = getProjectCapa
|
|
|
1706
1745
|
}
|
|
1707
1746
|
return null;
|
|
1708
1747
|
}
|
|
1748
|
+
function getCapabilityActionInputs(action) {
|
|
1749
|
+
const resolved = resolveCapabilityAction(action);
|
|
1750
|
+
if (!resolved) return null;
|
|
1751
|
+
return getProfileInputs(resolved.executable);
|
|
1752
|
+
}
|
|
1709
1753
|
function resolveCapabilityExecution(capability) {
|
|
1754
|
+
const firstWorkflowStep = capability.config.workflow?.steps[0];
|
|
1755
|
+
if (firstWorkflowStep) {
|
|
1756
|
+
return { executable: firstWorkflowStep.executable ?? firstWorkflowStep.capability, cliArgs: {} };
|
|
1757
|
+
}
|
|
1710
1758
|
const executable = capability.config.implementation ?? capability.config.executable ?? capability.config.implementations?.[0] ?? capability.config.executables?.[0] ?? (capability.config.role ? capability.slug : void 0) ?? (capability.config.tickScript ? "capability-tick-scripted" : "capability-tick");
|
|
1711
1759
|
const cliArgs = executableDeclaresInput(executable, "capability") ? { capability: capability.slug } : {};
|
|
1712
1760
|
return { executable, cliArgs };
|
|
@@ -1754,7 +1802,7 @@ function listExecutableCapabilityActions(root, source) {
|
|
|
1754
1802
|
const action = typeof raw.action === "string" && raw.action.trim() ? raw.action.trim() : "";
|
|
1755
1803
|
if (!action) continue;
|
|
1756
1804
|
if (!PUBLIC_EXECUTABLE_ROLES.has(String(raw.role))) continue;
|
|
1757
|
-
if (!
|
|
1805
|
+
if (typeof raw.kind !== "string" || !raw.kind.trim()) continue;
|
|
1758
1806
|
if (!Array.isArray(raw.inputs)) continue;
|
|
1759
1807
|
out.push({
|
|
1760
1808
|
action,
|
|
@@ -1770,14 +1818,13 @@ function listExecutableCapabilityActions(root, source) {
|
|
|
1770
1818
|
}
|
|
1771
1819
|
return out.sort((a, b) => a.action.localeCompare(b.action));
|
|
1772
1820
|
}
|
|
1773
|
-
function listFolderCapabilityActions(root, source
|
|
1821
|
+
function listFolderCapabilityActions(root, source) {
|
|
1774
1822
|
if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
|
|
1775
1823
|
const out = [];
|
|
1776
1824
|
for (const slug2 of listCapabilityFolderSlugs(root)) {
|
|
1777
1825
|
if (!isSafeName(slug2)) continue;
|
|
1778
1826
|
const capability = readCapabilityFolder(root, slug2);
|
|
1779
1827
|
if (!capability) continue;
|
|
1780
|
-
if (requireCapabilityKind && !capability.config.capabilityKind) continue;
|
|
1781
1828
|
const action = capability.config.action ?? slug2;
|
|
1782
1829
|
const { executable, cliArgs } = resolveCapabilityExecution(capability);
|
|
1783
1830
|
out.push({
|
|
@@ -1787,7 +1834,6 @@ function listFolderCapabilityActions(root, source, requireCapabilityKind = false
|
|
|
1787
1834
|
cliArgs,
|
|
1788
1835
|
source,
|
|
1789
1836
|
describe: capability.config.describe ?? capability.title,
|
|
1790
|
-
capabilityKind: capability.config.capabilityKind,
|
|
1791
1837
|
profilePath: capability.profilePath,
|
|
1792
1838
|
bodyPath: capability.bodyPath
|
|
1793
1839
|
});
|
|
@@ -1810,7 +1856,6 @@ function listBuiltinCapabilityActions(root = getBuiltinCapabilitiesRoot()) {
|
|
|
1810
1856
|
cliArgs: {},
|
|
1811
1857
|
source: "builtin",
|
|
1812
1858
|
describe: capability.config.describe ?? capability.title,
|
|
1813
|
-
capabilityKind: capability.config.capabilityKind,
|
|
1814
1859
|
profilePath: capability.profilePath,
|
|
1815
1860
|
bodyPath: capability.bodyPath
|
|
1816
1861
|
});
|
|
@@ -1853,14 +1898,13 @@ function parseGenericFlags(argv) {
|
|
|
1853
1898
|
if (positional.length > 0) args._ = positional;
|
|
1854
1899
|
return args;
|
|
1855
1900
|
}
|
|
1856
|
-
var PUBLIC_EXECUTABLE_ROLES
|
|
1901
|
+
var PUBLIC_EXECUTABLE_ROLES;
|
|
1857
1902
|
var init_registry = __esm({
|
|
1858
1903
|
"src/registry.ts"() {
|
|
1859
1904
|
"use strict";
|
|
1860
1905
|
init_capabilityFolders();
|
|
1861
1906
|
init_companyStore();
|
|
1862
1907
|
PUBLIC_EXECUTABLE_ROLES = /* @__PURE__ */ new Set(["primitive", "orchestrator", "container", "watch", "utility"]);
|
|
1863
|
-
PUBLIC_EXECUTABLE_CAPABILITY_KINDS = /* @__PURE__ */ new Set(["observe", "act", "verify"]);
|
|
1864
1908
|
}
|
|
1865
1909
|
});
|
|
1866
1910
|
|
|
@@ -3089,6 +3133,60 @@ var init_gha = __esm({
|
|
|
3089
3133
|
}
|
|
3090
3134
|
});
|
|
3091
3135
|
|
|
3136
|
+
// src/agents.ts
|
|
3137
|
+
import * as fs16 from "fs";
|
|
3138
|
+
import * as path16 from "path";
|
|
3139
|
+
function stripFrontmatter(raw) {
|
|
3140
|
+
const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
|
|
3141
|
+
return (match ? match[1] : raw).trim();
|
|
3142
|
+
}
|
|
3143
|
+
function loadAgentIdentity(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3144
|
+
const trimmed = slug2.trim();
|
|
3145
|
+
if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
|
|
3146
|
+
const agentPath = resolveAgentFile(cwd, trimmed, agentsDir);
|
|
3147
|
+
if (fs16.existsSync(agentPath)) {
|
|
3148
|
+
const body = stripFrontmatter(fs16.readFileSync(agentPath, "utf-8"));
|
|
3149
|
+
if (body) return body;
|
|
3150
|
+
const builtinForEmpty = BUILTIN_AGENTS[trimmed];
|
|
3151
|
+
if (builtinForEmpty) return builtinForEmpty;
|
|
3152
|
+
throw new Error(`loadAgentIdentity: agent '${trimmed}' agent identity body is empty (${agentPath})`);
|
|
3153
|
+
}
|
|
3154
|
+
const builtin = BUILTIN_AGENTS[trimmed];
|
|
3155
|
+
if (builtin) return builtin;
|
|
3156
|
+
throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
|
|
3157
|
+
}
|
|
3158
|
+
function resolveAgentFile(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3159
|
+
const localPath = path16.join(cwd, agentsDir, `${slug2}.md`);
|
|
3160
|
+
if (fs16.existsSync(localPath)) return localPath;
|
|
3161
|
+
const storeAgentRoot = getCompanyStoreAssetRoot("agents");
|
|
3162
|
+
if (storeAgentRoot) {
|
|
3163
|
+
const storePath = path16.join(storeAgentRoot, `${slug2}.md`);
|
|
3164
|
+
if (fs16.existsSync(storePath)) return storePath;
|
|
3165
|
+
}
|
|
3166
|
+
return localPath;
|
|
3167
|
+
}
|
|
3168
|
+
function frameAgentIdentity(slug2, agent) {
|
|
3169
|
+
return [
|
|
3170
|
+
`## Who you are \u2014 agent identity (authoritative identity)`,
|
|
3171
|
+
``,
|
|
3172
|
+
`You are operating as agent \`${slug2}\`. This identity defines *who* you are:`,
|
|
3173
|
+
`your authority, doctrine, voice, and hard limits. Honour it exactly. Where the`,
|
|
3174
|
+
`this identity's restrictions are stricter than the task, **the agent wins** \u2014 a task`,
|
|
3175
|
+
`can never grant you authority your agent withholds.`,
|
|
3176
|
+
``,
|
|
3177
|
+
agent
|
|
3178
|
+
].join("\n");
|
|
3179
|
+
}
|
|
3180
|
+
var DEFAULT_AGENT_DIR, BUILTIN_AGENTS;
|
|
3181
|
+
var init_agents = __esm({
|
|
3182
|
+
"src/agents.ts"() {
|
|
3183
|
+
"use strict";
|
|
3184
|
+
init_companyStore();
|
|
3185
|
+
DEFAULT_AGENT_DIR = ".kody/agents";
|
|
3186
|
+
BUILTIN_AGENTS = {};
|
|
3187
|
+
}
|
|
3188
|
+
});
|
|
3189
|
+
|
|
3092
3190
|
// src/capabilityReport.ts
|
|
3093
3191
|
function parseCapabilityReportsFromText(text) {
|
|
3094
3192
|
const reports = [];
|
|
@@ -3254,60 +3352,6 @@ var init_capabilityResult = __esm({
|
|
|
3254
3352
|
}
|
|
3255
3353
|
});
|
|
3256
3354
|
|
|
3257
|
-
// src/agents.ts
|
|
3258
|
-
import * as fs16 from "fs";
|
|
3259
|
-
import * as path16 from "path";
|
|
3260
|
-
function stripFrontmatter(raw) {
|
|
3261
|
-
const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
|
|
3262
|
-
return (match ? match[1] : raw).trim();
|
|
3263
|
-
}
|
|
3264
|
-
function loadAgentIdentity(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3265
|
-
const trimmed = slug2.trim();
|
|
3266
|
-
if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
|
|
3267
|
-
const agentPath = resolveAgentFile(cwd, trimmed, agentsDir);
|
|
3268
|
-
if (fs16.existsSync(agentPath)) {
|
|
3269
|
-
const body = stripFrontmatter(fs16.readFileSync(agentPath, "utf-8"));
|
|
3270
|
-
if (body) return body;
|
|
3271
|
-
const builtinForEmpty = BUILTIN_AGENTS[trimmed];
|
|
3272
|
-
if (builtinForEmpty) return builtinForEmpty;
|
|
3273
|
-
throw new Error(`loadAgentIdentity: agent '${trimmed}' agent identity body is empty (${agentPath})`);
|
|
3274
|
-
}
|
|
3275
|
-
const builtin = BUILTIN_AGENTS[trimmed];
|
|
3276
|
-
if (builtin) return builtin;
|
|
3277
|
-
throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
|
|
3278
|
-
}
|
|
3279
|
-
function resolveAgentFile(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
|
|
3280
|
-
const localPath = path16.join(cwd, agentsDir, `${slug2}.md`);
|
|
3281
|
-
if (fs16.existsSync(localPath)) return localPath;
|
|
3282
|
-
const storeAgentRoot = getCompanyStoreAssetRoot("agents");
|
|
3283
|
-
if (storeAgentRoot) {
|
|
3284
|
-
const storePath = path16.join(storeAgentRoot, `${slug2}.md`);
|
|
3285
|
-
if (fs16.existsSync(storePath)) return storePath;
|
|
3286
|
-
}
|
|
3287
|
-
return localPath;
|
|
3288
|
-
}
|
|
3289
|
-
function frameAgentIdentity(slug2, agent) {
|
|
3290
|
-
return [
|
|
3291
|
-
`## Who you are \u2014 agent identity (authoritative identity)`,
|
|
3292
|
-
``,
|
|
3293
|
-
`You are operating as agent \`${slug2}\`. This identity defines *who* you are:`,
|
|
3294
|
-
`your authority, doctrine, voice, and hard limits. Honour it exactly. Where the`,
|
|
3295
|
-
`this identity's restrictions are stricter than the task, **the agent wins** \u2014 a task`,
|
|
3296
|
-
`can never grant you authority your agent withholds.`,
|
|
3297
|
-
``,
|
|
3298
|
-
agent
|
|
3299
|
-
].join("\n");
|
|
3300
|
-
}
|
|
3301
|
-
var DEFAULT_AGENT_DIR, BUILTIN_AGENTS;
|
|
3302
|
-
var init_agents = __esm({
|
|
3303
|
-
"src/agents.ts"() {
|
|
3304
|
-
"use strict";
|
|
3305
|
-
init_companyStore();
|
|
3306
|
-
DEFAULT_AGENT_DIR = ".kody/agents";
|
|
3307
|
-
BUILTIN_AGENTS = {};
|
|
3308
|
-
}
|
|
3309
|
-
});
|
|
3310
|
-
|
|
3311
3355
|
// src/profile-error.ts
|
|
3312
3356
|
var ProfileError;
|
|
3313
3357
|
var init_profile_error = __esm({
|
|
@@ -3659,7 +3703,6 @@ function loadProfile(profilePath) {
|
|
|
3659
3703
|
implementation: execRef,
|
|
3660
3704
|
executable: execRef,
|
|
3661
3705
|
describe: typeof r.describe === "string" ? r.describe : base.describe,
|
|
3662
|
-
capabilityKind: parseCapabilityKind(profilePath, r.capabilityKind) ?? base.capabilityKind,
|
|
3663
3706
|
agent: typeof r.agent === "string" && r.agent.trim() ? r.agent.trim() : base.agent,
|
|
3664
3707
|
capabilityTools: parseStringArray2(r.capabilityTools ?? r.capabilityTools ?? r.tools) ?? base.capabilityTools,
|
|
3665
3708
|
mentions: Array.isArray(r.mentions) ? r.mentions.map((m) => String(m).trim()).filter(Boolean) : base.mentions
|
|
@@ -3704,7 +3747,6 @@ function loadProfile(profilePath) {
|
|
|
3704
3747
|
implementation: void 0,
|
|
3705
3748
|
executable: void 0,
|
|
3706
3749
|
describe: typeof r.describe === "string" ? r.describe : "",
|
|
3707
|
-
capabilityKind: parseCapabilityKind(profilePath, r.capabilityKind),
|
|
3708
3750
|
// Optional agent to run as. Empty/blank string → undefined (no agent).
|
|
3709
3751
|
agent: typeof r.agent === "string" && r.agent.trim() ? r.agent.trim() : void 0,
|
|
3710
3752
|
// Locked-toolbox palette + mentions from folder-capability profile metadata.
|
|
@@ -3799,13 +3841,6 @@ function requireString(p, r, key) {
|
|
|
3799
3841
|
}
|
|
3800
3842
|
return v;
|
|
3801
3843
|
}
|
|
3802
|
-
function parseCapabilityKind(p, raw) {
|
|
3803
|
-
if (raw === void 0 || raw === null || raw === "") return void 0;
|
|
3804
|
-
if (typeof raw !== "string" || !VALID_CAPABILITY_KINDS.has(raw)) {
|
|
3805
|
-
throw new ProfileError(p, `"capabilityKind" must be one of: observe | act | verify`);
|
|
3806
|
-
}
|
|
3807
|
-
return raw;
|
|
3808
|
-
}
|
|
3809
3844
|
function parseStringArray2(raw) {
|
|
3810
3845
|
if (!Array.isArray(raw)) return void 0;
|
|
3811
3846
|
const values = raw.map((t) => String(t).trim()).filter(Boolean);
|
|
@@ -4052,7 +4087,7 @@ function parseScriptList(p, key, raw) {
|
|
|
4052
4087
|
}
|
|
4053
4088
|
return out;
|
|
4054
4089
|
}
|
|
4055
|
-
var VALID_INPUT_TYPES, VALID_PERMISSION_MODES, VALID_ROLES, VALID_CONTAINER_CHILD_TARGETS, VALID_PHASES,
|
|
4090
|
+
var VALID_INPUT_TYPES, VALID_PERMISSION_MODES, VALID_ROLES, VALID_CONTAINER_CHILD_TARGETS, VALID_PHASES, KNOWN_PROFILE_KEYS;
|
|
4056
4091
|
var init_profile = __esm({
|
|
4057
4092
|
"src/profile.ts"() {
|
|
4058
4093
|
"use strict";
|
|
@@ -4068,7 +4103,6 @@ var init_profile = __esm({
|
|
|
4068
4103
|
VALID_ROLES = /* @__PURE__ */ new Set(["primitive", "orchestrator", "container", "watch", "utility"]);
|
|
4069
4104
|
VALID_CONTAINER_CHILD_TARGETS = /* @__PURE__ */ new Set(["issue", "pr"]);
|
|
4070
4105
|
VALID_PHASES = /* @__PURE__ */ new Set(["research", "planning", "implementing", "reviewing", "shipped", "failed", "idle"]);
|
|
4071
|
-
VALID_CAPABILITY_KINDS = /* @__PURE__ */ new Set(["observe", "act", "verify"]);
|
|
4072
4106
|
KNOWN_PROFILE_KEYS = /* @__PURE__ */ new Set([
|
|
4073
4107
|
"name",
|
|
4074
4108
|
"action",
|
|
@@ -4082,10 +4116,10 @@ var init_profile = __esm({
|
|
|
4082
4116
|
"capabilityTools",
|
|
4083
4117
|
"tools",
|
|
4084
4118
|
"mentions",
|
|
4085
|
-
"capabilityKind",
|
|
4086
4119
|
"stage",
|
|
4087
4120
|
"readsFrom",
|
|
4088
4121
|
"writesTo",
|
|
4122
|
+
"workflow",
|
|
4089
4123
|
"describe",
|
|
4090
4124
|
"role",
|
|
4091
4125
|
"kind",
|
|
@@ -6077,7 +6111,7 @@ function asPreferredRunTime(value) {
|
|
|
6077
6111
|
function asLoopTarget(value) {
|
|
6078
6112
|
const raw = asRecord(value);
|
|
6079
6113
|
if (!raw) return void 0;
|
|
6080
|
-
if (raw.type !== "goal" && raw.type !== "capability") return void 0;
|
|
6114
|
+
if (raw.type !== "goal" && raw.type !== "capability" && raw.type !== "workflow") return void 0;
|
|
6081
6115
|
if (typeof raw.id !== "string" || raw.id.trim().length === 0) return void 0;
|
|
6082
6116
|
return { type: raw.type, id: raw.id };
|
|
6083
6117
|
}
|
|
@@ -6173,10 +6207,10 @@ var init_state2 = __esm({
|
|
|
6173
6207
|
"use strict";
|
|
6174
6208
|
VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "done"]);
|
|
6175
6209
|
GoalStateError = class extends Error {
|
|
6176
|
-
constructor(
|
|
6177
|
-
super(`Invalid goal state at ${
|
|
6210
|
+
constructor(path49, message) {
|
|
6211
|
+
super(`Invalid goal state at ${path49}:
|
|
6178
6212
|
${message}`);
|
|
6179
|
-
this.path =
|
|
6213
|
+
this.path = path49;
|
|
6180
6214
|
this.name = "GoalStateError";
|
|
6181
6215
|
}
|
|
6182
6216
|
path;
|
|
@@ -6189,17 +6223,12 @@ import * as fs25 from "fs";
|
|
|
6189
6223
|
function stageGoalRunLogEvent(data, goalId, event, at = nowIso()) {
|
|
6190
6224
|
const logs = goalRunLogs(data);
|
|
6191
6225
|
const existing = logs[goalId];
|
|
6192
|
-
const
|
|
6226
|
+
const path49 = existing?.path ?? goalRunLogPath(goalId, data);
|
|
6193
6227
|
logs[goalId] = {
|
|
6194
|
-
path:
|
|
6228
|
+
path: path49,
|
|
6195
6229
|
events: [
|
|
6196
6230
|
...existing?.events ?? [],
|
|
6197
|
-
|
|
6198
|
-
version: 1,
|
|
6199
|
-
time: at,
|
|
6200
|
-
goalId,
|
|
6201
|
-
...event
|
|
6202
|
-
}
|
|
6231
|
+
buildGoalRunLogEvent(data, goalId, event, at)
|
|
6203
6232
|
]
|
|
6204
6233
|
};
|
|
6205
6234
|
}
|
|
@@ -6297,15 +6326,33 @@ function githubRunId() {
|
|
|
6297
6326
|
const attempt = process.env.GITHUB_RUN_ATTEMPT?.trim();
|
|
6298
6327
|
return attempt ? `gh-${runId}-${attempt}` : `gh-${runId}`;
|
|
6299
6328
|
}
|
|
6329
|
+
function buildGoalRunLogEvent(data, goalId, event, at) {
|
|
6330
|
+
const trigger = event.trigger ?? triggerContext();
|
|
6331
|
+
const job = event.job ?? jobContext(data);
|
|
6332
|
+
const base = {
|
|
6333
|
+
version: 1,
|
|
6334
|
+
time: at,
|
|
6335
|
+
goalId,
|
|
6336
|
+
...event
|
|
6337
|
+
};
|
|
6338
|
+
if (trigger !== void 0) base.trigger = trigger;
|
|
6339
|
+
if (job !== void 0) base.job = job;
|
|
6340
|
+
const context = event.dispatchContext ?? dispatchContext(base, trigger, job);
|
|
6341
|
+
if (context !== void 0) base.dispatchContext = context;
|
|
6342
|
+
return base;
|
|
6343
|
+
}
|
|
6300
6344
|
function enrichGoalRunLogEvent(config, data, logPath, event) {
|
|
6301
6345
|
const stateRepo = stateRepoContext(config, event.goalId, logPath);
|
|
6346
|
+
const trigger = event.trigger ?? triggerContext();
|
|
6347
|
+
const job = event.job ?? jobContext(data);
|
|
6302
6348
|
return pruneUndefined({
|
|
6303
6349
|
...event,
|
|
6304
6350
|
run: event.run ?? runContext(data),
|
|
6305
6351
|
repo: event.repo ?? repoContext(config),
|
|
6306
6352
|
stateRepo: event.stateRepo ?? stateRepo,
|
|
6307
|
-
trigger
|
|
6308
|
-
job
|
|
6353
|
+
trigger,
|
|
6354
|
+
job,
|
|
6355
|
+
dispatchContext: event.dispatchContext ?? dispatchContext(event, trigger, job),
|
|
6309
6356
|
links: event.links ?? linkContext(stateRepo)
|
|
6310
6357
|
});
|
|
6311
6358
|
}
|
|
@@ -6352,9 +6399,16 @@ function stateRepoContext(config, goalId, logPath) {
|
|
|
6352
6399
|
function triggerContext() {
|
|
6353
6400
|
const event = readGithubEvent();
|
|
6354
6401
|
const inputs = recordValue2(event?.inputs);
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6402
|
+
const eventName = process.env.GITHUB_EVENT_NAME?.trim() || void 0;
|
|
6403
|
+
const githubActor = process.env.GITHUB_ACTOR?.trim() || void 0;
|
|
6404
|
+
if (!eventName && !githubActor && !process.env.GITHUB_EVENT_PATH) return void 0;
|
|
6405
|
+
const trigger = pruneUndefined({
|
|
6406
|
+
source: eventName ? "github-actions" : "local",
|
|
6407
|
+
kind: triggerKind(eventName),
|
|
6408
|
+
eventName,
|
|
6409
|
+
actor: githubActor,
|
|
6410
|
+
githubActor,
|
|
6411
|
+
actorRole: triggerActorRole(eventName),
|
|
6358
6412
|
eventPath: process.env.GITHUB_EVENT_PATH?.trim() || void 0,
|
|
6359
6413
|
issue: numberValue(recordValue2(event?.issue)?.number),
|
|
6360
6414
|
pullRequest: numberValue(recordValue2(event?.pull_request)?.number),
|
|
@@ -6362,23 +6416,70 @@ function triggerContext() {
|
|
|
6362
6416
|
schedule: stringValue(event?.schedule),
|
|
6363
6417
|
inputs: inputs ? pickRecord(inputs, ["issue_number", "sessionId", "message", "model", "title", "executable", "base"]) : void 0
|
|
6364
6418
|
});
|
|
6419
|
+
return Object.keys(trigger).length > 0 ? trigger : void 0;
|
|
6420
|
+
}
|
|
6421
|
+
function triggerKind(eventName) {
|
|
6422
|
+
if (!eventName) return "local";
|
|
6423
|
+
if (eventName === "schedule") return "schedule";
|
|
6424
|
+
if (eventName === "workflow_dispatch") return "manual-workflow-dispatch";
|
|
6425
|
+
return eventName;
|
|
6426
|
+
}
|
|
6427
|
+
function triggerActorRole(eventName) {
|
|
6428
|
+
if (!eventName) return void 0;
|
|
6429
|
+
if (eventName === "schedule") return "github workflow run actor; not the manual dispatcher";
|
|
6430
|
+
if (eventName === "workflow_dispatch") return "manual workflow dispatcher";
|
|
6431
|
+
return "github event actor";
|
|
6365
6432
|
}
|
|
6366
6433
|
function jobContext(data) {
|
|
6367
6434
|
const job = pruneUndefined({
|
|
6368
|
-
id: stringValue(data.jobId),
|
|
6369
|
-
key: stringValue(data.jobKey),
|
|
6370
|
-
flavor: stringValue(data.jobFlavor),
|
|
6371
|
-
action: stringValue(data.jobAction),
|
|
6372
|
-
capability: stringValue(data.jobCapability),
|
|
6373
|
-
executable: stringValue(data.jobExecutable),
|
|
6374
|
-
agent: stringValue(data.jobAgent),
|
|
6375
|
-
schedule: stringValue(data.jobSchedule),
|
|
6376
|
-
target: data.jobTarget,
|
|
6435
|
+
id: stringValue(data.jobId) ?? void 0,
|
|
6436
|
+
key: stringValue(data.jobKey) ?? void 0,
|
|
6437
|
+
flavor: stringValue(data.jobFlavor) ?? void 0,
|
|
6438
|
+
action: stringValue(data.jobAction) ?? void 0,
|
|
6439
|
+
capability: stringValue(data.jobCapability) ?? void 0,
|
|
6440
|
+
executable: stringValue(data.jobExecutable) ?? void 0,
|
|
6441
|
+
agent: stringValue(data.jobAgent) ?? void 0,
|
|
6442
|
+
schedule: stringValue(data.jobSchedule) ?? void 0,
|
|
6443
|
+
target: data.jobTarget ?? void 0,
|
|
6377
6444
|
why: truncateString(stringValue(data.jobWhy), 1e3),
|
|
6378
6445
|
saveReport: data.jobSaveReport === true ? true : void 0
|
|
6379
6446
|
});
|
|
6380
6447
|
return Object.keys(job).length > 0 ? job : void 0;
|
|
6381
6448
|
}
|
|
6449
|
+
function dispatchContext(event, trigger, job) {
|
|
6450
|
+
if (!event.dispatch && event.status !== "dispatch") return void 0;
|
|
6451
|
+
const dispatch2 = event.dispatch ?? {};
|
|
6452
|
+
const context = pruneUndefined({
|
|
6453
|
+
triggeredBy: triggerLabel(trigger),
|
|
6454
|
+
triggerKind: stringValue(trigger?.kind),
|
|
6455
|
+
dispatchMode: dispatchMode(trigger),
|
|
6456
|
+
githubActor: stringValue(trigger?.githubActor) ?? stringValue(trigger?.actor),
|
|
6457
|
+
githubActorRole: stringValue(trigger?.actorRole),
|
|
6458
|
+
decidedBy: event.source,
|
|
6459
|
+
dispatchedBy: event.source,
|
|
6460
|
+
target: event.target,
|
|
6461
|
+
action: dispatch2.action ?? stringValue(job?.action),
|
|
6462
|
+
capability: dispatch2.capability ?? stringValue(job?.capability),
|
|
6463
|
+
reason: event.reason
|
|
6464
|
+
});
|
|
6465
|
+
return Object.keys(context).length > 0 ? context : void 0;
|
|
6466
|
+
}
|
|
6467
|
+
function triggerLabel(trigger) {
|
|
6468
|
+
const kind = stringValue(trigger?.kind);
|
|
6469
|
+
if (kind === "schedule") return "GitHub schedule";
|
|
6470
|
+
if (kind === "manual-workflow-dispatch") return "manual workflow dispatch";
|
|
6471
|
+
if (kind === "issue_comment") return "GitHub issue comment";
|
|
6472
|
+
if (kind === "pull_request") return "GitHub pull request";
|
|
6473
|
+
if (kind) return `GitHub ${kind}`;
|
|
6474
|
+
return "local run";
|
|
6475
|
+
}
|
|
6476
|
+
function dispatchMode(trigger) {
|
|
6477
|
+
const kind = stringValue(trigger?.kind);
|
|
6478
|
+
if (kind === "schedule") return "automated";
|
|
6479
|
+
if (kind === "manual-workflow-dispatch") return "manual";
|
|
6480
|
+
if (kind) return "event-driven";
|
|
6481
|
+
return "local";
|
|
6482
|
+
}
|
|
6382
6483
|
function linkContext(stateRepo) {
|
|
6383
6484
|
const links = {};
|
|
6384
6485
|
const runId = process.env.GITHUB_RUN_ID?.trim();
|
|
@@ -7003,12 +7104,20 @@ function isCapabilityCadenceGoal(goal, extra) {
|
|
|
7003
7104
|
function isGoalTargetLoop(goal) {
|
|
7004
7105
|
return goal.type === "agentLoop" && goal.loopTarget?.type === "goal" && goal.loopTarget.id.trim().length > 0;
|
|
7005
7106
|
}
|
|
7006
|
-
function
|
|
7107
|
+
function isWorkflowTargetLoop(goal) {
|
|
7108
|
+
return goal.type === "agentLoop" && goal.loopTarget?.type === "workflow" && goal.loopTarget.id.trim().length > 0;
|
|
7109
|
+
}
|
|
7110
|
+
function planTargetLoopSchedule(opts) {
|
|
7007
7111
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
7008
7112
|
const at = now.toISOString();
|
|
7009
|
-
const
|
|
7113
|
+
const target = opts.goal.loopTarget;
|
|
7114
|
+
const targetId = target?.id.trim() ?? "";
|
|
7010
7115
|
if (!targetId) {
|
|
7011
|
-
const reason = "
|
|
7116
|
+
const reason = "loop missing target";
|
|
7117
|
+
return targetLoopDecision("blocked", reason, at);
|
|
7118
|
+
}
|
|
7119
|
+
if (target?.type !== "goal" && target?.type !== "workflow") {
|
|
7120
|
+
const reason = `unsupported loop target: ${String(target?.type ?? "missing")}`;
|
|
7012
7121
|
return targetLoopDecision("blocked", reason, at);
|
|
7013
7122
|
}
|
|
7014
7123
|
const preferred = opts.goal.preferredRunTime;
|
|
@@ -7016,18 +7125,22 @@ function planGoalTargetLoopSchedule(opts) {
|
|
|
7016
7125
|
const gate = preferredRunTimeGate(preferred, now, opts.previousScheduleState);
|
|
7017
7126
|
if (!gate.ok) return targetLoopDecision("idle", gate.reason, at);
|
|
7018
7127
|
}
|
|
7128
|
+
const dispatch2 = target.type === "goal" ? { action: "goal-manager", executable: "goal-manager", cliArgs: { goal: targetId } } : { workflow: targetId, cliArgs: {} };
|
|
7019
7129
|
return {
|
|
7020
7130
|
kind: "dispatch",
|
|
7021
|
-
reason: `dispatch
|
|
7022
|
-
dispatch:
|
|
7131
|
+
reason: `dispatch ${target.type} ${targetId}`,
|
|
7132
|
+
dispatch: dispatch2,
|
|
7023
7133
|
scheduleState: {
|
|
7024
7134
|
mode: "agentLoop",
|
|
7025
7135
|
lastGoalTickAt: at,
|
|
7026
7136
|
lastDecision: {
|
|
7027
7137
|
kind: "dispatch",
|
|
7028
|
-
targetType:
|
|
7138
|
+
targetType: target.type,
|
|
7029
7139
|
targetId,
|
|
7030
|
-
|
|
7140
|
+
...dispatch2.action ? { action: dispatch2.action } : {},
|
|
7141
|
+
...dispatch2.capability ? { capability: dispatch2.capability } : {},
|
|
7142
|
+
...dispatch2.workflow ? { workflow: dispatch2.workflow } : {},
|
|
7143
|
+
...dispatch2.executable ? { executable: dispatch2.executable } : {},
|
|
7031
7144
|
reason: preferred ? `preferred time ${preferred.time} ${preferred.timezone}` : "ready target loop tick",
|
|
7032
7145
|
at
|
|
7033
7146
|
},
|
|
@@ -7237,8 +7350,8 @@ function stageManagedGoalDecision(data, goalId, goal, goalState, decision, detai
|
|
|
7237
7350
|
status: decision.kind,
|
|
7238
7351
|
dispatch: {
|
|
7239
7352
|
capability: decision.capability,
|
|
7240
|
-
|
|
7241
|
-
|
|
7353
|
+
cliArgs: decision.cliArgs,
|
|
7354
|
+
...decision.executable ? { executable: decision.executable } : {}
|
|
7242
7355
|
},
|
|
7243
7356
|
goal: details.goalSnapshot,
|
|
7244
7357
|
inspection: details.inspection,
|
|
@@ -7247,8 +7360,8 @@ function stageManagedGoalDecision(data, goalId, goal, goalState, decision, detai
|
|
|
7247
7360
|
evidence: decision.evidence,
|
|
7248
7361
|
stage: decision.stage,
|
|
7249
7362
|
capability: decision.capability,
|
|
7250
|
-
|
|
7251
|
-
|
|
7363
|
+
cliArgs: decision.cliArgs,
|
|
7364
|
+
...decision.executable ? { executable: decision.executable } : {}
|
|
7252
7365
|
},
|
|
7253
7366
|
change: details.change
|
|
7254
7367
|
});
|
|
@@ -7443,18 +7556,20 @@ var init_advanceManagedGoal = __esm({
|
|
|
7443
7556
|
ctx.output.reason = reason;
|
|
7444
7557
|
return;
|
|
7445
7558
|
}
|
|
7446
|
-
if (isGoalTargetLoop(managed)) {
|
|
7559
|
+
if (isGoalTargetLoop(managed) || isWorkflowTargetLoop(managed)) {
|
|
7447
7560
|
const beforeSnapshot = goalRunLogSnapshot(goal.id, goal.state, managed);
|
|
7448
7561
|
const previousScheduleState = goal.raw.extra.scheduleState && typeof goal.raw.extra.scheduleState === "object" ? goal.raw.extra.scheduleState : void 0;
|
|
7449
|
-
const decision2 =
|
|
7562
|
+
const decision2 = planTargetLoopSchedule({ goal: managed, previousScheduleState });
|
|
7450
7563
|
restoreGoalIdFact();
|
|
7451
7564
|
goal.raw = writeManagedGoalToState({ ...goal.raw, state: goal.state }, managed);
|
|
7452
7565
|
goal.raw.extra.scheduleState = decision2.scheduleState;
|
|
7453
7566
|
ctx.data.managedGoalDecision = decision2;
|
|
7454
7567
|
if (decision2.kind === "dispatch" && decision2.dispatch) {
|
|
7455
7568
|
ctx.output.nextDispatch = {
|
|
7456
|
-
action: decision2.dispatch.action,
|
|
7457
|
-
|
|
7569
|
+
...decision2.dispatch.action ? { action: decision2.dispatch.action } : {},
|
|
7570
|
+
...decision2.dispatch.capability ? { capability: decision2.dispatch.capability } : {},
|
|
7571
|
+
...decision2.dispatch.workflow ? { workflow: decision2.dispatch.workflow } : {},
|
|
7572
|
+
...decision2.dispatch.executable ? { executable: decision2.dispatch.executable } : {},
|
|
7458
7573
|
cliArgs: decision2.dispatch.cliArgs
|
|
7459
7574
|
};
|
|
7460
7575
|
}
|
|
@@ -7575,8 +7690,8 @@ var init_advanceManagedGoal = __esm({
|
|
|
7575
7690
|
}
|
|
7576
7691
|
ctx.output.nextDispatch = {
|
|
7577
7692
|
capability: decision.capability,
|
|
7578
|
-
executable: decision.executable,
|
|
7579
7693
|
cliArgs: decision.cliArgs,
|
|
7694
|
+
...decision.executable ? { executable: decision.executable } : {},
|
|
7580
7695
|
...decision.saveReport === true ? { saveReport: true } : {}
|
|
7581
7696
|
};
|
|
7582
7697
|
ctx.output.reason = `dispatch ${decision.capability} for ${decision.evidence}`;
|
|
@@ -7816,13 +7931,13 @@ function companyIntentPath(id) {
|
|
|
7816
7931
|
assertIntentId(id);
|
|
7817
7932
|
return `intents/${id}/intent.json`;
|
|
7818
7933
|
}
|
|
7819
|
-
function normalizeCompanyIntent(
|
|
7934
|
+
function normalizeCompanyIntent(path49, raw) {
|
|
7820
7935
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
7821
|
-
throw new Error(`${
|
|
7936
|
+
throw new Error(`${path49}: intent must be JSON object`);
|
|
7822
7937
|
}
|
|
7823
7938
|
const input = raw;
|
|
7824
7939
|
const id = stringField2(input.id);
|
|
7825
|
-
if (!id || !isCompanyIntentId(id)) throw new Error(`${
|
|
7940
|
+
if (!id || !isCompanyIntentId(id)) throw new Error(`${path49}: invalid intent id`);
|
|
7826
7941
|
const createdAt = stringField2(input.createdAt) || nowIso();
|
|
7827
7942
|
const updatedAt = stringField2(input.updatedAt) || createdAt;
|
|
7828
7943
|
return {
|
|
@@ -7861,8 +7976,8 @@ function listCompanyIntents(config, cwd) {
|
|
|
7861
7976
|
const records = [];
|
|
7862
7977
|
for (const entry of entries) {
|
|
7863
7978
|
if (entry.type !== "dir" || !entry.name || !isCompanyIntentId(entry.name)) continue;
|
|
7864
|
-
const
|
|
7865
|
-
const file = readStateText(config, cwd,
|
|
7979
|
+
const path49 = companyIntentPath(entry.name);
|
|
7980
|
+
const file = readStateText(config, cwd, path49);
|
|
7866
7981
|
if (!file) continue;
|
|
7867
7982
|
records.push({
|
|
7868
7983
|
id: entry.name,
|
|
@@ -7873,8 +7988,8 @@ function listCompanyIntents(config, cwd) {
|
|
|
7873
7988
|
return records.sort((a, b) => a.intent.priority - b.intent.priority || a.id.localeCompare(b.id));
|
|
7874
7989
|
}
|
|
7875
7990
|
function readCompanyIntent(config, cwd, id) {
|
|
7876
|
-
const
|
|
7877
|
-
const file = readStateText(config, cwd,
|
|
7991
|
+
const path49 = companyIntentPath(id);
|
|
7992
|
+
const file = readStateText(config, cwd, path49);
|
|
7878
7993
|
if (!file) return null;
|
|
7879
7994
|
return { id, path: file.path, intent: normalizeCompanyIntent(file.path, JSON.parse(file.content)) };
|
|
7880
7995
|
}
|
|
@@ -8361,6 +8476,9 @@ function goalReportBody(goalId, state, snapshot, latestEvent, evidenceItems) {
|
|
|
8361
8476
|
`- Missing evidence: ${listOrNone(missingEvidence)}`,
|
|
8362
8477
|
`- Blockers: ${listOrNone(blockers)}`,
|
|
8363
8478
|
"",
|
|
8479
|
+
"## Dispatch",
|
|
8480
|
+
...dispatchContextMarkdown(latestEvent),
|
|
8481
|
+
"",
|
|
8364
8482
|
"## Capability Evidence",
|
|
8365
8483
|
...capabilityEvidenceMarkdown(outputs),
|
|
8366
8484
|
"",
|
|
@@ -8398,6 +8516,27 @@ function evidenceOutputMarkdown(index, output) {
|
|
|
8398
8516
|
""
|
|
8399
8517
|
];
|
|
8400
8518
|
}
|
|
8519
|
+
function dispatchContextMarkdown(latestEvent) {
|
|
8520
|
+
const context = recordField2(latestEvent, "dispatchContext");
|
|
8521
|
+
if (!context) return ["- none"];
|
|
8522
|
+
const githubActor = stringField3(context, "githubActor");
|
|
8523
|
+
const githubActorRole = stringField3(context, "githubActorRole");
|
|
8524
|
+
const target = dispatchTargetLabel(recordField2(context, "target"));
|
|
8525
|
+
return [
|
|
8526
|
+
`- Triggered by: ${stringField3(context, "triggeredBy") ?? "unknown"}`,
|
|
8527
|
+
`- Mode: ${stringField3(context, "dispatchMode") ?? "unknown"}`,
|
|
8528
|
+
`- GitHub actor: ${githubActor ? `${githubActor}${githubActorRole ? ` (${githubActorRole})` : ""}` : "none"}`,
|
|
8529
|
+
`- Decided by: ${stringField3(context, "decidedBy") ?? "unknown"}`,
|
|
8530
|
+
`- Dispatched by: ${stringField3(context, "dispatchedBy") ?? "unknown"}`,
|
|
8531
|
+
`- Target: ${target ?? "none"}`
|
|
8532
|
+
];
|
|
8533
|
+
}
|
|
8534
|
+
function dispatchTargetLabel(target) {
|
|
8535
|
+
const type = stringField3(target, "type");
|
|
8536
|
+
const id = stringField3(target, "id");
|
|
8537
|
+
if (type && id) return `${type} ${id}`;
|
|
8538
|
+
return id ?? type;
|
|
8539
|
+
}
|
|
8401
8540
|
function artifactMarkdown(artifacts) {
|
|
8402
8541
|
if (artifacts.length === 0) return ["- none"];
|
|
8403
8542
|
return artifacts.map((artifact) => {
|
|
@@ -10444,10 +10583,9 @@ var init_dispatchClassified = __esm({
|
|
|
10444
10583
|
|
|
10445
10584
|
// src/jobIdentity.ts
|
|
10446
10585
|
function stableJobKey(job) {
|
|
10447
|
-
const capability = job.capability ?? job.action;
|
|
10586
|
+
const capability = job.workflow ?? job.capability ?? job.action;
|
|
10448
10587
|
const executable = job.executable ?? capability ?? "unknown";
|
|
10449
|
-
if (job.flavor === "scheduled" && job.capability)
|
|
10450
|
-
return `scheduled:${job.capability}:${executable}`;
|
|
10588
|
+
if (job.flavor === "scheduled" && job.capability) return `scheduled:${job.capability}:${executable}`;
|
|
10451
10589
|
const target = typeof job.target === "number" ? job.target : targetFromCliArgs(job.cliArgs);
|
|
10452
10590
|
const work = capability && executable && executable !== capability ? `${capability}:${executable}` : capability ?? executable;
|
|
10453
10591
|
return target === void 0 ? `${job.flavor}:${work}` : `${job.flavor}:${work}:${target}`;
|
|
@@ -16622,14 +16760,16 @@ function jobReferenceBlock(profileName, profile, data) {
|
|
|
16622
16760
|
const jobId = typeof data.jobId === "string" && data.jobId.length > 0 ? data.jobId : null;
|
|
16623
16761
|
const flavor = typeof data.jobFlavor === "string" && data.jobFlavor.length > 0 ? data.jobFlavor : null;
|
|
16624
16762
|
const schedule = typeof data.jobSchedule === "string" && data.jobSchedule.length > 0 ? data.jobSchedule : null;
|
|
16625
|
-
const isJob2 = Boolean(
|
|
16626
|
-
jobId || flavor || schedule || data.jobCapability || data.jobExecutable || data.jobWhy
|
|
16627
|
-
);
|
|
16763
|
+
const isJob2 = Boolean(jobId || flavor || schedule || data.jobCapability || data.jobExecutable || data.jobWhy);
|
|
16628
16764
|
if (!isJob2) return null;
|
|
16629
16765
|
const capability = typeof data.jobCapability === "string" && data.jobCapability.length > 0 ? data.jobCapability : profile.executable ? profile.name : null;
|
|
16630
16766
|
const executable = typeof profile.executable === "string" && profile.executable.length > 0 ? profile.executable : typeof data.jobExecutable === "string" && data.jobExecutable.length > 0 ? data.jobExecutable : profileName;
|
|
16631
16767
|
const agent = typeof profile.agent === "string" && profile.agent.length > 0 ? profile.agent : typeof data.jobAgent === "string" && data.jobAgent.length > 0 ? data.jobAgent : null;
|
|
16632
16768
|
const description = profile.describe.trim();
|
|
16769
|
+
const workflow = typeof data.workflowCapability === "string" && data.workflowCapability.length > 0 ? data.workflowCapability : null;
|
|
16770
|
+
const workflowStep = typeof data.workflowStep === "string" && data.workflowStep.length > 0 ? data.workflowStep : null;
|
|
16771
|
+
const workflowStepIndex = typeof data.workflowStepIndex === "number" && Number.isFinite(data.workflowStepIndex) ? data.workflowStepIndex : null;
|
|
16772
|
+
const workflowStepCount = typeof data.workflowStepCount === "number" && Number.isFinite(data.workflowStepCount) ? data.workflowStepCount : null;
|
|
16633
16773
|
const lines = [
|
|
16634
16774
|
"## Job reference",
|
|
16635
16775
|
"",
|
|
@@ -16641,7 +16781,9 @@ function jobReferenceBlock(profileName, profile, data) {
|
|
|
16641
16781
|
`- Capability: ${capability ?? "(none)"}`,
|
|
16642
16782
|
`- Executable: ${executable}`,
|
|
16643
16783
|
`- Agent: ${agent ?? "(none)"}`,
|
|
16644
|
-
`- Description: ${description || "(none)"}
|
|
16784
|
+
`- Description: ${description || "(none)"}`,
|
|
16785
|
+
...workflow ? [`- Workflow: ${workflow}`] : [],
|
|
16786
|
+
...workflowStep ? [`- Workflow step: ${workflowStepIndex ?? "?"}/${workflowStepCount ?? "?"} ${workflowStep}`] : []
|
|
16645
16787
|
];
|
|
16646
16788
|
return lines.join("\n");
|
|
16647
16789
|
}
|
|
@@ -17056,7 +17198,7 @@ async function runExecutableChain(profileName, input) {
|
|
|
17056
17198
|
};
|
|
17057
17199
|
}
|
|
17058
17200
|
process.stdout.write(
|
|
17059
|
-
`\u2192 kody: in-process return \u2192 ${afterJob.action ?? afterJob.capability} (hop ${hops}/${MAX_CHAIN_HOPS})
|
|
17201
|
+
`\u2192 kody: in-process return \u2192 ${afterJob.action ?? afterJob.capability ?? afterJob.workflow} (hop ${hops}/${MAX_CHAIN_HOPS})
|
|
17060
17202
|
|
|
17061
17203
|
`
|
|
17062
17204
|
);
|
|
@@ -17090,7 +17232,7 @@ async function runExecutableChain(profileName, input) {
|
|
|
17090
17232
|
};
|
|
17091
17233
|
}
|
|
17092
17234
|
process.stdout.write(
|
|
17093
|
-
`\u2192 kody: in-process hand-off \u2192 ${nextJob.action ?? nextJob.capability} (hop ${hops}/${MAX_CHAIN_HOPS})
|
|
17235
|
+
`\u2192 kody: in-process hand-off \u2192 ${nextJob.action ?? nextJob.capability ?? nextJob.workflow} (hop ${hops}/${MAX_CHAIN_HOPS})
|
|
17094
17236
|
|
|
17095
17237
|
`
|
|
17096
17238
|
);
|
|
@@ -17108,18 +17250,19 @@ async function runExecutableChain(profileName, input) {
|
|
|
17108
17250
|
};
|
|
17109
17251
|
}
|
|
17110
17252
|
if (result.nextDispatch || result.nextJob) {
|
|
17111
|
-
const pending = result.nextDispatch?.executable ?? result.nextJob?.executable ?? result.nextJob?.capability ?? "unknown";
|
|
17253
|
+
const pending = result.nextDispatch?.executable ?? result.nextDispatch?.workflow ?? result.nextJob?.executable ?? result.nextJob?.workflow ?? result.nextJob?.capability ?? "unknown";
|
|
17112
17254
|
process.stderr.write(`[kody] in-process hand-off cap (${MAX_CHAIN_HOPS}) reached; not running ${pending}
|
|
17113
17255
|
`);
|
|
17114
17256
|
}
|
|
17115
17257
|
return result;
|
|
17116
17258
|
}
|
|
17117
17259
|
function handoffToJob(handoff) {
|
|
17118
|
-
const dutyOrAction = handoff.action ?? handoff.capability;
|
|
17260
|
+
const dutyOrAction = handoff.workflow ?? handoff.action ?? handoff.capability;
|
|
17119
17261
|
if (!dutyOrAction) return null;
|
|
17120
17262
|
return {
|
|
17121
17263
|
action: handoff.action ?? handoff.capability,
|
|
17122
17264
|
capability: handoff.capability,
|
|
17265
|
+
workflow: handoff.workflow,
|
|
17123
17266
|
executable: handoff.executable,
|
|
17124
17267
|
cliArgs: handoff.cliArgs,
|
|
17125
17268
|
flavor: "instant",
|
|
@@ -17371,9 +17514,9 @@ var init_executor = __esm({
|
|
|
17371
17514
|
"src/executor.ts"() {
|
|
17372
17515
|
"use strict";
|
|
17373
17516
|
init_agent();
|
|
17517
|
+
init_agents();
|
|
17374
17518
|
init_capabilityReport();
|
|
17375
17519
|
init_capabilityResult();
|
|
17376
|
-
init_agents();
|
|
17377
17520
|
init_config();
|
|
17378
17521
|
init_container();
|
|
17379
17522
|
init_discipline();
|
|
@@ -17400,6 +17543,99 @@ var init_executor = __esm({
|
|
|
17400
17543
|
}
|
|
17401
17544
|
});
|
|
17402
17545
|
|
|
17546
|
+
// src/workflowDefinitions.ts
|
|
17547
|
+
import * as fs44 from "fs";
|
|
17548
|
+
import * as path42 from "path";
|
|
17549
|
+
function isWorkflowDefinitionId(value) {
|
|
17550
|
+
return WORKFLOW_ID_PATTERN.test(value);
|
|
17551
|
+
}
|
|
17552
|
+
function workflowDefinitionPath(id) {
|
|
17553
|
+
if (!isWorkflowDefinitionId(id)) {
|
|
17554
|
+
throw new Error(`Invalid workflow id "${id}"`);
|
|
17555
|
+
}
|
|
17556
|
+
return `workflows/${id}/workflow.json`;
|
|
17557
|
+
}
|
|
17558
|
+
function normalizeWorkflowDefinition(value) {
|
|
17559
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
17560
|
+
const raw = value;
|
|
17561
|
+
const name = typeof raw.name === "string" ? raw.name.trim() : "";
|
|
17562
|
+
const instructions = typeof raw.instructions === "string" ? raw.instructions.trim() : "";
|
|
17563
|
+
const capabilities = normalizeWorkflowCapabilities(raw.capabilities);
|
|
17564
|
+
if (!name || !instructions || capabilities.length === 0) return null;
|
|
17565
|
+
return {
|
|
17566
|
+
version: 1,
|
|
17567
|
+
name,
|
|
17568
|
+
instructions,
|
|
17569
|
+
capabilities,
|
|
17570
|
+
...typeof raw.createdAt === "string" ? { createdAt: raw.createdAt } : {},
|
|
17571
|
+
...typeof raw.updatedAt === "string" ? { updatedAt: raw.updatedAt } : {}
|
|
17572
|
+
};
|
|
17573
|
+
}
|
|
17574
|
+
function readWorkflowDefinition(config, cwd, id) {
|
|
17575
|
+
const file = readStateText(config, cwd, workflowDefinitionPath(id));
|
|
17576
|
+
if (!file) return readCompanyStoreWorkflowDefinition(id);
|
|
17577
|
+
return parseWorkflowDefinition(file.content);
|
|
17578
|
+
}
|
|
17579
|
+
function workflowDefinitionToCapabilityFolder(id, workflow, source = workflowDefinitionPath(id)) {
|
|
17580
|
+
return {
|
|
17581
|
+
slug: id,
|
|
17582
|
+
dir: path42.dirname(source),
|
|
17583
|
+
profilePath: source,
|
|
17584
|
+
bodyPath: source,
|
|
17585
|
+
title: workflow.name,
|
|
17586
|
+
body: workflow.instructions,
|
|
17587
|
+
rawBody: workflow.instructions,
|
|
17588
|
+
rawProfile: { name: id, workflow },
|
|
17589
|
+
config: {
|
|
17590
|
+
action: id,
|
|
17591
|
+
workflow: workflowDefinitionToConfig(workflow),
|
|
17592
|
+
describe: workflow.instructions
|
|
17593
|
+
}
|
|
17594
|
+
};
|
|
17595
|
+
}
|
|
17596
|
+
function normalizeWorkflowCapabilities(value) {
|
|
17597
|
+
if (!Array.isArray(value)) return [];
|
|
17598
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17599
|
+
const capabilities = [];
|
|
17600
|
+
for (const item of value) {
|
|
17601
|
+
if (typeof item !== "string") continue;
|
|
17602
|
+
const slug2 = item.trim();
|
|
17603
|
+
if (!CAPABILITY_ID_PATTERN.test(slug2) || seen.has(slug2)) continue;
|
|
17604
|
+
seen.add(slug2);
|
|
17605
|
+
capabilities.push(slug2);
|
|
17606
|
+
}
|
|
17607
|
+
return capabilities;
|
|
17608
|
+
}
|
|
17609
|
+
function workflowDefinitionToConfig(workflow) {
|
|
17610
|
+
return {
|
|
17611
|
+
steps: workflow.capabilities.map((capability) => ({ capability }))
|
|
17612
|
+
};
|
|
17613
|
+
}
|
|
17614
|
+
function readCompanyStoreWorkflowDefinition(id) {
|
|
17615
|
+
const root = getCompanyStoreAssetRoot("workflows");
|
|
17616
|
+
if (!root) return null;
|
|
17617
|
+
const filePath = path42.join(root, id, "workflow.json");
|
|
17618
|
+
if (!fs44.existsSync(filePath)) return null;
|
|
17619
|
+
return parseWorkflowDefinition(fs44.readFileSync(filePath, "utf8"));
|
|
17620
|
+
}
|
|
17621
|
+
function parseWorkflowDefinition(content) {
|
|
17622
|
+
try {
|
|
17623
|
+
return normalizeWorkflowDefinition(JSON.parse(content));
|
|
17624
|
+
} catch {
|
|
17625
|
+
return null;
|
|
17626
|
+
}
|
|
17627
|
+
}
|
|
17628
|
+
var WORKFLOW_ID_PATTERN, CAPABILITY_ID_PATTERN;
|
|
17629
|
+
var init_workflowDefinitions = __esm({
|
|
17630
|
+
"src/workflowDefinitions.ts"() {
|
|
17631
|
+
"use strict";
|
|
17632
|
+
init_companyStore();
|
|
17633
|
+
init_stateRepo();
|
|
17634
|
+
WORKFLOW_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{0,79}$/;
|
|
17635
|
+
CAPABILITY_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;
|
|
17636
|
+
}
|
|
17637
|
+
});
|
|
17638
|
+
|
|
17403
17639
|
// src/job.ts
|
|
17404
17640
|
var job_exports = {};
|
|
17405
17641
|
__export(job_exports, {
|
|
@@ -17412,7 +17648,7 @@ __export(job_exports, {
|
|
|
17412
17648
|
stableJobKey: () => stableJobKey,
|
|
17413
17649
|
validateJob: () => validateJob
|
|
17414
17650
|
});
|
|
17415
|
-
import * as
|
|
17651
|
+
import * as path43 from "path";
|
|
17416
17652
|
function newJobId(flavor) {
|
|
17417
17653
|
localJobSeq += 1;
|
|
17418
17654
|
const runId = process.env.GITHUB_RUN_ID;
|
|
@@ -17424,8 +17660,8 @@ function validateJob(input) {
|
|
|
17424
17660
|
throw new InvalidJobError("job must be an object");
|
|
17425
17661
|
}
|
|
17426
17662
|
const j = input;
|
|
17427
|
-
if (typeof j.capability !== "string" && typeof j.action !== "string") {
|
|
17428
|
-
throw new InvalidJobError("job must reference a capability action or
|
|
17663
|
+
if (typeof j.capability !== "string" && typeof j.action !== "string" && typeof j.workflow !== "string") {
|
|
17664
|
+
throw new InvalidJobError("job must reference a capability action, capability, or workflow");
|
|
17429
17665
|
}
|
|
17430
17666
|
if (j.flavor !== "instant" && j.flavor !== "scheduled") {
|
|
17431
17667
|
throw new InvalidJobError(`job.flavor must be "instant" or "scheduled" (got ${String(j.flavor)})`);
|
|
@@ -17437,6 +17673,7 @@ function validateJob(input) {
|
|
|
17437
17673
|
action: typeof j.action === "string" ? j.action : void 0,
|
|
17438
17674
|
executable: typeof j.executable === "string" ? j.executable : void 0,
|
|
17439
17675
|
capability: typeof j.capability === "string" ? j.capability : void 0,
|
|
17676
|
+
workflow: typeof j.workflow === "string" ? j.workflow : void 0,
|
|
17440
17677
|
why: typeof j.why === "string" ? j.why : void 0,
|
|
17441
17678
|
agent: typeof j.agent === "string" ? j.agent : void 0,
|
|
17442
17679
|
schedule: typeof j.schedule === "string" ? j.schedule : void 0,
|
|
@@ -17450,21 +17687,49 @@ function validateJob(input) {
|
|
|
17450
17687
|
async function runJob(job, base) {
|
|
17451
17688
|
const valid = validateJob(job);
|
|
17452
17689
|
const action = valid.action ?? valid.capability;
|
|
17453
|
-
const projectCapabilitiesRoot =
|
|
17454
|
-
const resolvedCapability = action ? resolveCapabilityAction(action, projectCapabilitiesRoot) : null;
|
|
17690
|
+
const projectCapabilitiesRoot = path43.join(base.cwd, ".kody", "capabilities");
|
|
17691
|
+
const resolvedCapability = !valid.workflow && action ? resolveCapabilityAction(action, projectCapabilitiesRoot) : null;
|
|
17455
17692
|
const capabilityIdentity = valid.capability ?? resolvedCapability?.capability;
|
|
17456
|
-
const capabilityContext = loadCapabilityContext(capabilityIdentity, base.cwd);
|
|
17693
|
+
const capabilityContext = valid.workflow ? null : loadCapabilityContext(capabilityIdentity, base.cwd);
|
|
17694
|
+
const workflowContext = valid.workflow ? loadWorkflowContext(valid.workflow, base) : !capabilityContext && !resolvedCapability ? loadWorkflowContext(capabilityIdentity ?? action, base) : null;
|
|
17457
17695
|
const explicitExecutableOnly = valid.executable !== void 0 && (valid.action === void 0 || valid.action === valid.executable) && (valid.capability === void 0 || valid.capability === valid.executable);
|
|
17458
|
-
if (!resolvedCapability && !capabilityContext && !explicitExecutableOnly) {
|
|
17459
|
-
throw new InvalidJobError(
|
|
17696
|
+
if (!resolvedCapability && !capabilityContext && !workflowContext && !explicitExecutableOnly) {
|
|
17697
|
+
throw new InvalidJobError(
|
|
17698
|
+
`job capability/workflow not found: ${valid.workflow ?? action ?? valid.capability ?? "<none>"}`
|
|
17699
|
+
);
|
|
17460
17700
|
}
|
|
17701
|
+
const workflow = capabilityContext?.config.workflow ?? workflowContext?.config.workflow;
|
|
17702
|
+
const workflowIdentity = valid.workflow ?? capabilityIdentity ?? workflowContext?.slug;
|
|
17461
17703
|
const capabilitySelectedExecutable = resolvedCapability?.executable ?? capabilityContext?.config.executable ?? capabilityContext?.config.executables?.[0] ?? (capabilityContext?.config.tickScript ? "capability-tick-scripted" : void 0);
|
|
17462
17704
|
const profileName = valid.executable ?? capabilitySelectedExecutable;
|
|
17463
|
-
if (
|
|
17464
|
-
|
|
17465
|
-
|
|
17466
|
-
);
|
|
17705
|
+
if (workflow && shouldRunCapabilityWorkflow(valid, workflow, workflowIdentity, capabilitySelectedExecutable, base)) {
|
|
17706
|
+
const workflowCapability = capabilityContext ?? workflowContext;
|
|
17707
|
+
const workflowJob = workflowContext && !valid.why ? { ...valid, why: workflowContext.body } : valid;
|
|
17708
|
+
return runCapabilityWorkflow(workflowJob, workflow, workflowCapability, base);
|
|
17467
17709
|
}
|
|
17710
|
+
if (!profileName) {
|
|
17711
|
+
throw new InvalidJobError(`job capability resolves to no executable: ${capabilityIdentity ?? action}`);
|
|
17712
|
+
}
|
|
17713
|
+
return runDefaultCapabilityWorkflow(
|
|
17714
|
+
valid,
|
|
17715
|
+
profileName,
|
|
17716
|
+
capabilityIdentity,
|
|
17717
|
+
capabilityContext,
|
|
17718
|
+
resolvedCapability,
|
|
17719
|
+
base
|
|
17720
|
+
);
|
|
17721
|
+
}
|
|
17722
|
+
async function runDefaultCapabilityWorkflow(job, profileName, capabilityIdentity, capabilityContext, resolvedCapability, base) {
|
|
17723
|
+
return runCapabilityImplementationStep(
|
|
17724
|
+
job,
|
|
17725
|
+
profileName,
|
|
17726
|
+
capabilityIdentity,
|
|
17727
|
+
capabilityContext,
|
|
17728
|
+
resolvedCapability,
|
|
17729
|
+
base
|
|
17730
|
+
);
|
|
17731
|
+
}
|
|
17732
|
+
async function runCapabilityImplementationStep(valid, profileName, capabilityIdentity, capabilityContext, resolvedCapability, base) {
|
|
17468
17733
|
const preloadedData = { ...base.preloadedData ?? {} };
|
|
17469
17734
|
preloadedData.jobId = newJobId(valid.flavor);
|
|
17470
17735
|
preloadedData.jobKey = stableJobKey(valid);
|
|
@@ -17473,9 +17738,7 @@ async function runJob(job, base) {
|
|
|
17473
17738
|
if (valid.action !== void 0 && valid.action.length > 0) preloadedData.jobAction = valid.action;
|
|
17474
17739
|
if (capabilityIdentity !== void 0 && capabilityIdentity.length > 0)
|
|
17475
17740
|
preloadedData.jobCapability = capabilityIdentity;
|
|
17476
|
-
|
|
17477
|
-
if (executableIdentity !== void 0 && executableIdentity.length > 0)
|
|
17478
|
-
preloadedData.jobExecutable = executableIdentity;
|
|
17741
|
+
preloadedData.jobExecutable = profileName;
|
|
17479
17742
|
if (valid.schedule !== void 0 && valid.schedule.length > 0) preloadedData.jobSchedule = valid.schedule;
|
|
17480
17743
|
if (valid.saveReport === true) preloadedData.jobSaveReport = true;
|
|
17481
17744
|
if (capabilityContext) {
|
|
@@ -17483,8 +17746,7 @@ async function runJob(job, base) {
|
|
|
17483
17746
|
preloadedData.capabilityTitle = capabilityContext.title;
|
|
17484
17747
|
preloadedData.dutyIntent = capabilityContext.body;
|
|
17485
17748
|
preloadedData.jobIntent = capabilityContext.body;
|
|
17486
|
-
if (preloadedData.jobCapability === void 0)
|
|
17487
|
-
preloadedData.jobCapability = capabilityContext.slug;
|
|
17749
|
+
if (preloadedData.jobCapability === void 0) preloadedData.jobCapability = capabilityContext.slug;
|
|
17488
17750
|
if (capabilityContext.config.agent && preloadedData.jobAgent === void 0) {
|
|
17489
17751
|
preloadedData.jobAgent = capabilityContext.config.agent;
|
|
17490
17752
|
}
|
|
@@ -17508,9 +17770,182 @@ async function runJob(job, base) {
|
|
|
17508
17770
|
const run = base.chain === false ? runExecutable : runExecutableChain;
|
|
17509
17771
|
return run(profileName, input);
|
|
17510
17772
|
}
|
|
17773
|
+
function shouldRunCapabilityWorkflow(job, workflow, capabilityIdentity, selectedExecutable, base) {
|
|
17774
|
+
if (workflow.steps.length === 0) return false;
|
|
17775
|
+
if (!capabilityIdentity) return false;
|
|
17776
|
+
const stack = Array.isArray(base.preloadedData?.workflowStack) ? base.preloadedData.workflowStack.filter((entry) => typeof entry === "string") : [];
|
|
17777
|
+
if (stack.includes(capabilityIdentity)) return false;
|
|
17778
|
+
if (!job.executable) return true;
|
|
17779
|
+
return job.executable === selectedExecutable || job.executable === capabilityIdentity || job.executable === job.action;
|
|
17780
|
+
}
|
|
17781
|
+
async function runCapabilityWorkflow(parent, workflow, capability, base) {
|
|
17782
|
+
let chainData = {
|
|
17783
|
+
...base.preloadedData ?? {},
|
|
17784
|
+
workflowCapability: capability.slug,
|
|
17785
|
+
workflowTitle: capability.title,
|
|
17786
|
+
workflowStepCount: workflow.steps.length,
|
|
17787
|
+
workflowIssueNumber: workflowIssueNumber(parent),
|
|
17788
|
+
workflowStack: [
|
|
17789
|
+
...Array.isArray(base.preloadedData?.workflowStack) ? base.preloadedData.workflowStack.filter((entry) => typeof entry === "string") : [],
|
|
17790
|
+
capability.slug
|
|
17791
|
+
]
|
|
17792
|
+
};
|
|
17793
|
+
let result = { exitCode: 0 };
|
|
17794
|
+
for (let index = 0; index < workflow.steps.length; index++) {
|
|
17795
|
+
const step = workflow.steps[index];
|
|
17796
|
+
const label = step.action ?? step.capability;
|
|
17797
|
+
if (!shouldRunWorkflowStep(step, chainData)) {
|
|
17798
|
+
process.stdout.write(
|
|
17799
|
+
`\u2192 kody: workflow ${capability.slug} step ${index + 1}/${workflow.steps.length} \u2192 ${label} (skipped)
|
|
17800
|
+
|
|
17801
|
+
`
|
|
17802
|
+
);
|
|
17803
|
+
continue;
|
|
17804
|
+
}
|
|
17805
|
+
const child = workflowStepToJob(step, parent, chainData);
|
|
17806
|
+
process.stdout.write(
|
|
17807
|
+
`\u2192 kody: workflow ${capability.slug} step ${index + 1}/${workflow.steps.length} \u2192 ${label}
|
|
17808
|
+
|
|
17809
|
+
`
|
|
17810
|
+
);
|
|
17811
|
+
result = await runJob(child, {
|
|
17812
|
+
...base,
|
|
17813
|
+
preloadedData: {
|
|
17814
|
+
...chainData,
|
|
17815
|
+
workflowStep: label,
|
|
17816
|
+
workflowStepIndex: index + 1,
|
|
17817
|
+
workflowStepReason: step.reason
|
|
17818
|
+
}
|
|
17819
|
+
});
|
|
17820
|
+
const outcome = workflowOutcome(result);
|
|
17821
|
+
const prUrl = result.taskState?.core.prUrl ?? (typeof chainData.workflowPrUrl === "string" ? chainData.workflowPrUrl : void 0);
|
|
17822
|
+
chainData = {
|
|
17823
|
+
...chainData,
|
|
17824
|
+
...result.taskState ? { taskState: result.taskState } : {},
|
|
17825
|
+
...outcome ? { workflowLastOutcome: outcome } : {},
|
|
17826
|
+
...prUrl ? { workflowPrUrl: prUrl } : {},
|
|
17827
|
+
...parsePrNumber5(prUrl) ? { workflowPrNumber: parsePrNumber5(prUrl) } : {}
|
|
17828
|
+
};
|
|
17829
|
+
if (result.exitCode !== 0 && !canContinueWorkflow(step, outcome)) {
|
|
17830
|
+
return {
|
|
17831
|
+
...result,
|
|
17832
|
+
reason: result.reason ?? `workflow ${capability.slug} stopped at step ${index + 1}/${workflow.steps.length}: ${label}`
|
|
17833
|
+
};
|
|
17834
|
+
}
|
|
17835
|
+
}
|
|
17836
|
+
return result;
|
|
17837
|
+
}
|
|
17838
|
+
function workflowStepToJob(step, parent, chainData) {
|
|
17839
|
+
const action = step.action ?? step.capability;
|
|
17840
|
+
const rawArgs = {
|
|
17841
|
+
...parent.cliArgs,
|
|
17842
|
+
...step.cliArgs ?? {}
|
|
17843
|
+
};
|
|
17844
|
+
const targetNumber = workflowStepTargetNumber(step, parent, chainData);
|
|
17845
|
+
if (step.target === "pr") {
|
|
17846
|
+
if (typeof targetNumber !== "number") {
|
|
17847
|
+
throw new InvalidJobError(`workflow step ${action} needs a PR target but no prior PR URL is available`);
|
|
17848
|
+
}
|
|
17849
|
+
rawArgs.pr = targetNumber;
|
|
17850
|
+
} else if (step.target === "issue" && typeof targetNumber === "number") {
|
|
17851
|
+
rawArgs.issue = targetNumber;
|
|
17852
|
+
}
|
|
17853
|
+
const cliArgs = filterCliArgsForStep(action, rawArgs);
|
|
17854
|
+
const target = typeof targetNumber === "number" ? targetNumber : typeof parent.target === "number" ? parent.target : targetFromCliArgs(cliArgs);
|
|
17855
|
+
return {
|
|
17856
|
+
action,
|
|
17857
|
+
capability: step.capability,
|
|
17858
|
+
...step.executable ? { executable: step.executable } : {},
|
|
17859
|
+
...composeStepWhy(parent.why, step) ? { why: composeStepWhy(parent.why, step) } : {},
|
|
17860
|
+
...step.agent ?? parent.agent ? { agent: step.agent ?? parent.agent } : {},
|
|
17861
|
+
...parent.schedule ? { schedule: parent.schedule } : {},
|
|
17862
|
+
...typeof target === "number" ? { target } : {},
|
|
17863
|
+
cliArgs,
|
|
17864
|
+
flavor: parent.flavor,
|
|
17865
|
+
force: parent.force,
|
|
17866
|
+
saveReport: step.saveReport === true || parent.saveReport === true
|
|
17867
|
+
};
|
|
17868
|
+
}
|
|
17869
|
+
function shouldRunWorkflowStep(step, data) {
|
|
17870
|
+
if (!step.runWhen) return true;
|
|
17871
|
+
const context = workflowConditionContext(data);
|
|
17872
|
+
return Object.entries(step.runWhen).every(
|
|
17873
|
+
([path49, expected]) => valueMatches(resolveDottedPath2(context, path49), expected)
|
|
17874
|
+
);
|
|
17875
|
+
}
|
|
17876
|
+
function canContinueWorkflow(step, outcome) {
|
|
17877
|
+
if (!outcome || !step.continueOn || step.continueOn.length === 0) return false;
|
|
17878
|
+
return step.continueOn.includes(outcome.type);
|
|
17879
|
+
}
|
|
17880
|
+
function workflowOutcome(result) {
|
|
17881
|
+
return result.taskState?.core.lastOutcome ?? null;
|
|
17882
|
+
}
|
|
17883
|
+
function workflowConditionContext(data) {
|
|
17884
|
+
const lastOutcome = data.workflowLastOutcome;
|
|
17885
|
+
return {
|
|
17886
|
+
...data,
|
|
17887
|
+
workflow: {
|
|
17888
|
+
lastOutcome,
|
|
17889
|
+
issueNumber: data.workflowIssueNumber,
|
|
17890
|
+
prNumber: data.workflowPrNumber,
|
|
17891
|
+
prUrl: data.workflowPrUrl
|
|
17892
|
+
},
|
|
17893
|
+
lastOutcome
|
|
17894
|
+
};
|
|
17895
|
+
}
|
|
17896
|
+
function resolveDottedPath2(root, dotted) {
|
|
17897
|
+
return dotted.split(".").reduce((cur, part) => {
|
|
17898
|
+
if (!cur || typeof cur !== "object") return void 0;
|
|
17899
|
+
return cur[part];
|
|
17900
|
+
}, root);
|
|
17901
|
+
}
|
|
17902
|
+
function valueMatches(actual, expected) {
|
|
17903
|
+
if (Array.isArray(expected)) return expected.some((entry) => valueMatches(actual, entry));
|
|
17904
|
+
return actual === expected;
|
|
17905
|
+
}
|
|
17906
|
+
function workflowStepTargetNumber(step, parent, chainData) {
|
|
17907
|
+
if (step.target === "pr") return workflowPrNumber(chainData) ?? targetFromCliArgs(step.cliArgs ?? {});
|
|
17908
|
+
if (step.target === "issue") return workflowIssueNumber(parent);
|
|
17909
|
+
return typeof parent.target === "number" ? parent.target : targetFromCliArgs({ ...parent.cliArgs, ...step.cliArgs ?? {} });
|
|
17910
|
+
}
|
|
17911
|
+
function workflowIssueNumber(parent) {
|
|
17912
|
+
return typeof parent.target === "number" ? parent.target : targetFromCliArgs(parent.cliArgs);
|
|
17913
|
+
}
|
|
17914
|
+
function workflowPrNumber(data) {
|
|
17915
|
+
if (typeof data.workflowPrNumber === "number" && Number.isFinite(data.workflowPrNumber)) return data.workflowPrNumber;
|
|
17916
|
+
const prUrl = typeof data.workflowPrUrl === "string" ? data.workflowPrUrl : typeof data.taskState?.core?.prUrl === "string" ? data.taskState.core.prUrl : void 0;
|
|
17917
|
+
return parsePrNumber5(prUrl) ?? void 0;
|
|
17918
|
+
}
|
|
17919
|
+
function parsePrNumber5(url) {
|
|
17920
|
+
if (!url) return null;
|
|
17921
|
+
const m = url.match(/\/pull\/(\d+)(?:[/?#]|$)/);
|
|
17922
|
+
if (!m) return null;
|
|
17923
|
+
const n = parseInt(m[1], 10);
|
|
17924
|
+
return Number.isFinite(n) ? n : null;
|
|
17925
|
+
}
|
|
17926
|
+
function filterCliArgsForStep(action, raw) {
|
|
17927
|
+
const inputs = getCapabilityActionInputs(action);
|
|
17928
|
+
if (!inputs) return raw;
|
|
17929
|
+
const allowed = /* @__PURE__ */ new Set(["_", "cwd", "verbose", "quiet"]);
|
|
17930
|
+
for (const input of inputs) {
|
|
17931
|
+
const flagKey = input.flag.replace(/^--/, "");
|
|
17932
|
+
allowed.add(input.name);
|
|
17933
|
+
allowed.add(flagKey);
|
|
17934
|
+
if (flagKey.includes("-")) allowed.add(flagKey.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase()));
|
|
17935
|
+
}
|
|
17936
|
+
return Object.fromEntries(Object.entries(raw).filter(([key]) => allowed.has(key)));
|
|
17937
|
+
}
|
|
17938
|
+
function composeStepWhy(parentWhy, step) {
|
|
17939
|
+
return [parentWhy?.trim(), step.reason ? `Workflow step: ${step.reason}` : ""].filter((part) => Boolean(part)).join("\n\n");
|
|
17940
|
+
}
|
|
17511
17941
|
function loadCapabilityContext(slug2, cwd) {
|
|
17512
17942
|
if (!slug2) return null;
|
|
17513
|
-
return resolveCapabilityFolder(slug2,
|
|
17943
|
+
return resolveCapabilityFolder(slug2, path43.join(cwd, ".kody", "capabilities"));
|
|
17944
|
+
}
|
|
17945
|
+
function loadWorkflowContext(slug2, base) {
|
|
17946
|
+
if (!slug2 || !base.config || !isWorkflowDefinitionId(slug2)) return null;
|
|
17947
|
+
const workflow = readWorkflowDefinition(base.config, base.cwd, slug2);
|
|
17948
|
+
return workflow ? workflowDefinitionToCapabilityFolder(slug2, workflow) : null;
|
|
17514
17949
|
}
|
|
17515
17950
|
function mintInstantJob(dispatch2, opts) {
|
|
17516
17951
|
return {
|
|
@@ -17542,6 +17977,7 @@ var init_job = __esm({
|
|
|
17542
17977
|
"use strict";
|
|
17543
17978
|
init_executor();
|
|
17544
17979
|
init_registry();
|
|
17980
|
+
init_workflowDefinitions();
|
|
17545
17981
|
init_jobIdentity();
|
|
17546
17982
|
init_jobIdentity();
|
|
17547
17983
|
DEFAULT_INSTANT_AGENT = "kody";
|
|
@@ -17662,9 +18098,9 @@ function translateOpenAISseToBrain(opts) {
|
|
|
17662
18098
|
}
|
|
17663
18099
|
|
|
17664
18100
|
// src/servers/brain-serve.ts
|
|
17665
|
-
import * as
|
|
18101
|
+
import * as fs47 from "fs";
|
|
17666
18102
|
import { createServer } from "http";
|
|
17667
|
-
import * as
|
|
18103
|
+
import * as path46 from "path";
|
|
17668
18104
|
|
|
17669
18105
|
// src/chat/loop.ts
|
|
17670
18106
|
init_agent();
|
|
@@ -18224,8 +18660,8 @@ init_config();
|
|
|
18224
18660
|
|
|
18225
18661
|
// src/kody-cli.ts
|
|
18226
18662
|
import { execFileSync as execFileSync25 } from "child_process";
|
|
18227
|
-
import * as
|
|
18228
|
-
import * as
|
|
18663
|
+
import * as fs45 from "fs";
|
|
18664
|
+
import * as path44 from "path";
|
|
18229
18665
|
|
|
18230
18666
|
// src/app-auth.ts
|
|
18231
18667
|
import { createSign } from "crypto";
|
|
@@ -18846,9 +19282,9 @@ async function resolveAuthToken(env = process.env) {
|
|
|
18846
19282
|
return void 0;
|
|
18847
19283
|
}
|
|
18848
19284
|
function detectPackageManager2(cwd) {
|
|
18849
|
-
if (
|
|
18850
|
-
if (
|
|
18851
|
-
if (
|
|
19285
|
+
if (fs45.existsSync(path44.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
19286
|
+
if (fs45.existsSync(path44.join(cwd, "yarn.lock"))) return "yarn";
|
|
19287
|
+
if (fs45.existsSync(path44.join(cwd, "bun.lockb"))) return "bun";
|
|
18852
19288
|
return "npm";
|
|
18853
19289
|
}
|
|
18854
19290
|
function shouldChainScheduledWatch(match) {
|
|
@@ -18941,8 +19377,8 @@ function postFailureTail(issueNumber, cwd, reason) {
|
|
|
18941
19377
|
const logPath = lastRunLogPath(cwd);
|
|
18942
19378
|
let tail = "";
|
|
18943
19379
|
try {
|
|
18944
|
-
if (
|
|
18945
|
-
const content =
|
|
19380
|
+
if (fs45.existsSync(logPath)) {
|
|
19381
|
+
const content = fs45.readFileSync(logPath, "utf-8");
|
|
18946
19382
|
tail = content.slice(-3e3);
|
|
18947
19383
|
}
|
|
18948
19384
|
} catch {
|
|
@@ -18967,7 +19403,7 @@ async function runCi(argv) {
|
|
|
18967
19403
|
return 0;
|
|
18968
19404
|
}
|
|
18969
19405
|
const args = parseCiArgs(argv);
|
|
18970
|
-
const cwd = args.cwd ?
|
|
19406
|
+
const cwd = args.cwd ? path44.resolve(args.cwd) : process.cwd();
|
|
18971
19407
|
let earlyConfig;
|
|
18972
19408
|
let earlyConfigError;
|
|
18973
19409
|
try {
|
|
@@ -18982,9 +19418,9 @@ async function runCi(argv) {
|
|
|
18982
19418
|
let manualWorkflowDispatch = false;
|
|
18983
19419
|
let forceRunAction = null;
|
|
18984
19420
|
let forceRunCliArgs = {};
|
|
18985
|
-
if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath &&
|
|
19421
|
+
if (!args.issueNumber && !autoFallback && eventName === "workflow_dispatch" && dispatchEventPath && fs45.existsSync(dispatchEventPath)) {
|
|
18986
19422
|
try {
|
|
18987
|
-
const evt = JSON.parse(
|
|
19423
|
+
const evt = JSON.parse(fs45.readFileSync(dispatchEventPath, "utf-8"));
|
|
18988
19424
|
const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
|
|
18989
19425
|
const sessionInput = String(evt?.inputs?.sessionId ?? "");
|
|
18990
19426
|
const dutyInput = String(evt?.inputs?.capability ?? evt?.inputs?.executable ?? "").trim();
|
|
@@ -19316,8 +19752,8 @@ init_repoWorkspace();
|
|
|
19316
19752
|
|
|
19317
19753
|
// src/scripts/brainTurnLog.ts
|
|
19318
19754
|
init_runtimePaths();
|
|
19319
|
-
import * as
|
|
19320
|
-
import * as
|
|
19755
|
+
import * as fs46 from "fs";
|
|
19756
|
+
import * as path45 from "path";
|
|
19321
19757
|
import posixPath4 from "path/posix";
|
|
19322
19758
|
var live = /* @__PURE__ */ new Map();
|
|
19323
19759
|
function brainEventsFilePath(dir, chatId) {
|
|
@@ -19328,8 +19764,8 @@ function brainEventsStatePath(chatId) {
|
|
|
19328
19764
|
}
|
|
19329
19765
|
function lastPersistedSeq(dir, chatId) {
|
|
19330
19766
|
const p = brainEventsFilePath(dir, chatId);
|
|
19331
|
-
if (!
|
|
19332
|
-
const lines =
|
|
19767
|
+
if (!fs46.existsSync(p)) return 0;
|
|
19768
|
+
const lines = fs46.readFileSync(p, "utf-8").split("\n").filter(Boolean);
|
|
19333
19769
|
if (lines.length === 0) return 0;
|
|
19334
19770
|
try {
|
|
19335
19771
|
return JSON.parse(lines[lines.length - 1]).seq || 0;
|
|
@@ -19339,9 +19775,9 @@ function lastPersistedSeq(dir, chatId) {
|
|
|
19339
19775
|
}
|
|
19340
19776
|
function readSince(dir, chatId, since) {
|
|
19341
19777
|
const p = brainEventsFilePath(dir, chatId);
|
|
19342
|
-
if (!
|
|
19778
|
+
if (!fs46.existsSync(p)) return [];
|
|
19343
19779
|
const out = [];
|
|
19344
|
-
for (const line of
|
|
19780
|
+
for (const line of fs46.readFileSync(p, "utf-8").split("\n")) {
|
|
19345
19781
|
if (!line) continue;
|
|
19346
19782
|
try {
|
|
19347
19783
|
const rec = JSON.parse(line);
|
|
@@ -19367,12 +19803,12 @@ function beginTurn(dir, chatId) {
|
|
|
19367
19803
|
};
|
|
19368
19804
|
live.set(chatId, state);
|
|
19369
19805
|
const p = brainEventsFilePath(dir, chatId);
|
|
19370
|
-
|
|
19806
|
+
fs46.mkdirSync(path45.dirname(p), { recursive: true });
|
|
19371
19807
|
return (event) => {
|
|
19372
19808
|
state.seq += 1;
|
|
19373
19809
|
const rec = { seq: state.seq, turn, ts: Date.now(), event };
|
|
19374
19810
|
try {
|
|
19375
|
-
|
|
19811
|
+
fs46.appendFileSync(p, `${JSON.stringify(rec)}
|
|
19376
19812
|
`);
|
|
19377
19813
|
} catch (err) {
|
|
19378
19814
|
process.stderr.write(
|
|
@@ -19411,7 +19847,7 @@ function endTurnIfUnterminated(dir, chatId, errMessage) {
|
|
|
19411
19847
|
event: { type: "error", error: errMessage || "turn ended unexpectedly", chatId }
|
|
19412
19848
|
};
|
|
19413
19849
|
try {
|
|
19414
|
-
|
|
19850
|
+
fs46.appendFileSync(brainEventsFilePath(dir, chatId), `${JSON.stringify(rec)}
|
|
19415
19851
|
`);
|
|
19416
19852
|
} catch {
|
|
19417
19853
|
}
|
|
@@ -19717,7 +20153,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
19717
20153
|
);
|
|
19718
20154
|
}
|
|
19719
20155
|
}
|
|
19720
|
-
|
|
20156
|
+
fs47.mkdirSync(path46.dirname(sessionFile), { recursive: true });
|
|
19721
20157
|
appendTurn(sessionFile, {
|
|
19722
20158
|
role: "user",
|
|
19723
20159
|
content: message,
|
|
@@ -19782,7 +20218,7 @@ async function handleChatTurn(req, res, chatId, opts) {
|
|
|
19782
20218
|
function buildServer(opts) {
|
|
19783
20219
|
const runTurn = opts.runTurn ?? runChatTurn;
|
|
19784
20220
|
const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
|
|
19785
|
-
const reposRoot = opts.reposRoot ??
|
|
20221
|
+
const reposRoot = opts.reposRoot ?? path46.join(path46.dirname(path46.resolve(opts.cwd)), "repos");
|
|
19786
20222
|
return createServer(async (req, res) => {
|
|
19787
20223
|
if (!req.method || !req.url) {
|
|
19788
20224
|
sendJson(res, 400, { error: "bad request" });
|
|
@@ -20377,8 +20813,8 @@ async function loadConfigSafe() {
|
|
|
20377
20813
|
}
|
|
20378
20814
|
|
|
20379
20815
|
// src/chat-cli.ts
|
|
20380
|
-
import * as
|
|
20381
|
-
import * as
|
|
20816
|
+
import * as fs49 from "fs";
|
|
20817
|
+
import * as path48 from "path";
|
|
20382
20818
|
|
|
20383
20819
|
// src/chat/inbox.ts
|
|
20384
20820
|
import { execFileSync as execFileSync26 } from "child_process";
|
|
@@ -20450,8 +20886,8 @@ function currentBranch(cwd) {
|
|
|
20450
20886
|
|
|
20451
20887
|
// src/chat/state-sync.ts
|
|
20452
20888
|
init_stateRepo();
|
|
20453
|
-
import * as
|
|
20454
|
-
import * as
|
|
20889
|
+
import * as fs48 from "fs";
|
|
20890
|
+
import * as path47 from "path";
|
|
20455
20891
|
function jsonlLines2(text) {
|
|
20456
20892
|
return text.split("\n").filter((line) => line.length > 0);
|
|
20457
20893
|
}
|
|
@@ -20468,15 +20904,15 @@ function mergeJsonl2(localText, remoteText) {
|
|
|
20468
20904
|
function syncJsonlFileFromState(opts) {
|
|
20469
20905
|
const remote = readStateText(opts.config, opts.cwd, opts.statePath);
|
|
20470
20906
|
if (!remote) return;
|
|
20471
|
-
const local =
|
|
20907
|
+
const local = fs48.existsSync(opts.localPath) ? fs48.readFileSync(opts.localPath, "utf-8") : "";
|
|
20472
20908
|
const next = mergeJsonl2(local, remote.content);
|
|
20473
20909
|
if (next === local) return;
|
|
20474
|
-
|
|
20475
|
-
|
|
20910
|
+
fs48.mkdirSync(path47.dirname(opts.localPath), { recursive: true });
|
|
20911
|
+
fs48.writeFileSync(opts.localPath, next);
|
|
20476
20912
|
}
|
|
20477
20913
|
function persistJsonlFileToState(opts) {
|
|
20478
|
-
if (!
|
|
20479
|
-
const localText =
|
|
20914
|
+
if (!fs48.existsSync(opts.localPath)) return;
|
|
20915
|
+
const localText = fs48.readFileSync(opts.localPath, "utf-8");
|
|
20480
20916
|
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
20481
20917
|
const remote = readStateText(opts.config, opts.cwd, opts.statePath);
|
|
20482
20918
|
const body = mergeJsonl2(localText, remote?.content ?? "");
|
|
@@ -20736,7 +21172,7 @@ async function runChat(argv) {
|
|
|
20736
21172
|
${CHAT_HELP}`);
|
|
20737
21173
|
return 64;
|
|
20738
21174
|
}
|
|
20739
|
-
const cwd = args.cwd ?
|
|
21175
|
+
const cwd = args.cwd ? path48.resolve(args.cwd) : process.cwd();
|
|
20740
21176
|
const sessionId = args.sessionId;
|
|
20741
21177
|
const unpackedSecrets = unpackAllSecrets();
|
|
20742
21178
|
if (unpackedSecrets > 0) {
|
|
@@ -20797,7 +21233,7 @@ ${CHAT_HELP}`);
|
|
|
20797
21233
|
const sink = buildSink(cwd, sessionId, args.dashboardUrl);
|
|
20798
21234
|
const meta = readMeta(sessionFile);
|
|
20799
21235
|
process.stdout.write(
|
|
20800
|
-
`\u2192 kody:chat: session file=${sessionFile} exists=${
|
|
21236
|
+
`\u2192 kody:chat: session file=${sessionFile} exists=${fs49.existsSync(sessionFile)} meta=${meta ? meta.mode : "none"}
|
|
20801
21237
|
`
|
|
20802
21238
|
);
|
|
20803
21239
|
try {
|
|
@@ -20957,8 +21393,8 @@ var FlyClient = class {
|
|
|
20957
21393
|
get fetch() {
|
|
20958
21394
|
return this.opts.fetchImpl ?? fetch;
|
|
20959
21395
|
}
|
|
20960
|
-
async call(
|
|
20961
|
-
const res = await this.fetch(`${FLY_API_BASE}${
|
|
21396
|
+
async call(path49, init = {}) {
|
|
21397
|
+
const res = await this.fetch(`${FLY_API_BASE}${path49}`, {
|
|
20962
21398
|
method: init.method ?? "GET",
|
|
20963
21399
|
headers: {
|
|
20964
21400
|
Authorization: `Bearer ${this.opts.token}`,
|
|
@@ -20969,7 +21405,7 @@ var FlyClient = class {
|
|
|
20969
21405
|
if (res.status === 404 && init.allow404) return null;
|
|
20970
21406
|
if (!res.ok) {
|
|
20971
21407
|
const text = await res.text().catch(() => "");
|
|
20972
|
-
throw new Error(`Fly API ${res.status} on ${
|
|
21408
|
+
throw new Error(`Fly API ${res.status} on ${path49}: ${text.slice(0, 200) || res.statusText}`);
|
|
20973
21409
|
}
|
|
20974
21410
|
if (res.status === 204) return null;
|
|
20975
21411
|
const raw = await res.text();
|
|
@@ -21684,7 +22120,7 @@ async function poolServe() {
|
|
|
21684
22120
|
|
|
21685
22121
|
// src/servers/runner-serve.ts
|
|
21686
22122
|
import { spawn as spawn8 } from "child_process";
|
|
21687
|
-
import * as
|
|
22123
|
+
import * as fs50 from "fs";
|
|
21688
22124
|
import { createServer as createServer5 } from "http";
|
|
21689
22125
|
var DEFAULT_PORT2 = 8080;
|
|
21690
22126
|
var DEFAULT_WORKDIR = "/workspace/repo";
|
|
@@ -21764,8 +22200,8 @@ async function defaultRunJob(job) {
|
|
|
21764
22200
|
const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
|
|
21765
22201
|
const branch = job.ref ?? "main";
|
|
21766
22202
|
const authUrl = `https://x-access-token:${job.githubToken}@github.com/${job.repo}.git`;
|
|
21767
|
-
|
|
21768
|
-
|
|
22203
|
+
fs50.rmSync(workdir, { recursive: true, force: true });
|
|
22204
|
+
fs50.mkdirSync(workdir, { recursive: true });
|
|
21769
22205
|
const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
|
|
21770
22206
|
const interactive = job.mode === "interactive";
|
|
21771
22207
|
const scheduled = job.mode === "scheduled";
|