@kody-ade/kody-engine 0.4.286 → 0.4.287

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 +39 -21
  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.286",
18
+ version: "0.4.287",
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",
@@ -443,7 +443,7 @@ var STATE_BRANCH;
443
443
  var init_stateBranch = __esm({
444
444
  "src/stateBranch.ts"() {
445
445
  "use strict";
446
- STATE_BRANCH = "kody-state";
446
+ STATE_BRANCH = "main";
447
447
  }
448
448
  });
449
449
 
@@ -497,18 +497,33 @@ function normalizeStatePath(raw, field = "statePath") {
497
497
  }
498
498
  return parts.join("/");
499
499
  }
500
+ function normalizeStateBranch(raw, field = "state.branch") {
501
+ const value = raw?.trim() || STATE_BRANCH;
502
+ if (!value) throw new Error(`kody.config.json: ${field} must not be empty`);
503
+ if (value.startsWith("/") || value.endsWith("/") || value.includes("\\") || value.includes("..") || value.includes("@{") || /[\x00-\x20\x7f~^:?*\[]/.test(value)) {
504
+ throw new Error(`kody.config.json: ${field} contains an invalid branch`);
505
+ }
506
+ for (const part of value.split("/")) {
507
+ if (!part || part === "." || part === ".." || part.startsWith(".") || part.endsWith(".lock")) {
508
+ throw new Error(`kody.config.json: ${field} contains an invalid branch`);
509
+ }
510
+ }
511
+ return value;
512
+ }
500
513
  function resolveStateRepoConfig(config) {
501
514
  if (config.state?.repo && config.state?.path) {
502
515
  parseStateRepoSlug(config.state.repo);
503
516
  return {
504
517
  repo: config.state.repo,
505
- path: normalizeStatePath(config.state.path)
518
+ path: normalizeStatePath(config.state.path),
519
+ branch: normalizeStateBranch(config.state.branch)
506
520
  };
507
521
  }
508
522
  if (config.github?.owner && config.github?.repo) {
509
523
  return {
510
524
  repo: `${config.github.owner}/kody-state`,
511
- path: normalizeStatePath(config.github.repo)
525
+ path: normalizeStatePath(config.github.repo),
526
+ branch: normalizeStateBranch(void 0)
512
527
  };
513
528
  }
514
529
  throw new Error("stateRepo: config.state or config.github owner/repo is required");
@@ -516,7 +531,7 @@ function resolveStateRepoConfig(config) {
516
531
  function parseStateRepo(config) {
517
532
  const state = resolveStateRepoConfig(config);
518
533
  const parsed = parseStateRepoSlug(state.repo);
519
- return { ...parsed, basePath: state.path };
534
+ return { ...parsed, basePath: state.path, branch: state.branch };
520
535
  }
521
536
  function stateRepoPath(config, filePath) {
522
537
  const state = resolveStateRepoConfig(config);
@@ -528,14 +543,15 @@ function apiPath(config, targetPath) {
528
543
  return `/repos/${parsed.owner}/${parsed.repo}/contents/${targetPath}`;
529
544
  }
530
545
  function branchApiPath(config, targetPath) {
531
- return `${apiPath(config, targetPath)}?ref=${encodeURIComponent(STATE_BRANCH)}`;
546
+ const state = resolveStateRepoConfig(config);
547
+ return `${apiPath(config, targetPath)}?ref=${encodeURIComponent(state.branch)}`;
532
548
  }
533
549
  function ensureStateBranch(config, cwd) {
534
550
  const parsed = parseStateRepo(config);
535
- const cacheKey3 = `${parsed.owner}/${parsed.repo}:${STATE_BRANCH}`;
551
+ const cacheKey3 = `${parsed.owner}/${parsed.repo}:${parsed.branch}`;
536
552
  if (ensuredStateBranches.has(cacheKey3)) return;
537
553
  try {
538
- gh(["api", `/repos/${parsed.owner}/${parsed.repo}/git/ref/heads/${STATE_BRANCH}`], { cwd });
554
+ gh(["api", `/repos/${parsed.owner}/${parsed.repo}/git/ref/heads/${parsed.branch}`], { cwd });
539
555
  ensuredStateBranches.add(cacheKey3);
540
556
  return;
541
557
  } catch (err) {
@@ -550,7 +566,7 @@ function ensureStateBranch(config, cwd) {
550
566
  try {
551
567
  gh(["api", "--method", "POST", `/repos/${parsed.owner}/${parsed.repo}/git/refs`, "--input", "-"], {
552
568
  cwd,
553
- input: JSON.stringify({ ref: `refs/heads/${STATE_BRANCH}`, sha })
569
+ input: JSON.stringify({ ref: `refs/heads/${parsed.branch}`, sha })
554
570
  });
555
571
  } catch (err) {
556
572
  if (!isAlreadyExists(err)) throw err;
@@ -590,7 +606,7 @@ function writeStateText(config, cwd, filePath, content, message, sha) {
590
606
  const payload = {
591
607
  message,
592
608
  content: Buffer.from(content, "utf-8").toString("base64"),
593
- branch: STATE_BRANCH
609
+ branch: resolveStateRepoConfig(config).branch
594
610
  };
595
611
  if (sha) payload.sha = sha;
596
612
  gh(["api", "--method", "PUT", apiPath(config, targetPath), "--input", "-"], {
@@ -722,12 +738,14 @@ function parseStateConfig(raw, github) {
722
738
  const nested = recordValue(raw.state) ?? {};
723
739
  const repoRaw = typeof raw.stateRepo === "string" ? raw.stateRepo : nested.repo;
724
740
  const pathRaw = typeof raw.statePath === "string" ? raw.statePath : nested.path;
741
+ const branchRaw = typeof raw.stateBranch === "string" ? raw.stateBranch : nested.branch;
725
742
  const stateRepo = typeof repoRaw === "string" && repoRaw.trim().length > 0 ? repoRaw.trim() : `https://github.com/${String(github.owner)}/kody-state`;
726
743
  parseStateRepoSlug(stateRepo);
727
744
  const statePath = typeof pathRaw === "string" && pathRaw.trim().length > 0 ? pathRaw.trim() : String(github.repo);
728
745
  return {
729
746
  repo: stateRepo,
730
- path: normalizeStatePath(statePath)
747
+ path: normalizeStatePath(statePath),
748
+ branch: typeof branchRaw === "string" && branchRaw.trim().length > 0 ? normalizeStateBranch(branchRaw) : normalizeStateBranch(void 0)
731
749
  };
732
750
  }
733
751
  function parseAccessConfig(raw) {
@@ -6878,6 +6896,7 @@ function stateRepoContext(config, goalId, logPath) {
6878
6896
  return {
6879
6897
  repo: state.repo,
6880
6898
  path: state.path,
6899
+ branch: state.branch,
6881
6900
  goalStatePath: `${state.path}/${goalStateLogPath(goalId)}`,
6882
6901
  logPath: `${state.path}/${logPath}`
6883
6902
  };
@@ -6976,16 +6995,17 @@ function linkContext(stateRepo) {
6976
6995
  const server = process.env.GITHUB_SERVER_URL?.trim() || "https://github.com";
6977
6996
  if (runId && repository) links.workflowRun = `${server}/${repository}/actions/runs/${runId}`;
6978
6997
  const repo = stringValue(stateRepo?.repo);
6998
+ const branch = stringValue(stateRepo?.branch);
6979
6999
  const goalStatePath2 = stringValue(stateRepo?.goalStatePath);
6980
7000
  const logPath = stringValue(stateRepo?.logPath);
6981
- if (repo && goalStatePath2) links.goalState = githubBlobUrl(repo, goalStatePath2);
6982
- if (repo && logPath) links.log = githubBlobUrl(repo, logPath);
7001
+ if (repo && branch && goalStatePath2) links.goalState = githubBlobUrl(repo, branch, goalStatePath2);
7002
+ if (repo && branch && logPath) links.log = githubBlobUrl(repo, branch, logPath);
6983
7003
  return Object.keys(links).length > 0 ? links : void 0;
6984
7004
  }
6985
- function githubBlobUrl(repo, filePath) {
7005
+ function githubBlobUrl(repo, branch, filePath) {
6986
7006
  try {
6987
7007
  const parsed = parseStateRepoSlug(repo);
6988
- return `https://github.com/${parsed.owner}/${parsed.repo}/blob/${STATE_BRANCH}/${filePath}`;
7008
+ return `https://github.com/${parsed.owner}/${parsed.repo}/blob/${encodeURIComponent(branch)}/${filePath}`;
6989
7009
  } catch {
6990
7010
  return void 0;
6991
7011
  }
@@ -7068,7 +7088,6 @@ var LOGS_KEY, LOG_RUN_KEY, LOG_STARTED_KEY;
7068
7088
  var init_runLog = __esm({
7069
7089
  "src/goal/runLog.ts"() {
7070
7090
  "use strict";
7071
- init_stateBranch();
7072
7091
  init_stateRepo();
7073
7092
  init_state2();
7074
7093
  LOGS_KEY = "__goalRunLogs";
@@ -17536,7 +17555,7 @@ function overlayDirectoryChildren(cwd, sourceDir, localDir) {
17536
17555
  function hydrateStateWorkspace(config, cwd) {
17537
17556
  if (process.env.VITEST && process.env[TEST_FETCH_ENV] !== "1") return;
17538
17557
  const parsed = parseStateRepo(config);
17539
- const hydrateKey = `${path41.resolve(cwd)}|${parsed.owner}/${parsed.repo}|${parsed.basePath}|${STATE_BRANCH}`;
17558
+ const hydrateKey = `${path41.resolve(cwd)}|${parsed.owner}/${parsed.repo}|${parsed.basePath}|${parsed.branch}`;
17540
17559
  if (hydratedWorkspaces.has(hydrateKey)) return;
17541
17560
  const snapshotRoot = fetchStateSnapshot(parsed);
17542
17561
  for (const mapping of DIR_MAPPINGS) {
@@ -17560,7 +17579,7 @@ function fetchStateSnapshot(parsed) {
17560
17579
  runGit3(["clone", "--no-checkout", "--filter=blob:none", url, cacheDir]);
17561
17580
  }
17562
17581
  runGit3(["-C", cacheDir, "remote", "set-url", "origin", url]);
17563
- runGit3(["-C", cacheDir, "fetch", "--depth=1", "origin", STATE_BRANCH]);
17582
+ runGit3(["-C", cacheDir, "fetch", "--depth=1", "origin", parsed.branch]);
17564
17583
  runGit3(["-C", cacheDir, "sparse-checkout", "init", "--cone"]);
17565
17584
  runGit3(["-C", cacheDir, "sparse-checkout", "set", parsed.basePath]);
17566
17585
  runGit3(["-C", cacheDir, "checkout", "--force", "--detach", "FETCH_HEAD"]);
@@ -17568,7 +17587,7 @@ function fetchStateSnapshot(parsed) {
17568
17587
  } catch (err) {
17569
17588
  const msg = err instanceof Error ? err.message : String(err);
17570
17589
  throw new Error(
17571
- `stateWorkspace: failed to fetch ${parsed.owner}/${parsed.repo}:${parsed.basePath}@${STATE_BRANCH}: ${msg}`
17590
+ `stateWorkspace: failed to fetch ${parsed.owner}/${parsed.repo}:${parsed.basePath}@${parsed.branch}: ${msg}`
17572
17591
  );
17573
17592
  }
17574
17593
  return path41.join(cacheDir, parsed.basePath);
@@ -17577,7 +17596,7 @@ function cacheRoot2() {
17577
17596
  return process.env[CACHE_ENV2]?.trim() || path41.join(os7.homedir(), ".cache", "kody", "state-repo");
17578
17597
  }
17579
17598
  function cacheKey2(parsed) {
17580
- return crypto3.createHash("sha256").update(`${parsed.owner}/${parsed.repo}#${STATE_BRANCH}#${parsed.basePath}`).digest("hex").slice(0, 24);
17599
+ return crypto3.createHash("sha256").update(`${parsed.owner}/${parsed.repo}#${parsed.branch}#${parsed.basePath}`).digest("hex").slice(0, 24);
17581
17600
  }
17582
17601
  function runGit3(args) {
17583
17602
  try {
@@ -17612,7 +17631,6 @@ var DIR_MAPPINGS, FILE_MAPPINGS, CACHE_ENV2, TEST_FETCH_ENV, hydratedWorkspaces;
17612
17631
  var init_stateWorkspace = __esm({
17613
17632
  "src/stateWorkspace.ts"() {
17614
17633
  "use strict";
17615
- init_stateBranch();
17616
17634
  init_stateRepo();
17617
17635
  DIR_MAPPINGS = [
17618
17636
  { stateDir: "executables", localDir: path41.join(".kody", "executables") },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.286",
3
+ "version": "0.4.287",
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",