@kody-ade/kody-engine 0.4.244 → 0.4.245

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.244",
18
+ version: "0.4.245",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative agentAction profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -194,8 +194,8 @@ function isRunningAsBot() {
194
194
  }
195
195
  function postIssueComment(issueNumber, body, cwd) {
196
196
  if (isRunningAsBot()) {
197
- const slug = detectBotDispatchShape(body);
198
- if (slug) throw new BotDispatchCommentError(slug);
197
+ const slug2 = detectBotDispatchShape(body);
198
+ if (slug2) throw new BotDispatchCommentError(slug2);
199
199
  }
200
200
  try {
201
201
  gh(["issue", "comment", String(issueNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
@@ -295,8 +295,8 @@ function getPrLatestReviewBody(prNumber, cwd) {
295
295
  }
296
296
  function postPrReviewComment(prNumber, body, cwd) {
297
297
  if (isRunningAsBot()) {
298
- const slug = detectBotDispatchShape(body);
299
- if (slug) throw new BotDispatchCommentError(slug);
298
+ const slug2 = detectBotDispatchShape(body);
299
+ if (slug2) throw new BotDispatchCommentError(slug2);
300
300
  }
301
301
  try {
302
302
  gh(["pr", "comment", String(prNumber), "--body-file", "-"], { input: stripKodyMentions(body), cwd });
@@ -313,9 +313,9 @@ var init_issue = __esm({
313
313
  "use strict";
314
314
  API_TIMEOUT_MS = 3e4;
315
315
  BotDispatchCommentError = class extends Error {
316
- constructor(slug) {
316
+ constructor(slug2) {
317
317
  super(
318
- `bot self-dispatch via @kody comments is banned. Refusing to post "@kody ${slug} \u2026" \u2014 use runAgentActionChain (same-run) or dispatchAgentAction (cross-run) instead. See docs/agent-responsibility-dispatch.md for the contract.`
318
+ `bot self-dispatch via @kody comments is banned. Refusing to post "@kody ${slug2} \u2026" \u2014 use runAgentActionChain (same-run) or dispatchAgentAction (cross-run) instead. See docs/agent-responsibility-dispatch.md for the contract.`
319
319
  );
320
320
  this.name = "BotDispatchCommentError";
321
321
  }
@@ -332,8 +332,8 @@ function is404(err) {
332
332
  const msg = err instanceof Error ? err.message : String(err);
333
333
  return /HTTP 404/i.test(msg) || /Not Found/i.test(msg);
334
334
  }
335
- function parseStateRepoSlug(slug, field = "stateRepo") {
336
- const value = slug.trim();
335
+ function parseStateRepoSlug(slug2, field = "stateRepo") {
336
+ const value = slug2.trim();
337
337
  let repoPath = value;
338
338
  if (/^https?:\/\//i.test(value)) {
339
339
  let parsed;
@@ -460,6 +460,18 @@ function appendStateLine(config, cwd, filePath, line, message) {
460
460
  `}`;
461
461
  writeStateText(config, cwd, filePath, next, message, prior?.sha);
462
462
  }
463
+ function listStateDirectory(config, cwd, dirPath) {
464
+ const targetPath = stateRepoPath(config, dirPath);
465
+ let raw = "";
466
+ try {
467
+ raw = gh(["api", apiPath(config, targetPath)], { cwd });
468
+ } catch (err) {
469
+ if (is404(err)) return [];
470
+ throw err;
471
+ }
472
+ const parsed = JSON.parse(raw);
473
+ return Array.isArray(parsed) ? parsed : [];
474
+ }
463
475
  var init_stateRepo = __esm({
464
476
  "src/stateRepo.ts"() {
465
477
  "use strict";
@@ -619,11 +631,11 @@ function parseGoalActivations(raw) {
619
631
  const seen = /* @__PURE__ */ new Set();
620
632
  for (const value of raw) {
621
633
  if (typeof value === "string") {
622
- const slug = parseSlug(value, "company.activeGoals");
623
- if (!slug) continue;
624
- if (!seen.has(slug)) {
625
- seen.add(slug);
626
- out.push(slug);
634
+ const slug2 = parseSlug(value, "company.activeGoals");
635
+ if (!slug2) continue;
636
+ if (!seen.has(slug2)) {
637
+ seen.add(slug2);
638
+ out.push(slug2);
627
639
  }
628
640
  continue;
629
641
  }
@@ -658,20 +670,20 @@ function parseSlugArray(raw, field) {
658
670
  if (!Array.isArray(raw)) throw new Error(`kody.config.json: ${field} must be an array of strings`);
659
671
  const out = [];
660
672
  for (const value of raw) {
661
- const slug = parseSlug(value, field);
662
- if (!slug) continue;
663
- out.push(slug);
673
+ const slug2 = parseSlug(value, field);
674
+ if (!slug2) continue;
675
+ out.push(slug2);
664
676
  }
665
677
  return [...new Set(out)];
666
678
  }
667
679
  function parseSlug(value, field) {
668
680
  if (typeof value !== "string") throw new Error(`kody.config.json: ${field} entries must be strings`);
669
- const slug = value.trim();
670
- if (!slug) return "";
671
- if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(slug)) {
681
+ const slug2 = value.trim();
682
+ if (!slug2) return "";
683
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(slug2)) {
672
684
  throw new Error(`kody.config.json: ${field} contains invalid slug "${value}"`);
673
685
  }
674
- return slug;
686
+ return slug2;
675
687
  }
676
688
  function recordValue(raw) {
677
689
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : void 0;
@@ -2303,56 +2315,6 @@ var init_agent = __esm({
2303
2315
  }
2304
2316
  });
2305
2317
 
2306
- // src/scripts/scheduleEvery.ts
2307
- function isScheduleEvery(value) {
2308
- return typeof value === "string" && SCHEDULE_EVERY_VALUES.includes(value);
2309
- }
2310
- function scheduleEveryToMs(every) {
2311
- const MIN = 60 * 1e3;
2312
- const HOUR = 60 * MIN;
2313
- const DAY = 24 * HOUR;
2314
- switch (every) {
2315
- case "15m":
2316
- return 15 * MIN;
2317
- case "30m":
2318
- return 30 * MIN;
2319
- case "1h":
2320
- return HOUR;
2321
- case "2h":
2322
- return 2 * HOUR;
2323
- case "6h":
2324
- return 6 * HOUR;
2325
- case "12h":
2326
- return 12 * HOUR;
2327
- case "1d":
2328
- return DAY;
2329
- case "3d":
2330
- return 3 * DAY;
2331
- case "7d":
2332
- return 7 * DAY;
2333
- case "manual":
2334
- return Number.POSITIVE_INFINITY;
2335
- }
2336
- }
2337
- var SCHEDULE_EVERY_VALUES;
2338
- var init_scheduleEvery = __esm({
2339
- "src/scripts/scheduleEvery.ts"() {
2340
- "use strict";
2341
- SCHEDULE_EVERY_VALUES = [
2342
- "15m",
2343
- "30m",
2344
- "1h",
2345
- "2h",
2346
- "6h",
2347
- "12h",
2348
- "1d",
2349
- "3d",
2350
- "7d",
2351
- "manual"
2352
- ];
2353
- }
2354
- });
2355
-
2356
2318
  // src/agent-responsibilityFolders.ts
2357
2319
  import * as fs6 from "fs";
2358
2320
  import * as path8 from "path";
@@ -2369,8 +2331,8 @@ function listAgentResponsibilityFolderSlugs(absDir) {
2369
2331
  function isAgentResponsibilityFolder(dir) {
2370
2332
  return fs6.existsSync(path8.join(dir, AGENT_RESPONSIBILITY_PROFILE_FILE)) && fs6.existsSync(path8.join(dir, AGENT_RESPONSIBILITY_BODY_FILE));
2371
2333
  }
2372
- function readAgentResponsibilityFolder(root, slug) {
2373
- const dir = path8.join(root, slug);
2334
+ function readAgentResponsibilityFolder(root, slug2) {
2335
+ const dir = path8.join(root, slug2);
2374
2336
  const profilePath = path8.join(dir, AGENT_RESPONSIBILITY_PROFILE_FILE);
2375
2337
  const bodyPath = path8.join(dir, AGENT_RESPONSIBILITY_BODY_FILE);
2376
2338
  if (!fs6.existsSync(profilePath) || !fs6.statSync(profilePath).isFile()) return null;
@@ -2378,9 +2340,9 @@ function readAgentResponsibilityFolder(root, slug) {
2378
2340
  try {
2379
2341
  const rawProfile = JSON.parse(fs6.readFileSync(profilePath, "utf-8"));
2380
2342
  const rawBody = fs6.readFileSync(bodyPath, "utf-8");
2381
- const { title, body } = parseAgentResponsibilityBody(rawBody, slug);
2343
+ const { title, body } = parseAgentResponsibilityBody(rawBody, slug2);
2382
2344
  return {
2383
- slug,
2345
+ slug: slug2,
2384
2346
  dir,
2385
2347
  profilePath,
2386
2348
  bodyPath,
@@ -2399,7 +2361,6 @@ function parseAgentResponsibilityConfig(raw) {
2399
2361
  return {
2400
2362
  action: stringField(raw.action),
2401
2363
  agentAction: stringField(raw.agentAction),
2402
- every: isScheduleEvery(raw.every) ? raw.every : void 0,
2403
2364
  tickScript: stringField(raw.tickScript),
2404
2365
  disabled: typeof raw.disabled === "boolean" ? raw.disabled : void 0,
2405
2366
  agent: stringField(raw.agent),
@@ -2413,11 +2374,11 @@ function parseAgentResponsibilityConfig(raw) {
2413
2374
  writesTo: stringList(raw.writesTo ?? raw.writes_to)
2414
2375
  };
2415
2376
  }
2416
- function parseAgentResponsibilityBody(raw, slug) {
2377
+ function parseAgentResponsibilityBody(raw, slug2) {
2417
2378
  const trimmed = raw.trim();
2418
2379
  const firstLine2 = trimmed.split("\n", 1)[0] ?? "";
2419
2380
  const h1 = /^#\s+(.+?)\s*$/.exec(firstLine2);
2420
- const title = h1 ? h1[1].trim() : humanizeSlug(slug);
2381
+ const title = h1 ? h1[1].trim() : humanizeSlug(slug2);
2421
2382
  const body = stripLeadingH1(raw);
2422
2383
  return { title, body };
2423
2384
  }
@@ -2431,8 +2392,8 @@ function stripLeadingH1(raw) {
2431
2392
  }
2432
2393
  return lines.slice(i).join("\n");
2433
2394
  }
2434
- function humanizeSlug(slug) {
2435
- return slug.split(/[-_]+/).filter(Boolean).map((part) => part[0].toUpperCase() + part.slice(1)).join(" ");
2395
+ function humanizeSlug(slug2) {
2396
+ return slug2.split(/[-_]+/).filter(Boolean).map((part) => part[0].toUpperCase() + part.slice(1)).join(" ");
2436
2397
  }
2437
2398
  function stringField(value) {
2438
2399
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
@@ -2454,7 +2415,6 @@ var AGENT_RESPONSIBILITY_PROFILE_FILE, AGENT_RESPONSIBILITY_BODY_FILE;
2454
2415
  var init_agent_responsibilityFolders = __esm({
2455
2416
  "src/agent-responsibilityFolders.ts"() {
2456
2417
  "use strict";
2457
- init_scheduleEvery();
2458
2418
  AGENT_RESPONSIBILITY_PROFILE_FILE = "profile.json";
2459
2419
  AGENT_RESPONSIBILITY_BODY_FILE = "agent-responsibility.md";
2460
2420
  }
@@ -2680,10 +2640,10 @@ function resolveAgentResponsibilityAction(action, projectAgentResponsibilitiesRo
2680
2640
  function hasAgentResponsibilityAction(action, projectAgentResponsibilitiesRoot = getProjectAgentResponsibilitiesRoot()) {
2681
2641
  return resolveAgentResponsibilityAction(action, projectAgentResponsibilitiesRoot) !== null;
2682
2642
  }
2683
- function resolveAgentResponsibilityFolder(slug, projectAgentResponsibilitiesRoot = getProjectAgentResponsibilitiesRoot()) {
2684
- if (!isSafeName(slug)) return null;
2643
+ function resolveAgentResponsibilityFolder(slug2, projectAgentResponsibilitiesRoot = getProjectAgentResponsibilitiesRoot()) {
2644
+ if (!isSafeName(slug2)) return null;
2685
2645
  for (const root of getAgentResponsibilityRoots(projectAgentResponsibilitiesRoot)) {
2686
- const agentResponsibility = readAgentResponsibilityFolder(root, slug);
2646
+ const agentResponsibility = readAgentResponsibilityFolder(root, slug2);
2687
2647
  if (agentResponsibility) return agentResponsibility;
2688
2648
  }
2689
2649
  return null;
@@ -2742,15 +2702,15 @@ function listAgentActionResponsibilityActions(root, source) {
2742
2702
  function listFolderAgentResponsibilityActions(root, source) {
2743
2703
  if (!fs8.existsSync(root) || !fs8.statSync(root).isDirectory()) return [];
2744
2704
  const out = [];
2745
- for (const slug of listAgentResponsibilityFolderSlugs(root)) {
2746
- if (!isSafeName(slug)) continue;
2747
- const agentResponsibility = readAgentResponsibilityFolder(root, slug);
2705
+ for (const slug2 of listAgentResponsibilityFolderSlugs(root)) {
2706
+ if (!isSafeName(slug2)) continue;
2707
+ const agentResponsibility = readAgentResponsibilityFolder(root, slug2);
2748
2708
  if (!agentResponsibility) continue;
2749
- const action = agentResponsibility.config.action ?? slug;
2709
+ const action = agentResponsibility.config.action ?? slug2;
2750
2710
  const { agentAction, cliArgs } = resolveAgentResponsibilityExecution(agentResponsibility);
2751
2711
  out.push({
2752
2712
  action,
2753
- agentResponsibility: slug,
2713
+ agentResponsibility: slug2,
2754
2714
  agentAction,
2755
2715
  cliArgs,
2756
2716
  source,
@@ -2765,15 +2725,15 @@ function listFolderAgentResponsibilityActions(root, source) {
2765
2725
  function listBuiltinAgentResponsibilityActions(root = getBuiltinAgentResponsibilitiesRoot()) {
2766
2726
  if (!fs8.existsSync(root) || !fs8.statSync(root).isDirectory()) return [];
2767
2727
  const out = [];
2768
- for (const slug of listAgentResponsibilityFolderSlugs(root)) {
2769
- if (!isSafeName(slug)) continue;
2770
- const agentResponsibility = readAgentResponsibilityFolder(root, slug);
2728
+ for (const slug2 of listAgentResponsibilityFolderSlugs(root)) {
2729
+ if (!isSafeName(slug2)) continue;
2730
+ const agentResponsibility = readAgentResponsibilityFolder(root, slug2);
2771
2731
  if (!agentResponsibility) continue;
2772
- const action = agentResponsibility.config.action ?? slug;
2773
- const agentAction = agentResponsibility.config.agentAction ?? slug;
2732
+ const action = agentResponsibility.config.action ?? slug2;
2733
+ const agentAction = agentResponsibility.config.agentAction ?? slug2;
2774
2734
  out.push({
2775
2735
  action,
2776
- agentResponsibility: slug,
2736
+ agentResponsibility: slug2,
2777
2737
  agentAction,
2778
2738
  cliArgs: {},
2779
2739
  source: "builtin",
@@ -3199,8 +3159,8 @@ function stripFrontmatter(raw) {
3199
3159
  const match = /^---\n[\s\S]*?\n---\n?([\s\S]*)$/.exec(raw);
3200
3160
  return (match ? match[1] : raw).trim();
3201
3161
  }
3202
- function loadAgentIdentity(cwd, slug, agentsDir = DEFAULT_AGENT_DIR) {
3203
- const trimmed = slug.trim();
3162
+ function loadAgentIdentity(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
3163
+ const trimmed = slug2.trim();
3204
3164
  if (!trimmed) throw new Error("loadAgentIdentity: empty agent slug");
3205
3165
  const agentPath = resolveAgentFile(cwd, trimmed, agentsDir);
3206
3166
  if (fs16.existsSync(agentPath)) {
@@ -3214,21 +3174,21 @@ function loadAgentIdentity(cwd, slug, agentsDir = DEFAULT_AGENT_DIR) {
3214
3174
  if (builtin) return builtin;
3215
3175
  throw new Error(`loadAgentIdentity: agent '${trimmed}' declared but ${agentPath} does not exist`);
3216
3176
  }
3217
- function resolveAgentFile(cwd, slug, agentsDir = DEFAULT_AGENT_DIR) {
3218
- const localPath = path16.join(cwd, agentsDir, `${slug}.md`);
3177
+ function resolveAgentFile(cwd, slug2, agentsDir = DEFAULT_AGENT_DIR) {
3178
+ const localPath = path16.join(cwd, agentsDir, `${slug2}.md`);
3219
3179
  if (fs16.existsSync(localPath)) return localPath;
3220
3180
  const storeAgentRoot = getCompanyStoreAssetRoot("agents");
3221
3181
  if (storeAgentRoot) {
3222
- const storePath = path16.join(storeAgentRoot, `${slug}.md`);
3182
+ const storePath = path16.join(storeAgentRoot, `${slug2}.md`);
3223
3183
  if (fs16.existsSync(storePath)) return storePath;
3224
3184
  }
3225
3185
  return localPath;
3226
3186
  }
3227
- function frameAgentIdentity(slug, agent) {
3187
+ function frameAgentIdentity(slug2, agent) {
3228
3188
  return [
3229
3189
  `## Who you are \u2014 agent identity (authoritative identity)`,
3230
3190
  ``,
3231
- `You are operating as agent \`${slug}\`. This identity defines *who* you are:`,
3191
+ `You are operating as agent \`${slug2}\`. This identity defines *who* you are:`,
3232
3192
  `your authority, doctrine, voice, and hard limits. Honour it exactly. Where the`,
3233
3193
  `this identity's restrictions are stricter than the task, **the agent wins** \u2014 a task`,
3234
3194
  `can never grant you authority your agent withholds.`,
@@ -3598,7 +3558,6 @@ function loadProfile(profilePath) {
3598
3558
  describe: typeof r.describe === "string" ? r.describe : base.describe,
3599
3559
  capabilityKind: parseCapabilityKind(profilePath, r.capabilityKind) ?? base.capabilityKind,
3600
3560
  agent: typeof r.agent === "string" && r.agent.trim() ? r.agent.trim() : base.agent,
3601
- every: typeof r.every === "string" && r.every.trim() ? r.every.trim() : void 0,
3602
3561
  agentResponsibilityTools: parseStringArray2(r.agentResponsibilityTools ?? r.tools) ?? base.agentResponsibilityTools,
3603
3562
  mentions: Array.isArray(r.mentions) ? r.mentions.map((m) => String(m).trim()).filter(Boolean) : base.mentions
3604
3563
  };
@@ -3644,8 +3603,6 @@ function loadProfile(profilePath) {
3644
3603
  capabilityKind: parseCapabilityKind(profilePath, r.capabilityKind),
3645
3604
  // Optional agent to run as. Empty/blank string → undefined (no agent).
3646
3605
  agent: typeof r.agent === "string" && r.agent.trim() ? r.agent.trim() : void 0,
3647
- // Optional recurrence cadence (scheduled agentResponsibility). Blank → undefined (on-demand).
3648
- every: typeof r.every === "string" && r.every.trim() ? r.every.trim() : void 0,
3649
3606
  // Locked-toolbox palette + mentions from folder-agentResponsibility profile metadata.
3650
3607
  agentResponsibilityTools: parseStringArray2(r.agentResponsibilityTools ?? r.tools),
3651
3608
  mentions: Array.isArray(r.mentions) ? r.mentions.map((m) => String(m).trim()).filter(Boolean) : void 0,
@@ -5891,8 +5848,8 @@ function applySimpleGoalTaskSummary(goal, summary) {
5891
5848
  }
5892
5849
  function isFactReference(value) {
5893
5850
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
5894
- const record = value;
5895
- return Object.keys(record).length === 1 && typeof record.fact === "string" && record.fact.length > 0;
5851
+ const record2 = value;
5852
+ return Object.keys(record2).length === 1 && typeof record2.fact === "string" && record2.fact.length > 0;
5896
5853
  }
5897
5854
  function isCliArgValue(value) {
5898
5855
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
@@ -5967,7 +5924,8 @@ function planManagedGoalTick(goal) {
5967
5924
  stage: step.stage,
5968
5925
  agentResponsibility: step.agentResponsibility,
5969
5926
  agentAction: step.agentAction,
5970
- cliArgs: resolved.cliArgs
5927
+ cliArgs: resolved.cliArgs,
5928
+ ...step.saveReport === true ? { saveReport: true } : {}
5971
5929
  };
5972
5930
  }
5973
5931
  function asStringArray(value) {
@@ -5994,7 +5952,8 @@ function asRoute(value) {
5994
5952
  stage: raw.stage,
5995
5953
  agentResponsibility: raw.agentResponsibility,
5996
5954
  agentAction: typeof raw.agentAction === "string" ? raw.agentAction : void 0,
5997
- args: args ?? void 0
5955
+ args: args ?? void 0,
5956
+ saveReport: raw.saveReport === true
5998
5957
  });
5999
5958
  }
6000
5959
  return route;
@@ -6088,10 +6047,10 @@ var init_state2 = __esm({
6088
6047
  "use strict";
6089
6048
  VALID_STATES = /* @__PURE__ */ new Set(["active", "abandoned", "closed", "done"]);
6090
6049
  GoalStateError = class extends Error {
6091
- constructor(path47, message) {
6092
- super(`Invalid goal state at ${path47}:
6050
+ constructor(path46, message) {
6051
+ super(`Invalid goal state at ${path46}:
6093
6052
  ${message}`);
6094
- this.path = path47;
6053
+ this.path = path46;
6095
6054
  this.name = "GoalStateError";
6096
6055
  }
6097
6056
  path;
@@ -6336,8 +6295,8 @@ function isStateUnchanged(prev, next) {
6336
6295
  if (prev.done !== next.done) return false;
6337
6296
  return JSON.stringify(prev.data) === JSON.stringify(next.data);
6338
6297
  }
6339
- function stateFilePath(jobsDir, slug) {
6340
- return `${jobsDir.replace(/\/+$/, "")}/${slug}/state.json`;
6298
+ function stateFilePath(jobsDir, slug2) {
6299
+ return `${jobsDir.replace(/\/+$/, "")}/${slug2}/state.json`;
6341
6300
  }
6342
6301
  function slugFromStateFilePath(filePath) {
6343
6302
  if (/\/state\.json$/i.test(filePath)) {
@@ -6379,8 +6338,8 @@ var init_contentsApiBackend = __esm({
6379
6338
  this.jobsDir = stateRepoJobsDir(opts.jobsDir);
6380
6339
  this.cwd = opts.cwd;
6381
6340
  }
6382
- load(slug) {
6383
- const filePath = stateFilePath(this.jobsDir, slug);
6341
+ load(slug2) {
6342
+ const filePath = stateFilePath(this.jobsDir, slug2);
6384
6343
  const loaded = readStateText(this.config, this.cwd, filePath);
6385
6344
  if (!loaded) {
6386
6345
  return { path: filePath, handle: null, state: initialStateEnvelope("seed"), created: true };
@@ -6400,20 +6359,20 @@ var init_contentsApiBackend = __esm({
6400
6359
  if (!loaded.created && isStateUnchanged(loaded.state, next)) {
6401
6360
  return false;
6402
6361
  }
6403
- const slug = slugFromStateFilePath(loaded.path);
6362
+ const slug2 = slugFromStateFilePath(loaded.path);
6404
6363
  const body = `${JSON.stringify(next, null, 2)}
6405
6364
  `;
6406
- const message = `chore(jobs): update state for ${slug} (rev ${next.rev})`;
6365
+ const message = `chore(jobs): update state for ${slug2} (rev ${next.rev})`;
6407
6366
  const sha = typeof loaded.handle === "string" ? loaded.handle : void 0;
6408
6367
  try {
6409
6368
  writeStateText(this.config, this.cwd, loaded.path, body, message, sha);
6410
6369
  } catch (err) {
6411
6370
  if (!isShaConflict(err)) throw err;
6412
- const current = this.load(slug);
6371
+ const current = this.load(slug2);
6413
6372
  if (!current.created && isStateUnchanged(current.state, next)) return false;
6414
6373
  const currentSha = typeof current.handle === "string" ? current.handle : void 0;
6415
6374
  process.stderr.write(
6416
- `[kody] jobState: concurrent write detected for ${slug}; reloaded SHA and retrying (last-write-wins)
6375
+ `[kody] jobState: concurrent write detected for ${slug2}; reloaded SHA and retrying (last-write-wins)
6417
6376
  `
6418
6377
  );
6419
6378
  writeStateText(this.config, this.cwd, loaded.path, body, message, currentSha);
@@ -6540,8 +6499,8 @@ var init_localFileBackend = __esm({
6540
6499
  `);
6541
6500
  }
6542
6501
  }
6543
- load(slug) {
6544
- const relPath = stateFilePath(this.jobsDir, slug);
6502
+ load(slug2) {
6503
+ const relPath = stateFilePath(this.jobsDir, slug2);
6545
6504
  const absPath = path24.join(this.cwd, relPath);
6546
6505
  if (!fs25.existsSync(absPath)) {
6547
6506
  return { path: relPath, handle: null, state: initialStateEnvelope("seed"), created: true };
@@ -6614,28 +6573,27 @@ function isAgentResponsibilityCadenceGoal(goal, extra) {
6614
6573
  return extra.scheduleMode === "agentLoop" || extra.scheduler === "agentLoop" || goal.type === "standing" && goal.agentResponsibilities.length > 0;
6615
6574
  }
6616
6575
  async function planGoalAgentResponsibilitySchedule(opts) {
6617
- const now = opts.now ?? /* @__PURE__ */ new Date();
6618
- const at = now.toISOString();
6619
6576
  const jobsDir = opts.jobsDir ?? ".kody/agent-responsibilities";
6620
6577
  const jobsRoot = path25.join(opts.cwd, jobsDir);
6578
+ const now = opts.now ?? /* @__PURE__ */ new Date();
6579
+ const at = now.toISOString();
6621
6580
  const backend = resolveBackend({ config: opts.config, cwd: opts.cwd, jobsDir });
6622
6581
  const statuses = {};
6623
6582
  const blockers = [];
6624
- for (const slug of opts.goal.agentResponsibilities) {
6625
- const agentResponsibility2 = resolveAgentResponsibilityFolder(slug, jobsRoot);
6583
+ for (const slug2 of opts.goal.agentResponsibilities) {
6584
+ const agentResponsibility2 = resolveAgentResponsibilityFolder(slug2, jobsRoot);
6626
6585
  const status = await describeAgentResponsibilitySchedule(
6627
6586
  agentResponsibility2,
6628
- slug,
6587
+ slug2,
6629
6588
  backend,
6630
- now.getTime(),
6631
- opts.previousScheduleState?.agentResponsibilities[slug]
6589
+ opts.previousScheduleState?.agentResponsibilities[slug2]
6632
6590
  );
6633
- statuses[slug] = status;
6634
- if (status.state === "blocked") blockers.push(`${slug}: ${status.reason}`);
6591
+ statuses[slug2] = status;
6592
+ if (status.state === "blocked") blockers.push(`${slug2}: ${status.reason}`);
6635
6593
  }
6636
- const due = opts.goal.agentResponsibilities.map((slug) => statuses[slug]).find((status) => status?.state === "due");
6594
+ const due = opts.goal.agentResponsibilities.map((slug2) => statuses[slug2]).filter((status) => status?.state === "due").sort(compareOldestLastFired)[0];
6637
6595
  if (!due) {
6638
- const reason = blockers.length > 0 ? "no runnable due agentResponsibility; blocked agentResponsibilities need attention" : "no agentResponsibility due now";
6596
+ const reason = blockers.length > 0 ? "no runnable agentResponsibility; blocked agentResponsibilities need attention" : "no runnable agentResponsibility";
6639
6597
  const kind = blockers.length > 0 ? "blocked" : "idle";
6640
6598
  return {
6641
6599
  kind,
@@ -6682,29 +6640,19 @@ async function planGoalAgentResponsibilitySchedule(opts) {
6682
6640
  }
6683
6641
  };
6684
6642
  }
6685
- async function describeAgentResponsibilitySchedule(agentResponsibility, slug, backend, now, previous) {
6686
- if (!agentResponsibility) return { slug, state: "blocked", reason: "agentResponsibility folder missing" };
6643
+ async function describeAgentResponsibilitySchedule(agentResponsibility, slug2, backend, previous) {
6644
+ if (!agentResponsibility) return { slug: slug2, state: "blocked", reason: "agentResponsibility folder missing" };
6687
6645
  const { config } = agentResponsibility;
6688
6646
  if (config.disabled === true) {
6689
- return { slug, title: agentResponsibility.title, cadence: config.every, state: "disabled", reason: "disabled" };
6690
- }
6691
- if (config.every === "manual" || !config.every && !config.agent && config.agentAction) {
6692
- return { slug, title: agentResponsibility.title, cadence: config.every, state: "manual", reason: "manual only" };
6647
+ return { slug: slug2, title: agentResponsibility.title, state: "disabled", reason: "disabled" };
6693
6648
  }
6694
6649
  if (!config.agent || config.agent.trim().length === 0) {
6695
- return {
6696
- slug,
6697
- title: agentResponsibility.title,
6698
- cadence: config.every,
6699
- state: "blocked",
6700
- reason: "no agent assigned"
6701
- };
6650
+ return { slug: slug2, title: agentResponsibility.title, state: "blocked", reason: "no agent assigned" };
6702
6651
  }
6703
6652
  if (config.agentActions && config.agentActions.length > 1) {
6704
6653
  return {
6705
- slug,
6654
+ slug: slug2,
6706
6655
  title: agentResponsibility.title,
6707
- cadence: config.every,
6708
6656
  state: "blocked",
6709
6657
  reason: "multi-agentAction agentResponsibility needs task-jobs route"
6710
6658
  };
@@ -6712,79 +6660,46 @@ async function describeAgentResponsibilitySchedule(agentResponsibility, slug, ba
6712
6660
  let lastFiredAt = validIso(previous?.lastFiredAt) ? previous?.lastFiredAt : void 0;
6713
6661
  try {
6714
6662
  if (!lastFiredAt) {
6715
- const loaded = await backend.load(slug);
6663
+ const loaded = await backend.load(slug2);
6716
6664
  const raw = loaded.state.data?.lastFiredAt;
6717
6665
  if (typeof raw === "string" && validIso(raw)) lastFiredAt = raw;
6718
6666
  }
6719
6667
  } catch {
6720
6668
  return {
6721
- slug,
6722
- title: agentResponsibility.title,
6723
- cadence: config.every,
6724
- state: "due",
6725
- reason: "state unreadable; run to refresh"
6726
- };
6727
- }
6728
- if (!config.every) {
6729
- return {
6730
- slug,
6669
+ slug: slug2,
6731
6670
  title: agentResponsibility.title,
6732
6671
  state: "due",
6733
- reason: "no cadence; check every goal tick",
6734
- lastFiredAt
6735
- };
6736
- }
6737
- if (!lastFiredAt) {
6738
- return {
6739
- slug,
6740
- title: agentResponsibility.title,
6741
- cadence: config.every,
6742
- state: "due",
6743
- reason: `first check for ${config.every}`
6744
- };
6745
- }
6746
- const last = Date.parse(lastFiredAt);
6747
- const interval = scheduleEveryToMs(config.every);
6748
- const next = new Date(last + interval).toISOString();
6749
- if (now - last >= interval) {
6750
- return {
6751
- slug,
6752
- title: agentResponsibility.title,
6753
- cadence: config.every,
6754
- state: "due",
6755
- reason: `due ${config.every}`,
6756
- lastFiredAt,
6757
- nextEligibleAt: next
6672
+ reason: "state unreadable; ready for loop tick"
6758
6673
  };
6759
6674
  }
6760
6675
  return {
6761
- slug,
6676
+ slug: slug2,
6762
6677
  title: agentResponsibility.title,
6763
- cadence: config.every,
6764
- state: "waiting",
6765
- reason: `next due ${next}`,
6766
- lastFiredAt,
6767
- nextEligibleAt: next
6678
+ state: "due",
6679
+ reason: "ready for loop tick",
6680
+ lastFiredAt
6768
6681
  };
6769
6682
  }
6770
6683
  function dutyDispatch(agentResponsibility) {
6771
6684
  const { agentAction, cliArgs } = resolveAgentResponsibilityExecution(agentResponsibility);
6772
6685
  return { agentResponsibility: agentResponsibility.slug, agentAction, cliArgs };
6773
6686
  }
6687
+ function compareOldestLastFired(a, b) {
6688
+ const aTime = validIso(a.lastFiredAt) ? Date.parse(a.lastFiredAt) : Number.NEGATIVE_INFINITY;
6689
+ const bTime = validIso(b.lastFiredAt) ? Date.parse(b.lastFiredAt) : Number.NEGATIVE_INFINITY;
6690
+ return aTime - bTime;
6691
+ }
6774
6692
  function validIso(value) {
6775
6693
  return typeof value === "string" && !Number.isNaN(Date.parse(value));
6776
6694
  }
6777
6695
  function markAgentResponsibilitySelected(status, now) {
6778
- const lastFiredAt = now.toISOString();
6779
- const nextEligibleAt = status.cadence && status.cadence !== "manual" ? new Date(now.getTime() + scheduleEveryToMs(status.cadence)).toISOString() : status.nextEligibleAt;
6780
- return { ...status, lastFiredAt, nextEligibleAt };
6696
+ return { ...status, lastFiredAt: now.toISOString() };
6781
6697
  }
6782
6698
  var init_goalAgentResponsibilityScheduling = __esm({
6783
6699
  "src/scripts/goalAgentResponsibilityScheduling.ts"() {
6784
6700
  "use strict";
6785
6701
  init_registry();
6786
6702
  init_jobState();
6787
- init_scheduleEvery();
6788
6703
  }
6789
6704
  });
6790
6705
 
@@ -6812,8 +6727,8 @@ function routeNeedsIssueFact(goal) {
6812
6727
  return goal.route.some(
6813
6728
  (step) => Object.values(step.args ?? {}).some((value) => {
6814
6729
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
6815
- const record = value;
6816
- return Object.keys(record).length === 1 && record.fact === "issue";
6730
+ const record2 = value;
6731
+ return Object.keys(record2).length === 1 && record2.fact === "issue";
6817
6732
  })
6818
6733
  );
6819
6734
  }
@@ -6907,7 +6822,8 @@ var init_advanceManagedGoal = __esm({
6907
6822
  ctx.output.nextDispatch = {
6908
6823
  agentResponsibility: decision2.dispatch.agentResponsibility,
6909
6824
  agentAction: decision2.dispatch.agentAction,
6910
- cliArgs: decision2.dispatch.cliArgs
6825
+ cliArgs: decision2.dispatch.cliArgs,
6826
+ ...goal.raw.extra.saveReport === true ? { saveReport: true } : {}
6911
6827
  };
6912
6828
  }
6913
6829
  ctx.output.reason = decision2.reason;
@@ -6930,7 +6846,8 @@ var init_advanceManagedGoal = __esm({
6930
6846
  ctx.output.nextDispatch = {
6931
6847
  agentResponsibility: decision.agentResponsibility,
6932
6848
  agentAction: decision.agentAction,
6933
- cliArgs: decision.cliArgs
6849
+ cliArgs: decision.cliArgs,
6850
+ ...decision.saveReport === true ? { saveReport: true } : {}
6934
6851
  };
6935
6852
  ctx.output.reason = `dispatch ${decision.agentResponsibility} for ${decision.evidence}`;
6936
6853
  };
@@ -6944,9 +6861,9 @@ function resolveTrigger(force) {
6944
6861
  if (force || event === "issue_comment" || event === "workflow_dispatch") return "manual";
6945
6862
  return "event";
6946
6863
  }
6947
- function appendLine(ctx, record) {
6948
- const filePath = `activity/${record.ts.slice(0, 10)}.jsonl`;
6949
- appendStateLine(ctx.config, ctx.cwd, filePath, JSON.stringify(record), `chore(activity): ${record.action}`);
6864
+ function appendLine(ctx, record2) {
6865
+ const filePath = `activity/${record2.ts.slice(0, 10)}.jsonl`;
6866
+ appendStateLine(ctx.config, ctx.cwd, filePath, JSON.stringify(record2), `chore(activity): ${record2.action}`);
6950
6867
  }
6951
6868
  var appendCompanyActivity;
6952
6869
  var init_appendCompanyActivity = __esm({
@@ -6962,7 +6879,7 @@ var init_appendCompanyActivity = __esm({
6962
6879
  const agent = ctx.data.agentSlug || null;
6963
6880
  const agentTitle = ctx.data.agentTitle || null;
6964
6881
  const force = ctx.args?.force === true;
6965
- const record = {
6882
+ const record2 = {
6966
6883
  ts: (/* @__PURE__ */ new Date()).toISOString(),
6967
6884
  action: `Ran agentResponsibility: ${agentResponsibilityTitle ?? agentResponsibility}`,
6968
6885
  agentResponsibility,
@@ -6976,7 +6893,7 @@ var init_appendCompanyActivity = __esm({
6976
6893
  durationMs: agentResult?.durationMs ?? null,
6977
6894
  runUrl: getRunUrl() || null
6978
6895
  };
6979
- appendLine(ctx, record);
6896
+ appendLine(ctx, record2);
6980
6897
  } catch (err) {
6981
6898
  process.stderr.write(
6982
6899
  `[activity] company-activity append failed: ${err instanceof Error ? err.message : String(err)}
@@ -6987,6 +6904,338 @@ var init_appendCompanyActivity = __esm({
6987
6904
  }
6988
6905
  });
6989
6906
 
6907
+ // src/companyManagerDecision.ts
6908
+ function parseCompanyManagerDecisionText(finalText) {
6909
+ const raw = extractDecisionJson(finalText);
6910
+ const parsed = JSON.parse(raw);
6911
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
6912
+ throw new Error("company-manager decision must be JSON object");
6913
+ }
6914
+ const input = parsed;
6915
+ const actions = Array.isArray(input.actions) ? input.actions.map(parseAction) : [];
6916
+ return {
6917
+ summary: typeof input.summary === "string" ? input.summary.trim() : "",
6918
+ actions
6919
+ };
6920
+ }
6921
+ function buildManagedGoalState(action) {
6922
+ const at = nowIso();
6923
+ return {
6924
+ state: "active",
6925
+ createdAt: at,
6926
+ updatedAt: at,
6927
+ extra: {
6928
+ type: action.goalType ?? "release",
6929
+ destination: { outcome: action.outcome, evidence: action.evidence },
6930
+ agentResponsibilities: action.agentResponsibilities,
6931
+ route: action.route,
6932
+ facts: action.facts ?? {},
6933
+ blockers: [],
6934
+ createdByIntent: action.intentId,
6935
+ manager: "cto"
6936
+ }
6937
+ };
6938
+ }
6939
+ function buildAgentLoopState(action) {
6940
+ const at = nowIso();
6941
+ return {
6942
+ state: "active",
6943
+ createdAt: at,
6944
+ updatedAt: at,
6945
+ extra: {
6946
+ type: "agentLoop",
6947
+ scheduleMode: "agentLoop",
6948
+ schedule: action.every,
6949
+ destination: { outcome: action.outcome, evidence: [] },
6950
+ agentResponsibilities: action.agentResponsibilities,
6951
+ route: [],
6952
+ facts: {},
6953
+ blockers: [],
6954
+ createdByIntent: action.intentId,
6955
+ manager: "cto"
6956
+ }
6957
+ };
6958
+ }
6959
+ function extractDecisionJson(finalText) {
6960
+ const fence = finalText.match(/```(?:kody-company-manager-decision|json)\s*([\s\S]*?)```/i);
6961
+ if (fence?.[1]) return fence[1].trim();
6962
+ const line = finalText.match(/KODY_COMPANY_MANAGER_DECISION=(\{[\s\S]*\})/);
6963
+ if (line?.[1]) return line[1].trim();
6964
+ throw new Error("missing kody-company-manager-decision JSON");
6965
+ }
6966
+ function parseAction(value) {
6967
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
6968
+ throw new Error("company-manager action must be object");
6969
+ }
6970
+ const input = value;
6971
+ const kind = input.kind;
6972
+ if (kind === "createManagedGoal") return parseCreateManagedGoal(input);
6973
+ if (kind === "createAgentLoop") return parseCreateAgentLoop(input);
6974
+ if (kind === "setGoalLifecycle") return parseSetGoalLifecycle(input);
6975
+ if (kind === "updateIntentPortfolio") return parseUpdateIntentPortfolio(input);
6976
+ if (kind === "note") return parseNote(input);
6977
+ throw new Error(`unsupported company-manager action kind: ${String(kind)}`);
6978
+ }
6979
+ function parseCreateManagedGoal(input) {
6980
+ const route = Array.isArray(input.route) ? input.route.map(parseRouteStep) : [];
6981
+ if (route.length === 0) throw new Error("createManagedGoal requires route");
6982
+ const evidence = stringArray2(input.evidence);
6983
+ if (evidence.length === 0) throw new Error("createManagedGoal requires evidence");
6984
+ return {
6985
+ kind: "createManagedGoal",
6986
+ intentId: slug(input.intentId, "intentId"),
6987
+ id: slug(input.id, "id"),
6988
+ outcome: requiredString(input.outcome, "outcome"),
6989
+ goalType: typeof input.goalType === "string" && input.goalType.trim() ? input.goalType.trim() : void 0,
6990
+ evidence,
6991
+ agentResponsibilities: nonEmptyStringArray(input.agentResponsibilities, "agentResponsibilities"),
6992
+ route,
6993
+ facts: record(input.facts) ?? {},
6994
+ reason: requiredString(input.reason, "reason")
6995
+ };
6996
+ }
6997
+ function parseCreateAgentLoop(input) {
6998
+ return {
6999
+ kind: "createAgentLoop",
7000
+ intentId: slug(input.intentId, "intentId"),
7001
+ id: slug(input.id, "id"),
7002
+ outcome: requiredString(input.outcome, "outcome"),
7003
+ every: oneOf(input.every, ["manual", "1h", "1d", "7d", "30d"], "1d"),
7004
+ agentResponsibilities: nonEmptyStringArray(input.agentResponsibilities, "agentResponsibilities"),
7005
+ reason: requiredString(input.reason, "reason")
7006
+ };
7007
+ }
7008
+ function parseSetGoalLifecycle(input) {
7009
+ return {
7010
+ kind: "setGoalLifecycle",
7011
+ intentId: slug(input.intentId, "intentId"),
7012
+ id: slug(input.id, "id"),
7013
+ state: oneOf(input.state, ["active", "closed", "abandoned"], "active"),
7014
+ reason: requiredString(input.reason, "reason")
7015
+ };
7016
+ }
7017
+ function parseUpdateIntentPortfolio(input) {
7018
+ return {
7019
+ kind: "updateIntentPortfolio",
7020
+ intentId: slug(input.intentId, "intentId"),
7021
+ goals: stringArray2(input.goals).filter(isSlug),
7022
+ loops: stringArray2(input.loops).filter(isSlug),
7023
+ responsibilities: stringArray2(input.responsibilities).filter(isSlug),
7024
+ reason: requiredString(input.reason, "reason")
7025
+ };
7026
+ }
7027
+ function parseNote(input) {
7028
+ return {
7029
+ kind: "note",
7030
+ intentId: typeof input.intentId === "string" && isSlug(input.intentId) ? input.intentId : void 0,
7031
+ message: requiredString(input.message ?? input.content, "message")
7032
+ };
7033
+ }
7034
+ function parseRouteStep(value) {
7035
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("route step must be object");
7036
+ const input = value;
7037
+ return {
7038
+ stage: requiredString(input.stage, "route.stage"),
7039
+ evidence: requiredString(input.evidence, "route.evidence"),
7040
+ agentResponsibility: slug(input.agentResponsibility, "route.agentResponsibility"),
7041
+ ...typeof input.agentAction === "string" && input.agentAction.trim() ? { agentAction: input.agentAction.trim() } : {},
7042
+ ...record(input.args) ? { args: record(input.args) } : {}
7043
+ };
7044
+ }
7045
+ function slug(value, field) {
7046
+ const text = requiredString(value, field);
7047
+ if (!isSlug(text)) throw new Error(`${field} must be lowercase slug`);
7048
+ return text;
7049
+ }
7050
+ function isSlug(value) {
7051
+ return SLUG_RE.test(value);
7052
+ }
7053
+ function requiredString(value, field) {
7054
+ if (typeof value !== "string" || !value.trim()) throw new Error(`${field} is required`);
7055
+ return value.trim();
7056
+ }
7057
+ function stringArray2(value) {
7058
+ if (!Array.isArray(value)) return [];
7059
+ return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
7060
+ }
7061
+ function nonEmptyStringArray(value, field) {
7062
+ const values = stringArray2(value);
7063
+ if (values.length === 0) throw new Error(`${field} must not be empty`);
7064
+ return values;
7065
+ }
7066
+ function record(value) {
7067
+ return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : null;
7068
+ }
7069
+ function oneOf(value, allowed, fallback) {
7070
+ return typeof value === "string" && allowed.includes(value) ? value : fallback;
7071
+ }
7072
+ var SLUG_RE;
7073
+ var init_companyManagerDecision = __esm({
7074
+ "src/companyManagerDecision.ts"() {
7075
+ "use strict";
7076
+ init_state2();
7077
+ SLUG_RE = /^[a-z][a-z0-9-]{0,63}$/;
7078
+ }
7079
+ });
7080
+
7081
+ // src/companyIntent.ts
7082
+ function isCompanyIntentId(value) {
7083
+ return SLUG_RE2.test(value);
7084
+ }
7085
+ function companyIntentPath(id) {
7086
+ assertIntentId(id);
7087
+ return `intents/${id}/intent.json`;
7088
+ }
7089
+ function normalizeCompanyIntent(path46, raw) {
7090
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
7091
+ throw new Error(`${path46}: intent must be JSON object`);
7092
+ }
7093
+ const input = raw;
7094
+ const id = stringField2(input.id);
7095
+ if (!id || !isCompanyIntentId(id)) throw new Error(`${path46}: invalid intent id`);
7096
+ const createdAt = stringField2(input.createdAt) || nowIso();
7097
+ const updatedAt = stringField2(input.updatedAt) || createdAt;
7098
+ return {
7099
+ version: 1,
7100
+ id,
7101
+ status: oneOf2(input.status, ["active", "paused", "archived"], "active"),
7102
+ for: stringField2(input.for),
7103
+ priority: numberField(input.priority, 100),
7104
+ posture: oneOf2(
7105
+ input.posture,
7106
+ ["confidence", "speed", "stability-recovery", "maintenance", "balanced"],
7107
+ "balanced"
7108
+ ),
7109
+ scope: {
7110
+ repos: stringArray3(recordField(input.scope)?.repos),
7111
+ areas: stringArray3(recordField(input.scope)?.areas)
7112
+ },
7113
+ principles: stringArray3(input.principles),
7114
+ metrics: stringArray3(input.metrics),
7115
+ policy: {
7116
+ release: normalizeReleasePolicy(recordField(recordField(input.policy)?.release)),
7117
+ automation: normalizeAutomationPolicy(recordField(recordField(input.policy)?.automation))
7118
+ },
7119
+ portfolio: {
7120
+ goals: stringArray3(recordField(input.portfolio)?.goals).filter(isCompanyIntentId),
7121
+ loops: stringArray3(recordField(input.portfolio)?.loops).filter(isCompanyIntentId),
7122
+ responsibilities: stringArray3(recordField(input.portfolio)?.responsibilities).filter(isCompanyIntentId)
7123
+ },
7124
+ manager: normalizeManager(recordField(input.manager)),
7125
+ createdAt,
7126
+ updatedAt
7127
+ };
7128
+ }
7129
+ function listCompanyIntents(config, cwd) {
7130
+ const entries = listStateDirectory(config, cwd, "intents");
7131
+ const records = [];
7132
+ for (const entry of entries) {
7133
+ if (entry.type !== "dir" || !entry.name || !isCompanyIntentId(entry.name)) continue;
7134
+ const path46 = companyIntentPath(entry.name);
7135
+ const file = readStateText(config, cwd, path46);
7136
+ if (!file) continue;
7137
+ records.push({
7138
+ id: entry.name,
7139
+ path: file.path,
7140
+ intent: normalizeCompanyIntent(file.path, JSON.parse(file.content))
7141
+ });
7142
+ }
7143
+ return records.sort((a, b) => a.intent.priority - b.intent.priority || a.id.localeCompare(b.id));
7144
+ }
7145
+ function readCompanyIntent(config, cwd, id) {
7146
+ const path46 = companyIntentPath(id);
7147
+ const file = readStateText(config, cwd, path46);
7148
+ if (!file) return null;
7149
+ return { id, path: file.path, intent: normalizeCompanyIntent(file.path, JSON.parse(file.content)) };
7150
+ }
7151
+ function writeCompanyIntent(config, cwd, intent, message = `chore(intents): update ${intent.id}`) {
7152
+ upsertStateText(config, cwd, companyIntentPath(intent.id), `${JSON.stringify(intent, null, 2)}
7153
+ `, message);
7154
+ }
7155
+ function appendCompanyIntentDecision(config, cwd, intentId, entry) {
7156
+ assertIntentId(intentId);
7157
+ appendStateLine(config, cwd, `intents/${intentId}/decisions.jsonl`, JSON.stringify(entry), `chore(intents): log ${intentId} decision`);
7158
+ }
7159
+ function listCompanyPortfolio(config, cwd) {
7160
+ const entries = listStateDirectory(config, cwd, "goals/instances");
7161
+ const goals = [];
7162
+ for (const entry of entries) {
7163
+ if (entry.type !== "dir" || !entry.name || !isCompanyIntentId(entry.name)) continue;
7164
+ const file = readStateText(config, cwd, `goals/instances/${entry.name}/state.json`);
7165
+ if (!file) continue;
7166
+ const state = parseGoalState(file.path, JSON.parse(file.content));
7167
+ const destination = recordField(state.extra.destination);
7168
+ goals.push({
7169
+ id: entry.name,
7170
+ state: state.state,
7171
+ type: stringField2(state.extra.type) || void 0,
7172
+ outcome: stringField2(destination?.outcome) || void 0,
7173
+ agentResponsibilities: stringArray3(state.extra.agentResponsibilities),
7174
+ isLoop: state.extra.scheduleMode === "agentLoop" || state.extra.type === "agentLoop",
7175
+ updatedAt: state.updatedAt
7176
+ });
7177
+ }
7178
+ return { goals: goals.sort((a, b) => a.id.localeCompare(b.id)) };
7179
+ }
7180
+ function writeCompanyGoalState(config, cwd, id, state, message) {
7181
+ assertIntentId(id);
7182
+ upsertStateText(config, cwd, `goals/instances/${id}/state.json`, serializeGoalState(state), message);
7183
+ }
7184
+ function assertIntentId(id) {
7185
+ if (!isCompanyIntentId(id)) throw new Error(`invalid intent/portfolio id: ${id}`);
7186
+ }
7187
+ function stringField2(value) {
7188
+ return typeof value === "string" ? value.trim() : "";
7189
+ }
7190
+ function numberField(value, fallback) {
7191
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
7192
+ }
7193
+ function recordField(value) {
7194
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
7195
+ }
7196
+ function stringArray3(value) {
7197
+ if (!Array.isArray(value)) return [];
7198
+ return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
7199
+ }
7200
+ function oneOf2(value, allowed, fallback) {
7201
+ return typeof value === "string" && allowed.includes(value) ? value : fallback;
7202
+ }
7203
+ function normalizeReleasePolicy(raw) {
7204
+ if (!raw) return void 0;
7205
+ return {
7206
+ cadence: oneOf2(raw.cadence, ["manual", "1d", "1w"], "manual"),
7207
+ qaDepth: oneOf2(raw.qaDepth, ["light", "standard", "strict"], "standard"),
7208
+ blockerLevel: oneOf2(raw.blockerLevel, ["low", "standard", "strict"], "standard"),
7209
+ approval: oneOf2(raw.approval, ["none", "before-production", "before-risky-actions"], "before-risky-actions")
7210
+ };
7211
+ }
7212
+ function normalizeAutomationPolicy(raw) {
7213
+ return {
7214
+ authority: "full-auto",
7215
+ maxConcurrentGoals: Math.max(1, Math.floor(numberField(raw?.maxConcurrentGoals, 1))),
7216
+ maxDailyActions: Math.max(1, Math.floor(numberField(raw?.maxDailyActions, 6))),
7217
+ requiresHumanFor: stringArray3(raw?.requiresHumanFor)
7218
+ };
7219
+ }
7220
+ function normalizeManager(raw) {
7221
+ return {
7222
+ agent: "cto",
7223
+ loop: "company-manager-loop",
7224
+ responsibility: "company-manager",
7225
+ reviewEvery: oneOf2(raw?.reviewEvery, ["1d", "1w"], "1d"),
7226
+ ...typeof raw?.lastReviewedAt === "string" ? { lastReviewedAt: raw.lastReviewedAt } : {}
7227
+ };
7228
+ }
7229
+ var SLUG_RE2;
7230
+ var init_companyIntent = __esm({
7231
+ "src/companyIntent.ts"() {
7232
+ "use strict";
7233
+ init_state2();
7234
+ init_stateRepo();
7235
+ SLUG_RE2 = /^[a-z][a-z0-9-]{0,63}$/;
7236
+ }
7237
+ });
7238
+
6990
7239
  // src/goal/stateStore.ts
6991
7240
  function statePath(goalId) {
6992
7241
  return `goals/instances/${goalId}/state.json`;
@@ -7008,6 +7257,133 @@ var init_stateStore = __esm({
7008
7257
  }
7009
7258
  });
7010
7259
 
7260
+ // src/scripts/applyCompanyManagerDecision.ts
7261
+ function applyAction(config, cwd, action) {
7262
+ if (action.kind === "createManagedGoal") {
7263
+ const existing = fetchGoalState(config, action.id, cwd);
7264
+ if (existing) return applied(action, false, "goal already exists");
7265
+ writeCompanyGoalState(config, cwd, action.id, buildManagedGoalState(action), `chore(goals): create ${action.id} from intent ${action.intentId}`);
7266
+ return applied(action, true, action.reason, action.id);
7267
+ }
7268
+ if (action.kind === "createAgentLoop") {
7269
+ const existing = fetchGoalState(config, action.id, cwd);
7270
+ if (existing) return applied(action, false, "loop already exists");
7271
+ writeCompanyGoalState(config, cwd, action.id, buildAgentLoopState(action), `chore(goals): create loop ${action.id} from intent ${action.intentId}`);
7272
+ return applied(action, true, action.reason, action.id);
7273
+ }
7274
+ if (action.kind === "setGoalLifecycle") {
7275
+ const state = fetchGoalState(config, action.id, cwd);
7276
+ if (!state) return applied(action, false, "goal/loop missing", action.id);
7277
+ const before = state.state;
7278
+ if (before === action.state) return applied(action, false, "state already set", action.id);
7279
+ const next = {
7280
+ ...state,
7281
+ state: action.state,
7282
+ updatedAt: nowIso(),
7283
+ extra: {
7284
+ ...state.extra,
7285
+ lifecycleChangedByIntent: action.intentId,
7286
+ lifecycleChangeReason: action.reason
7287
+ }
7288
+ };
7289
+ writeCompanyGoalState(config, cwd, action.id, next, `chore(goals): ${action.state} ${action.id} from intent ${action.intentId}`);
7290
+ return applied(action, true, action.reason, action.id);
7291
+ }
7292
+ if (action.kind === "updateIntentPortfolio") {
7293
+ const record2 = readCompanyIntent(config, cwd, action.intentId);
7294
+ if (!record2) return applied(action, false, "intent missing");
7295
+ const intent = {
7296
+ ...record2.intent,
7297
+ portfolio: {
7298
+ goals: mergeUnique(record2.intent.portfolio.goals, action.goals ?? []),
7299
+ loops: mergeUnique(record2.intent.portfolio.loops, action.loops ?? []),
7300
+ responsibilities: mergeUnique(record2.intent.portfolio.responsibilities, action.responsibilities ?? [])
7301
+ },
7302
+ updatedAt: nowIso()
7303
+ };
7304
+ writeCompanyIntent(config, cwd, intent, `chore(intents): update ${action.intentId} portfolio`);
7305
+ return applied(action, true, action.reason);
7306
+ }
7307
+ if (action.kind === "note") {
7308
+ return {
7309
+ kind: action.kind,
7310
+ intentId: action.intentId,
7311
+ changed: false,
7312
+ reason: action.message
7313
+ };
7314
+ }
7315
+ return { kind: "unknown", changed: false, reason: "unsupported action" };
7316
+ }
7317
+ function applied(action, changed, reason, resource) {
7318
+ return {
7319
+ kind: action.kind,
7320
+ intentId: "intentId" in action ? action.intentId : void 0,
7321
+ resource,
7322
+ changed,
7323
+ reason
7324
+ };
7325
+ }
7326
+ function mergeUnique(left, right) {
7327
+ return [.../* @__PURE__ */ new Set([...left, ...right])].sort();
7328
+ }
7329
+ function logAppliedCompanyManagerActions(config, cwd, appliedActions) {
7330
+ const at = nowIso();
7331
+ for (const action of appliedActions) {
7332
+ if (!action.intentId) continue;
7333
+ appendCompanyIntentDecision(config, cwd, action.intentId, {
7334
+ at,
7335
+ agent: "cto",
7336
+ intentId: action.intentId,
7337
+ action: action.kind,
7338
+ reason: action.reason,
7339
+ after: { changed: action.changed },
7340
+ resources: action.resource ? [action.resource] : []
7341
+ });
7342
+ }
7343
+ }
7344
+ var applyCompanyManagerDecision;
7345
+ var init_applyCompanyManagerDecision = __esm({
7346
+ "src/scripts/applyCompanyManagerDecision.ts"() {
7347
+ "use strict";
7348
+ init_companyManagerDecision();
7349
+ init_companyIntent();
7350
+ init_stateStore();
7351
+ init_state2();
7352
+ applyCompanyManagerDecision = async (ctx) => {
7353
+ const decision = ctx.data.companyManagerDecision;
7354
+ if (!decision || !Array.isArray(decision.actions)) return;
7355
+ if (ctx.output.exitCode !== 0) return;
7356
+ const applied2 = [];
7357
+ for (const action of decision.actions) {
7358
+ applied2.push(applyAction(ctx.config, ctx.cwd, action));
7359
+ }
7360
+ ctx.data.companyManagerApplied = applied2;
7361
+ ctx.data.companyManagerApplySummary = `company-manager applied ${applied2.filter((item) => item.changed).length}/${applied2.length} action(s)`;
7362
+ };
7363
+ }
7364
+ });
7365
+
7366
+ // src/scripts/appendCompanyIntentDecision.ts
7367
+ var appendCompanyIntentDecision2;
7368
+ var init_appendCompanyIntentDecision = __esm({
7369
+ "src/scripts/appendCompanyIntentDecision.ts"() {
7370
+ "use strict";
7371
+ init_applyCompanyManagerDecision();
7372
+ appendCompanyIntentDecision2 = async (ctx) => {
7373
+ const applied2 = ctx.data.companyManagerApplied;
7374
+ if (!applied2 || applied2.length === 0) return;
7375
+ try {
7376
+ logAppliedCompanyManagerActions(ctx.config, ctx.cwd, applied2);
7377
+ } catch (err) {
7378
+ process.stderr.write(
7379
+ `[company-manager] failed append intent decision log: ${err instanceof Error ? err.message : String(err)}
7380
+ `
7381
+ );
7382
+ }
7383
+ };
7384
+ }
7385
+ });
7386
+
7011
7387
  // src/scripts/applyAgentResponsibilityReports.ts
7012
7388
  function collectReports(raw, agentResult) {
7013
7389
  const out = [];
@@ -8214,7 +8590,7 @@ function discoverPayloadCollections(cwd) {
8214
8590
  const content = fs29.readFileSync(filePath, "utf-8").slice(0, 1e4);
8215
8591
  const slugMatch = content.match(/slug:\s*['"]([a-z0-9-]+)['"]/);
8216
8592
  if (!slugMatch) continue;
8217
- const slug = slugMatch[1];
8593
+ const slug2 = slugMatch[1];
8218
8594
  const name = file.replace(/\.(ts|tsx)$/, "");
8219
8595
  const fields = [];
8220
8596
  const fieldMatches = content.matchAll(/name:\s*['"]([a-zA-Z_][a-zA-Z0-9_]*)['"]/g);
@@ -8224,7 +8600,7 @@ function discoverPayloadCollections(cwd) {
8224
8600
  const hasAdmin = /components:\s*\{/.test(content) || /Field:\s*['"]/.test(content) || /Cell:\s*['"]/.test(content) || /views:\s*\{/.test(content);
8225
8601
  out.push({
8226
8602
  name,
8227
- slug,
8603
+ slug: slug2,
8228
8604
  filePath: path29.relative(cwd, filePath),
8229
8605
  fields: fields.slice(0, 20),
8230
8606
  hasAdmin
@@ -8621,425 +8997,34 @@ var init_dispatch = __esm({
8621
8997
  };
8622
8998
  ctx.data.action = action;
8623
8999
  if (state) state.core.lastOutcome = action;
8624
- return;
8625
- }
8626
- if (state?.flow) {
8627
- state.flow.step = next;
8628
- }
8629
- const usePr = target === "pr" && state?.core.prUrl;
8630
- const targetNumber = usePr ? parsePr(state.core.prUrl) ?? issueNumber : issueNumber;
8631
- ctx.output.nextDispatch = {
8632
- action: next,
8633
- cliArgs: usePr ? { pr: targetNumber } : { issue: targetNumber }
8634
- };
8635
- };
8636
- }
8637
- });
8638
-
8639
- // src/jobIdentity.ts
8640
- function stableJobKey(job) {
8641
- const agentResponsibility = job.agentResponsibility ?? job.action;
8642
- const agentAction = job.agentAction ?? agentResponsibility ?? "unknown";
8643
- if (job.flavor === "scheduled" && job.agentResponsibility)
8644
- return `scheduled:${job.agentResponsibility}:${agentAction}`;
8645
- const target = typeof job.target === "number" ? job.target : targetFromCliArgs(job.cliArgs);
8646
- const work = agentResponsibility && agentAction && agentAction !== agentResponsibility ? `${agentResponsibility}:${agentAction}` : agentResponsibility ?? agentAction;
8647
- return target === void 0 ? `${job.flavor}:${work}` : `${job.flavor}:${work}:${target}`;
8648
- }
8649
- function targetFromCliArgs(cliArgs) {
8650
- if (!cliArgs) return void 0;
8651
- for (const key of ["issue", "pr", "target", "issue_number"]) {
8652
- const value = cliArgs[key];
8653
- if (typeof value === "number" && Number.isFinite(value)) return value;
8654
- }
8655
- return void 0;
8656
- }
8657
- var init_jobIdentity = __esm({
8658
- "src/jobIdentity.ts"() {
8659
- "use strict";
8660
- }
8661
- });
8662
-
8663
- // src/scripts/planTaskJobs.ts
8664
- function parseTaskJobSpecs(body) {
8665
- const match = body.match(new RegExp(`<!--\\s*${TASK_JOBS_MARKER}\\s*([\\s\\S]*?)-->`));
8666
- if (!match) return [];
8667
- let parsed;
8668
- try {
8669
- parsed = JSON.parse(match[1].trim());
8670
- } catch (err) {
8671
- throw new Error(`task job plan is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
8672
- }
8673
- if (!Array.isArray(parsed)) throw new Error("task job plan must be a JSON array");
8674
- return parsed.map((entry, index) => normalizeSpec(entry, index));
8675
- }
8676
- function taskJobSpecToJob(spec, issueNumber) {
8677
- const cliArgs = spec.cliArgs ?? { issue: issueNumber };
8678
- const target = typeof spec.target === "number" ? spec.target : targetFromCliArgs(cliArgs) ?? issueNumber;
8679
- return {
8680
- agentResponsibility: spec.agentResponsibility ?? spec.agentAction,
8681
- agentAction: spec.agentAction,
8682
- why: spec.reason,
8683
- agent: spec.agent,
8684
- schedule: spec.schedule,
8685
- target,
8686
- cliArgs,
8687
- flavor: spec.flavor ?? "instant"
8688
- };
8689
- }
8690
- function normalizeSpec(input, index) {
8691
- if (!input || typeof input !== "object" || Array.isArray(input)) {
8692
- throw new Error(`task job plan entry ${index} must be an object`);
8693
- }
8694
- const raw = input;
8695
- const agentAction = typeof raw.agentAction === "string" ? raw.agentAction.trim() : "";
8696
- if (!/^[a-z][a-z0-9-]*$/.test(agentAction)) {
8697
- throw new Error(`task job plan entry ${index} must have a valid agentAction`);
8698
- }
8699
- const cliArgs = raw.cliArgs;
8700
- if (cliArgs !== void 0 && (!cliArgs || typeof cliArgs !== "object" || Array.isArray(cliArgs))) {
8701
- throw new Error(`task job plan entry ${index} cliArgs must be an object`);
8702
- }
8703
- const flavor = raw.flavor;
8704
- if (flavor !== void 0 && flavor !== "instant" && flavor !== "scheduled") {
8705
- throw new Error(`task job plan entry ${index} flavor must be "instant" or "scheduled"`);
8706
- }
8707
- return {
8708
- agentAction,
8709
- ...typeof raw.agentResponsibility === "string" && raw.agentResponsibility.trim() ? { agentResponsibility: raw.agentResponsibility.trim() } : {},
8710
- ...typeof raw.reason === "string" && raw.reason.trim() ? { reason: raw.reason.trim() } : {},
8711
- ...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
8712
- ...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
8713
- ...cliArgs ? { cliArgs } : {},
8714
- ...typeof raw.target === "number" && Number.isFinite(raw.target) ? { target: raw.target } : {},
8715
- ...flavor === "instant" || flavor === "scheduled" ? { flavor } : {},
8716
- ...typeof raw.schedule === "string" && raw.schedule.trim() ? { schedule: raw.schedule.trim() } : {}
8717
- };
8718
- }
8719
- function jobToPlannedTaskJob(job) {
8720
- return {
8721
- id: stableJobKey(job),
8722
- agentAction: job.agentAction ?? job.agentResponsibility ?? "unknown",
8723
- agentResponsibility: job.agentResponsibility ?? job.action ?? job.agentAction ?? "unknown",
8724
- ...job.agent ? { agent: job.agent } : {},
8725
- ...job.flavor ? { flavor: job.flavor } : {},
8726
- ...job.schedule ? { schedule: job.schedule } : {},
8727
- ...typeof job.target === "number" ? { target: job.target } : {},
8728
- ...job.why ? { reason: job.why } : {}
8729
- };
8730
- }
8731
- function assertUniqueJobIds(planned) {
8732
- const seen = /* @__PURE__ */ new Set();
8733
- for (const job of planned) {
8734
- if (seen.has(job.id)) throw new Error(`duplicate planned task job id: ${job.id}`);
8735
- seen.add(job.id);
8736
- }
8737
- }
8738
- var TASK_JOBS_MARKER, planTaskJobs;
8739
- var init_planTaskJobs = __esm({
8740
- "src/scripts/planTaskJobs.ts"() {
8741
- "use strict";
8742
- init_jobIdentity();
8743
- init_state();
8744
- TASK_JOBS_MARKER = "kody:task-jobs:v1";
8745
- planTaskJobs = async (ctx) => {
8746
- const issueNumber = ctx.args.issue;
8747
- if (!issueNumber) {
8748
- ctx.skipAgent = true;
8749
- ctx.output.exitCode = 64;
8750
- ctx.output.reason = "planTaskJobs requires --issue";
8751
- return;
8752
- }
8753
- const issue = ctx.data.issue;
8754
- const specs = parseTaskJobSpecs(issue?.body ?? "");
8755
- if (specs.length === 0) {
8756
- ctx.skipAgent = true;
8757
- ctx.output.exitCode = 64;
8758
- ctx.output.reason = `no ${TASK_JOBS_MARKER} block found on issue #${issueNumber}`;
8759
- return;
8760
- }
8761
- const jobs = specs.map((spec) => taskJobSpecToJob(spec, issueNumber));
8762
- const planned = jobs.map(jobToPlannedTaskJob);
8763
- assertUniqueJobIds(planned);
8764
- const prior = ctx.data.taskState ?? emptyState();
8765
- const next = upsertTaskJobs(prior, planned, (/* @__PURE__ */ new Date()).toISOString());
8766
- ctx.data.taskState = next;
8767
- ctx.data.plannedTaskJobs = jobs;
8768
- ctx.data.plannedTaskJobIds = planned.map((job) => job.id);
8769
- const target = ctx.data.commentTargetType;
8770
- const number = ctx.data.commentTargetNumber;
8771
- if (target && number) writeTaskState(target, number, next, ctx.cwd, ctx.config);
8772
- };
8773
- }
8774
- });
8775
-
8776
- // src/scripts/dispatchAgentResponsibilityFileTicks.ts
8777
- import * as path31 from "path";
8778
- async function decideShouldFire(every, slug, backend, now) {
8779
- if (!every) return { skip: false, reason: "no schedule (every cron tick)" };
8780
- if (every === "manual") {
8781
- return { skip: true, reason: "manual-only (no auto-fire; trigger via dashboard Run now)" };
8782
- }
8783
- let lastFiredAt = null;
8784
- try {
8785
- const loaded = await backend.load(slug);
8786
- const raw = loaded.state.data?.lastFiredAt;
8787
- if (typeof raw === "string") {
8788
- const ms = Date.parse(raw);
8789
- if (!Number.isNaN(ms)) lastFiredAt = ms;
8790
- }
8791
- } catch {
8792
- return { skip: false, reason: "state unreadable; firing" };
8793
- }
8794
- if (lastFiredAt === null) {
8795
- return { skip: false, reason: `first tick (every ${every})` };
8796
- }
8797
- const intervalMs = scheduleEveryToMs(every);
8798
- const elapsedMs = now - lastFiredAt;
8799
- if (elapsedMs >= intervalMs) {
8800
- return { skip: false, reason: `due (every ${every}, last ${formatAgo(elapsedMs)} ago)` };
8801
- }
8802
- const remainingMs = intervalMs - elapsedMs;
8803
- return {
8804
- skip: true,
8805
- reason: `every ${every}; ${formatAgo(elapsedMs)} since last tick, next in ${formatAgo(remainingMs)}`
8806
- };
8807
- }
8808
- function formatAgo(ms) {
8809
- const sec = Math.max(0, Math.round(ms / 1e3));
8810
- if (sec < 60) return `${sec}s`;
8811
- const min = Math.round(sec / 60);
8812
- if (min < 60) return `${min}m`;
8813
- const hr = Math.round(min / 60);
8814
- if (hr < 48) return `${hr}h`;
8815
- const day = Math.round(hr / 24);
8816
- return `${day}d`;
8817
- }
8818
- function parseAgentResponsibilityFilter(raw) {
8819
- return typeof raw === "string" && raw.trim().length > 0 ? raw.trim() : void 0;
8820
- }
8821
- function filterSlugs(slugs, onlyAgentResponsibility) {
8822
- return onlyAgentResponsibility ? slugs.filter((slug) => slug === onlyAgentResponsibility) : slugs;
8823
- }
8824
- function listActivatedAgentResponsibilitySlugs(projectRoot, storeRoot, activeStoreAgentResponsibilities) {
8825
- const seen = /* @__PURE__ */ new Set();
8826
- const out = [];
8827
- for (const slug of listAgentResponsibilityFolderSlugs(projectRoot)) {
8828
- if (seen.has(slug)) continue;
8829
- seen.add(slug);
8830
- out.push(slug);
8831
- }
8832
- const active = new Set(activeStoreAgentResponsibilities ?? []);
8833
- if (storeRoot && active.size > 0) {
8834
- for (const slug of listAgentResponsibilityFolderSlugs(storeRoot)) {
8835
- if (!active.has(slug) || seen.has(slug)) continue;
8836
- seen.add(slug);
8837
- out.push(slug);
8838
- }
8839
- }
8840
- return out.sort();
8841
- }
8842
- function createAgentResponsibilityTaskIssue(opts) {
8843
- const title = `AgentResponsibility ${opts.slug} - multi-agentAction task`;
8844
- const body = buildAgentResponsibilityTaskIssueBody(opts.slug, opts.body, opts.config);
8845
- const out = gh(["issue", "create", "--title", title, "--body-file", "-"], { input: body, cwd: opts.cwd });
8846
- const url = out.split("\n").map((line) => line.trim()).filter(Boolean).pop() ?? "";
8847
- const match = url.match(/\/issues\/(\d+)\b/);
8848
- if (!match) throw new Error(`gh issue create returned unexpected output: ${out}`);
8849
- return { number: Number(match[1]), url };
8850
- }
8851
- function buildAgentResponsibilityTaskIssueBody(slug, agentResponsibilityBody, config) {
8852
- const specs = (config.agentActions ?? []).map((agentAction) => ({
8853
- agentAction,
8854
- agentResponsibility: slug,
8855
- ...config.agent ? { agent: config.agent } : {},
8856
- reason: `AgentResponsibility \`${slug}\` slice for \`${agentAction}\`.`,
8857
- flavor: "scheduled",
8858
- ...config.every ? { schedule: config.every } : {}
8859
- }));
8860
- return [
8861
- `# AgentResponsibility task: ${slug}`,
8862
- "",
8863
- agentResponsibilityBody.trim() || "(no agentResponsibility body)",
8864
- "",
8865
- `<!-- ${TASK_JOBS_MARKER}`,
8866
- JSON.stringify(specs, null, 2),
8867
- "-->",
8868
- ""
8869
- ].join("\n");
8870
- }
8871
- async function stampFired(backend, slug, now, task) {
8872
- try {
8873
- const loaded = await backend.load(slug);
8874
- const nextData = {
8875
- ...loaded.state.data ?? {},
8876
- lastFiredAt: new Date(now).toISOString(),
8877
- ...task ? { lastTaskIssue: task.number, lastTaskUrl: task.url } : {}
8878
- };
8879
- await backend.save(loaded, { ...loaded.state, data: nextData });
8880
- } catch (err) {
8881
- process.stderr.write(`[jobs] failed to stamp lastFiredAt for ${slug}: ${String(err)}
8882
- `);
8883
- }
8884
- }
8885
- var dispatchAgentResponsibilityFileTicks;
8886
- var init_dispatchAgentResponsibilityFileTicks = __esm({
8887
- "src/scripts/dispatchAgentResponsibilityFileTicks.ts"() {
8888
- "use strict";
8889
- init_agent_responsibilityFolders();
8890
- init_issue();
8891
- init_job();
8892
- init_registry();
8893
- init_jobState();
8894
- init_planTaskJobs();
8895
- init_scheduleEvery();
8896
- dispatchAgentResponsibilityFileTicks = async (ctx, _profile, args) => {
8897
- ctx.skipAgent = true;
8898
- const targetAgentAction = String(args?.targetAgentAction ?? "");
8899
- if (!targetAgentAction) {
8900
- throw new Error("dispatchAgentResponsibilityFileTicks: `with.targetAgentAction` is required");
8901
- }
8902
- const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
8903
- const scriptedAgentAction = String(args?.scriptedAgentAction ?? "agent-responsibility-tick-scripted");
8904
- const slugArg = String(args?.slugArg ?? "agentResponsibility");
8905
- const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
8906
- if (backend.hydrate) {
8907
- await backend.hydrate();
8908
- }
8909
- try {
8910
- const onlyAgentResponsibility = parseAgentResponsibilityFilter(ctx.args.agentResponsibility);
8911
- if (args?.requireExplicitAgentResponsibility === true && !onlyAgentResponsibility) {
8912
- ctx.output.exitCode = 0;
8913
- ctx.output.reason = "scheduled agentResponsibility fan-out is owned by goal-scheduler";
8914
- process.stdout.write(
8915
- "[jobs] no flat agentResponsibility fan-out; goal-scheduler owns scheduled agentResponsibility decisions\n"
8916
- );
8917
- return;
8918
- }
8919
- const jobsPath = path31.join(ctx.cwd, jobsDir);
8920
- const storeJobsPath = getCompanyStoreAgentResponsibilitiesRoot();
8921
- const slugs = filterSlugs(
8922
- listActivatedAgentResponsibilitySlugs(jobsPath, storeJobsPath, ctx.config.company?.activeAgentResponsibilities),
8923
- onlyAgentResponsibility
8924
- );
8925
- ctx.data.jobSlugCount = slugs.length;
8926
- if (slugs.length === 0) {
8927
- const filter = onlyAgentResponsibility ? ` matching ${onlyAgentResponsibility}` : "";
8928
- process.stdout.write(`[jobs] no agentResponsibility folders${filter} in ${jobsDir}
8929
- `);
8930
- return;
8931
- }
8932
- const filtered = onlyAgentResponsibility ? ` matching ${onlyAgentResponsibility}` : "";
8933
- process.stdout.write(
8934
- `[jobs] ticking ${slugs.length} agent responsibility/ies${filtered} via ${targetAgentAction}
8935
- `
8936
- );
8937
- const results = [];
8938
- const now = Date.now();
8939
- for (const slug of slugs) {
8940
- const agentResponsibility = resolveAgentResponsibilityFolder(slug, jobsPath);
8941
- if (!agentResponsibility) {
8942
- process.stderr.write(
8943
- `[jobs] \u23ED skip ${slug}: agentResponsibility folder is missing profile.json or agent-responsibility.md
8944
- `
8945
- );
8946
- results.push({ slug, exitCode: 0, skipped: true, reason: "incomplete agentResponsibility folder" });
8947
- continue;
8948
- }
8949
- const config = agentResponsibility.config;
8950
- if (config.disabled === true) {
8951
- process.stdout.write(`[jobs] \u23ED skip ${slug}: disabled in profile.json
8952
- `);
8953
- results.push({ slug, exitCode: 0, skipped: true, reason: "disabled" });
8954
- continue;
8955
- }
8956
- if (!config.agent || config.agent.trim().length === 0) {
8957
- process.stderr.write(`[jobs] \u23ED skip ${slug}: no agent assigned (add "agent" to profile.json)
8958
- `);
8959
- results.push({ slug, exitCode: 0, skipped: true, reason: "no agent assigned" });
8960
- continue;
8961
- }
8962
- const decision = await decideShouldFire(config.every, slug, backend, now);
8963
- if (decision.skip) {
8964
- process.stdout.write(`[jobs] \u23ED skip ${slug}: ${decision.reason}
8965
- `);
8966
- results.push({ slug, exitCode: 0, skipped: true, reason: decision.reason });
8967
- continue;
8968
- }
8969
- if (config.agentActions && config.agentActions.length > 0) {
8970
- try {
8971
- const task = createAgentResponsibilityTaskIssue({
8972
- slug,
8973
- body: agentResponsibility.body,
8974
- config,
8975
- cwd: ctx.cwd
8976
- });
8977
- await stampFired(backend, slug, now, task);
8978
- process.stdout.write(`[jobs] \u2192 run ${slug} multi-agentAction task #${task.number} (task-jobs)
8979
- `);
8980
- const out = await runJob(
8981
- mintScheduledJob({
8982
- agentResponsibility: slug,
8983
- agentAction: "task-jobs",
8984
- schedule: config.every,
8985
- agent: config.agent,
8986
- cliArgs: { issue: task.number }
8987
- }),
8988
- { cwd: ctx.cwd, config: ctx.config, verbose: ctx.verbose, quiet: ctx.quiet }
8989
- );
8990
- results.push({ slug, exitCode: out.exitCode, reason: out.reason });
8991
- if (out.exitCode !== 0) {
8992
- process.stderr.write(`[jobs] task ${slug} failed (exit ${out.exitCode}): ${out.reason ?? ""}
8993
- `);
8994
- }
8995
- } catch (err) {
8996
- const msg = err instanceof Error ? err.message : String(err);
8997
- process.stderr.write(`[jobs] task ${slug} crashed: ${msg}
8998
- `);
8999
- results.push({ slug, exitCode: 99, reason: msg });
9000
- }
9001
- continue;
9002
- }
9003
- const slugTarget = config.tickScript ? scriptedAgentAction : config.agentAction ?? targetAgentAction;
9004
- const cliArgs = config.agentAction && !config.tickScript ? {} : { [slugArg]: slug };
9005
- process.stdout.write(`[jobs] \u2192 tick ${slug} (${slugTarget})
9006
- `);
9007
- try {
9008
- const out = await runJob(
9009
- mintScheduledJob({
9010
- agentResponsibility: slug,
9011
- agentAction: slugTarget,
9012
- schedule: config.every,
9013
- agent: config.agent,
9014
- cliArgs
9015
- }),
9016
- { cwd: ctx.cwd, config: ctx.config, verbose: ctx.verbose, quiet: ctx.quiet, chain: false }
9017
- );
9018
- results.push({ slug, exitCode: out.exitCode, reason: out.reason });
9019
- if (out.exitCode !== 0) {
9020
- process.stderr.write(`[jobs] tick ${slug} failed (exit ${out.exitCode}): ${out.reason ?? ""}
9021
- `);
9022
- }
9023
- } catch (err) {
9024
- const msg = err instanceof Error ? err.message : String(err);
9025
- process.stderr.write(`[jobs] tick ${slug} crashed: ${msg}
9026
- `);
9027
- results.push({ slug, exitCode: 99, reason: msg });
9028
- }
9029
- }
9030
- ctx.data.jobTickResults = results;
9031
- ctx.output.exitCode = 0;
9032
- } finally {
9033
- if (backend.persist) {
9034
- try {
9035
- await backend.persist();
9036
- } catch (err) {
9037
- const msg = err instanceof Error ? err.message : String(err);
9038
- process.stderr.write(`[jobs] backend persist failed: ${msg}
9039
- `);
9040
- }
9041
- }
9000
+ return;
9001
+ }
9002
+ if (state?.flow) {
9003
+ state.flow.step = next;
9042
9004
  }
9005
+ const usePr = target === "pr" && state?.core.prUrl;
9006
+ const targetNumber = usePr ? parsePr(state.core.prUrl) ?? issueNumber : issueNumber;
9007
+ ctx.output.nextDispatch = {
9008
+ action: next,
9009
+ cliArgs: usePr ? { pr: targetNumber } : { issue: targetNumber }
9010
+ };
9011
+ };
9012
+ }
9013
+ });
9014
+
9015
+ // src/scripts/dispatchAgentResponsibilityFileTicks.ts
9016
+ var dispatchAgentResponsibilityFileTicks;
9017
+ var init_dispatchAgentResponsibilityFileTicks = __esm({
9018
+ "src/scripts/dispatchAgentResponsibilityFileTicks.ts"() {
9019
+ "use strict";
9020
+ dispatchAgentResponsibilityFileTicks = async (ctx) => {
9021
+ ctx.skipAgent = true;
9022
+ ctx.data.jobTickResults = [];
9023
+ ctx.output.exitCode = 0;
9024
+ ctx.output.reason = "responsibility scheduling is owned by goals and loops";
9025
+ process.stdout.write(
9026
+ "[jobs] no flat agentResponsibility fan-out; goals and loops own scheduled responsibility decisions\n"
9027
+ );
9043
9028
  };
9044
9029
  }
9045
9030
  });
@@ -9147,6 +9132,30 @@ var init_dispatchClassified = __esm({
9147
9132
  }
9148
9133
  });
9149
9134
 
9135
+ // src/jobIdentity.ts
9136
+ function stableJobKey(job) {
9137
+ const agentResponsibility = job.agentResponsibility ?? job.action;
9138
+ const agentAction = job.agentAction ?? agentResponsibility ?? "unknown";
9139
+ if (job.flavor === "scheduled" && job.agentResponsibility)
9140
+ return `scheduled:${job.agentResponsibility}:${agentAction}`;
9141
+ const target = typeof job.target === "number" ? job.target : targetFromCliArgs(job.cliArgs);
9142
+ const work = agentResponsibility && agentAction && agentAction !== agentResponsibility ? `${agentResponsibility}:${agentAction}` : agentResponsibility ?? agentAction;
9143
+ return target === void 0 ? `${job.flavor}:${work}` : `${job.flavor}:${work}:${target}`;
9144
+ }
9145
+ function targetFromCliArgs(cliArgs) {
9146
+ if (!cliArgs) return void 0;
9147
+ for (const key of ["issue", "pr", "target", "issue_number"]) {
9148
+ const value = cliArgs[key];
9149
+ if (typeof value === "number" && Number.isFinite(value)) return value;
9150
+ }
9151
+ return void 0;
9152
+ }
9153
+ var init_jobIdentity = __esm({
9154
+ "src/jobIdentity.ts"() {
9155
+ "use strict";
9156
+ }
9157
+ });
9158
+
9150
9159
  // src/scripts/dispatchNextTaskJob.ts
9151
9160
  function taskJobToJob(job, issueArg) {
9152
9161
  const target = typeof job.target === "number" ? job.target : typeof issueArg === "number" ? issueArg : void 0;
@@ -9669,8 +9678,8 @@ function git3(args, cwd) {
9669
9678
  }).trim();
9670
9679
  }
9671
9680
  function deriveBranchName(issueNumber, title) {
9672
- const slug = title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 50).replace(/-$/, "");
9673
- return slug ? `${issueNumber}-${slug}` : `${issueNumber}-task`;
9681
+ const slug2 = title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 50).replace(/-$/, "");
9682
+ return slug2 ? `${issueNumber}-${slug2}` : `${issueNumber}-task`;
9674
9683
  }
9675
9684
  function getCurrentBranch(cwd) {
9676
9685
  return git3(["branch", "--show-current"], cwd);
@@ -10076,11 +10085,11 @@ var init_fixFlow = __esm({
10076
10085
  // src/scripts/initFlow.ts
10077
10086
  import { execFileSync as execFileSync15 } from "child_process";
10078
10087
  import * as fs31 from "fs";
10079
- import * as path32 from "path";
10088
+ import * as path31 from "path";
10080
10089
  function detectPackageManager(cwd) {
10081
- if (fs31.existsSync(path32.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
10082
- if (fs31.existsSync(path32.join(cwd, "yarn.lock"))) return "yarn";
10083
- if (fs31.existsSync(path32.join(cwd, "bun.lockb"))) return "bun";
10090
+ if (fs31.existsSync(path31.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
10091
+ if (fs31.existsSync(path31.join(cwd, "yarn.lock"))) return "yarn";
10092
+ if (fs31.existsSync(path31.join(cwd, "bun.lockb"))) return "bun";
10084
10093
  return "npm";
10085
10094
  }
10086
10095
  function qualityCommandsFor(pm) {
@@ -10152,7 +10161,7 @@ function performInit(cwd, force) {
10152
10161
  const pm = detectPackageManager(cwd);
10153
10162
  const ownerRepo = detectOwnerRepo(cwd);
10154
10163
  const defaultBranch2 = defaultBranchFromGit(cwd);
10155
- const configPath = path32.join(cwd, "kody.config.json");
10164
+ const configPath = path31.join(cwd, "kody.config.json");
10156
10165
  if (fs31.existsSync(configPath) && !force) {
10157
10166
  skipped.push("kody.config.json");
10158
10167
  } else {
@@ -10161,8 +10170,8 @@ function performInit(cwd, force) {
10161
10170
  `);
10162
10171
  wrote.push("kody.config.json");
10163
10172
  }
10164
- const workflowDir = path32.join(cwd, ".github", "workflows");
10165
- const workflowPath = path32.join(workflowDir, "kody.yml");
10173
+ const workflowDir = path31.join(cwd, ".github", "workflows");
10174
+ const workflowPath = path31.join(workflowDir, "kody.yml");
10166
10175
  if (fs31.existsSync(workflowPath) && !force) {
10167
10176
  skipped.push(".github/workflows/kody.yml");
10168
10177
  } else {
@@ -10170,8 +10179,8 @@ function performInit(cwd, force) {
10170
10179
  fs31.writeFileSync(workflowPath, WORKFLOW_TEMPLATE);
10171
10180
  wrote.push(".github/workflows/kody.yml");
10172
10181
  }
10173
- const agentsDir = path32.join(cwd, ".kody", "agents");
10174
- const agentPath = path32.join(agentsDir, "kody.md");
10182
+ const agentsDir = path31.join(cwd, ".kody", "agents");
10183
+ const agentPath = path31.join(agentsDir, "kody.md");
10175
10184
  if (fs31.existsSync(agentPath) && !force) {
10176
10185
  skipped.push(".kody/agents/kody.md");
10177
10186
  } else {
@@ -10187,7 +10196,7 @@ function performInit(cwd, force) {
10187
10196
  continue;
10188
10197
  }
10189
10198
  if (profile.kind !== "scheduled" || !profile.schedule) continue;
10190
- const target = path32.join(workflowDir, `kody-${exe.name}.yml`);
10199
+ const target = path31.join(workflowDir, `kody-${exe.name}.yml`);
10191
10200
  if (fs31.existsSync(target) && !force) {
10192
10201
  skipped.push(`.github/workflows/kody-${exe.name}.yml`);
10193
10202
  continue;
@@ -10385,7 +10394,7 @@ function stripDirective(body) {
10385
10394
  }
10386
10395
  return lines.slice(start).join("\n").trim();
10387
10396
  }
10388
- function parseAgentFile(raw, slug) {
10397
+ function parseAgentFile(raw, slug2) {
10389
10398
  const stripped = stripLeadingFrontmatter(raw);
10390
10399
  const trimmed = stripped.trim();
10391
10400
  const firstLine2 = trimmed.split("\n", 1)[0] ?? "";
@@ -10394,14 +10403,14 @@ function parseAgentFile(raw, slug) {
10394
10403
  const rest = trimmed.slice(firstLine2.length).replace(/^\n+/, "");
10395
10404
  return { title: h1[1].trim(), body: rest };
10396
10405
  }
10397
- return { title: humanizeSlug2(slug), body: trimmed };
10406
+ return { title: humanizeSlug2(slug2), body: trimmed };
10398
10407
  }
10399
10408
  function stripLeadingFrontmatter(raw) {
10400
10409
  const match = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/.exec(raw);
10401
10410
  return match ? raw.slice(match[0].length) : raw;
10402
10411
  }
10403
- function humanizeSlug2(slug) {
10404
- return slug.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
10412
+ function humanizeSlug2(slug2) {
10413
+ return slug2.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
10405
10414
  }
10406
10415
  var loadAgentAdhoc;
10407
10416
  var init_loadAgentAdhoc = __esm({
@@ -10444,19 +10453,19 @@ var init_loadAgentResponsibilityState = __esm({
10444
10453
  AGENT_RESPONSIBILITY_TOOL_PALETTE = new Set(AGENT_RESPONSIBILITY_MCP_TOOL_NAMES);
10445
10454
  loadAgentResponsibilityState = async (ctx, profile, args) => {
10446
10455
  const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
10447
- const slug = profile.name;
10456
+ const slug2 = profile.name;
10448
10457
  const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
10449
10458
  if (backend.hydrate) await backend.hydrate();
10450
- const loaded = await backend.load(slug);
10451
- ctx.data.jobSlug = slug;
10459
+ const loaded = await backend.load(slug2);
10460
+ ctx.data.jobSlug = slug2;
10452
10461
  ctx.data.jobState = loaded;
10453
10462
  ctx.data.jobStateJson = JSON.stringify(loaded.state, null, 2);
10454
- ctx.data.agentResponsibilitySlug = slug;
10463
+ ctx.data.agentResponsibilitySlug = slug2;
10455
10464
  ctx.data.agentResponsibilityTitle = profile.describe;
10456
10465
  ctx.data.agentActionSlug = profile.agentAction ?? profile.name;
10457
10466
  ctx.data.agentSlug = profile.agent ?? "";
10458
10467
  ctx.data.agentTitle = "";
10459
- ctx.data.agentResponsibilitySchedule = profile.every ?? profile.schedule ?? "";
10468
+ ctx.data.agentResponsibilitySchedule = String(ctx.data.jobSchedule ?? "");
10460
10469
  const mentions = (profile.mentions ?? []).map((l) => `@${l}`).join(" ");
10461
10470
  ctx.data.mentions = mentions;
10462
10471
  const declaredTools = profile.agentResponsibilityTools ?? [];
@@ -10464,7 +10473,7 @@ var init_loadAgentResponsibilityState = __esm({
10464
10473
  const unknown = declaredTools.filter((name) => !AGENT_RESPONSIBILITY_TOOL_PALETTE.has(name));
10465
10474
  if (unknown.length > 0) {
10466
10475
  throw new Error(
10467
- `loadAgentResponsibilityState: agentResponsibility '${slug}' declared agentResponsibilityTools not in the kody-agentResponsibility palette: ${unknown.join(", ")}. Available: ${[...AGENT_RESPONSIBILITY_MCP_TOOL_NAMES].join(", ")}`
10476
+ `loadAgentResponsibilityState: agentResponsibility '${slug2}' declared agentResponsibilityTools not in the kody-agentResponsibility palette: ${unknown.join(", ")}. Available: ${[...AGENT_RESPONSIBILITY_MCP_TOOL_NAMES].join(", ")}`
10468
10477
  );
10469
10478
  }
10470
10479
  ctx.data.agentResponsibilityTools = declaredTools;
@@ -10478,6 +10487,43 @@ var init_loadAgentResponsibilityState = __esm({
10478
10487
  }
10479
10488
  });
10480
10489
 
10490
+ // src/scripts/loadCompanyIntents.ts
10491
+ var loadCompanyIntents;
10492
+ var init_loadCompanyIntents = __esm({
10493
+ "src/scripts/loadCompanyIntents.ts"() {
10494
+ "use strict";
10495
+ init_companyIntent();
10496
+ loadCompanyIntents = async (ctx) => {
10497
+ const intents = listCompanyIntents(ctx.config, ctx.cwd);
10498
+ const active = intents.filter((record2) => record2.intent.status === "active");
10499
+ ctx.data.companyIntents = intents;
10500
+ ctx.data.companyActiveIntents = active;
10501
+ ctx.data.companyIntentsJson = JSON.stringify(
10502
+ active.map((record2) => record2.intent),
10503
+ null,
10504
+ 2
10505
+ );
10506
+ if (active.length === 0) {
10507
+ ctx.output.reason = "no active company intents";
10508
+ }
10509
+ };
10510
+ }
10511
+ });
10512
+
10513
+ // src/scripts/loadCompanyPortfolio.ts
10514
+ var loadCompanyPortfolio;
10515
+ var init_loadCompanyPortfolio = __esm({
10516
+ "src/scripts/loadCompanyPortfolio.ts"() {
10517
+ "use strict";
10518
+ init_companyIntent();
10519
+ loadCompanyPortfolio = async (ctx) => {
10520
+ const portfolio = listCompanyPortfolio(ctx.config, ctx.cwd);
10521
+ ctx.data.companyPortfolio = portfolio;
10522
+ ctx.data.companyPortfolioJson = JSON.stringify(portfolio, null, 2);
10523
+ };
10524
+ }
10525
+ });
10526
+
10481
10527
  // src/scripts/loadGoalState.ts
10482
10528
  function retryDelaysMs() {
10483
10529
  const raw = process.env.KODY_GOAL_STATE_RETRY_DELAYS_MS?.trim();
@@ -10620,8 +10666,8 @@ var init_loadIssueStateComment = __esm({
10620
10666
 
10621
10667
  // src/scripts/loadJobFromFile.ts
10622
10668
  import * as fs33 from "fs";
10623
- import * as path33 from "path";
10624
- function parseJobFile(raw, slug) {
10669
+ import * as path32 from "path";
10670
+ function parseJobFile(raw, slug2) {
10625
10671
  let stripped = raw;
10626
10672
  if (stripped.startsWith("---\n")) {
10627
10673
  const end = stripped.indexOf("\n---\n", 4);
@@ -10636,10 +10682,10 @@ function parseJobFile(raw, slug) {
10636
10682
  const rest = trimmed.slice(firstLine2.length).replace(/^\n+/, "");
10637
10683
  return { title: h1[1].trim(), body: rest };
10638
10684
  }
10639
- return { title: humanizeSlug3(slug), body: trimmed };
10685
+ return { title: humanizeSlug3(slug2), body: trimmed };
10640
10686
  }
10641
- function humanizeSlug3(slug) {
10642
- return slug.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
10687
+ function humanizeSlug3(slug2) {
10688
+ return slug2.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s[0].toUpperCase() + s.slice(1)).join(" ");
10643
10689
  }
10644
10690
  var AGENT_RESPONSIBILITY_TOOL_PALETTE2, loadJobFromFile;
10645
10691
  var init_loadJobFromFile = __esm({
@@ -10654,14 +10700,14 @@ var init_loadJobFromFile = __esm({
10654
10700
  const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
10655
10701
  const agentsDir = String(args?.agentsDir ?? ".kody/agents");
10656
10702
  const slugArg = String(args?.slugArg ?? "job");
10657
- const slug = String(ctx.args[slugArg] ?? "").trim();
10658
- if (!slug) {
10703
+ const slug2 = String(ctx.args[slugArg] ?? "").trim();
10704
+ if (!slug2) {
10659
10705
  throw new Error(`loadJobFromFile: ctx.args.${slugArg} must be a non-empty slug`);
10660
10706
  }
10661
- const agentResponsibility = resolveAgentResponsibilityFolder(slug, path33.join(ctx.cwd, jobsDir));
10707
+ const agentResponsibility = resolveAgentResponsibilityFolder(slug2, path32.join(ctx.cwd, jobsDir));
10662
10708
  if (!agentResponsibility) {
10663
10709
  throw new Error(
10664
- `loadJobFromFile: agentResponsibility folder not found or incomplete: ${path33.join(ctx.cwd, jobsDir, slug)}`
10710
+ `loadJobFromFile: agentResponsibility folder not found or incomplete: ${path32.join(ctx.cwd, jobsDir, slug2)}`
10665
10711
  );
10666
10712
  }
10667
10713
  const { title, body, config } = agentResponsibility;
@@ -10673,7 +10719,7 @@ var init_loadJobFromFile = __esm({
10673
10719
  const agentPath = resolveAgentFile(ctx.cwd, agentSlug, agentsDir);
10674
10720
  if (!fs33.existsSync(agentPath)) {
10675
10721
  throw new Error(
10676
- `loadJobFromFile: agentResponsibility '${slug}' declares agent '${agentSlug}' but ${agentPath} does not exist`
10722
+ `loadJobFromFile: agentResponsibility '${slug2}' declares agent '${agentSlug}' but ${agentPath} does not exist`
10677
10723
  );
10678
10724
  }
10679
10725
  const agentRaw = fs33.readFileSync(agentPath, "utf-8");
@@ -10682,28 +10728,28 @@ var init_loadJobFromFile = __esm({
10682
10728
  agentIdentity = parsed.body;
10683
10729
  }
10684
10730
  const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
10685
- const loaded = await backend.load(slug);
10686
- ctx.data.jobSlug = slug;
10731
+ const loaded = await backend.load(slug2);
10732
+ ctx.data.jobSlug = slug2;
10687
10733
  ctx.data.jobTitle = title;
10688
- ctx.data.jobIntent = body.replace(/\{\{\s*mentions\s*\}\}/g, mentions).replace(/\{\{\s*agentResponsibility\s*\}\}/g, slug);
10734
+ ctx.data.jobIntent = body.replace(/\{\{\s*mentions\s*\}\}/g, mentions).replace(/\{\{\s*agentResponsibility\s*\}\}/g, slug2);
10689
10735
  ctx.data.jobState = loaded;
10690
10736
  ctx.data.jobStateJson = JSON.stringify(loaded.state, null, 2);
10691
10737
  ctx.data.agentSlug = agentSlug;
10692
10738
  ctx.data.agentTitle = agentTitle;
10693
10739
  ctx.data.agentIdentity = agentIdentity;
10694
10740
  ctx.data.mentions = mentions;
10695
- ctx.data.agentResponsibilitySlug = slug;
10741
+ ctx.data.agentResponsibilitySlug = slug2;
10696
10742
  ctx.data.agentResponsibilityTitle = title;
10697
10743
  ctx.data.agentSlug = agentSlug;
10698
10744
  ctx.data.agentTitle = agentTitle;
10699
10745
  ctx.data.agentActionSlug = profile.name;
10700
- ctx.data.agentResponsibilitySchedule = config.every ?? "";
10746
+ ctx.data.agentResponsibilitySchedule = String(ctx.data.jobSchedule ?? "");
10701
10747
  const declaredTools = config.tools ?? [];
10702
10748
  if (declaredTools.length > 0) {
10703
10749
  const unknown = declaredTools.filter((name) => !AGENT_RESPONSIBILITY_TOOL_PALETTE2.has(name));
10704
10750
  if (unknown.length > 0) {
10705
10751
  throw new Error(
10706
- `loadJobFromFile: agentResponsibility '${slug}' declared tools not in the kody-agentResponsibility palette: ${unknown.join(", ")}. Available: ${[...AGENT_RESPONSIBILITY_MCP_TOOL_NAMES].join(", ")}`
10752
+ `loadJobFromFile: agentResponsibility '${slug2}' declared tools not in the kody-agentResponsibility palette: ${unknown.join(", ")}. Available: ${[...AGENT_RESPONSIBILITY_MCP_TOOL_NAMES].join(", ")}`
10707
10753
  );
10708
10754
  }
10709
10755
  const mcpToolNames = declaredTools.map((name) => `mcp__kody-agent-responsibility__${name}`);
@@ -10751,9 +10797,9 @@ ${truncate(issue.body, FINDING_BODY_MAX_BYTES)}`;
10751
10797
 
10752
10798
  // src/scripts/kodyVariables.ts
10753
10799
  import * as fs34 from "fs";
10754
- import * as path34 from "path";
10800
+ import * as path33 from "path";
10755
10801
  function readKodyVariables(cwd) {
10756
- const full = path34.join(cwd, KODY_VARIABLES_REL_PATH);
10802
+ const full = path33.join(cwd, KODY_VARIABLES_REL_PATH);
10757
10803
  let raw;
10758
10804
  try {
10759
10805
  raw = fs34.readFileSync(full, "utf-8");
@@ -10782,7 +10828,7 @@ var init_kodyVariables = __esm({
10782
10828
 
10783
10829
  // src/scripts/loadQaContext.ts
10784
10830
  import * as fs35 from "fs";
10785
- import * as path35 from "path";
10831
+ import * as path34 from "path";
10786
10832
  function parseSlugList(value) {
10787
10833
  const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
10788
10834
  return inner.split(",").map(
@@ -10811,7 +10857,7 @@ function readProfileAgents(raw) {
10811
10857
  return { agent: agent ?? legacy ?? ["kody"], body };
10812
10858
  }
10813
10859
  function readProfile(cwd) {
10814
- const dir = path35.join(cwd, CONTEXT_DIR_REL_PATH);
10860
+ const dir = path34.join(cwd, CONTEXT_DIR_REL_PATH);
10815
10861
  if (!fs35.existsSync(dir)) return "";
10816
10862
  let entries;
10817
10863
  try {
@@ -10822,7 +10868,7 @@ function readProfile(cwd) {
10822
10868
  const blocks = [];
10823
10869
  for (const file of entries) {
10824
10870
  try {
10825
- const raw = fs35.readFileSync(path35.join(dir, file), "utf-8");
10871
+ const raw = fs35.readFileSync(path34.join(dir, file), "utf-8");
10826
10872
  const { agent, body } = readProfileAgents(raw);
10827
10873
  if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
10828
10874
  blocks.push(`## ${file}
@@ -10869,7 +10915,7 @@ var init_loadQaContext = __esm({
10869
10915
 
10870
10916
  // src/taskContext.ts
10871
10917
  import * as fs36 from "fs";
10872
- import * as path36 from "path";
10918
+ import * as path35 from "path";
10873
10919
  function buildTaskContext(args) {
10874
10920
  return {
10875
10921
  schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
@@ -10886,7 +10932,7 @@ function persistTaskContext(cwd, ctx) {
10886
10932
  try {
10887
10933
  const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
10888
10934
  fs36.mkdirSync(dir, { recursive: true });
10889
- const file = path36.join(dir, "task-context.json");
10935
+ const file = path35.join(dir, "task-context.json");
10890
10936
  fs36.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
10891
10937
  `);
10892
10938
  return file;
@@ -11303,8 +11349,8 @@ function parseAgentFactoryBundle(raw) {
11303
11349
  return { title, summary, files };
11304
11350
  }
11305
11351
  function buildAgentFactoryBranchName(issueNumber, title, now = Date.now()) {
11306
- const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48).replace(/-+$/g, "");
11307
- const suffix = slug ? `-${slug}` : "";
11352
+ const slug2 = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48).replace(/-+$/g, "");
11353
+ const suffix = slug2 ? `-${slug2}` : "";
11308
11354
  return `agent-factory/issue-${issueNumber}-${now.toString(36)}${suffix}`;
11309
11355
  }
11310
11356
  function normalizeBundleFiles(ctx, bundle) {
@@ -11537,21 +11583,21 @@ var init_openQaIssue = __esm({
11537
11583
  ctx.data.action = failedAction3(reason);
11538
11584
  return;
11539
11585
  }
11540
- const reportBody = agentResult.finalText.trim();
11541
- if (!reportBody) {
11586
+ const reportBody2 = agentResult.finalText.trim();
11587
+ if (!reportBody2) {
11542
11588
  process.stderr.write("qa-engineer: agent produced no report body\n");
11543
11589
  ctx.output.exitCode = 1;
11544
11590
  ctx.output.reason = "empty report body";
11545
11591
  ctx.data.action = failedAction3("empty report body");
11546
11592
  return;
11547
11593
  }
11548
- const verdict = detectVerdict(reportBody);
11594
+ const verdict = detectVerdict(reportBody2);
11549
11595
  ctx.data.qaVerdict = verdict;
11550
- ctx.data.qaReport = reportBody;
11596
+ ctx.data.qaReport = reportBody2;
11551
11597
  const existingIssue = ctx.args.issue;
11552
11598
  if (typeof existingIssue === "number" && Number.isFinite(existingIssue) && existingIssue > 0) {
11553
11599
  try {
11554
- postIssueComment(existingIssue, reportBody, ctx.cwd);
11600
+ postIssueComment(existingIssue, reportBody2, ctx.cwd);
11555
11601
  } catch (err) {
11556
11602
  const msg = err instanceof Error ? err.message : String(err);
11557
11603
  ctx.output.exitCode = 4;
@@ -11573,7 +11619,7 @@ QA_REPORT_POSTED=https://github.com/${ctx.config.github.owner}/${ctx.config.gith
11573
11619
  const hasLabel = ensureLabel2(ctx.cwd);
11574
11620
  let created;
11575
11621
  try {
11576
- created = createQaIssue(title, reportBody, hasLabel, ctx.cwd);
11622
+ created = createQaIssue(title, reportBody2, hasLabel, ctx.cwd);
11577
11623
  } catch (err) {
11578
11624
  const msg = err instanceof Error ? err.message : String(err);
11579
11625
  ctx.output.exitCode = 4;
@@ -11636,6 +11682,39 @@ var init_parseAgentResult = __esm({
11636
11682
  }
11637
11683
  });
11638
11684
 
11685
+ // src/scripts/parseCompanyManagerDecision.ts
11686
+ function makeAction3(type, payload) {
11687
+ return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
11688
+ }
11689
+ var parseCompanyManagerDecision;
11690
+ var init_parseCompanyManagerDecision = __esm({
11691
+ "src/scripts/parseCompanyManagerDecision.ts"() {
11692
+ "use strict";
11693
+ init_companyManagerDecision();
11694
+ parseCompanyManagerDecision = async (ctx, _profile, agentResult) => {
11695
+ if (!agentResult) {
11696
+ ctx.data.companyManagerDecision = { summary: "", actions: [] };
11697
+ ctx.data.action = makeAction3("COMPANY_MANAGER_NOT_RUN", { reason: "no agent result" });
11698
+ return;
11699
+ }
11700
+ try {
11701
+ const decision = parseCompanyManagerDecisionText(agentResult.finalText);
11702
+ ctx.data.companyManagerDecision = decision;
11703
+ ctx.data.action = makeAction3("COMPANY_MANAGER_DECIDED", {
11704
+ summary: decision.summary,
11705
+ actionCount: decision.actions.length
11706
+ });
11707
+ } catch (err) {
11708
+ const reason = err instanceof Error ? err.message : String(err);
11709
+ ctx.data.companyManagerDecisionError = reason;
11710
+ ctx.data.action = makeAction3("COMPANY_MANAGER_FAILED", { reason });
11711
+ ctx.output.exitCode = 1;
11712
+ ctx.output.reason = reason;
11713
+ }
11714
+ };
11715
+ }
11716
+ });
11717
+
11639
11718
  // src/scripts/stateEnvelope.ts
11640
11719
  function isPartialEnvelope(x) {
11641
11720
  if (x === null || typeof x !== "object") return false;
@@ -11896,6 +11975,119 @@ var init_persistFlowState = __esm({
11896
11975
  }
11897
11976
  });
11898
11977
 
11978
+ // src/scripts/planTaskJobs.ts
11979
+ function parseTaskJobSpecs(body) {
11980
+ const match = body.match(new RegExp(`<!--\\s*${TASK_JOBS_MARKER}\\s*([\\s\\S]*?)-->`));
11981
+ if (!match) return [];
11982
+ let parsed;
11983
+ try {
11984
+ parsed = JSON.parse(match[1].trim());
11985
+ } catch (err) {
11986
+ throw new Error(`task job plan is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
11987
+ }
11988
+ if (!Array.isArray(parsed)) throw new Error("task job plan must be a JSON array");
11989
+ return parsed.map((entry, index) => normalizeSpec(entry, index));
11990
+ }
11991
+ function taskJobSpecToJob(spec, issueNumber) {
11992
+ const cliArgs = spec.cliArgs ?? { issue: issueNumber };
11993
+ const target = typeof spec.target === "number" ? spec.target : targetFromCliArgs(cliArgs) ?? issueNumber;
11994
+ return {
11995
+ agentResponsibility: spec.agentResponsibility ?? spec.agentAction,
11996
+ agentAction: spec.agentAction,
11997
+ why: spec.reason,
11998
+ agent: spec.agent,
11999
+ schedule: spec.schedule,
12000
+ target,
12001
+ cliArgs,
12002
+ flavor: spec.flavor ?? "instant"
12003
+ };
12004
+ }
12005
+ function normalizeSpec(input, index) {
12006
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
12007
+ throw new Error(`task job plan entry ${index} must be an object`);
12008
+ }
12009
+ const raw = input;
12010
+ const agentAction = typeof raw.agentAction === "string" ? raw.agentAction.trim() : "";
12011
+ if (!/^[a-z][a-z0-9-]*$/.test(agentAction)) {
12012
+ throw new Error(`task job plan entry ${index} must have a valid agentAction`);
12013
+ }
12014
+ const cliArgs = raw.cliArgs;
12015
+ if (cliArgs !== void 0 && (!cliArgs || typeof cliArgs !== "object" || Array.isArray(cliArgs))) {
12016
+ throw new Error(`task job plan entry ${index} cliArgs must be an object`);
12017
+ }
12018
+ const flavor = raw.flavor;
12019
+ if (flavor !== void 0 && flavor !== "instant" && flavor !== "scheduled") {
12020
+ throw new Error(`task job plan entry ${index} flavor must be "instant" or "scheduled"`);
12021
+ }
12022
+ return {
12023
+ agentAction,
12024
+ ...typeof raw.agentResponsibility === "string" && raw.agentResponsibility.trim() ? { agentResponsibility: raw.agentResponsibility.trim() } : {},
12025
+ ...typeof raw.reason === "string" && raw.reason.trim() ? { reason: raw.reason.trim() } : {},
12026
+ ...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
12027
+ ...typeof raw.agent === "string" && raw.agent.trim() ? { agent: raw.agent.trim() } : {},
12028
+ ...cliArgs ? { cliArgs } : {},
12029
+ ...typeof raw.target === "number" && Number.isFinite(raw.target) ? { target: raw.target } : {},
12030
+ ...flavor === "instant" || flavor === "scheduled" ? { flavor } : {},
12031
+ ...typeof raw.schedule === "string" && raw.schedule.trim() ? { schedule: raw.schedule.trim() } : {}
12032
+ };
12033
+ }
12034
+ function jobToPlannedTaskJob(job) {
12035
+ return {
12036
+ id: stableJobKey(job),
12037
+ agentAction: job.agentAction ?? job.agentResponsibility ?? "unknown",
12038
+ agentResponsibility: job.agentResponsibility ?? job.action ?? job.agentAction ?? "unknown",
12039
+ ...job.agent ? { agent: job.agent } : {},
12040
+ ...job.flavor ? { flavor: job.flavor } : {},
12041
+ ...job.schedule ? { schedule: job.schedule } : {},
12042
+ ...typeof job.target === "number" ? { target: job.target } : {},
12043
+ ...job.why ? { reason: job.why } : {}
12044
+ };
12045
+ }
12046
+ function assertUniqueJobIds(planned) {
12047
+ const seen = /* @__PURE__ */ new Set();
12048
+ for (const job of planned) {
12049
+ if (seen.has(job.id)) throw new Error(`duplicate planned task job id: ${job.id}`);
12050
+ seen.add(job.id);
12051
+ }
12052
+ }
12053
+ var TASK_JOBS_MARKER, planTaskJobs;
12054
+ var init_planTaskJobs = __esm({
12055
+ "src/scripts/planTaskJobs.ts"() {
12056
+ "use strict";
12057
+ init_jobIdentity();
12058
+ init_state();
12059
+ TASK_JOBS_MARKER = "kody:task-jobs:v1";
12060
+ planTaskJobs = async (ctx) => {
12061
+ const issueNumber = ctx.args.issue;
12062
+ if (!issueNumber) {
12063
+ ctx.skipAgent = true;
12064
+ ctx.output.exitCode = 64;
12065
+ ctx.output.reason = "planTaskJobs requires --issue";
12066
+ return;
12067
+ }
12068
+ const issue = ctx.data.issue;
12069
+ const specs = parseTaskJobSpecs(issue?.body ?? "");
12070
+ if (specs.length === 0) {
12071
+ ctx.skipAgent = true;
12072
+ ctx.output.exitCode = 64;
12073
+ ctx.output.reason = `no ${TASK_JOBS_MARKER} block found on issue #${issueNumber}`;
12074
+ return;
12075
+ }
12076
+ const jobs = specs.map((spec) => taskJobSpecToJob(spec, issueNumber));
12077
+ const planned = jobs.map(jobToPlannedTaskJob);
12078
+ assertUniqueJobIds(planned);
12079
+ const prior = ctx.data.taskState ?? emptyState();
12080
+ const next = upsertTaskJobs(prior, planned, (/* @__PURE__ */ new Date()).toISOString());
12081
+ ctx.data.taskState = next;
12082
+ ctx.data.plannedTaskJobs = jobs;
12083
+ ctx.data.plannedTaskJobIds = planned.map((job) => job.id);
12084
+ const target = ctx.data.commentTargetType;
12085
+ const number = ctx.data.commentTargetNumber;
12086
+ if (target && number) writeTaskState(target, number, next, ctx.cwd, ctx.config);
12087
+ };
12088
+ }
12089
+ });
12090
+
11899
12091
  // src/scripts/postAgentSummaryComment.ts
11900
12092
  function postAgentSummaryComment(ctx, opts = {}) {
11901
12093
  if (!ctx.data.agentDone) return;
@@ -12195,7 +12387,7 @@ function tryAuditComment(issueNumber, body, cwd) {
12195
12387
  } catch {
12196
12388
  }
12197
12389
  }
12198
- function makeAction3(type, payload) {
12390
+ function makeAction4(type, payload) {
12199
12391
  return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
12200
12392
  }
12201
12393
  function failedAction4(reason) {
@@ -12232,7 +12424,7 @@ var init_recordClassification = __esm({
12232
12424
  ctx.output.reason = "classify: no decision";
12233
12425
  return;
12234
12426
  }
12235
- ctx.data.action = makeAction3(`CLASSIFIED_AS_${classification.toUpperCase()}`, {
12427
+ ctx.data.action = makeAction4(`CLASSIFIED_AS_${classification.toUpperCase()}`, {
12236
12428
  classification,
12237
12429
  reason: reason ?? "",
12238
12430
  source: ctx.data.classificationSource ?? "agent"
@@ -13075,12 +13267,12 @@ fi
13075
13267
 
13076
13268
  // src/scripts/runPreviewBuild.ts
13077
13269
  import { copyFile, writeFile } from "fs/promises";
13078
- import * as path37 from "path";
13270
+ import * as path36 from "path";
13079
13271
  import { fileURLToPath } from "url";
13080
13272
  function bundledDockerfilePath(mode) {
13081
- const here = path37.dirname(fileURLToPath(import.meta.url));
13273
+ const here = path36.dirname(fileURLToPath(import.meta.url));
13082
13274
  const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
13083
- return path37.join(here, "preview-build-templates", file);
13275
+ return path36.join(here, "preview-build-templates", file);
13084
13276
  }
13085
13277
  function required(name) {
13086
13278
  const v = (process.env[name] ?? "").trim();
@@ -13339,10 +13531,10 @@ var init_runPreviewBuild = __esm({
13339
13531
  console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
13340
13532
  if (Object.keys(buildEnv).length > 0) {
13341
13533
  const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
13342
- await writeFile(path37.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
13534
+ await writeFile(path36.join(ctx.cwd, ".env.production.local"), `${lines.join("\n")}
13343
13535
  `, "utf8");
13344
13536
  }
13345
- const consumerDockerfile = path37.join(ctx.cwd, "Dockerfile.preview");
13537
+ const consumerDockerfile = path36.join(ctx.cwd, "Dockerfile.preview");
13346
13538
  const { stat } = await import("fs/promises");
13347
13539
  let hasConsumerDockerfile = false;
13348
13540
  try {
@@ -13527,7 +13719,7 @@ var init_tickShellRunner = __esm({
13527
13719
 
13528
13720
  // src/scripts/runScheduledAgentActionTick.ts
13529
13721
  import * as fs37 from "fs";
13530
- import * as path38 from "path";
13722
+ import * as path37 from "path";
13531
13723
  var runScheduledAgentActionTick;
13532
13724
  var init_runScheduledAgentActionTick = __esm({
13533
13725
  "src/scripts/runScheduledAgentActionTick.ts"() {
@@ -13541,19 +13733,19 @@ var init_runScheduledAgentActionTick = __esm({
13541
13733
  const slugArg = String(args?.slugArg ?? "agentResponsibility");
13542
13734
  const fenceLabel = String(args?.fenceLabel ?? "kody-job-next-state");
13543
13735
  const shell = String(args?.shell ?? "tick.sh");
13544
- const slug = String(args?.slug ?? ctx.args[slugArg] ?? "").trim();
13545
- if (!slug) {
13736
+ const slug2 = String(args?.slug ?? ctx.args[slugArg] ?? "").trim();
13737
+ if (!slug2) {
13546
13738
  ctx.output.exitCode = 99;
13547
13739
  ctx.output.reason = `runScheduledAgentActionTick: args.slug or ctx.args.${slugArg} must be non-empty agentResponsibility slug`;
13548
13740
  return;
13549
13741
  }
13550
- const agentResponsibility = resolveAgentResponsibilityFolder(slug, path38.join(ctx.cwd, jobsDir));
13742
+ const agentResponsibility = resolveAgentResponsibilityFolder(slug2, path37.join(ctx.cwd, jobsDir));
13551
13743
  if (!agentResponsibility) {
13552
13744
  ctx.output.exitCode = 99;
13553
- ctx.output.reason = `runScheduledAgentActionTick: agentResponsibility folder not found or incomplete: ${slug} (searched ${jobsDir} and company store)`;
13745
+ ctx.output.reason = `runScheduledAgentActionTick: agentResponsibility folder not found or incomplete: ${slug2} (searched ${jobsDir} and company store)`;
13554
13746
  return;
13555
13747
  }
13556
- const shellPath = path38.join(profile.dir, shell);
13748
+ const shellPath = path37.join(profile.dir, shell);
13557
13749
  if (!fs37.existsSync(shellPath)) {
13558
13750
  ctx.output.exitCode = 99;
13559
13751
  ctx.output.reason = `runScheduledAgentActionTick: shell not found: ${shell} (looked in ${profile.dir})`;
@@ -13562,14 +13754,14 @@ var init_runScheduledAgentActionTick = __esm({
13562
13754
  const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
13563
13755
  let loaded;
13564
13756
  try {
13565
- loaded = await backend.load(slug);
13757
+ loaded = await backend.load(slug2);
13566
13758
  } catch (err) {
13567
13759
  ctx.output.exitCode = 99;
13568
13760
  ctx.output.reason = `runScheduledAgentActionTick: state load failed: ${err instanceof Error ? err.message : String(err)}`;
13569
13761
  return;
13570
13762
  }
13571
- ctx.data.jobSlug = slug;
13572
- ctx.data.agentResponsibilitySlug = slug;
13763
+ ctx.data.jobSlug = slug2;
13764
+ ctx.data.agentResponsibilitySlug = slug2;
13573
13765
  ctx.data.agentActionSlug = profile.name;
13574
13766
  ctx.data.jobState = loaded;
13575
13767
  runTickShellAndParse({
@@ -13586,7 +13778,7 @@ var init_runScheduledAgentActionTick = __esm({
13586
13778
 
13587
13779
  // src/scripts/runTickScript.ts
13588
13780
  import * as fs38 from "fs";
13589
- import * as path39 from "path";
13781
+ import * as path38 from "path";
13590
13782
  var runTickScript;
13591
13783
  var init_runTickScript = __esm({
13592
13784
  "src/scripts/runTickScript.ts"() {
@@ -13599,25 +13791,25 @@ var init_runTickScript = __esm({
13599
13791
  const jobsDir = String(args?.jobsDir ?? ".kody/agent-responsibilities");
13600
13792
  const slugArg = String(args?.slugArg ?? "job");
13601
13793
  const fenceLabel = String(args?.fenceLabel ?? "kody-job-next-state");
13602
- const slug = String(ctx.args[slugArg] ?? "").trim();
13603
- if (!slug) {
13794
+ const slug2 = String(ctx.args[slugArg] ?? "").trim();
13795
+ if (!slug2) {
13604
13796
  ctx.output.exitCode = 99;
13605
13797
  ctx.output.reason = `runTickScript: ctx.args.${slugArg} must be a non-empty slug`;
13606
13798
  return;
13607
13799
  }
13608
- const agentResponsibility = readAgentResponsibilityFolder(path39.join(ctx.cwd, jobsDir), slug);
13800
+ const agentResponsibility = readAgentResponsibilityFolder(path38.join(ctx.cwd, jobsDir), slug2);
13609
13801
  if (!agentResponsibility) {
13610
13802
  ctx.output.exitCode = 99;
13611
- ctx.output.reason = `runTickScript: agentResponsibility folder not found or incomplete: ${path39.join(ctx.cwd, jobsDir, slug)}`;
13803
+ ctx.output.reason = `runTickScript: agentResponsibility folder not found or incomplete: ${path38.join(ctx.cwd, jobsDir, slug2)}`;
13612
13804
  return;
13613
13805
  }
13614
13806
  const tickScript = agentResponsibility.config.tickScript;
13615
13807
  if (!tickScript) {
13616
13808
  ctx.output.exitCode = 99;
13617
- ctx.output.reason = `runTickScript: agentResponsibility ${slug} has no \`tickScript\` in profile.json \u2014 route via agent-responsibility-tick instead`;
13809
+ ctx.output.reason = `runTickScript: agentResponsibility ${slug2} has no \`tickScript\` in profile.json \u2014 route via agent-responsibility-tick instead`;
13618
13810
  return;
13619
13811
  }
13620
- const scriptPath = path39.isAbsolute(tickScript) ? tickScript : path39.join(ctx.cwd, tickScript);
13812
+ const scriptPath = path38.isAbsolute(tickScript) ? tickScript : path38.join(ctx.cwd, tickScript);
13621
13813
  if (!fs38.existsSync(scriptPath)) {
13622
13814
  ctx.output.exitCode = 99;
13623
13815
  ctx.output.reason = `runTickScript: tickScript not found: ${scriptPath}`;
@@ -13626,13 +13818,13 @@ var init_runTickScript = __esm({
13626
13818
  const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
13627
13819
  let loaded;
13628
13820
  try {
13629
- loaded = await backend.load(slug);
13821
+ loaded = await backend.load(slug2);
13630
13822
  } catch (err) {
13631
13823
  ctx.output.exitCode = 99;
13632
13824
  ctx.output.reason = `runTickScript: state load failed: ${err instanceof Error ? err.message : String(err)}`;
13633
13825
  return;
13634
13826
  }
13635
- ctx.data.jobSlug = slug;
13827
+ ctx.data.jobSlug = slug2;
13636
13828
  ctx.data.jobState = loaded;
13637
13829
  runTickShellAndParse({
13638
13830
  ctx,
@@ -14577,6 +14769,86 @@ var init_writeJobStateFile = __esm({
14577
14769
  }
14578
14770
  });
14579
14771
 
14772
+ // src/scripts/writeResponsibilityReport.ts
14773
+ function writeReport(ctx, profile, agentResult) {
14774
+ const slug2 = responsibilitySlug(ctx);
14775
+ if (!slug2) {
14776
+ fail2(ctx, "writeResponsibilityReport: missing responsibility slug");
14777
+ return;
14778
+ }
14779
+ if (!REPORT_SLUG_RE.test(slug2)) {
14780
+ fail2(ctx, `writeResponsibilityReport: invalid responsibility slug "${slug2}"`);
14781
+ return;
14782
+ }
14783
+ const body = reportBody(ctx, agentResult, profile);
14784
+ if (!body.trim()) {
14785
+ fail2(ctx, `writeResponsibilityReport: ${slug2} produced no report output`);
14786
+ return;
14787
+ }
14788
+ const filePath = `reports/${slug2}.md`;
14789
+ const current = readStateText(ctx.config, ctx.cwd, filePath);
14790
+ if (current?.content === body) {
14791
+ ctx.data.responsibilityReport = { slug: slug2, path: current.path, changed: false };
14792
+ return;
14793
+ }
14794
+ upsertStateText(
14795
+ ctx.config,
14796
+ ctx.cwd,
14797
+ filePath,
14798
+ body,
14799
+ `chore(reports): refresh ${slug2}`
14800
+ );
14801
+ ctx.data.responsibilityReport = { slug: slug2, path: filePath, changed: true };
14802
+ }
14803
+ function responsibilitySlug(ctx) {
14804
+ const candidates = [
14805
+ ctx.data.jobAgentResponsibility,
14806
+ ctx.data.agentResponsibilitySlug,
14807
+ ctx.data.jobSlug
14808
+ ];
14809
+ for (const candidate of candidates) {
14810
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
14811
+ }
14812
+ return null;
14813
+ }
14814
+ function reportBody(ctx, agentResult, profile) {
14815
+ const prSummary = ctx.data.prSummary;
14816
+ if (typeof prSummary === "string" && prSummary.trim()) return ensureTrailingNewline(prSummary.trim());
14817
+ if (agentResult?.finalText.trim()) return ensureTrailingNewline(agentResult.finalText.trim());
14818
+ const reason = ctx.output.reason || ctx.data.agentFailureReason || agentResult?.error;
14819
+ if (typeof reason === "string" && reason.trim()) {
14820
+ return `# ${profile.name}
14821
+
14822
+ FAILED: ${reason.trim()}
14823
+ `;
14824
+ }
14825
+ return "";
14826
+ }
14827
+ function fail2(ctx, reason) {
14828
+ ctx.output.reason = ctx.output.reason ? `${ctx.output.reason}; ${reason}` : reason;
14829
+ if (ctx.output.exitCode === 0) ctx.output.exitCode = 99;
14830
+ }
14831
+ function ensureTrailingNewline(value) {
14832
+ return value.endsWith("\n") ? value : `${value}
14833
+ `;
14834
+ }
14835
+ var REPORT_SLUG_RE, writeResponsibilityReport;
14836
+ var init_writeResponsibilityReport = __esm({
14837
+ "src/scripts/writeResponsibilityReport.ts"() {
14838
+ "use strict";
14839
+ init_stateRepo();
14840
+ REPORT_SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
14841
+ writeResponsibilityReport = async (ctx, profile, agentResult) => {
14842
+ if (ctx.data.jobSaveReport !== true) return;
14843
+ try {
14844
+ writeReport(ctx, profile, agentResult);
14845
+ } catch (err) {
14846
+ fail2(ctx, `writeResponsibilityReport: ${err instanceof Error ? err.message : String(err)}`);
14847
+ }
14848
+ };
14849
+ }
14850
+ });
14851
+
14580
14852
  // src/scripts/index.ts
14581
14853
  var preflightScripts, postflightScripts, allScriptNames;
14582
14854
  var init_scripts = __esm({
@@ -14586,7 +14858,9 @@ var init_scripts = __esm({
14586
14858
  init_advanceFlow();
14587
14859
  init_advanceManagedGoal();
14588
14860
  init_appendCompanyActivity();
14861
+ init_appendCompanyIntentDecision();
14589
14862
  init_applyAgentResponsibilityReports();
14863
+ init_applyCompanyManagerDecision();
14590
14864
  init_buildSyntheticPlugin();
14591
14865
  init_checkCoverageWithRetry();
14592
14866
  init_classifyByLabel();
@@ -14611,6 +14885,8 @@ var init_scripts = __esm({
14611
14885
  init_initFlow();
14612
14886
  init_loadAgentAdhoc();
14613
14887
  init_loadAgentResponsibilityState();
14888
+ init_loadCompanyIntents();
14889
+ init_loadCompanyPortfolio();
14614
14890
  init_loadConventions();
14615
14891
  init_loadCoverageRules();
14616
14892
  init_loadGoalState();
@@ -14631,6 +14907,7 @@ var init_scripts = __esm({
14631
14907
  init_openAgentFactoryStatePr();
14632
14908
  init_openQaIssue();
14633
14909
  init_parseAgentResult();
14910
+ init_parseCompanyManagerDecision();
14634
14911
  init_parseIssueStateFromAgentResult();
14635
14912
  init_parseJobStateFromAgentResult();
14636
14913
  init_parseReproOutput();
@@ -14673,6 +14950,7 @@ var init_scripts = __esm({
14673
14950
  init_writeAgentRunSummary();
14674
14951
  init_writeIssueStateComment();
14675
14952
  init_writeJobStateFile();
14953
+ init_writeResponsibilityReport();
14676
14954
  preflightScripts = {
14677
14955
  runFlow,
14678
14956
  fixFlow,
@@ -14689,6 +14967,8 @@ var init_scripts = __esm({
14689
14967
  loadIssueStateComment,
14690
14968
  loadJobFromFile,
14691
14969
  loadAgentResponsibilityState,
14970
+ loadCompanyIntents,
14971
+ loadCompanyPortfolio,
14692
14972
  loadAgentAdhoc,
14693
14973
  loadConventions,
14694
14974
  loadCoverageRules,
@@ -14723,12 +15003,15 @@ var init_scripts = __esm({
14723
15003
  };
14724
15004
  postflightScripts = {
14725
15005
  parseAgentResult: parseAgentResult2,
15006
+ parseCompanyManagerDecision,
14726
15007
  parseIssueStateFromAgentResult,
14727
15008
  parseJobStateFromAgentResult,
14728
15009
  parseReproOutput,
14729
15010
  writeIssueStateComment,
14730
15011
  writeJobStateFile,
14731
15012
  appendCompanyActivity,
15013
+ appendCompanyIntentDecision: appendCompanyIntentDecision2,
15014
+ applyCompanyManagerDecision,
14732
15015
  requireFeedbackActions,
14733
15016
  requirePlanDeviations,
14734
15017
  verify,
@@ -14746,6 +15029,7 @@ var init_scripts = __esm({
14746
15029
  postReviewResult,
14747
15030
  persistArtifacts,
14748
15031
  writeAgentRunSummary,
15032
+ writeResponsibilityReport,
14749
15033
  saveTaskState,
14750
15034
  mirrorStateToPr,
14751
15035
  startFlow,
@@ -14842,7 +15126,7 @@ var init_tools = __esm({
14842
15126
  // src/executor.ts
14843
15127
  import { spawn as spawn7 } from "child_process";
14844
15128
  import * as fs40 from "fs";
14845
- import * as path40 from "path";
15129
+ import * as path39 from "path";
14846
15130
  function isMutatingPostflight(scriptName) {
14847
15131
  return MUTATING_POSTFLIGHTS.has(scriptName ?? "");
14848
15132
  }
@@ -15007,13 +15291,13 @@ async function runAgentAction(profileName, input) {
15007
15291
  })
15008
15292
  };
15009
15293
  })() : null;
15010
- const ndjsonDir = path40.join(input.cwd, ".kody");
15294
+ const ndjsonDir = path39.join(input.cwd, ".kody");
15011
15295
  const agentSlug = typeof profile.agent === "string" && profile.agent.length > 0 ? profile.agent : typeof ctx.data.jobAgent === "string" && ctx.data.jobAgent.length > 0 ? ctx.data.jobAgent : null;
15012
15296
  const agentIdentityBlock = agentSlug ? frameAgentIdentity(agentSlug, loadAgentIdentity(input.cwd, agentSlug)) : null;
15013
15297
  const jobWhyBlock = typeof ctx.data.jobWhy === "string" ? operatorRequestBlock(ctx.data.jobWhy) : null;
15014
15298
  const jobRefBlock = jobReferenceBlock(profileName, profile, ctx.data);
15015
15299
  const invokeAgent = async (prompt) => {
15016
- const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path40.isAbsolute(p) ? p : path40.resolve(profile.dir, p)).filter((p) => p.length > 0);
15300
+ const externalPlugins = (profile.claudeCode.plugins ?? []).map((p) => path39.isAbsolute(p) ? p : path39.resolve(profile.dir, p)).filter((p) => p.length > 0);
15017
15301
  const syntheticPath = ctx.data.syntheticPluginPath;
15018
15302
  const pluginPaths = [...externalPlugins, ...syntheticPath ? [syntheticPath] : []];
15019
15303
  const agents = loadSubagents(profile);
@@ -15248,6 +15532,7 @@ async function runAgentAction(profileName, input) {
15248
15532
  outcome: postOutcome
15249
15533
  });
15250
15534
  }
15535
+ await writeResponsibilityReport(ctx, profile, agentResult);
15251
15536
  return finishAndEnd({
15252
15537
  exitCode: ctx.output.exitCode ?? 0,
15253
15538
  prUrl: ctx.output.prUrl,
@@ -15376,7 +15661,8 @@ function handoffToJob(handoff) {
15376
15661
  agentResponsibility: handoff.agentResponsibility,
15377
15662
  agentAction: handoff.agentAction,
15378
15663
  cliArgs: handoff.cliArgs,
15379
- flavor: "instant"
15664
+ flavor: "instant",
15665
+ saveReport: handoff.saveReport === true
15380
15666
  };
15381
15667
  }
15382
15668
  function clearStampedLifecycleLabels(profile, ctx) {
@@ -15395,13 +15681,13 @@ function clearStampedLifecycleLabels(profile, ctx) {
15395
15681
  function resolveProfilePath(profileName) {
15396
15682
  const found = resolveAgentAction(profileName);
15397
15683
  if (found) return found;
15398
- const here = path40.dirname(new URL(import.meta.url).pathname);
15684
+ const here = path39.dirname(new URL(import.meta.url).pathname);
15399
15685
  const candidates = [
15400
- path40.join(here, "agent-actions", profileName, "profile.json"),
15686
+ path39.join(here, "agent-actions", profileName, "profile.json"),
15401
15687
  // same-dir sibling (dev)
15402
- path40.join(here, "..", "agent-actions", profileName, "profile.json"),
15688
+ path39.join(here, "..", "agent-actions", profileName, "profile.json"),
15403
15689
  // up one (prod: dist/bin → dist/agent-actions)
15404
- path40.join(here, "..", "src", "agent-actions", profileName, "profile.json")
15690
+ path39.join(here, "..", "src", "agent-actions", profileName, "profile.json")
15405
15691
  // fallback
15406
15692
  ];
15407
15693
  for (const c of candidates) {
@@ -15503,7 +15789,7 @@ function resolveShellTimeoutMs(entry) {
15503
15789
  }
15504
15790
  async function runShellEntry(entry, ctx, profile) {
15505
15791
  const shellName = entry.shell;
15506
- const shellPath = path40.join(profile.dir, shellName);
15792
+ const shellPath = path39.join(profile.dir, shellName);
15507
15793
  if (!fs40.existsSync(shellPath)) {
15508
15794
  ctx.skipAgent = true;
15509
15795
  ctx.output.exitCode = 99;
@@ -15636,6 +15922,7 @@ var init_executor = __esm({
15636
15922
  init_profile();
15637
15923
  init_registry();
15638
15924
  init_scripts();
15925
+ init_writeResponsibilityReport();
15639
15926
  init_subagents();
15640
15927
  init_task_artifacts();
15641
15928
  init_tools();
@@ -15663,7 +15950,7 @@ __export(job_exports, {
15663
15950
  stableJobKey: () => stableJobKey,
15664
15951
  validateJob: () => validateJob
15665
15952
  });
15666
- import * as path41 from "path";
15953
+ import * as path40 from "path";
15667
15954
  function newJobId(flavor) {
15668
15955
  localJobSeq += 1;
15669
15956
  const runId = process.env.GITHUB_RUN_ID;
@@ -15694,13 +15981,14 @@ function validateJob(input) {
15694
15981
  target: typeof j.target === "number" ? j.target : void 0,
15695
15982
  cliArgs: j.cliArgs ?? {},
15696
15983
  flavor: j.flavor,
15697
- force: j.force === true
15984
+ force: j.force === true,
15985
+ saveReport: j.saveReport === true
15698
15986
  };
15699
15987
  }
15700
15988
  async function runJob(job, base) {
15701
15989
  const valid = validateJob(job);
15702
15990
  const action = valid.action ?? valid.agentResponsibility;
15703
- const projectAgentResponsibilitiesRoot = path41.join(base.cwd, ".kody", "agent-responsibilities");
15991
+ const projectAgentResponsibilitiesRoot = path40.join(base.cwd, ".kody", "agent-responsibilities");
15704
15992
  const resolvedAgentResponsibility = action ? resolveAgentResponsibilityAction(action, projectAgentResponsibilitiesRoot) : null;
15705
15993
  const agentResponsibilityIdentity = valid.agentResponsibility ?? resolvedAgentResponsibility?.agentResponsibility;
15706
15994
  const agentResponsibilityContext = loadAgentResponsibilityContext(agentResponsibilityIdentity, base.cwd);
@@ -15727,6 +16015,7 @@ async function runJob(job, base) {
15727
16015
  if (executableIdentity !== void 0 && executableIdentity.length > 0)
15728
16016
  preloadedData.jobAgentAction = executableIdentity;
15729
16017
  if (valid.schedule !== void 0 && valid.schedule.length > 0) preloadedData.jobSchedule = valid.schedule;
16018
+ if (valid.saveReport === true) preloadedData.jobSaveReport = true;
15730
16019
  if (agentResponsibilityContext) {
15731
16020
  preloadedData.agentResponsibilitySlug = agentResponsibilityContext.slug;
15732
16021
  preloadedData.agentResponsibilityTitle = agentResponsibilityContext.title;
@@ -15737,9 +16026,6 @@ async function runJob(job, base) {
15737
16026
  if (agentResponsibilityContext.config.agent && preloadedData.jobAgent === void 0) {
15738
16027
  preloadedData.jobAgent = agentResponsibilityContext.config.agent;
15739
16028
  }
15740
- if (agentResponsibilityContext.config.every && preloadedData.jobSchedule === void 0) {
15741
- preloadedData.jobSchedule = agentResponsibilityContext.config.every;
15742
- }
15743
16029
  if (agentResponsibilityContext.config.mentions && agentResponsibilityContext.config.mentions.length > 0) {
15744
16030
  preloadedData.mentions = agentResponsibilityContext.config.mentions.map((login) => `@${login}`).join(" ");
15745
16031
  }
@@ -15760,9 +16046,9 @@ async function runJob(job, base) {
15760
16046
  const run = base.chain === false ? runAgentAction : runAgentActionChain;
15761
16047
  return run(profileName, input);
15762
16048
  }
15763
- function loadAgentResponsibilityContext(slug, cwd) {
15764
- if (!slug) return null;
15765
- return resolveAgentResponsibilityFolder(slug, path41.join(cwd, ".kody", "agent-responsibilities"));
16049
+ function loadAgentResponsibilityContext(slug2, cwd) {
16050
+ if (!slug2) return null;
16051
+ return resolveAgentResponsibilityFolder(slug2, path40.join(cwd, ".kody", "agent-responsibilities"));
15766
16052
  }
15767
16053
  function mintInstantJob(dispatch2, opts) {
15768
16054
  return {
@@ -15784,7 +16070,8 @@ function mintScheduledJob(input) {
15784
16070
  schedule: input.schedule,
15785
16071
  agent: input.agent,
15786
16072
  cliArgs: input.cliArgs ?? {},
15787
- flavor: "scheduled"
16073
+ flavor: "scheduled",
16074
+ saveReport: input.saveReport === true
15788
16075
  };
15789
16076
  }
15790
16077
  var DEFAULT_INSTANT_AGENT, localJobSeq, InvalidJobError;
@@ -15915,7 +16202,7 @@ function translateOpenAISseToBrain(opts) {
15915
16202
  // src/servers/brain-serve.ts
15916
16203
  import * as fs43 from "fs";
15917
16204
  import { createServer } from "http";
15918
- import * as path44 from "path";
16205
+ import * as path43 from "path";
15919
16206
 
15920
16207
  // src/chat/loop.ts
15921
16208
  init_agent();
@@ -16458,7 +16745,7 @@ init_config();
16458
16745
  // src/kody-cli.ts
16459
16746
  import { execFileSync as execFileSync25 } from "child_process";
16460
16747
  import * as fs41 from "fs";
16461
- import * as path42 from "path";
16748
+ import * as path41 from "path";
16462
16749
 
16463
16750
  // src/app-auth.ts
16464
16751
  import { createSign } from "crypto";
@@ -17054,9 +17341,9 @@ async function resolveAuthToken(env = process.env) {
17054
17341
  return void 0;
17055
17342
  }
17056
17343
  function detectPackageManager2(cwd) {
17057
- if (fs41.existsSync(path42.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
17058
- if (fs41.existsSync(path42.join(cwd, "yarn.lock"))) return "yarn";
17059
- if (fs41.existsSync(path42.join(cwd, "bun.lockb"))) return "bun";
17344
+ if (fs41.existsSync(path41.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
17345
+ if (fs41.existsSync(path41.join(cwd, "yarn.lock"))) return "yarn";
17346
+ if (fs41.existsSync(path41.join(cwd, "bun.lockb"))) return "bun";
17060
17347
  return "npm";
17061
17348
  }
17062
17349
  function shellOut(cmd, args, cwd, stream = true) {
@@ -17143,7 +17430,7 @@ function configureGitIdentity(cwd) {
17143
17430
  }
17144
17431
  function postFailureTail(issueNumber, cwd, reason) {
17145
17432
  if (!issueNumber) return;
17146
- const logPath = path42.join(cwd, ".kody", "last-run.jsonl");
17433
+ const logPath = path41.join(cwd, ".kody", "last-run.jsonl");
17147
17434
  let tail = "";
17148
17435
  try {
17149
17436
  if (fs41.existsSync(logPath)) {
@@ -17172,7 +17459,7 @@ async function runCi(argv) {
17172
17459
  return 0;
17173
17460
  }
17174
17461
  const args = parseCiArgs(argv);
17175
- const cwd = args.cwd ? path42.resolve(args.cwd) : process.cwd();
17462
+ const cwd = args.cwd ? path41.resolve(args.cwd) : process.cwd();
17176
17463
  let earlyConfig;
17177
17464
  let earlyConfigError;
17178
17465
  try {
@@ -17514,10 +17801,10 @@ init_repoWorkspace();
17514
17801
 
17515
17802
  // src/scripts/brainTurnLog.ts
17516
17803
  import * as fs42 from "fs";
17517
- import * as path43 from "path";
17804
+ import * as path42 from "path";
17518
17805
  var live = /* @__PURE__ */ new Map();
17519
17806
  function eventsPath2(dir, chatId) {
17520
- return path43.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
17807
+ return path42.join(dir, ".kody", "brain-events", `${chatId}.jsonl`);
17521
17808
  }
17522
17809
  function lastPersistedSeq(dir, chatId) {
17523
17810
  const p = eventsPath2(dir, chatId);
@@ -17560,7 +17847,7 @@ function beginTurn(dir, chatId) {
17560
17847
  };
17561
17848
  live.set(chatId, state);
17562
17849
  const p = eventsPath2(dir, chatId);
17563
- fs42.mkdirSync(path43.dirname(p), { recursive: true });
17850
+ fs42.mkdirSync(path42.dirname(p), { recursive: true });
17564
17851
  return (event) => {
17565
17852
  state.seq += 1;
17566
17853
  const rec = { seq: state.seq, turn, ts: Date.now(), event };
@@ -17835,7 +18122,7 @@ async function handleChatTurn(req, res, chatId, opts) {
17835
18122
  const repo = strField(body, "repo");
17836
18123
  const repoToken = strField(body, "repoToken");
17837
18124
  const sessionFile = sessionFilePath(opts.cwd, chatId);
17838
- fs43.mkdirSync(path44.dirname(sessionFile), { recursive: true });
18125
+ fs43.mkdirSync(path43.dirname(sessionFile), { recursive: true });
17839
18126
  appendTurn(sessionFile, {
17840
18127
  role: "user",
17841
18128
  content: message,
@@ -17882,7 +18169,7 @@ async function handleChatTurn(req, res, chatId, opts) {
17882
18169
  function buildServer(opts) {
17883
18170
  const runTurn = opts.runTurn ?? runChatTurn;
17884
18171
  const cloneRepo = opts.cloneRepo ?? defaultCloneRepo;
17885
- const reposRoot = opts.reposRoot ?? path44.join(path44.dirname(path44.resolve(opts.cwd)), "repos");
18172
+ const reposRoot = opts.reposRoot ?? path43.join(path43.dirname(path43.resolve(opts.cwd)), "repos");
17886
18173
  return createServer(async (req, res) => {
17887
18174
  if (!req.method || !req.url) {
17888
18175
  sendJson(res, 400, { error: "bad request" });
@@ -18478,13 +18765,13 @@ async function loadConfigSafe() {
18478
18765
  // src/chat-cli.ts
18479
18766
  import { execFileSync as execFileSync28 } from "child_process";
18480
18767
  import * as fs45 from "fs";
18481
- import * as path46 from "path";
18768
+ import * as path45 from "path";
18482
18769
 
18483
18770
  // src/chat/modes/interactive.ts
18484
18771
  init_issue();
18485
18772
  import { execFileSync as execFileSync27 } from "child_process";
18486
18773
  import * as fs44 from "fs";
18487
- import * as path45 from "path";
18774
+ import * as path44 from "path";
18488
18775
 
18489
18776
  // src/chat/inbox.ts
18490
18777
  import { execFileSync as execFileSync26 } from "child_process";
@@ -18644,9 +18931,9 @@ function findNextUserTurn(turns, fromIdx) {
18644
18931
  return -1;
18645
18932
  }
18646
18933
  function commitTurn(cwd, sessionId, _verbose) {
18647
- const sessionRel = path45.relative(cwd, sessionFilePath(cwd, sessionId));
18648
- const eventsRel = path45.relative(cwd, eventsFilePath(cwd, sessionId));
18649
- const rels = [sessionRel, eventsRel].filter((p) => fs44.existsSync(path45.join(cwd, p)));
18934
+ const sessionRel = path44.relative(cwd, sessionFilePath(cwd, sessionId));
18935
+ const eventsRel = path44.relative(cwd, eventsFilePath(cwd, sessionId));
18936
+ const rels = [sessionRel, eventsRel].filter((p) => fs44.existsSync(path44.join(cwd, p)));
18650
18937
  if (rels.length === 0) return;
18651
18938
  const repository = process.env.GITHUB_REPOSITORY;
18652
18939
  if (!repository) {
@@ -18658,8 +18945,8 @@ function commitTurn(cwd, sessionId, _verbose) {
18658
18945
  }
18659
18946
  const branch = defaultBranch(cwd) ?? "main";
18660
18947
  for (const rel of rels) {
18661
- const repoPath = rel.split(path45.sep).join("/");
18662
- const localText = fs44.readFileSync(path45.join(cwd, rel), "utf-8");
18948
+ const repoPath = rel.split(path44.sep).join("/");
18949
+ const localText = fs44.readFileSync(path44.join(cwd, rel), "utf-8");
18663
18950
  putJsonlViaContents(repository, branch, repoPath, localText, sessionId, cwd);
18664
18951
  }
18665
18952
  }
@@ -18804,12 +19091,12 @@ function parseChatArgs(argv, env = process.env) {
18804
19091
  return result;
18805
19092
  }
18806
19093
  function commitChatFiles(cwd, sessionId, verbose) {
18807
- const sessionFile = path46.relative(cwd, sessionFilePath(cwd, sessionId));
18808
- const eventsFile = path46.relative(cwd, eventsFilePath(cwd, sessionId));
19094
+ const sessionFile = path45.relative(cwd, sessionFilePath(cwd, sessionId));
19095
+ const eventsFile = path45.relative(cwd, eventsFilePath(cwd, sessionId));
18809
19096
  const safeSession = sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
18810
- const tasksDir = path46.join(".kody", "tasks", safeSession);
19097
+ const tasksDir = path45.join(".kody", "tasks", safeSession);
18811
19098
  const candidatePaths = [sessionFile, eventsFile, tasksDir];
18812
- const paths = candidatePaths.filter((p) => fs45.existsSync(path46.join(cwd, p)));
19099
+ const paths = candidatePaths.filter((p) => fs45.existsSync(path45.join(cwd, p)));
18813
19100
  if (paths.length === 0) return;
18814
19101
  const opts = { cwd, stdio: verbose ? "inherit" : "pipe" };
18815
19102
  try {
@@ -18853,7 +19140,7 @@ async function runChat(argv) {
18853
19140
  ${CHAT_HELP}`);
18854
19141
  return 64;
18855
19142
  }
18856
- const cwd = args.cwd ? path46.resolve(args.cwd) : process.cwd();
19143
+ const cwd = args.cwd ? path45.resolve(args.cwd) : process.cwd();
18857
19144
  const sessionId = args.sessionId;
18858
19145
  const unpackedSecrets = unpackAllSecrets();
18859
19146
  if (unpackedSecrets > 0) {
@@ -19064,8 +19351,8 @@ var FlyClient = class {
19064
19351
  get fetch() {
19065
19352
  return this.opts.fetchImpl ?? fetch;
19066
19353
  }
19067
- async call(path47, init = {}) {
19068
- const res = await this.fetch(`${FLY_API_BASE}${path47}`, {
19354
+ async call(path46, init = {}) {
19355
+ const res = await this.fetch(`${FLY_API_BASE}${path46}`, {
19069
19356
  method: init.method ?? "GET",
19070
19357
  headers: {
19071
19358
  Authorization: `Bearer ${this.opts.token}`,
@@ -19076,7 +19363,7 @@ var FlyClient = class {
19076
19363
  if (res.status === 404 && init.allow404) return null;
19077
19364
  if (!res.ok) {
19078
19365
  const text = await res.text().catch(() => "");
19079
- throw new Error(`Fly API ${res.status} on ${path47}: ${text.slice(0, 200) || res.statusText}`);
19366
+ throw new Error(`Fly API ${res.status} on ${path46}: ${text.slice(0, 200) || res.statusText}`);
19080
19367
  }
19081
19368
  if (res.status === 204) return null;
19082
19369
  const raw = await res.text();