@kody-ade/kody-engine 0.4.271 → 0.4.272
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 +221 -16
- package/package.json +1 -1
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.272",
|
|
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",
|
|
@@ -2146,15 +2146,7 @@ function dispatchWorkflow(workflowFile, capability, issueNumber, repoSlug) {
|
|
|
2146
2146
|
}
|
|
2147
2147
|
}
|
|
2148
2148
|
try {
|
|
2149
|
-
gh([
|
|
2150
|
-
"workflow",
|
|
2151
|
-
"run",
|
|
2152
|
-
workflowFile,
|
|
2153
|
-
"-f",
|
|
2154
|
-
`capability=${capability}`,
|
|
2155
|
-
"-f",
|
|
2156
|
-
`issue_number=${issueNumber}`
|
|
2157
|
-
]);
|
|
2149
|
+
gh(["workflow", "run", workflowFile, "-f", `capability=${capability}`, "-f", `issue_number=${issueNumber}`]);
|
|
2158
2150
|
return { ok: true };
|
|
2159
2151
|
} catch (err) {
|
|
2160
2152
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
@@ -2189,6 +2181,132 @@ function isDispatchGated(capability, mode) {
|
|
|
2189
2181
|
function trustRefusal(capabilitySlug) {
|
|
2190
2182
|
return `Not dispatched: capability \`${capabilitySlug ?? "?"}\` is in ASK mode (not trusted for autonomy). Do NOT retry the dispatch. Instead notify the operator (use recommend_to_operator, or rely on the tracking issue that already @-mentions them), then submit_state. To let this capability act on its own, grant it Auto on the dashboard Trust page.`;
|
|
2191
2183
|
}
|
|
2184
|
+
function dashboardBaseUrl() {
|
|
2185
|
+
const raw = process.env.KODY_CMS_DASHBOARD_URL?.trim() || process.env.KODY_DASHBOARD_URL?.trim() || process.env.DASHBOARD_URL?.trim() || "";
|
|
2186
|
+
if (!raw) return null;
|
|
2187
|
+
try {
|
|
2188
|
+
const parsed = new URL(raw);
|
|
2189
|
+
return parsed.origin;
|
|
2190
|
+
} catch {
|
|
2191
|
+
return null;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
function dashboardCmsToken() {
|
|
2195
|
+
return process.env.KODY_CMS_TOKEN?.trim() || process.env.KODY_DASHBOARD_TOKEN?.trim() || process.env.KODY_TOKEN?.trim() || process.env.GH_TOKEN?.trim() || process.env.GITHUB_TOKEN?.trim() || process.env.GH_PAT?.trim() || null;
|
|
2196
|
+
}
|
|
2197
|
+
function cmsHeaders(opts) {
|
|
2198
|
+
const token = dashboardCmsToken();
|
|
2199
|
+
const [owner, repo] = opts.repoSlug.split("/");
|
|
2200
|
+
if (!token) {
|
|
2201
|
+
return {
|
|
2202
|
+
ok: false,
|
|
2203
|
+
error: "missing_cms_token",
|
|
2204
|
+
message: "Set KODY_CMS_TOKEN, KODY_DASHBOARD_TOKEN, KODY_TOKEN, GH_TOKEN, GITHUB_TOKEN, or GH_PAT."
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
if (!owner || !repo) {
|
|
2208
|
+
return { ok: false, error: "invalid_repo", message: `Invalid repo slug: ${opts.repoSlug}` };
|
|
2209
|
+
}
|
|
2210
|
+
return {
|
|
2211
|
+
ok: true,
|
|
2212
|
+
headers: {
|
|
2213
|
+
"Content-Type": "application/json",
|
|
2214
|
+
"x-kody-token": token,
|
|
2215
|
+
"x-kody-owner": owner,
|
|
2216
|
+
"x-kody-repo": repo
|
|
2217
|
+
}
|
|
2218
|
+
};
|
|
2219
|
+
}
|
|
2220
|
+
async function callDashboardCms(opts, path49, init = {}) {
|
|
2221
|
+
const baseUrl = dashboardBaseUrl();
|
|
2222
|
+
if (!baseUrl) {
|
|
2223
|
+
return {
|
|
2224
|
+
ok: false,
|
|
2225
|
+
error: "missing_dashboard_url",
|
|
2226
|
+
message: "Set KODY_CMS_DASHBOARD_URL or KODY_DASHBOARD_URL to the Dashboard origin."
|
|
2227
|
+
};
|
|
2228
|
+
}
|
|
2229
|
+
const headerResult = cmsHeaders(opts);
|
|
2230
|
+
if (!headerResult.ok) return headerResult;
|
|
2231
|
+
try {
|
|
2232
|
+
const res = await fetch(`${baseUrl}${path49}`, {
|
|
2233
|
+
...init,
|
|
2234
|
+
headers: {
|
|
2235
|
+
...headerResult.headers,
|
|
2236
|
+
...init.headers
|
|
2237
|
+
}
|
|
2238
|
+
});
|
|
2239
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
2240
|
+
const data = contentType.includes("application/json") ? await res.json().catch(() => null) : await res.text().catch(() => "");
|
|
2241
|
+
if (!res.ok) {
|
|
2242
|
+
return {
|
|
2243
|
+
ok: false,
|
|
2244
|
+
status: res.status,
|
|
2245
|
+
error: stringFieldFromRecord(data, "error") ?? "cms_request_failed",
|
|
2246
|
+
message: stringFieldFromRecord(data, "message") ?? `Dashboard CMS request failed with ${res.status}.`,
|
|
2247
|
+
data
|
|
2248
|
+
};
|
|
2249
|
+
}
|
|
2250
|
+
return { ok: true, status: res.status, data };
|
|
2251
|
+
} catch (err) {
|
|
2252
|
+
return {
|
|
2253
|
+
ok: false,
|
|
2254
|
+
error: "cms_request_error",
|
|
2255
|
+
message: err instanceof Error ? err.message : String(err)
|
|
2256
|
+
};
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
function cmsToolResponse(result) {
|
|
2260
|
+
return {
|
|
2261
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
2262
|
+
...result.ok ? {} : { isError: true }
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2265
|
+
function assertCmsWriteAllowed(opts) {
|
|
2266
|
+
if (isDispatchGated(opts.capabilitySlug, readCapabilityTrustMode(opts.state, opts.repoSlug, opts.capabilitySlug))) {
|
|
2267
|
+
return trustRefusal(opts.capabilitySlug);
|
|
2268
|
+
}
|
|
2269
|
+
return null;
|
|
2270
|
+
}
|
|
2271
|
+
function cmsQuery(args) {
|
|
2272
|
+
const params = new URLSearchParams();
|
|
2273
|
+
const q = stringArg(args.q);
|
|
2274
|
+
if (q) params.set("q", q);
|
|
2275
|
+
const limit = numberArg(args.limit);
|
|
2276
|
+
if (limit !== void 0) params.set("limit", String(limit));
|
|
2277
|
+
const offset = numberArg(args.offset);
|
|
2278
|
+
if (offset !== void 0) params.set("offset", String(offset));
|
|
2279
|
+
if (args.filters && typeof args.filters === "object" && !Array.isArray(args.filters)) {
|
|
2280
|
+
params.set("filters", JSON.stringify(args.filters));
|
|
2281
|
+
}
|
|
2282
|
+
if (Array.isArray(args.sort)) {
|
|
2283
|
+
const sort = args.sort.flatMap((entry) => {
|
|
2284
|
+
if (!entry || typeof entry !== "object") return [];
|
|
2285
|
+
const field = stringArg(entry.field);
|
|
2286
|
+
if (!field) return [];
|
|
2287
|
+
const direction = entry.direction === "asc" ? "asc" : "desc";
|
|
2288
|
+
return [`${field}:${direction}`];
|
|
2289
|
+
}).join(",");
|
|
2290
|
+
if (sort) params.set("sort", sort);
|
|
2291
|
+
}
|
|
2292
|
+
const value = params.toString();
|
|
2293
|
+
return value ? `?${value}` : "";
|
|
2294
|
+
}
|
|
2295
|
+
function stringArg(value) {
|
|
2296
|
+
return typeof value === "string" ? value.trim() : "";
|
|
2297
|
+
}
|
|
2298
|
+
function numberArg(value) {
|
|
2299
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
2300
|
+
const n = Number(value);
|
|
2301
|
+
return Number.isFinite(n) ? n : void 0;
|
|
2302
|
+
}
|
|
2303
|
+
function documentArg(value) {
|
|
2304
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
2305
|
+
return value;
|
|
2306
|
+
}
|
|
2307
|
+
function stringFieldFromRecord(value, field) {
|
|
2308
|
+
return value && typeof value === "object" && !Array.isArray(value) && typeof value[field] === "string" ? String(value[field]) : void 0;
|
|
2309
|
+
}
|
|
2192
2310
|
function capabilityToolDefinitions(opts) {
|
|
2193
2311
|
const workflowFile = opts.workflowFile ?? "kody.yml";
|
|
2194
2312
|
const listTool = {
|
|
@@ -2337,10 +2455,7 @@ function capabilityToolDefinitions(opts) {
|
|
|
2337
2455
|
handler: async (args) => {
|
|
2338
2456
|
const capability = String(args.capability ?? args.executable ?? "");
|
|
2339
2457
|
const issueNumber = Number(args.issueNumber);
|
|
2340
|
-
if (isDispatchGated(
|
|
2341
|
-
capability,
|
|
2342
|
-
readCapabilityTrustMode(opts.state, opts.repoSlug, opts.capabilitySlug)
|
|
2343
|
-
)) {
|
|
2458
|
+
if (isDispatchGated(capability, readCapabilityTrustMode(opts.state, opts.repoSlug, opts.capabilitySlug))) {
|
|
2344
2459
|
return { content: [{ type: "text", text: trustRefusal(opts.capabilitySlug) }] };
|
|
2345
2460
|
}
|
|
2346
2461
|
const result = dispatchWorkflow(workflowFile, capability, issueNumber, opts.repoSlug);
|
|
@@ -2348,6 +2463,86 @@ function capabilityToolDefinitions(opts) {
|
|
|
2348
2463
|
return { content: [{ type: "text", text }] };
|
|
2349
2464
|
}
|
|
2350
2465
|
};
|
|
2466
|
+
const cmsListCollectionsTool = {
|
|
2467
|
+
name: "cms_list_collections",
|
|
2468
|
+
description: "List configured Dashboard CMS collections and their supported operations. Read-only.",
|
|
2469
|
+
inputSchema: {},
|
|
2470
|
+
handler: async () => cmsToolResponse(await callDashboardCms(opts, "/api/kody/cms"))
|
|
2471
|
+
};
|
|
2472
|
+
const cmsListDocumentsTool = {
|
|
2473
|
+
name: "cms_list_documents",
|
|
2474
|
+
description: "List or search Dashboard CMS documents from one configured collection. Read-only.",
|
|
2475
|
+
inputSchema: {
|
|
2476
|
+
collection: z2.string().min(1).describe("CMS collection name."),
|
|
2477
|
+
q: z2.string().optional().describe("Optional search query."),
|
|
2478
|
+
filters: z2.record(z2.string(), z2.unknown()).optional().describe("Optional filter object keyed by field."),
|
|
2479
|
+
sort: z2.array(
|
|
2480
|
+
z2.object({
|
|
2481
|
+
field: z2.string().min(1),
|
|
2482
|
+
direction: z2.enum(["asc", "desc"]).default("desc")
|
|
2483
|
+
})
|
|
2484
|
+
).optional(),
|
|
2485
|
+
limit: z2.number().int().min(1).max(100).optional(),
|
|
2486
|
+
offset: z2.number().int().min(0).optional()
|
|
2487
|
+
},
|
|
2488
|
+
handler: async (args) => {
|
|
2489
|
+
const collection = encodeURIComponent(stringArg(args.collection));
|
|
2490
|
+
return cmsToolResponse(await callDashboardCms(opts, `/api/kody/cms/${collection}${cmsQuery(args)}`));
|
|
2491
|
+
}
|
|
2492
|
+
};
|
|
2493
|
+
const cmsGetDocumentTool = {
|
|
2494
|
+
name: "cms_get_document",
|
|
2495
|
+
description: "Get one Dashboard CMS document by collection and id. Read-only.",
|
|
2496
|
+
inputSchema: {
|
|
2497
|
+
collection: z2.string().min(1).describe("CMS collection name."),
|
|
2498
|
+
id: z2.string().min(1).describe("Document id.")
|
|
2499
|
+
},
|
|
2500
|
+
handler: async (args) => {
|
|
2501
|
+
const collection = encodeURIComponent(stringArg(args.collection));
|
|
2502
|
+
const id = encodeURIComponent(stringArg(args.id));
|
|
2503
|
+
return cmsToolResponse(await callDashboardCms(opts, `/api/kody/cms/${collection}/${id}`));
|
|
2504
|
+
}
|
|
2505
|
+
};
|
|
2506
|
+
const cmsCreateDocumentTool = {
|
|
2507
|
+
name: "cms_create_document",
|
|
2508
|
+
description: "Create one Dashboard CMS document when the capability is trusted and the CMS collection allows create.",
|
|
2509
|
+
inputSchema: {
|
|
2510
|
+
collection: z2.string().min(1).describe("CMS collection name."),
|
|
2511
|
+
data: z2.record(z2.string(), z2.unknown()).describe("Document fields to create.")
|
|
2512
|
+
},
|
|
2513
|
+
handler: async (args) => {
|
|
2514
|
+
const refusal = assertCmsWriteAllowed(opts);
|
|
2515
|
+
if (refusal) return { content: [{ type: "text", text: refusal }] };
|
|
2516
|
+
const collection = encodeURIComponent(stringArg(args.collection));
|
|
2517
|
+
return cmsToolResponse(
|
|
2518
|
+
await callDashboardCms(opts, `/api/kody/cms/${collection}`, {
|
|
2519
|
+
method: "POST",
|
|
2520
|
+
body: JSON.stringify(documentArg(args.data))
|
|
2521
|
+
})
|
|
2522
|
+
);
|
|
2523
|
+
}
|
|
2524
|
+
};
|
|
2525
|
+
const cmsUpdateDocumentTool = {
|
|
2526
|
+
name: "cms_update_document",
|
|
2527
|
+
description: "Update one Dashboard CMS document when the capability is trusted and the CMS collection allows update.",
|
|
2528
|
+
inputSchema: {
|
|
2529
|
+
collection: z2.string().min(1).describe("CMS collection name."),
|
|
2530
|
+
id: z2.string().min(1).describe("Document id."),
|
|
2531
|
+
data: z2.record(z2.string(), z2.unknown()).describe("Partial document fields to update.")
|
|
2532
|
+
},
|
|
2533
|
+
handler: async (args) => {
|
|
2534
|
+
const refusal = assertCmsWriteAllowed(opts);
|
|
2535
|
+
if (refusal) return { content: [{ type: "text", text: refusal }] };
|
|
2536
|
+
const collection = encodeURIComponent(stringArg(args.collection));
|
|
2537
|
+
const id = encodeURIComponent(stringArg(args.id));
|
|
2538
|
+
return cmsToolResponse(
|
|
2539
|
+
await callDashboardCms(opts, `/api/kody/cms/${collection}/${id}`, {
|
|
2540
|
+
method: "PATCH",
|
|
2541
|
+
body: JSON.stringify(documentArg(args.data))
|
|
2542
|
+
})
|
|
2543
|
+
);
|
|
2544
|
+
}
|
|
2545
|
+
};
|
|
2351
2546
|
return [
|
|
2352
2547
|
listTool,
|
|
2353
2548
|
syncTool,
|
|
@@ -2359,7 +2554,12 @@ function capabilityToolDefinitions(opts) {
|
|
|
2359
2554
|
readThreadTool,
|
|
2360
2555
|
ensureIssueTool,
|
|
2361
2556
|
ensureCommentTool,
|
|
2362
|
-
dispatchTool
|
|
2557
|
+
dispatchTool,
|
|
2558
|
+
cmsListCollectionsTool,
|
|
2559
|
+
cmsListDocumentsTool,
|
|
2560
|
+
cmsGetDocumentTool,
|
|
2561
|
+
cmsCreateDocumentTool,
|
|
2562
|
+
cmsUpdateDocumentTool
|
|
2363
2563
|
];
|
|
2364
2564
|
}
|
|
2365
2565
|
function buildCapabilityMcpServer(opts) {
|
|
@@ -2406,7 +2606,12 @@ var init_capabilityMcp = __esm({
|
|
|
2406
2606
|
"read_thread",
|
|
2407
2607
|
"ensure_issue",
|
|
2408
2608
|
"ensure_comment",
|
|
2409
|
-
"dispatch_workflow"
|
|
2609
|
+
"dispatch_workflow",
|
|
2610
|
+
"cms_list_collections",
|
|
2611
|
+
"cms_list_documents",
|
|
2612
|
+
"cms_get_document",
|
|
2613
|
+
"cms_create_document",
|
|
2614
|
+
"cms_update_document"
|
|
2410
2615
|
];
|
|
2411
2616
|
}
|
|
2412
2617
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.272",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|