@kody-ade/kody-engine 0.4.120 → 0.4.122

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
@@ -880,7 +880,7 @@ var init_loadPriorArt = __esm({
880
880
  // package.json
881
881
  var package_default = {
882
882
  name: "@kody-ade/kody-engine",
883
- version: "0.4.120",
883
+ version: "0.4.122",
884
884
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
885
885
  license: "MIT",
886
886
  type: "module",
@@ -900,7 +900,8 @@ var package_default = {
900
900
  build: "tsup && node scripts/copy-assets.cjs",
901
901
  "check:modularity": "tsx scripts/check-script-modularity.ts",
902
902
  pretest: "pnpm check:modularity",
903
- test: "vitest run tests/unit tests/int --no-coverage",
903
+ test: "vitest run tests/unit tests/int --coverage",
904
+ "test:smoke": "vitest run tests/smoke --no-coverage",
904
905
  "test:e2e": "vitest run tests/e2e --no-coverage",
905
906
  "test:all": "vitest run tests --no-coverage",
906
907
  typecheck: "tsc --noEmit",
@@ -917,6 +918,7 @@ var package_default = {
917
918
  devDependencies: {
918
919
  "@biomejs/biome": "^2.4.12",
919
920
  "@types/node": "^22.5.4",
921
+ "@vitest/coverage-v8": "^4.1.4",
920
922
  tsup: "^8.5.1",
921
923
  tsx: "^4.21.0",
922
924
  typescript: "~5.7.0",
@@ -4727,6 +4729,13 @@ async function defaultRunJob(job) {
4727
4729
  REPO: job.repo,
4728
4730
  REF: branch,
4729
4731
  GITHUB_TOKEN: job.githubToken,
4732
+ // GITHUB_REPOSITORY + GH_TOKEN are normally injected by GitHub Actions.
4733
+ // The engine's interactive mode needs GITHUB_REPOSITORY to persist
4734
+ // chat.ready / events to .kody/events via the Contents API (the durable
4735
+ // signal the dashboard polls for readiness) — without it commitTurn bails
4736
+ // and the session never appears "ready". GH_TOKEN auths the `gh` CLI.
4737
+ GITHUB_REPOSITORY: job.repo,
4738
+ GH_TOKEN: job.githubToken,
4730
4739
  // Issue mode bakes ISSUE_NUMBER → `kody run --issue N`. Interactive mode
4731
4740
  // leaves it empty and sets SESSION_ID so the engine boots a chat session.
4732
4741
  ISSUE_NUMBER: interactive ? "" : String(job.issueNumber),
@@ -4986,6 +4995,19 @@ var PoolManager = class {
4986
4995
  total: this.free.length + this.booting + this.claimsInFlight
4987
4996
  };
4988
4997
  }
4998
+ /**
4999
+ * Resize the warm target at runtime (per-repo, sourced from the repo's vault
5000
+ * POOL_MIN). Raising it warms up immediately via refill; lowering it just
5001
+ * stops topping up — surplus machines drain as they're claimed/auto-destroyed,
5002
+ * never force-killed. No-op when unchanged or given a bad value.
5003
+ */
5004
+ setMin(min) {
5005
+ if (!Number.isInteger(min) || min < 0) return;
5006
+ if (min === this.deps.config.min) return;
5007
+ this.deps.config.min = min;
5008
+ this.log(`min set to ${min}`);
5009
+ void this.refill();
5010
+ }
4989
5011
  /**
4990
5012
  * Adopt existing pooled machines on owner (re)start: suspended ones become
4991
5013
  * free; anything else is left to finish/auto-destroy. Then refill to `min`.
@@ -5222,6 +5244,14 @@ async function readRepoSecrets(opts) {
5222
5244
  }
5223
5245
 
5224
5246
  // src/pool/registry.ts
5247
+ var POOL_MIN_VAULT_KEY = "POOL_MIN";
5248
+ var POOL_MIN_MAX = 10;
5249
+ function parsePoolMin(raw, dflt) {
5250
+ if (raw == null || raw.trim() === "") return dflt;
5251
+ const n = Number(raw);
5252
+ if (!Number.isInteger(n) || n < 0) return dflt;
5253
+ return Math.min(n, POOL_MIN_MAX);
5254
+ }
5225
5255
  var PoolRegistry = class {
5226
5256
  constructor(cfg) {
5227
5257
  this.cfg = cfg;
@@ -5234,10 +5264,21 @@ var PoolRegistry = class {
5234
5264
  repo,
5235
5265
  name: "FLY_API_TOKEN"
5236
5266
  }));
5267
+ this.resolvePoolMin = cfg.resolvePoolMin ?? (async (owner, repo) => parsePoolMin(
5268
+ await readRepoSecret({
5269
+ githubToken: cfg.githubToken,
5270
+ masterKey: cfg.masterKey,
5271
+ owner,
5272
+ repo,
5273
+ name: POOL_MIN_VAULT_KEY
5274
+ }),
5275
+ cfg.base.min
5276
+ ));
5237
5277
  }
5238
5278
  cfg;
5239
5279
  pools = /* @__PURE__ */ new Map();
5240
5280
  resolveFlyToken;
5281
+ resolvePoolMin;
5241
5282
  log;
5242
5283
  key(owner, repo) {
5243
5284
  return `${owner}/${repo}`.toLowerCase();
@@ -5258,10 +5299,16 @@ var PoolRegistry = class {
5258
5299
  this.log(`registry: ${repoTag} has no FLY_API_TOKEN \u2014 no pool`);
5259
5300
  return null;
5260
5301
  }
5302
+ let min = this.cfg.base.min;
5303
+ try {
5304
+ min = await this.resolvePoolMin(owner, repo);
5305
+ } catch (err) {
5306
+ this.log(`registry: pool-min read failed for ${repoTag}, using default ${min}: ${err instanceof Error ? err.message : String(err)}`);
5307
+ }
5261
5308
  const fly = new FlyClient({ token: flyToken, app: this.cfg.base.app });
5262
5309
  const pm = new PoolManager({
5263
5310
  fly,
5264
- config: { ...this.cfg.base, repoTag },
5311
+ config: { ...this.cfg.base, repoTag, min },
5265
5312
  log: (m) => this.log(`[${repoTag}] ${m}`)
5266
5313
  });
5267
5314
  this.pools.set(repoTag, pm);
@@ -5279,7 +5326,10 @@ var PoolRegistry = class {
5279
5326
  owner,
5280
5327
  repo
5281
5328
  });
5282
- allSecrets = Object.fromEntries(Object.entries(vault).filter(([k]) => k !== "FLY_API_TOKEN"));
5329
+ pm.setMin(parsePoolMin(vault[POOL_MIN_VAULT_KEY], this.cfg.base.min));
5330
+ allSecrets = Object.fromEntries(
5331
+ Object.entries(vault).filter(([k]) => k !== "FLY_API_TOKEN" && k !== POOL_MIN_VAULT_KEY)
5332
+ );
5283
5333
  } catch (err) {
5284
5334
  this.log(`[${this.key(owner, repo)}] vault secrets read failed: ${err instanceof Error ? err.message : String(err)}`);
5285
5335
  }
@@ -5303,9 +5353,17 @@ var PoolRegistry = class {
5303
5353
  status(owner, repo) {
5304
5354
  return this.pools.get(this.key(owner, repo))?.status() ?? null;
5305
5355
  }
5306
- /** Resync every active repo pool (periodic self-heal). */
5356
+ /** Resync every active repo pool (periodic self-heal). Also re-reads each
5357
+ * repo's POOL_MIN from its vault so a dashboard resize warms up/drains within
5358
+ * one tick — no owner restart needed. */
5307
5359
  async resyncAll() {
5308
5360
  for (const [repoTag, pm] of this.pools) {
5361
+ const [owner, repo] = repoTag.split("/");
5362
+ try {
5363
+ pm.setMin(await this.resolvePoolMin(owner, repo));
5364
+ } catch (err) {
5365
+ this.log(`[${repoTag}] pool-min refresh: ${err instanceof Error ? err.message : String(err)}`);
5366
+ }
5309
5367
  await pm.resync().catch((err) => this.log(`[${repoTag}] resync: ${err instanceof Error ? err.message : String(err)}`));
5310
5368
  }
5311
5369
  }
@@ -7394,8 +7452,8 @@ function parseFlatYaml(text) {
7394
7452
  const lower = value.toLowerCase();
7395
7453
  if (lower === "true") out.disabled = true;
7396
7454
  else if (lower === "false") out.disabled = false;
7397
- } else if (key === "worker" && value.length > 0) {
7398
- out.worker = value;
7455
+ } else if (key === "staff" && value.length > 0) {
7456
+ out.staff = value;
7399
7457
  }
7400
7458
  }
7401
7459
  return out;
@@ -7755,7 +7813,7 @@ var dispatchJobFileTicks = async (ctx, _profile, args) => {
7755
7813
  if (!targetExecutable) {
7756
7814
  throw new Error("dispatchJobFileTicks: `with.targetExecutable` is required");
7757
7815
  }
7758
- const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
7816
+ const jobsDir = String(args?.jobsDir ?? ".kody/duties");
7759
7817
  const scriptedExecutable = String(args?.scriptedExecutable ?? "job-tick-scripted");
7760
7818
  const slugArg = String(args?.slugArg ?? "job");
7761
7819
  const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
@@ -7782,12 +7840,12 @@ var dispatchJobFileTicks = async (ctx, _profile, args) => {
7782
7840
  results.push({ slug, exitCode: 0, skipped: true, reason: "disabled" });
7783
7841
  continue;
7784
7842
  }
7785
- if (!frontmatter.worker || frontmatter.worker.trim().length === 0) {
7843
+ if (!frontmatter.staff || frontmatter.staff.trim().length === 0) {
7786
7844
  process.stderr.write(
7787
- `[jobs] \u23ED skip ${slug}: no worker assigned (add 'worker: <slug>' frontmatter)
7845
+ `[jobs] \u23ED skip ${slug}: no staff assigned (add 'staff: <slug>' frontmatter)
7788
7846
  `
7789
7847
  );
7790
- results.push({ slug, exitCode: 0, skipped: true, reason: "no worker assigned" });
7848
+ results.push({ slug, exitCode: 0, skipped: true, reason: "no staff assigned" });
7791
7849
  continue;
7792
7850
  }
7793
7851
  const decision = await decideShouldFire(frontmatter.every, slug, backend, now);
@@ -8327,6 +8385,7 @@ var finalizeGoal = async (ctx) => {
8327
8385
  `);
8328
8386
  }
8329
8387
  }
8388
+ const leafIssues = new Set(prIssueNumbers(leaf));
8330
8389
  const openIssues = (goal.childTasks ?? []).filter((t) => t.state === "OPEN");
8331
8390
  for (const t of openIssues) {
8332
8391
  if (uncarriedIssues.has(t.number)) {
@@ -8336,6 +8395,18 @@ var finalizeGoal = async (ctx) => {
8336
8395
  );
8337
8396
  continue;
8338
8397
  }
8398
+ if (leafIssues.has(t.number)) {
8399
+ process.stdout.write(
8400
+ `[goal-tick] leaving leaf task issue #${t.number} OPEN as the review anchor for deliverable PR #${leaf.number}
8401
+ `
8402
+ );
8403
+ commentOnIssue(
8404
+ t.number,
8405
+ `_Goal \`${goal.id}\` finalized \u2014 this task's PR #${leaf.number} (open against \`${goal.defaultBranch}\`) is the goal's single deliverable and carries every task's changes. This issue stays open as the review anchor; merge PR #${leaf.number} to ship._`,
8406
+ ctx.cwd
8407
+ );
8408
+ continue;
8409
+ }
8339
8410
  process.stdout.write(`[goal-tick] closing task issue #${t.number} (goal finalized \u2014 carried by PR #${leaf.number})
8340
8411
  `);
8341
8412
  const closed = closeIssue(
@@ -8983,6 +9054,13 @@ function qualityCommandsFor(pm) {
8983
9054
  testUnit: `${pm} test`
8984
9055
  };
8985
9056
  }
9057
+ function schemaUrlFromPkg() {
9058
+ const fallback = "https://raw.githubusercontent.com/aharonyaircohen/kody-engine/main/kody.config.schema.json";
9059
+ const repoUrl = package_default.repository?.url;
9060
+ const m = repoUrl?.match(/github\.com[:/]([^/]+)\/([^/]+?)(?:\.git)?$/) ?? null;
9061
+ if (!m) return fallback;
9062
+ return `https://raw.githubusercontent.com/${m[1]}/${m[2]}/main/kody.config.schema.json`;
9063
+ }
8986
9064
  function detectOwnerRepo(cwd) {
8987
9065
  let url;
8988
9066
  try {
@@ -9000,7 +9078,7 @@ function detectOwnerRepo(cwd) {
9000
9078
  }
9001
9079
  function makeConfig(pm, ownerRepo, defaultBranch2) {
9002
9080
  return {
9003
- $schema: "https://raw.githubusercontent.com/aharonyaircohen/kody-engine/main/kody.config.schema.json",
9081
+ $schema: schemaUrlFromPkg(),
9004
9082
  quality: qualityCommandsFor(pm),
9005
9083
  git: { defaultBranch: defaultBranch2 },
9006
9084
  github: {
@@ -9127,10 +9205,10 @@ function performInit(cwd, force) {
9127
9205
  }
9128
9206
  const builtinJobs = listBuiltinJobs();
9129
9207
  if (builtinJobs.length > 0) {
9130
- const jobsDir = path29.join(cwd, ".kody", "jobs");
9208
+ const jobsDir = path29.join(cwd, ".kody", "duties");
9131
9209
  fs31.mkdirSync(jobsDir, { recursive: true });
9132
9210
  for (const job of builtinJobs) {
9133
- const rel = path29.join(".kody", "jobs", `${job.slug}.md`);
9211
+ const rel = path29.join(".kody", "duties", `${job.slug}.md`);
9134
9212
  const target = path29.join(cwd, rel);
9135
9213
  if (fs31.existsSync(target) && !force) {
9136
9214
  skipped.push(rel);
@@ -9404,8 +9482,8 @@ var loadIssueStateComment = async (ctx, _profile, args) => {
9404
9482
  import * as fs33 from "fs";
9405
9483
  import * as path31 from "path";
9406
9484
  var loadJobFromFile = async (ctx, _profile, args) => {
9407
- const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
9408
- const workersDir = String(args?.workersDir ?? ".kody/workers");
9485
+ const jobsDir = String(args?.jobsDir ?? ".kody/duties");
9486
+ const workersDir = String(args?.workersDir ?? ".kody/staff");
9409
9487
  const slugArg = String(args?.slugArg ?? "job");
9410
9488
  const slug = String(ctx.args[slugArg] ?? "").trim();
9411
9489
  if (!slug) {
@@ -9417,14 +9495,14 @@ var loadJobFromFile = async (ctx, _profile, args) => {
9417
9495
  }
9418
9496
  const raw = fs33.readFileSync(absPath, "utf-8");
9419
9497
  const { title, body } = parseJobFile(raw, slug);
9420
- const workerSlug = (splitFrontmatter2(raw).frontmatter.worker ?? "").trim();
9498
+ const workerSlug = (splitFrontmatter2(raw).frontmatter.staff ?? "").trim();
9421
9499
  let workerTitle = "";
9422
9500
  let workerPersona = "";
9423
9501
  if (workerSlug) {
9424
9502
  const workerPath = path31.join(ctx.cwd, workersDir, `${workerSlug}.md`);
9425
9503
  if (!fs33.existsSync(workerPath)) {
9426
9504
  throw new Error(
9427
- `loadJobFromFile: job '${slug}' declares worker '${workerSlug}' but ${workerPath} does not exist`
9505
+ `loadJobFromFile: duty '${slug}' declares staff '${workerSlug}' but ${workerPath} does not exist`
9428
9506
  );
9429
9507
  }
9430
9508
  const workerRaw = fs33.readFileSync(workerPath, "utf-8");
@@ -9468,7 +9546,7 @@ function humanizeSlug(slug) {
9468
9546
  import * as fs34 from "fs";
9469
9547
  import * as path32 from "path";
9470
9548
  var loadWorkerAdhoc = async (ctx, _profile, args) => {
9471
- const workersDir = String(args?.workersDir ?? ".kody/workers");
9549
+ const workersDir = String(args?.workersDir ?? ".kody/staff");
9472
9550
  const workerSlug = String(ctx.args.worker ?? "").trim();
9473
9551
  if (!workerSlug) {
9474
9552
  throw new Error("loadWorkerAdhoc: ctx.args.worker must be a non-empty slug");
@@ -10932,7 +11010,7 @@ import * as fs37 from "fs";
10932
11010
  import * as path35 from "path";
10933
11011
  var runTickScript = async (ctx, _profile, args) => {
10934
11012
  ctx.skipAgent = true;
10935
- const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
11013
+ const jobsDir = String(args?.jobsDir ?? ".kody/duties");
10936
11014
  const slugArg = String(args?.slugArg ?? "job");
10937
11015
  const fenceLabel = String(args?.fenceLabel ?? "kody-job-next-state");
10938
11016
  const slug = String(ctx.args[slugArg] ?? "").trim();
@@ -11966,7 +12044,7 @@ var writeJobStateFile = async (ctx, _profile, _agentResult, args) => {
11966
12044
  lastFiredAt: (/* @__PURE__ */ new Date()).toISOString()
11967
12045
  }
11968
12046
  };
11969
- const jobsDir = String(args?.jobsDir ?? ".kody/jobs");
12047
+ const jobsDir = String(args?.jobsDir ?? ".kody/duties");
11970
12048
  const backend = resolveBackend({ config: ctx.config, cwd: ctx.cwd, jobsDir });
11971
12049
  await backend.save(loaded, stamped);
11972
12050
  };
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "job-scheduler",
3
3
  "role": "watch",
4
- "describe": "Scheduled: for every job file under .kody/jobs/, invoke job-tick once. No agent on the scheduler itself.",
4
+ "describe": "Scheduled: for every duty file under .kody/duties/, invoke job-tick once. No agent on the scheduler itself.",
5
5
  "kind": "scheduled",
6
6
  "schedule": "*/5 * * * *",
7
7
  "inputs": [],
@@ -38,7 +38,7 @@
38
38
  {
39
39
  "script": "dispatchJobFileTicks",
40
40
  "with": {
41
- "jobsDir": ".kody/jobs",
41
+ "jobsDir": ".kody/duties",
42
42
  "targetExecutable": "job-tick",
43
43
  "slugArg": "job"
44
44
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "job-tick",
3
3
  "role": "primitive",
4
- "describe": "One classifier tick for one job file: read intent + state, decide and execute via gh, emit next state.",
4
+ "describe": "One classifier tick for one duty file: read intent + state, decide and execute via gh, emit next state.",
5
5
  "kind": "oneshot",
6
6
  "inputs": [
7
7
  {
@@ -9,7 +9,7 @@
9
9
  "flag": "--job",
10
10
  "type": "string",
11
11
  "required": true,
12
- "describe": "Job slug — basename (without .md) of the file under .kody/jobs/."
12
+ "describe": "Duty slug — basename (without .md) of the file under .kody/duties/."
13
13
  },
14
14
  {
15
15
  "name": "force",
@@ -51,7 +51,7 @@
51
51
  {
52
52
  "script": "loadJobFromFile",
53
53
  "with": {
54
- "jobsDir": ".kody/jobs",
54
+ "jobsDir": ".kody/duties",
55
55
  "slugArg": "job"
56
56
  }
57
57
  },
@@ -9,7 +9,7 @@
9
9
  "flag": "--job",
10
10
  "type": "string",
11
11
  "required": true,
12
- "describe": "Job slug — basename (without .md) of the file under .kody/jobs/."
12
+ "describe": "Duty slug — basename (without .md) of the file under .kody/duties/."
13
13
  },
14
14
  {
15
15
  "name": "force",
@@ -51,7 +51,7 @@
51
51
  {
52
52
  "script": "runTickScript",
53
53
  "with": {
54
- "jobsDir": ".kody/jobs",
54
+ "jobsDir": ".kody/duties",
55
55
  "slugArg": "job",
56
56
  "fenceLabel": "kody-job-next-state"
57
57
  }
@@ -61,7 +61,7 @@
61
61
  {
62
62
  "script": "writeJobStateFile",
63
63
  "with": {
64
- "jobsDir": ".kody/jobs"
64
+ "jobsDir": ".kody/duties"
65
65
  }
66
66
  }
67
67
  ]
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "worker-ask",
3
3
  "role": "primitive",
4
- "describe": "Ad-hoc one-shot: run a worker persona against an inline message + context (from a dashboard @worker mention). Stateless — no job file, no state, no commit. Replies into the originating thread.",
4
+ "describe": "Ad-hoc one-shot: run a staff persona against an inline message + context (from a dashboard @staff mention). Stateless — no duty file, no state, no commit. Replies into the originating thread.",
5
5
  "kind": "oneshot",
6
6
  "inputs": [
7
7
  {
@@ -9,7 +9,7 @@
9
9
  "flag": "--worker",
10
10
  "type": "string",
11
11
  "required": true,
12
- "describe": "Worker slug — basename (without .md) of the persona file under .kody/workers/."
12
+ "describe": "Staff slug — basename (without .md) of the persona file under .kody/staff/."
13
13
  },
14
14
  {
15
15
  "name": "thread",
@@ -58,7 +58,7 @@
58
58
  {
59
59
  "script": "loadWorkerAdhoc",
60
60
  "with": {
61
- "workersDir": ".kody/workers"
61
+ "workersDir": ".kody/staff"
62
62
  }
63
63
  },
64
64
  {
@@ -393,7 +393,7 @@
393
393
  },
394
394
  "jobs": {
395
395
  "type": "object",
396
- "description": "File-based job configuration. Jobs are long-running scheduled executables defined under .kody/jobs/<slug>.md.",
396
+ "description": "File-based job configuration. Jobs are long-running scheduled executables defined under .kody/duties/<slug>.md.",
397
397
  "properties": {
398
398
  "stateBackend": {
399
399
  "type": "string",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.120",
3
+ "version": "0.4.122",
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",
@@ -12,6 +12,24 @@
12
12
  "templates",
13
13
  "kody.config.schema.json"
14
14
  ],
15
+ "scripts": {
16
+ "kody:run": "tsx bin/kody.ts",
17
+ "serve": "tsx bin/kody.ts serve",
18
+ "serve:vscode": "tsx bin/kody.ts serve vscode",
19
+ "serve:claude": "tsx bin/kody.ts serve claude",
20
+ "build": "tsup && node scripts/copy-assets.cjs",
21
+ "check:modularity": "tsx scripts/check-script-modularity.ts",
22
+ "pretest": "pnpm check:modularity",
23
+ "test": "vitest run tests/unit tests/int --coverage",
24
+ "test:smoke": "vitest run tests/smoke --no-coverage",
25
+ "test:e2e": "vitest run tests/e2e --no-coverage",
26
+ "test:all": "vitest run tests --no-coverage",
27
+ "typecheck": "tsc --noEmit",
28
+ "lint": "biome check",
29
+ "lint:fix": "biome check --write",
30
+ "format": "biome format --write",
31
+ "prepublishOnly": "pnpm build"
32
+ },
15
33
  "dependencies": {
16
34
  "@actions/cache": "^6.0.0",
17
35
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
@@ -20,6 +38,7 @@
20
38
  "devDependencies": {
21
39
  "@biomejs/biome": "^2.4.12",
22
40
  "@types/node": "^22.5.4",
41
+ "@vitest/coverage-v8": "^4.1.4",
23
42
  "tsup": "^8.5.1",
24
43
  "tsx": "^4.21.0",
25
44
  "typescript": "~5.7.0",
@@ -33,21 +52,5 @@
33
52
  "url": "git+https://github.com/aharonyaircohen/kody-engine.git"
34
53
  },
35
54
  "homepage": "https://github.com/aharonyaircohen/kody-engine",
36
- "bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
37
- "scripts": {
38
- "kody:run": "tsx bin/kody.ts",
39
- "serve": "tsx bin/kody.ts serve",
40
- "serve:vscode": "tsx bin/kody.ts serve vscode",
41
- "serve:claude": "tsx bin/kody.ts serve claude",
42
- "build": "tsup && node scripts/copy-assets.cjs",
43
- "check:modularity": "tsx scripts/check-script-modularity.ts",
44
- "pretest": "pnpm check:modularity",
45
- "test": "vitest run tests/unit tests/int --no-coverage",
46
- "test:e2e": "vitest run tests/e2e --no-coverage",
47
- "test:all": "vitest run tests --no-coverage",
48
- "typecheck": "tsc --noEmit",
49
- "lint": "biome check",
50
- "lint:fix": "biome check --write",
51
- "format": "biome format --write"
52
- }
53
- }
55
+ "bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
56
+ }