@kody-ade/kody-engine 0.4.275 → 0.4.276

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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +279 -45
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "package.json"() {
16
16
  package_default = {
17
17
  name: "@kody-ade/kody-engine",
18
- version: "0.4.275",
18
+ version: "0.4.276",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -19579,6 +19579,68 @@ init_job();
19579
19579
  init_registry();
19580
19580
  init_runtimePaths();
19581
19581
  init_stateWorkspace();
19582
+
19583
+ // src/run-request.ts
19584
+ var RUN_REQUEST_ENV = "KODY_RUN_REQUEST_JSON";
19585
+ var INTENTS = /* @__PURE__ */ new Set(["continue", "manage", "run", "tick"]);
19586
+ var SOURCES = /* @__PURE__ */ new Set(["dashboard", "github", "schedule"]);
19587
+ var TARGET_TYPES = /* @__PURE__ */ new Set(["chat", "goal", "issue", "workflow"]);
19588
+ function isRecord(value) {
19589
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19590
+ }
19591
+ function readString(value) {
19592
+ return typeof value === "string" ? value.trim() : "";
19593
+ }
19594
+ function parseTarget(input) {
19595
+ if (!isRecord(input)) return { error: "runRequest.target must be an object" };
19596
+ const type = readString(input.type);
19597
+ if (!TARGET_TYPES.has(type)) return { error: "runRequest.target.type is invalid" };
19598
+ if (type === "issue") {
19599
+ const id2 = Number(input.id);
19600
+ if (!Number.isInteger(id2) || id2 <= 0) return { error: "runRequest.target.id must be a positive issue number" };
19601
+ return { target: { type, id: id2 } };
19602
+ }
19603
+ const id = readString(input.id);
19604
+ if (!id) return { error: "runRequest.target.id is required" };
19605
+ return { target: { type, id } };
19606
+ }
19607
+ function parseRunRequest(input) {
19608
+ let body = input;
19609
+ if (typeof input === "string") {
19610
+ const raw = input.trim();
19611
+ if (!raw) return { error: `${RUN_REQUEST_ENV} is empty` };
19612
+ try {
19613
+ body = JSON.parse(raw);
19614
+ } catch {
19615
+ return { error: `${RUN_REQUEST_ENV} must be valid JSON` };
19616
+ }
19617
+ }
19618
+ if (!isRecord(body)) return { error: "runRequest must be an object" };
19619
+ const parsedTarget = parseTarget(body.target);
19620
+ if ("error" in parsedTarget) return parsedTarget;
19621
+ const intent = readString(body.intent);
19622
+ if (!INTENTS.has(intent)) return { error: "runRequest.intent is invalid" };
19623
+ const source = readString(body.source);
19624
+ if (!SOURCES.has(source)) return { error: "runRequest.source is invalid" };
19625
+ if (body.input !== void 0 && !isRecord(body.input)) {
19626
+ return { error: "runRequest.input must be an object when provided" };
19627
+ }
19628
+ return {
19629
+ request: {
19630
+ target: parsedTarget.target,
19631
+ intent,
19632
+ source,
19633
+ ...body.input !== void 0 ? { input: body.input } : {}
19634
+ }
19635
+ };
19636
+ }
19637
+ function readRunRequestFromEnv(env = process.env) {
19638
+ const raw = env[RUN_REQUEST_ENV];
19639
+ if (raw == null || raw.trim() === "") return null;
19640
+ return parseRunRequest(raw);
19641
+ }
19642
+
19643
+ // src/kody-cli.ts
19582
19644
  var CI_HELP = `kody ci \u2014 minimal-YAML autonomous engineer (CI preflight + run)
19583
19645
 
19584
19646
  Usage:
@@ -19637,6 +19699,30 @@ function parseCiArgs(argv) {
19637
19699
  }
19638
19700
  return result;
19639
19701
  }
19702
+ function routeRunRequest(request) {
19703
+ const { target, intent } = request;
19704
+ if (target.type === "chat" || target.type === "issue") return { kind: "ignore" };
19705
+ if (target.type === "goal") {
19706
+ if (intent !== "manage" && intent !== "run" && intent !== "tick") {
19707
+ return { kind: "error", error: `goal target does not support intent '${intent}'` };
19708
+ }
19709
+ return {
19710
+ kind: "action",
19711
+ action: "goal-manager",
19712
+ cliArgs: { goal: target.id }
19713
+ };
19714
+ }
19715
+ if (target.type === "workflow") {
19716
+ if (target.id === "scheduled-fanout") {
19717
+ return { kind: "fanout", force: intent === "run" };
19718
+ }
19719
+ if (intent !== "run" && intent !== "tick") {
19720
+ return { kind: "error", error: `workflow target does not support intent '${intent}'` };
19721
+ }
19722
+ return { kind: "action", action: target.id, cliArgs: {} };
19723
+ }
19724
+ return { kind: "error", error: "unsupported run request target" };
19725
+ }
19640
19726
  function unpackAllSecrets(env = process.env) {
19641
19727
  const raw = env.ALL_SECRETS;
19642
19728
  if (!raw) return 0;
@@ -19848,15 +19934,38 @@ async function runCi(argv) {
19848
19934
  let manualWorkflowDispatch = false;
19849
19935
  let forceRunAction = null;
19850
19936
  let forceRunCliArgs = {};
19937
+ let runRequestFanOut = false;
19938
+ let runRequestFanOutForce = false;
19939
+ const parsedRunRequest = readRunRequestFromEnv();
19940
+ if (parsedRunRequest && "error" in parsedRunRequest) {
19941
+ process.stderr.write(`[kody] ${parsedRunRequest.error}
19942
+ `);
19943
+ return 64;
19944
+ }
19945
+ if (!args.issueNumber && !autoFallback && parsedRunRequest && "request" in parsedRunRequest) {
19946
+ const route = routeRunRequest(parsedRunRequest.request);
19947
+ if (route.kind === "error") {
19948
+ process.stderr.write(`[kody] ${route.error}
19949
+ `);
19950
+ return 64;
19951
+ }
19952
+ if (route.kind === "fanout") {
19953
+ runRequestFanOut = true;
19954
+ runRequestFanOutForce = route.force;
19955
+ } else if (route.kind === "action") {
19956
+ forceRunAction = route.action;
19957
+ forceRunCliArgs = route.cliArgs;
19958
+ }
19959
+ }
19851
19960
  const envForceAction = (process.env.KODY_FORCE_ACTION ?? "").trim();
19852
19961
  const envForceMessage = (process.env.KODY_FORCE_MESSAGE ?? "").trim();
19853
- if (!args.issueNumber && !autoFallback && envForceAction) {
19962
+ if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && envForceAction) {
19854
19963
  forceRunAction = envForceAction;
19855
19964
  if (envForceAction === "goal-manager" && envForceMessage) {
19856
19965
  forceRunCliArgs = { goal: envForceMessage };
19857
19966
  }
19858
19967
  }
19859
- if (!args.issueNumber && !autoFallback && !forceRunAction && eventName === "workflow_dispatch" && dispatchEventPath && fs46.existsSync(dispatchEventPath)) {
19968
+ if (!args.issueNumber && !autoFallback && !forceRunAction && !runRequestFanOut && eventName === "workflow_dispatch" && dispatchEventPath && fs46.existsSync(dispatchEventPath)) {
19860
19969
  try {
19861
19970
  const evt = JSON.parse(fs46.readFileSync(dispatchEventPath, "utf-8"));
19862
19971
  const issueInput = parseInt(String(evt?.inputs?.issue_number ?? ""), 10);
@@ -19948,6 +20057,9 @@ async function runCi(argv) {
19948
20057
  const ec = result.exitCode;
19949
20058
  return ec === 0 || ec === 1 || ec === 2 ? ec : 99;
19950
20059
  }
20060
+ if (!args.issueNumber && !autoFallback && runRequestFanOut) {
20061
+ return runScheduledFanOut(cwd, args, { force: runRequestFanOutForce });
20062
+ }
19951
20063
  if (!args.issueNumber && !autoFallback && (eventName === "schedule" || manualWorkflowDispatch)) {
19952
20064
  return runScheduledFanOut(cwd, args, { force: manualWorkflowDispatch });
19953
20065
  }
@@ -21571,6 +21683,10 @@ function parseChatArgs(argv, env = process.env) {
21571
21683
  else if (arg?.startsWith("--")) result.errors.push(`unknown arg: ${arg}`);
21572
21684
  else if (arg) result.errors.push(`unexpected positional: ${arg}`);
21573
21685
  }
21686
+ const runRequest = readRunRequestFromEnv(env);
21687
+ if (runRequest && "error" in runRequest) result.errors.push(runRequest.error);
21688
+ const chatTarget = runRequest && "request" in runRequest && runRequest.request.target.type === "chat" ? runRequest.request.target.id : void 0;
21689
+ result.sessionId = result.sessionId ?? chatTarget;
21574
21690
  result.sessionId = result.sessionId ?? env.SESSION_ID ?? void 0;
21575
21691
  result.initMessage = result.initMessage ?? env.INIT_MESSAGE ?? void 0;
21576
21692
  result.model = result.model ?? env.MODEL ?? void 0;
@@ -21764,7 +21880,11 @@ async function runCapabilityFallbackTick(deps) {
21764
21880
  const res = await deps.claim(owner, repo, {
21765
21881
  jobId: `sched-${owner}-${repo}-${clock()}`,
21766
21882
  repo: tag,
21767
- mode: "scheduled"
21883
+ runRequest: {
21884
+ target: { type: "workflow", id: "scheduled-fanout" },
21885
+ intent: "tick",
21886
+ source: "schedule"
21887
+ }
21768
21888
  });
21769
21889
  if (res.ok) {
21770
21890
  claimed++;
@@ -22339,7 +22459,7 @@ var PoolRegistry = class {
22339
22459
  jobId: req.jobId,
22340
22460
  repo: `${owner}/${repo}`,
22341
22461
  githubToken: this.cfg.githubToken,
22342
- mode: req.mode ?? "issue",
22462
+ runRequest: req.runRequest,
22343
22463
  issueNumber: req.issueNumber,
22344
22464
  sessionId: req.sessionId,
22345
22465
  idleExitMs: req.idleExitMs,
@@ -22425,24 +22545,78 @@ function parseClaimRequest(body) {
22425
22545
  const repo = typeof b.repo === "string" ? b.repo.trim() : "";
22426
22546
  if (!/^[^/\s]+\/[^/\s]+$/.test(repo)) return { error: "repo must be 'owner/name'" };
22427
22547
  const mode = b.mode === "interactive" ? "interactive" : b.mode === "scheduled" ? "scheduled" : "issue";
22428
- const req = { jobId, repo, mode };
22429
- if (mode === "issue") {
22430
- const issueNumber = Number(b.issueNumber);
22431
- if (!Number.isInteger(issueNumber) || issueNumber <= 0) return { error: "issueNumber required for issue mode" };
22432
- req.issueNumber = issueNumber;
22433
- } else if (mode === "interactive") {
22434
- const sessionId = typeof b.sessionId === "string" ? b.sessionId.trim() : "";
22435
- if (!sessionId) return { error: "sessionId required for interactive mode" };
22436
- req.sessionId = sessionId;
22548
+ const action = typeof b.action === "string" && b.action.trim() ? b.action.trim() : void 0;
22549
+ const message = typeof b.message === "string" && b.message.trim() ? b.message.trim() : void 0;
22550
+ const runRequest = b.runRequest !== void 0 ? parseRunRequest(b.runRequest) : synthesizeLegacyClaimRequest({
22551
+ mode,
22552
+ issueNumber: b.issueNumber,
22553
+ sessionId: b.sessionId,
22554
+ action,
22555
+ message
22556
+ });
22557
+ if ("error" in runRequest) return { error: runRequest.error };
22558
+ const req = { jobId, repo, runRequest: runRequest.request };
22559
+ if (req.runRequest.target.type === "issue") {
22560
+ req.issueNumber = req.runRequest.target.id;
22561
+ } else if (req.runRequest.target.type === "chat") {
22562
+ req.sessionId = req.runRequest.target.id;
22437
22563
  if (Number.isFinite(Number(b.idleExitMs))) req.idleExitMs = Number(b.idleExitMs);
22438
22564
  if (Number.isFinite(Number(b.hardCapMs))) req.hardCapMs = Number(b.hardCapMs);
22439
22565
  }
22440
22566
  if (typeof b.ref === "string" && b.ref.trim()) req.ref = b.ref.trim();
22441
22567
  if (typeof b.model === "string" && b.model.trim()) req.model = b.model.trim();
22442
- if (typeof b.sessionId === "string" && b.sessionId.trim()) req.sessionId = b.sessionId.trim();
22443
22568
  if (typeof b.dashboardUrl === "string" && b.dashboardUrl.trim()) req.dashboardUrl = b.dashboardUrl.trim();
22444
22569
  return { req };
22445
22570
  }
22571
+ function synthesizeLegacyClaimRequest(input) {
22572
+ if (input.mode === "issue") {
22573
+ const issueNumber = Number(input.issueNumber);
22574
+ if (!Number.isInteger(issueNumber) || issueNumber <= 0) return { error: "issueNumber required for issue mode" };
22575
+ return {
22576
+ request: {
22577
+ target: { type: "issue", id: issueNumber },
22578
+ intent: "run",
22579
+ source: "dashboard"
22580
+ }
22581
+ };
22582
+ }
22583
+ if (input.mode === "interactive") {
22584
+ const sessionId = typeof input.sessionId === "string" ? input.sessionId.trim() : "";
22585
+ if (!sessionId) return { error: "sessionId required for interactive mode" };
22586
+ return {
22587
+ request: {
22588
+ target: { type: "chat", id: sessionId },
22589
+ intent: "continue",
22590
+ source: "dashboard"
22591
+ }
22592
+ };
22593
+ }
22594
+ if (input.action === "goal-manager" && input.message) {
22595
+ return {
22596
+ request: {
22597
+ target: { type: "goal", id: input.message },
22598
+ intent: "manage",
22599
+ source: "dashboard"
22600
+ }
22601
+ };
22602
+ }
22603
+ if (input.action) {
22604
+ return {
22605
+ request: {
22606
+ target: { type: "workflow", id: input.action },
22607
+ intent: "run",
22608
+ source: "dashboard"
22609
+ }
22610
+ };
22611
+ }
22612
+ return {
22613
+ request: {
22614
+ target: { type: "workflow", id: "scheduled-fanout" },
22615
+ intent: "tick",
22616
+ source: "schedule"
22617
+ }
22618
+ };
22619
+ }
22446
22620
  async function poolServe() {
22447
22621
  const masterRaw = process.env.KODY_MASTER_KEY?.trim();
22448
22622
  if (!masterRaw) throw new Error("KODY_MASTER_KEY required for pool-serve");
@@ -22610,33 +22784,85 @@ function parseJob(body) {
22610
22784
  if (!/^[^/\s]+\/[^/\s]+$/.test(repo)) return { error: "repo must be 'owner/name'" };
22611
22785
  const githubToken = typeof b.githubToken === "string" ? b.githubToken.trim() : "";
22612
22786
  if (!githubToken) return { error: "githubToken required" };
22787
+ const action = typeof b.action === "string" && b.action.trim() ? b.action.trim() : void 0;
22788
+ const message = typeof b.message === "string" && b.message.trim() ? b.message.trim() : void 0;
22613
22789
  const mode = b.mode === "interactive" ? "interactive" : b.mode === "scheduled" ? "scheduled" : "issue";
22614
- const job = { jobId, repo, githubToken, mode };
22615
- if (mode === "issue") {
22616
- const issueNumber = Number(b.issueNumber);
22617
- if (!Number.isInteger(issueNumber) || issueNumber <= 0) {
22618
- return { error: "issueNumber (positive integer) required for issue mode" };
22619
- }
22620
- job.issueNumber = issueNumber;
22621
- } else if (mode === "interactive") {
22622
- const sessionId = typeof b.sessionId === "string" ? b.sessionId.trim() : "";
22623
- if (!sessionId) return { error: "sessionId required for interactive mode" };
22624
- job.sessionId = sessionId;
22790
+ const runRequest = b.runRequest !== void 0 ? parseRunRequest(b.runRequest) : synthesizeLegacyRunRequest({
22791
+ mode,
22792
+ issueNumber: b.issueNumber,
22793
+ sessionId: b.sessionId,
22794
+ action,
22795
+ message
22796
+ });
22797
+ if ("error" in runRequest) return { error: runRequest.error };
22798
+ const job = { jobId, repo, githubToken, runRequest: runRequest.request };
22799
+ if (job.runRequest.target.type === "issue") {
22800
+ job.issueNumber = job.runRequest.target.id;
22801
+ } else if (job.runRequest.target.type === "chat") {
22802
+ job.sessionId = job.runRequest.target.id;
22625
22803
  if (Number.isFinite(Number(b.idleExitMs))) job.idleExitMs = Number(b.idleExitMs);
22626
22804
  if (Number.isFinite(Number(b.hardCapMs))) job.hardCapMs = Number(b.hardCapMs);
22627
22805
  }
22628
22806
  if (typeof b.ref === "string" && b.ref.trim()) job.ref = b.ref.trim();
22629
22807
  if (typeof b.model === "string" && b.model.trim()) job.model = b.model.trim();
22630
22808
  if (typeof b.reasoningEffort === "string" && b.reasoningEffort.trim()) job.reasoningEffort = b.reasoningEffort.trim();
22631
- if (typeof b.action === "string" && b.action.trim()) job.action = b.action.trim();
22632
- if (typeof b.message === "string" && b.message.trim()) job.message = b.message.trim();
22633
- if (typeof b.sessionId === "string" && b.sessionId.trim()) job.sessionId = b.sessionId.trim();
22634
22809
  if (typeof b.dashboardUrl === "string" && b.dashboardUrl.trim()) job.dashboardUrl = b.dashboardUrl.trim();
22635
22810
  if (b.allSecrets && (typeof b.allSecrets === "object" || typeof b.allSecrets === "string")) {
22636
22811
  job.allSecrets = b.allSecrets;
22637
22812
  }
22638
22813
  return { job };
22639
22814
  }
22815
+ function synthesizeLegacyRunRequest(input) {
22816
+ if (input.mode === "issue") {
22817
+ const issueNumber = Number(input.issueNumber);
22818
+ if (!Number.isInteger(issueNumber) || issueNumber <= 0) {
22819
+ return { error: "issueNumber (positive integer) required for issue mode" };
22820
+ }
22821
+ return {
22822
+ request: {
22823
+ target: { type: "issue", id: issueNumber },
22824
+ intent: "run",
22825
+ source: "dashboard"
22826
+ }
22827
+ };
22828
+ }
22829
+ if (input.mode === "interactive") {
22830
+ const sessionId = typeof input.sessionId === "string" ? input.sessionId.trim() : "";
22831
+ if (!sessionId) return { error: "sessionId required for interactive mode" };
22832
+ return {
22833
+ request: {
22834
+ target: { type: "chat", id: sessionId },
22835
+ intent: "continue",
22836
+ source: "dashboard"
22837
+ }
22838
+ };
22839
+ }
22840
+ if (input.action === "goal-manager" && input.message) {
22841
+ return {
22842
+ request: {
22843
+ target: { type: "goal", id: input.message },
22844
+ intent: "manage",
22845
+ source: "dashboard"
22846
+ }
22847
+ };
22848
+ }
22849
+ if (input.action) {
22850
+ return {
22851
+ request: {
22852
+ target: { type: "workflow", id: input.action },
22853
+ intent: "run",
22854
+ source: "dashboard"
22855
+ }
22856
+ };
22857
+ }
22858
+ return {
22859
+ request: {
22860
+ target: { type: "workflow", id: "scheduled-fanout" },
22861
+ intent: "tick",
22862
+ source: "schedule"
22863
+ }
22864
+ };
22865
+ }
22640
22866
  async function defaultRunJob(job) {
22641
22867
  const workdir = process.env.RUNNER_WORKDIR ?? DEFAULT_WORKDIR;
22642
22868
  const branch = job.ref ?? "main";
@@ -22644,20 +22870,17 @@ async function defaultRunJob(job) {
22644
22870
  fs51.rmSync(workdir, { recursive: true, force: true });
22645
22871
  fs51.mkdirSync(workdir, { recursive: true });
22646
22872
  const allSecrets = typeof job.allSecrets === "string" ? job.allSecrets : JSON.stringify(job.allSecrets ?? {});
22647
- const interactive = job.mode === "interactive";
22648
- const scheduled = job.mode === "scheduled";
22649
- const runMode = interactive ? "interactive" : scheduled ? "scheduled" : "issue";
22873
+ const target = job.runRequest.target;
22874
+ const interactive = target.type === "chat";
22875
+ const scheduled = target.type === "goal" || target.type === "workflow";
22876
+ const issueNumber = target.type === "issue" ? target.id : void 0;
22877
+ const sessionId = target.type === "chat" ? target.id : void 0;
22650
22878
  const childEnv = {
22651
22879
  ...process.env,
22652
22880
  REPO: job.repo,
22653
22881
  REF: branch,
22654
22882
  GITHUB_TOKEN: job.githubToken,
22655
- KODY_RUN_MODE: runMode,
22656
- // Scheduled mode drives the engine down the same path GitHub Actions' cron
22657
- // takes (runScheduledFanOut → due capabilities/goals). Bare `kody` routes on this.
22658
- ...scheduled ? { GITHUB_EVENT_NAME: "schedule" } : {},
22659
- ...job.action ? { KODY_FORCE_ACTION: job.action } : {},
22660
- ...job.message ? { KODY_FORCE_MESSAGE: job.message } : {},
22883
+ [RUN_REQUEST_ENV]: JSON.stringify(job.runRequest),
22661
22884
  // GITHUB_REPOSITORY + GH_TOKEN are normally injected by GitHub Actions.
22662
22885
  // The engine's interactive mode needs GITHUB_REPOSITORY to resolve the
22663
22886
  // configured state repo and persist chat.ready / events (the durable signal
@@ -22665,11 +22888,9 @@ async function defaultRunJob(job) {
22665
22888
  // and the session never appears "ready". GH_TOKEN auths the `gh` CLI.
22666
22889
  GITHUB_REPOSITORY: job.repo,
22667
22890
  GH_TOKEN: job.githubToken,
22668
- // Issue mode carries ISSUE_NUMBER. Interactive mode leaves it empty and
22669
- // sets SESSION_ID so the engine boots a chat session.
22670
- ISSUE_NUMBER: interactive || scheduled ? "" : String(job.issueNumber),
22891
+ ISSUE_NUMBER: issueNumber ? String(issueNumber) : "",
22671
22892
  ALL_SECRETS: allSecrets,
22672
- SESSION_ID: job.sessionId ?? "",
22893
+ SESSION_ID: sessionId ?? "",
22673
22894
  DASHBOARD_URL: job.dashboardUrl ?? "",
22674
22895
  MODEL: job.model ?? "",
22675
22896
  REASONING_EFFORT: job.reasoningEffort ?? "",
@@ -22698,7 +22919,7 @@ async function defaultRunJob(job) {
22698
22919
  const authorEmail = process.env.GIT_AUTHOR_EMAIL ?? "kody-bot@users.noreply.github.com";
22699
22920
  await run("git", ["config", "user.name", authorName], workdir);
22700
22921
  await run("git", ["config", "user.email", authorEmail], workdir);
22701
- const jobDesc = interactive ? `interactive session ${job.sessionId}` : scheduled ? "scheduled fan-out" : `running issue #${job.issueNumber}`;
22922
+ const jobDesc = interactive ? `chat session ${sessionId}` : scheduled ? `${target.type} ${target.id}` : `issue #${issueNumber}`;
22702
22923
  process.stdout.write(`[runner-serve] job ${job.jobId}: ${jobDesc}
22703
22924
  `);
22704
22925
  const runCode = await run("kody", [], workdir);
@@ -22781,7 +23002,7 @@ async function runnerServe() {
22781
23002
  init_config();
22782
23003
  init_litellm();
22783
23004
  import { spawn as spawn9 } from "child_process";
22784
- function parseTarget(positional) {
23005
+ function parseTarget2(positional) {
22785
23006
  if (!Array.isArray(positional) || positional.length === 0) return "none";
22786
23007
  const first = String(positional[0]).toLowerCase();
22787
23008
  if (first === "vscode" || first === "code") return "vscode";
@@ -22796,7 +23017,7 @@ function buildProxyEnv(url) {
22796
23017
  };
22797
23018
  }
22798
23019
  async function serve(opts) {
22799
- const target = parseTarget(opts.args);
23020
+ const target = parseTarget2(opts.args);
22800
23021
  const model = parseProviderModel(opts.config.agent.model);
22801
23022
  const usesProxy = needsLitellmProxy(model);
22802
23023
  let handle = null;
@@ -23110,6 +23331,17 @@ function envRunMode(env = process.env) {
23110
23331
  }
23111
23332
  return { ...result, errors: [`unknown KODY_RUN_MODE: ${mode}`] };
23112
23333
  }
23334
+ function envRunRequest(env = process.env) {
23335
+ const result = { command: "help", errors: [] };
23336
+ const parsed = readRunRequestFromEnv(env);
23337
+ if (!parsed) return null;
23338
+ if ("error" in parsed) return { ...result, errors: [parsed.error] };
23339
+ const { target } = parsed.request;
23340
+ if (target.type === "chat") return { ...result, command: "chat", chatArgv: [] };
23341
+ if (target.type === "issue") return { ...result, command: "ci", ciArgv: ["--issue", String(target.id)] };
23342
+ if (target.type === "goal" || target.type === "workflow") return { ...result, command: "ci", ciArgv: [] };
23343
+ return { ...result, errors: [`unsupported runRequest target: ${target.type ?? "unknown"}`] };
23344
+ }
23113
23345
  var HELP_TEXT = `kody-engine \u2014 single-session autonomous engineer
23114
23346
 
23115
23347
  Usage:
@@ -23146,6 +23378,8 @@ Exit codes:
23146
23378
  function parseArgs(argv) {
23147
23379
  const result = { command: "help", errors: [] };
23148
23380
  if (argv.length === 0) {
23381
+ const runRequest = envRunRequest();
23382
+ if (runRequest) return runRequest;
23149
23383
  const mode = envRunMode();
23150
23384
  if (mode) return mode;
23151
23385
  if (process.env.SESSION_ID) return { ...result, command: "chat", chatArgv: [] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.275",
3
+ "version": "0.4.276",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",