@akanjs/cli 3.0.0-beta.17 → 3.0.0-beta.19

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 (149) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-gjqnc2mg.js → CodeAgent-6cm97kay.js} +2 -2
  3. package/{CodeAgentRpcHost-qvwfv0n9.js → CodeAgentRpcHost-p7h6n2hp.js} +1 -1
  4. package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
  5. package/{CodeTui-nd9hqvrw.js → CodeTui-za4jsm41.js} +205 -34
  6. package/{TunnelShare-r5tc2qk5.js → TunnelShare-2j6s511d.js} +2 -2
  7. package/{agent.command-n664dtcv.js → agent.command-e0wpbbyg.js} +6 -6
  8. package/akanCode.js +7 -5
  9. package/{application.command-t5542jte.js → application.command-8wyxqc8q.js} +28 -15
  10. package/{applicationBuildRunner-x4gbfn7y.js → applicationBuildRunner-n9gzaxd0.js} +35 -10
  11. package/{applicationReleasePackager-z61ep017.js → applicationReleasePackager-vpggfqgq.js} +1 -1
  12. package/buildBatch.proc.js +3 -3
  13. package/{capacitorApp-shv3ajh5.js → capacitorApp-q3z0qht0.js} +2 -2
  14. package/{cloud.command-dk5tj39k.js → cloud.command-4zwa5dsx.js} +34 -12
  15. package/cloud.script-fwx3vb34.js +20 -0
  16. package/{code.command-88sebgnn.js → code.command-468c9d7s.js} +41 -19
  17. package/commandManifest.json +1 -1
  18. package/{context.command-pqsm5jrk.js → context.command-dsnw0jby.js} +14 -14
  19. package/context.runner-rs4rj15d.js +22 -0
  20. package/{dependencyScanner-shs82ynp.js → dependencyScanner-0z2h2tks.js} +1 -1
  21. package/{devTui-gy6mendg.js → devTui-ffjsarqa.js} +3 -3
  22. package/{devTuiView-y1548wy6.js → devTuiView-1q1mdgrv.js} +1 -1
  23. package/{guideline.command-rpc2emw8.js → guideline.command-vhw13pqr.js} +8 -13
  24. package/guidelines/agentRule/agentRule.instruction.md +27 -10
  25. package/guidelines/conventions/conventions.instruction.md +53 -26
  26. package/guidelines/queryRule/queryRule.instruction.md +17 -7
  27. package/guidelines/runtimeRule/runtimeRule.instruction.md +74 -0
  28. package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
  29. package/guidelines/transportRule/transportRule.instruction.md +10 -8
  30. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +4 -3
  31. package/incrementalBuilder.proc.js +3 -2
  32. package/{index-4n4821gp.js → index-10dkrrww.js} +4 -4
  33. package/{index-bzakk0c2.js → index-14zrtgfa.js} +5 -3
  34. package/{index-v17gj504.js → index-18zybgkc.js} +2 -2
  35. package/{index-qh7brn20.js → index-22xtgmhn.js} +6 -2
  36. package/{index-qhtj9y6j.js → index-2446k7b4.js} +74 -21
  37. package/{index-g9zghs4h.js → index-3jrp517k.js} +12 -12
  38. package/{index-vpx68e4x.js → index-4m929vvn.js} +2 -2
  39. package/{index-4cvpzkq6.js → index-53176s7j.js} +3 -3
  40. package/{index-jwrpsrg3.js → index-667w0yah.js} +1 -1
  41. package/{index-3mg4h788.js → index-7ep8qtvp.js} +2 -2
  42. package/{index-w8kmx1b6.js → index-89hy31kf.js} +30 -7
  43. package/index-9d6nvkz2.js +656 -0
  44. package/index-9dp031by.js +12 -0
  45. package/{index-zn8qgeqx.js → index-a1w6934z.js} +3 -3
  46. package/{index-p0tew3fq.js → index-ab0c38ea.js} +10 -5
  47. package/index-bc88j1ry.js +1166 -0
  48. package/{index-ns128c4q.js → index-bftkz6cp.js} +280 -73
  49. package/{index-kcxmv48c.js → index-bhtmj233.js} +4 -1
  50. package/{index-kvzjda3v.js → index-bwf965h6.js} +5 -5
  51. package/{index-p4p9t45x.js → index-crmeqnmf.js} +56 -44
  52. package/{index-8k16atqy.js → index-d2242ksy.js} +23 -6
  53. package/{index-2sq06vv0.js → index-e4v6vhxq.js} +417 -105
  54. package/{index-xjc7gg65.js → index-esk82rvk.js} +23 -33
  55. package/{index-sn7dnzq4.js → index-kwaq3n9n.js} +1 -1
  56. package/{index-gm76f0qb.js → index-n3cv0tm4.js} +1 -1
  57. package/{index-6na0sd2b.js → index-qdgzsnhg.js} +5 -2
  58. package/{index-twq9p2sp.js → index-s5rhm04y.js} +0 -6
  59. package/{index-n8kt2wh6.js → index-sq2dzkzm.js} +35 -10
  60. package/{index-myj01w9r.js → index-srmay5jw.js} +15 -2
  61. package/{index-2pm1j01n.js → index-txr7dj2g.js} +4 -4
  62. package/{index-3cymrzsb.js → index-vqx8bdxz.js} +17 -3
  63. package/{index-te0y1c0m.js → index-zqgj2rt2.js} +12 -7
  64. package/index.js +21 -21
  65. package/{library.command-m8p2r1dh.js → library.command-cqr175dy.js} +3 -3
  66. package/{localRegistry.command-yppdqrxv.js → localRegistry.command-49z55qqz.js} +9 -9
  67. package/{module.command-mfzvqt0n.js → module.command-9p8mm3b0.js} +5 -5
  68. package/{package.command-cgp2p2v5.js → package.command-wxyz909t.js} +5 -5
  69. package/package.json +2 -2
  70. package/{page.command-taenb02b.js → page.command-gsrsfqqs.js} +3 -3
  71. package/{primitive.command-7kpncmkk.js → primitive.command-ns1mptje.js} +6 -6
  72. package/{prompter-9mn3kp36.js → prompter-1f8d9pcc.js} +1 -1
  73. package/{quality.command-1ar94hrw.js → quality.command-e76k2q9k.js} +18 -17
  74. package/{repair.command-n08t6j8p.js → repair.command-pkrsm3cw.js} +5 -5
  75. package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
  76. package/{scalar.command-mq8qfp4t.js → scalar.command-0cpt3fc8.js} +4 -4
  77. package/skills/akan-code/SKILL.md +122 -0
  78. package/skills/akan-module/SKILL.md +2 -2
  79. package/skills/akan-store/SKILL.md +6 -2
  80. package/{subspace.command-jqv5n79w.js → subspace.command-fktpwp0g.js} +20 -10
  81. package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
  82. package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
  83. package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
  84. package/templates/appSample/lib/task/task.abstract.ts +12 -32
  85. package/templates/appSample/lib/task/task.signal.spec.ts +15 -18
  86. package/templates/appSample/lib/task/task.signal.test.ts +15 -1
  87. package/templates/appSample/lib/task/task.signal.ts +1 -1
  88. package/templates/appSample/srvkit/AuthGuard.ts +4 -1
  89. package/templates/appSample/srvkit/SessionInternalArg.ts +3 -1
  90. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
  91. package/templates/crudPages/[__model__Id]/page.tsx +2 -1
  92. package/templates/crudPages/new/page.tsx +2 -1
  93. package/templates/crudPages/page.tsx +2 -1
  94. package/templates/crudSinglePage/page.tsx +2 -1
  95. package/templates/localDev/docker-compose.yaml.template +3 -14
  96. package/templates/module/__model__.signal.ts +12 -4
  97. package/templates/pkgRoot/tsconfig.json.template +2 -7
  98. package/templates/service/__model__.abstract.md.template +8 -0
  99. package/{tunnel.command-ht2es78c.js → tunnel.command-d5jy9gk8.js} +4 -4
  100. package/{workflow.command-tvz4nm9n.js → workflow.command-6tkcysmx.js} +9 -9
  101. package/{workspace.command-txv1yv5e.js → workspace.command-gv84eh1p.js} +25 -24
  102. package/cloud.script-ch3xrw3s.js +0 -20
  103. package/context.runner-bys6ykcp.js +0 -22
  104. package/guidelines/agentRule/agentRule.generate.json +0 -31
  105. package/guidelines/componentRule/componentRule.generate.json +0 -31
  106. package/guidelines/conventions/conventions.generate.json +0 -25
  107. package/guidelines/cssRule/cssRule.generate.json +0 -31
  108. package/guidelines/docPageRule/docPageRule.generate.json +0 -31
  109. package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
  110. package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
  111. package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
  112. package/guidelines/enumConstant/enumConstant.generate.json +0 -31
  113. package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
  114. package/guidelines/fieldRule/fieldRule.generate.json +0 -31
  115. package/guidelines/framework/framework.generate.json +0 -32
  116. package/guidelines/mcpRule/mcpRule.generate.json +0 -35
  117. package/guidelines/modelConstant/modelConstant.generate.json +0 -32
  118. package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
  119. package/guidelines/modelDocument/modelDocument.generate.json +0 -31
  120. package/guidelines/modelService/modelService.generate.json +0 -31
  121. package/guidelines/modelSignal/modelSignal.generate.json +0 -31
  122. package/guidelines/modelStore/modelStore.generate.json +0 -31
  123. package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
  124. package/guidelines/modelUnit/modelUnit.generate.json +0 -31
  125. package/guidelines/modelUtil/modelUtil.generate.json +0 -31
  126. package/guidelines/modelView/modelView.generate.json +0 -31
  127. package/guidelines/modelZone/modelZone.generate.json +0 -31
  128. package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
  129. package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
  130. package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
  131. package/guidelines/queryRule/queryRule.generate.json +0 -31
  132. package/guidelines/recipeRule/recipeRule.generate.json +0 -31
  133. package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
  134. package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
  135. package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
  136. package/guidelines/scalarModule/scalarModule.generate.json +0 -31
  137. package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
  138. package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
  139. package/guidelines/ssrRule/ssrRule.generate.json +0 -31
  140. package/guidelines/transportRule/transportRule.generate.json +0 -31
  141. package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
  142. package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
  143. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
  144. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -34
  145. package/index-57p9p179.js +0 -461
  146. package/index-qt8dqgnf.js +0 -250
  147. package/templates/__scalar/__model__/__model__.abstract.md +0 -28
  148. package/templates/module/__model__.abstract.md +0 -28
  149. package/templates/service/__model__.abstract.md +0 -28
@@ -2,16 +2,16 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-6na0sd2b.js";
5
+ } from "./index-qdgzsnhg.js";
6
6
  import {
7
7
  WorkspaceExecutor,
8
8
  AppExecutor,
9
9
  LibExecutor,
10
10
  PkgExecutor
11
- } from "./index-p4p9t45x.js";
11
+ } from "./index-crmeqnmf.js";
12
12
  import {
13
13
  LibraryScript
14
- } from "./index-3mg4h788.js";
14
+ } from "./index-7ep8qtvp.js";
15
15
  import {
16
16
  HmrWatcher,
17
17
  WatchRootResolver
@@ -22,20 +22,13 @@ import {
22
22
  import {
23
23
  SlicePlanner,
24
24
  formatSlicePlan
25
- } from "./index-sn7dnzq4.js";
25
+ } from "./index-kwaq3n9n.js";
26
26
  import {
27
27
  resolveMobileTargets
28
28
  } from "./index-47pj3aee.js";
29
-
30
- // pkgs/@akanjs/cli/openBrowser.ts
31
- import { spawn } from "child_process";
32
- function openBrowser(url) {
33
- const command = process.platform === "darwin" ? ["open", url] : process.platform === "win32" ? ["cmd", "/c", "start", "", url] : ["xdg-open", url];
34
- const child = spawn(command[0], command.slice(1), { detached: true, stdio: "ignore" });
35
- child.on("error", () => {});
36
- child.unref();
37
- return Promise.resolve();
38
- }
29
+ import {
30
+ openBrowser
31
+ } from "./index-9dp031by.js";
39
32
 
40
33
  // pkgs/@akanjs/devkit/applicationBuildReporter.ts
41
34
  import { Logger } from "akanjs/common";
@@ -1351,16 +1344,18 @@ ${this.#backendStderrTail.join(`
1351
1344
  this.#recycleBuilderForRss(settledBytes === null ? reason : `${reason}; still ${asMib(settledBytes)}MiB after settling`);
1352
1345
  }
1353
1346
  static async readProcessRssBytes(pid) {
1347
+ if (process.platform === "win32")
1348
+ return await AkanAppHost.#readRssKbVia(["tasklist", "/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], AkanAppHost.#tasklistRssKb);
1354
1349
  const status = await Bun.file(`/proc/${pid}/status`).text().catch(() => null);
1355
1350
  const vmRssKb = status === null ? null : /VmRSS:\s+(\d+) kB/.exec(status)?.[1];
1356
1351
  if (vmRssKb)
1357
1352
  return Number(vmRssKb) * 1024;
1358
- return await AkanAppHost.#readRssViaPs(pid);
1353
+ return await AkanAppHost.#readRssKbVia(["ps", "-o", "rss=", "-p", String(pid)], (output) => Number(output.trim()));
1359
1354
  }
1360
- static async#readRssViaPs(pid, timeoutMs = PS_RSS_TIMEOUT_MS) {
1355
+ static async#readRssKbVia(command, parseKb, timeoutMs = PS_RSS_TIMEOUT_MS) {
1361
1356
  let proc;
1362
1357
  try {
1363
- proc = Bun.spawn(["ps", "-o", "rss=", "-p", String(pid)], { stdio: ["ignore", "pipe", "ignore"] });
1358
+ proc = Bun.spawn(command, { stdio: ["ignore", "pipe", "ignore"] });
1364
1359
  } catch {
1365
1360
  return null;
1366
1361
  }
@@ -1368,7 +1363,7 @@ ${this.#backendStderrTail.join(`
1368
1363
  try {
1369
1364
  const output = await new Response(proc.stdout).text();
1370
1365
  await proc.exited;
1371
- const rssKb = Number(output.trim());
1366
+ const rssKb = parseKb(output);
1372
1367
  return Number.isFinite(rssKb) && rssKb > 0 ? rssKb * 1024 : null;
1373
1368
  } catch {
1374
1369
  return null;
@@ -1376,6 +1371,10 @@ ${this.#backendStderrTail.join(`
1376
1371
  clearTimeout(killer);
1377
1372
  }
1378
1373
  }
1374
+ static #tasklistRssKb(output) {
1375
+ const memUsage = /"([^"]*)"\s*$/m.exec(output)?.[1];
1376
+ return memUsage ? Number(memUsage.replace(/\D/g, "")) : Number.NaN;
1377
+ }
1379
1378
  #cancelRssRecycle() {
1380
1379
  this.#rssRecycleReason = null;
1381
1380
  this.#rssRecycleOver = null;
@@ -1966,9 +1965,9 @@ ${uniqueCandidates.map((candidate) => ` - ${candidate}`).join(`
1966
1965
 
1967
1966
  // pkgs/@akanjs/cli/application/application.runner.ts
1968
1967
  import { Logger as Logger4 } from "akanjs/common";
1969
- var loadBuildRunner = async () => (await import("./applicationBuildRunner-x4gbfn7y.js")).ApplicationBuildRunner;
1970
- var loadReleasePackager = async () => (await import("./applicationReleasePackager-z61ep017.js")).ApplicationReleasePackager;
1971
- var loadCapacitorApp = async () => (await import("./capacitorApp-shv3ajh5.js")).CapacitorApp;
1968
+ var loadBuildRunner = async () => (await import("./applicationBuildRunner-n9gzaxd0.js")).ApplicationBuildRunner;
1969
+ var loadReleasePackager = async () => (await import("./applicationReleasePackager-vpggfqgq.js")).ApplicationReleasePackager;
1970
+ var loadCapacitorApp = async () => (await import("./capacitorApp-q3z0qht0.js")).CapacitorApp;
1972
1971
  var loadPrompts = async () => await import("@inquirer/prompts");
1973
1972
 
1974
1973
  class ApplicationRunner extends runner("application") {
@@ -2011,7 +2010,7 @@ class ApplicationRunner extends runner("application") {
2011
2010
  if (!await app.exists(scriptPath))
2012
2011
  throw new Error(`Script file not found: apps/${app.name}/${scriptPath}`);
2013
2012
  await app.spawn("bun", [scriptPath], {
2014
- env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "script" }),
2013
+ env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "script", ...await app.getDatabaseModeEnv() }),
2015
2014
  stdio: "inherit"
2016
2015
  });
2017
2016
  }
@@ -2083,7 +2082,7 @@ const serverModule = await import(${JSON.stringify(serverPath)});
2083
2082
  const { assertAkanConsoleAllowed, startAkanConsole } = await import("akanjs/server");
2084
2083
  const server = serverModule.server;
2085
2084
  if (!server?.start) throw new Error("server.ts must export server with start()");
2086
- assertAkanConsoleAllowed(server.env);
2085
+ assertAkanConsoleAllowed();
2087
2086
  await server.start({ listen: false, web: false });
2088
2087
  try {
2089
2088
  await startAkanConsole(server, {
@@ -2102,7 +2101,29 @@ try {
2102
2101
  }
2103
2102
  `;
2104
2103
  await app.spawn("bun", ["-e", code], {
2105
- env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "console" }),
2104
+ env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "console", ...await app.getDatabaseModeEnv() }),
2105
+ stdio: "inherit"
2106
+ });
2107
+ }
2108
+ async transferDatabase(app, direction, dir) {
2109
+ const serverPath = `${app.cwdPath}/server.ts`;
2110
+ if (!await app.exists("server.ts"))
2111
+ throw new Error(`Server file not found: apps/${app.name}/server.ts`);
2112
+ const target = path5.resolve(app.workspace.workspaceRoot, dir);
2113
+ const code = `
2114
+ const { server } = await import(${JSON.stringify(serverPath)});
2115
+ const { DatabaseAdaptorRole, DocumentTransfer } = await import("akanjs/service");
2116
+ await server.start({ listen: false, web: false });
2117
+ try {
2118
+ const transfer = new DocumentTransfer(server.get(DatabaseAdaptorRole));
2119
+ const reports = await transfer.${direction === "export" ? "exportTo" : "importFrom"}(${JSON.stringify(target)});
2120
+ for (const { table, rows } of reports) console.info(\`${direction === "export" ? "exported" : "imported"} \${table}: \${rows} rows\`);
2121
+ } finally {
2122
+ await server.stop();
2123
+ }
2124
+ `;
2125
+ await app.spawn("bun", ["-e", code], {
2126
+ env: app.getCommandEnv({ AKAN_COMMAND_TYPE: "script", ...await app.getDatabaseModeEnv() }),
2106
2127
  stdio: "inherit"
2107
2128
  });
2108
2129
  }
@@ -2262,9 +2283,15 @@ try {
2262
2283
  if (mode === "single")
2263
2284
  return [];
2264
2285
  if (mode === "multiple")
2265
- return ["redis", "libsql"];
2286
+ return ["redis"];
2266
2287
  return ["redis", "postgres"];
2267
2288
  }
2289
+ async#assertComposeHas(workspace, services) {
2290
+ const compose = Bun.YAML.parse(await Bun.file(`${workspace.workspaceRoot}/local/docker-compose.yaml`).text());
2291
+ const missing = services.filter((service) => !compose?.services?.[service]);
2292
+ if (missing.length)
2293
+ throw new Error(`local/docker-compose.yaml declares no ${missing.join(" or ")} service. Add it, or move the file aside so the next akan dbup writes the current template.`);
2294
+ }
2268
2295
  async#isLocalDatabaseUp(workspace, mode) {
2269
2296
  const requiredServices = this.#getLocalDatabaseServices(mode);
2270
2297
  if (!requiredServices.length)
@@ -2278,16 +2305,18 @@ try {
2278
2305
  async dbup(workspace, mode = "multiple") {
2279
2306
  if (mode === "single")
2280
2307
  return true;
2308
+ const services = this.#getLocalDatabaseServices(mode);
2309
+ await workspace.applyTemplate({
2310
+ basePath: "local",
2311
+ template: "localDev",
2312
+ dict: { repoName: workspace.repoName },
2313
+ overwrite: false
2314
+ });
2315
+ await this.#assertComposeHas(workspace, services);
2281
2316
  try {
2282
- await workspace.applyTemplate({
2283
- basePath: "local",
2284
- template: "localDev",
2285
- dict: { repoName: workspace.repoName },
2286
- overwrite: false
2287
- });
2288
2317
  const wasAlreadyUp = await this.#isLocalDatabaseUp(workspace, mode);
2289
2318
  if (!wasAlreadyUp)
2290
- await workspace.spawn(`docker`, ["compose", "up", "-d", ...this.#getLocalDatabaseServices(mode)], {
2319
+ await workspace.spawn(`docker`, ["compose", "up", "-d", ...services], {
2291
2320
  cwd: `${workspace.workspaceRoot}/local`
2292
2321
  });
2293
2322
  return wasAlreadyUp;
@@ -2348,9 +2377,187 @@ ${detail}`
2348
2377
  }
2349
2378
  }
2350
2379
 
2380
+ // pkgs/@akanjs/cli/application/hostProcessProbe.ts
2381
+ import { readdirSync, readFileSync, readlinkSync } from "fs";
2382
+
2383
+ class HostProcessProbe {
2384
+ static timeoutMs = 3000;
2385
+ static win32TimeoutMs = 20000;
2386
+ static #procTcpListen = "0A";
2387
+ static #win32ProcessQuery = "[Console]::OutputEncoding=[Text.Encoding]::UTF8; Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress";
2388
+ platform;
2389
+ #win32Table = null;
2390
+ constructor(platform = process.platform) {
2391
+ this.platform = platform;
2392
+ }
2393
+ async listenersOn(port) {
2394
+ if (this.platform === "win32")
2395
+ return HostProcessProbe.parseNetstat(await HostProcessProbe.run(["netstat", "-ano"]), port);
2396
+ if (this.platform === "linux")
2397
+ return HostProcessProbe.#procListenersOn(port);
2398
+ const output = await HostProcessProbe.run(["lsof", "-ti", `tcp:${port}`, "-sTCP:LISTEN"]);
2399
+ return [
2400
+ ...new Set(output.split(`
2401
+ `).map((line) => Number(line.trim())).filter((pid) => Number.isInteger(pid) && pid > 0))
2402
+ ];
2403
+ }
2404
+ async parentOf(pid) {
2405
+ if (this.platform === "win32") {
2406
+ const child = await this.#win32Process(pid);
2407
+ const parent = child ? await this.#win32Process(child.ppid) : null;
2408
+ return child && parent ? HostProcessProbe.parentPidOf(child, parent) : null;
2409
+ }
2410
+ if (this.platform === "linux") {
2411
+ const stat = HostProcessProbe.#readProc(pid, "stat");
2412
+ return stat === null ? null : HostProcessProbe.parseProcStatPpid(stat);
2413
+ }
2414
+ const parsed = Number((await HostProcessProbe.run(["ps", "-p", String(pid), "-o", "ppid="])).trim());
2415
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
2416
+ }
2417
+ async commandOf(pid) {
2418
+ if (this.platform === "win32")
2419
+ return (await this.#win32Process(pid))?.command ?? null;
2420
+ if (this.platform === "linux") {
2421
+ const cmdline = HostProcessProbe.#readProc(pid, "cmdline");
2422
+ return cmdline?.split("\x00").filter(Boolean).join(" ") || null;
2423
+ }
2424
+ return (await HostProcessProbe.run(["ps", "-ww", "-p", String(pid), "-o", "command="])).trim() || null;
2425
+ }
2426
+ static parentPidOf(child, parent) {
2427
+ if (child.ppid !== parent.pid)
2428
+ return null;
2429
+ if (parent.startedAt !== null && child.startedAt !== null && parent.startedAt > child.startedAt)
2430
+ return null;
2431
+ return parent.pid;
2432
+ }
2433
+ static parseNetstat(output, port) {
2434
+ const pids = new Set;
2435
+ for (const line of output.split(/\r?\n/)) {
2436
+ const fields = line.trim().split(/\s+/);
2437
+ if (fields[0] !== "TCP" || fields.length < 5)
2438
+ continue;
2439
+ const [, local, remote] = fields;
2440
+ if (!local?.endsWith(`:${port}`) || !remote?.endsWith(":0"))
2441
+ continue;
2442
+ const pid = Number(fields.at(-1));
2443
+ if (Number.isInteger(pid) && pid > 0)
2444
+ pids.add(pid);
2445
+ }
2446
+ return [...pids];
2447
+ }
2448
+ static parseProcNetTcp(text, port) {
2449
+ const inodes = [];
2450
+ for (const line of text.split(`
2451
+ `).slice(1)) {
2452
+ const fields = line.trim().split(/\s+/);
2453
+ const [, local, , state, , , , , , inode] = fields;
2454
+ if (!local || !inode || state !== HostProcessProbe.#procTcpListen || inode === "0")
2455
+ continue;
2456
+ if (Number.parseInt(local.slice(local.lastIndexOf(":") + 1), 16) === port)
2457
+ inodes.push(inode);
2458
+ }
2459
+ return inodes;
2460
+ }
2461
+ static parseProcStatPpid(stat) {
2462
+ const ppid = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1]);
2463
+ return Number.isInteger(ppid) && ppid > 0 ? ppid : null;
2464
+ }
2465
+ static parseWin32Processes(json) {
2466
+ const table = new Map;
2467
+ let parsed;
2468
+ try {
2469
+ parsed = JSON.parse(json.trim() || "[]");
2470
+ } catch {
2471
+ return table;
2472
+ }
2473
+ const rows = Array.isArray(parsed) ? parsed : [parsed];
2474
+ for (const row of rows) {
2475
+ if (typeof row?.ProcessId !== "number")
2476
+ continue;
2477
+ table.set(row.ProcessId, {
2478
+ pid: row.ProcessId,
2479
+ ppid: row.ParentProcessId ?? 0,
2480
+ command: row.CommandLine?.trim() || null,
2481
+ startedAt: HostProcessProbe.#parseCimDate(row.CreationDate)
2482
+ });
2483
+ }
2484
+ return table;
2485
+ }
2486
+ static async run(command, timeoutMs = HostProcessProbe.timeoutMs) {
2487
+ let proc;
2488
+ try {
2489
+ proc = Bun.spawn(command, { stdio: ["ignore", "pipe", "ignore"], windowsHide: true });
2490
+ } catch {
2491
+ return "";
2492
+ }
2493
+ const timer = setTimeout(() => proc.kill("SIGKILL"), timeoutMs);
2494
+ try {
2495
+ return await new Response(proc.stdout).text();
2496
+ } catch {
2497
+ return "";
2498
+ } finally {
2499
+ clearTimeout(timer);
2500
+ }
2501
+ }
2502
+ async#win32Process(pid) {
2503
+ this.#win32Table ??= await HostProcessProbe.#queryWin32Processes();
2504
+ if (!this.#win32Table.has(pid))
2505
+ this.#win32Table = await HostProcessProbe.#queryWin32Processes();
2506
+ return this.#win32Table.get(pid) ?? null;
2507
+ }
2508
+ static async#queryWin32Processes() {
2509
+ const output = await HostProcessProbe.run(["powershell", "-NoProfile", "-NonInteractive", "-Command", HostProcessProbe.#win32ProcessQuery], HostProcessProbe.win32TimeoutMs);
2510
+ return HostProcessProbe.parseWin32Processes(output);
2511
+ }
2512
+ static #parseCimDate(value) {
2513
+ if (!value)
2514
+ return null;
2515
+ const legacy = /\/Date\((\d+)/.exec(value)?.[1];
2516
+ const ms = legacy ? Number(legacy) : Date.parse(value);
2517
+ return Number.isFinite(ms) ? ms : null;
2518
+ }
2519
+ static #procListenersOn(port) {
2520
+ const inodes = new Set(["tcp", "tcp6"].flatMap((table) => HostProcessProbe.parseProcNetTcp(HostProcessProbe.#readProc("net", table) ?? "", port)));
2521
+ if (!inodes.size)
2522
+ return [];
2523
+ const pids = [];
2524
+ for (const entry of HostProcessProbe.#listDir("/proc")) {
2525
+ if (!/^\d+$/.test(entry))
2526
+ continue;
2527
+ const holds = HostProcessProbe.#listDir(`/proc/${entry}/fd`).some((fd) => {
2528
+ const inode = /^socket:\[(\d+)\]$/.exec(HostProcessProbe.#readLink(`/proc/${entry}/fd/${fd}`))?.[1];
2529
+ return !!inode && inodes.has(inode);
2530
+ });
2531
+ if (holds)
2532
+ pids.push(Number(entry));
2533
+ }
2534
+ return pids;
2535
+ }
2536
+ static #readProc(pid, file) {
2537
+ try {
2538
+ return readFileSync(`/proc/${pid}/${file}`, "utf8");
2539
+ } catch {
2540
+ return null;
2541
+ }
2542
+ }
2543
+ static #listDir(dir) {
2544
+ try {
2545
+ return readdirSync(dir);
2546
+ } catch {
2547
+ return [];
2548
+ }
2549
+ }
2550
+ static #readLink(link) {
2551
+ try {
2552
+ return readlinkSync(link);
2553
+ } catch {
2554
+ return "";
2555
+ }
2556
+ }
2557
+ }
2558
+
2351
2559
  // pkgs/@akanjs/cli/application/devPortReclaimer.ts
2352
2560
  class DevPortReclaimer {
2353
- static lsofTimeoutMs = 3000;
2354
2561
  static releaseTimeoutMs = 8000;
2355
2562
  static maxAncestorDepth = 8;
2356
2563
  static #releasePollMs = 100;
@@ -2359,7 +2566,12 @@ class DevPortReclaimer {
2359
2566
  return [...new Set(ports.flatMap((port) => [port, port + DevPortReclaimer.wsPortOffset]))].sort((left, right) => left - right);
2360
2567
  }
2361
2568
  static isAkanCommand(command) {
2362
- return /(^|\/)akan(\s|$)/.test(command) || command.includes("@akanjs/cli") || command.includes("akanjs/server") || /\bapps\/[^/\s]+\/main\.ts\b/.test(command) || command.includes("incrementalBuilder.proc") || command.includes("rscWorker");
2569
+ const normalized = command.replaceAll("\\", "/");
2570
+ return /(^|\/)akan(\.exe)?"?(\s|$)/.test(normalized) || normalized.includes("@akanjs/cli") || normalized.includes("akanjs/server") || /\bapps\/[^/\s]+\/main\.ts\b/.test(normalized) || normalized.includes("incrementalBuilder.proc") || normalized.includes("rscWorker");
2571
+ }
2572
+ #probe;
2573
+ constructor(probe = new HostProcessProbe) {
2574
+ this.#probe = probe;
2363
2575
  }
2364
2576
  async reclaim(ports) {
2365
2577
  const killed = [];
@@ -2384,10 +2596,10 @@ class DevPortReclaimer {
2384
2596
  }
2385
2597
  async holdersOf(port) {
2386
2598
  const holders = [];
2387
- for (const listenerPid of await this.#pidsOn(port)) {
2599
+ for (const listenerPid of await this.#probe.listenersOn(port)) {
2388
2600
  if (listenerPid === process.pid || listenerPid === process.ppid)
2389
2601
  continue;
2390
- const command = await this.#commandOf(listenerPid);
2602
+ const command = await this.#probe.commandOf(listenerPid);
2391
2603
  if (!command)
2392
2604
  continue;
2393
2605
  if (!DevPortReclaimer.isAkanCommand(command)) {
@@ -2402,44 +2614,37 @@ class DevPortReclaimer {
2402
2614
  async#akanRootOf(pid, command) {
2403
2615
  let root = { pid, command };
2404
2616
  for (let depth = 0;depth < DevPortReclaimer.maxAncestorDepth; depth += 1) {
2405
- const parentPid = await this.#ppidOf(root.pid);
2617
+ const parentPid = await this.#probe.parentOf(root.pid);
2406
2618
  if (parentPid === null || parentPid <= 1 || parentPid === process.pid || parentPid === process.ppid)
2407
2619
  break;
2408
- const parentCommand = await this.#commandOf(parentPid);
2620
+ const parentCommand = await this.#probe.commandOf(parentPid);
2409
2621
  if (!parentCommand || !DevPortReclaimer.isAkanCommand(parentCommand))
2410
2622
  break;
2411
2623
  root = { pid: parentPid, command: parentCommand };
2412
2624
  }
2413
2625
  return root;
2414
2626
  }
2415
- async#ppidOf(pid) {
2416
- const output = await this.#run(["ps", "-p", String(pid), "-o", "ppid="]);
2417
- const parsed = Number(output.trim());
2418
- return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
2419
- }
2420
- async#pidsOn(port) {
2421
- const output = await this.#run(["lsof", "-ti", `tcp:${port}`, "-sTCP:LISTEN"]);
2422
- return [
2423
- ...new Set(output.split(`
2424
- `).map((line) => Number(line.trim())).filter((pid) => Number.isInteger(pid) && pid > 0))
2425
- ];
2426
- }
2427
- async#commandOf(pid) {
2428
- const output = await this.#run(["ps", "-p", String(pid), "-o", "command="]);
2429
- return output.trim() || null;
2430
- }
2431
2627
  async#terminate(pid) {
2628
+ if (this.#probe.platform === "win32") {
2629
+ await HostProcessProbe.run(["taskkill", "/PID", String(pid), "/T", "/F"]);
2630
+ return await this.#released(pid);
2631
+ }
2432
2632
  if (!this.#signal(pid, "SIGTERM"))
2433
2633
  return !this.#alive(pid);
2634
+ if (await this.#released(pid))
2635
+ return true;
2636
+ this.#signal(pid, "SIGKILL");
2637
+ await Bun.sleep(DevPortReclaimer.#releasePollMs);
2638
+ return !this.#alive(pid);
2639
+ }
2640
+ async#released(pid) {
2434
2641
  const deadline = Date.now() + DevPortReclaimer.releaseTimeoutMs;
2435
2642
  while (Date.now() < deadline) {
2436
2643
  if (!this.#alive(pid))
2437
2644
  return true;
2438
2645
  await Bun.sleep(DevPortReclaimer.#releasePollMs);
2439
2646
  }
2440
- this.#signal(pid, "SIGKILL");
2441
- await Bun.sleep(DevPortReclaimer.#releasePollMs);
2442
- return !this.#alive(pid);
2647
+ return false;
2443
2648
  }
2444
2649
  #signal(pid, signal) {
2445
2650
  try {
@@ -2457,17 +2662,6 @@ class DevPortReclaimer {
2457
2662
  return error.code === "EPERM";
2458
2663
  }
2459
2664
  }
2460
- async#run(command) {
2461
- const proc = Bun.spawn(command, { stdio: ["ignore", "pipe", "ignore"] });
2462
- const timer = setTimeout(() => proc.kill("SIGKILL"), DevPortReclaimer.lsofTimeoutMs);
2463
- try {
2464
- return await new Response(proc.stdout).text();
2465
- } catch {
2466
- return "";
2467
- } finally {
2468
- clearTimeout(timer);
2469
- }
2470
- }
2471
2665
  }
2472
2666
 
2473
2667
  // pkgs/@akanjs/cli/application/devStreamView.ts
@@ -3182,7 +3376,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3182
3376
  async startOne(app, { open = false, dbup = true, stdio = "inherit", write = true, onDevEvent } = {}) {
3183
3377
  await app.scanSync({ write });
3184
3378
  const akanConfig = await app.getConfig();
3185
- const databaseMode = process.env.AKAN_DATABASE_MODE ?? akanConfig.defaultDatabaseMode ?? "single";
3379
+ const databaseMode = akanConfig.resolveDatabaseMode();
3186
3380
  await this.syncDatabaseModeDependencies(app, akanConfig, databaseMode);
3187
3381
  if (app.getEnv() === "local" && dbup && databaseMode !== "single") {
3188
3382
  const wasDbAlreadyUp = await this.dbup(app.workspace, databaseMode);
@@ -3226,7 +3420,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3226
3420
  throw new Error("No app selected to start");
3227
3421
  const startedDatabase = dbup ? await this.#prepareSharedDatabase(apps) : false;
3228
3422
  const supervisor = new DevSupervisor({ apps, mode, concurrency, open, write, shares });
3229
- const view = mode === "tui" ? await (await import("./devTuiView-y1548wy6.js")).createDevTuiView(supervisor) : new DevStreamView(apps.map((app) => app.name));
3423
+ const view = mode === "tui" ? await (await import("./devTuiView-1q1mdgrv.js")).createDevTuiView(supervisor) : new DevStreamView(apps.map((app) => app.name));
3230
3424
  await supervisor.run(view);
3231
3425
  if (startedDatabase)
3232
3426
  await this.#stopDatabase(workspace);
@@ -3240,7 +3434,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3240
3434
  if (app.getEnv() !== "local")
3241
3435
  continue;
3242
3436
  const akanConfig = await app.getConfig();
3243
- const mode = process.env.AKAN_DATABASE_MODE ?? akanConfig.defaultDatabaseMode ?? "single";
3437
+ const mode = akanConfig.resolveDatabaseMode();
3244
3438
  await this.syncDatabaseModeDependencies(app, akanConfig, mode);
3245
3439
  if (mode !== "single")
3246
3440
  modes.add(mode);
@@ -3328,6 +3522,19 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3328
3522
  async codepush(app, os) {
3329
3523
  await this.applicationRunner.codepush(app, os);
3330
3524
  }
3525
+ async transferDatabase(app, direction, dir) {
3526
+ await this.applicationRunner.transferDatabase(app, direction, dir);
3527
+ }
3528
+ async dbupDeclared(workspace, mode) {
3529
+ const declared = mode ? [mode] : await Promise.all((await workspace.getApps()).map(async (appName) => (await AppExecutor.from(workspace, appName).getConfig()).database.modes)).then((modes) => [...new Set(modes.flat())]);
3530
+ const needing = declared.filter((each) => each !== "single");
3531
+ if (!needing.length) {
3532
+ workspace.log("No app here declares a database mode that runs on local services; single needs none.");
3533
+ return;
3534
+ }
3535
+ for (const each of needing)
3536
+ await this.dbup(workspace, each);
3537
+ }
3331
3538
  async dbup(workspace, mode = "multiple") {
3332
3539
  const spinner = workspace.spinning(`Starting local database (${mode})...`);
3333
3540
  const wasAlreadyUp = await this.applicationRunner.dbup(workspace, mode);
@@ -3351,7 +3558,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3351
3558
  await Promise.all(shares.map(async (share) => await share.close()));
3352
3559
  }, "Abandoning the tunnel release; the shares expire on their own.");
3353
3560
  await Promise.all(apps.map(async (app) => {
3354
- const { TunnelShare } = await import("./TunnelShare-r5tc2qk5.js");
3561
+ const { TunnelShare } = await import("./TunnelShare-2j6s511d.js");
3355
3562
  const share = await TunnelShare.open(app, { workspace: app.workspace });
3356
3563
  shares.push(share);
3357
3564
  urls.set(app.name, share.url);
@@ -3385,4 +3592,4 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3385
3592
  }
3386
3593
  }
3387
3594
 
3388
- export { openBrowser, ApplicationScript };
3595
+ export { ApplicationScript };
@@ -10,7 +10,10 @@ import ignore from "ignore";
10
10
  import ts from "typescript";
11
11
  var testFileRegex = /\.(?:test|spec)\.[cm]?[tj]sx?$/;
12
12
  var skipDirs = ["node_modules", "dist", "build", ".git", ".next", "public", "ios", "android", "__fixtures__"];
13
- var isSkippedPath = (filePath) => skipDirs.some((dir) => filePath.includes(`/${dir}/`) || filePath.startsWith(`${dir}/`));
13
+ var isSkippedPath = (filePath) => {
14
+ const posixPath = filePath.split(path.sep).join("/");
15
+ return skipDirs.some((dir) => posixPath.includes(`/${dir}/`) || posixPath.startsWith(`${dir}/`));
16
+ };
14
17
  var builtinModuleSet = new Set([...builtinModules, ...builtinModules.map((mod) => `node:${mod}`)]);
15
18
  var stripShebang = (source) => source.replace(/^#!.*(?:\r?\n|$)/, "");
16
19
 
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-6na0sd2b.js";
5
+ } from "./index-qdgzsnhg.js";
6
6
  import {
7
7
  AGENT_BLOCK_START,
8
8
  AGENT_BLOCK_END,
@@ -13,17 +13,17 @@ import {
13
13
  CLAUDE_COMMENT_RULE,
14
14
  AppExecutor,
15
15
  LibExecutor
16
- } from "./index-p4p9t45x.js";
16
+ } from "./index-crmeqnmf.js";
17
17
  import {
18
18
  collectRecipeSources2,
19
19
  scanRecipes2
20
20
  } from "./index-by5gpp8x.js";
21
21
  import {
22
22
  AkanContextAnalyzer
23
- } from "./index-v17gj504.js";
23
+ } from "./index-18zybgkc.js";
24
24
  import {
25
25
  Prompter2
26
- } from "./index-twq9p2sp.js";
26
+ } from "./index-s5rhm04y.js";
27
27
 
28
28
  // pkgs/@akanjs/cli/agent/agent.script.ts
29
29
  import { Logger as Logger2 } from "akanjs/common";
@@ -148,7 +148,7 @@ If generated output is stale or broken, update the owning source file and run \`
148
148
  ${recipeIndex}## MCP Workflow Policy
149
149
 
150
150
  - **Prefer an Akan workflow to a direct source edit.** A direct edit is denied when an allowlisted workflow or repair tool can make the change.
151
- - Inspect with \`akan mcp --mode plan\` (\`list_workflows\`, \`explain_workflow\`, \`plan_workflow\`); apply with \`akan mcp --mode apply\`, which allowlists \`apply_workflow\`, \`run_validation\`, and the repair tools.
151
+ - Inspect with \`akan mcp --mode plan\` (\`list_workflows\`, \`explain_workflow\`, \`plan_workflow\`); apply with \`akan mcp --mode apply\`, which allowlists \`apply_workflow\`, \`run_validation\`, and three of the five repair tools \u2014 \`repair_generated\`, \`repair_imports\` and \`repair_module_shape\`. \`akan repair format\` and \`akan repair dictionary\` are CLI-only.
152
152
  - If \`plan_workflow\` returns \`planPath\` or \`next.tool=apply_workflow\`, call \`apply_workflow({ planPath })\` before editing source. Then run \`run_validation\` with \`validationTarget\` when present, otherwise \`applyReportPath\`.
153
153
  - Split a compound request into workflows and apply each \`planPath\` in order, such as \`create-module\` followed by \`add-field\`.
154
154
  - When no workflow exists, or apply reports unsupported/no-op/failed diagnostics needing manual action, keep edits scoped to owning source files and never patch generated files directly.