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

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 (95) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-6cm97kay.js → CodeAgent-awv258wb.js} +2 -2
  3. package/{CodeTui-za4jsm41.js → CodeTui-1nqh35ez.js} +20 -22
  4. package/TunnelShare-scf4e4pd.js +9 -0
  5. package/{agent.command-e0wpbbyg.js → agent.command-1s9ag7sb.js} +8 -9
  6. package/akanCode.js +4 -4
  7. package/{application.command-8wyxqc8q.js → application.command-49hwy6va.js} +25 -56
  8. package/{applicationBuildRunner-n9gzaxd0.js → applicationBuildRunner-ybyp97pv.js} +33 -59
  9. package/{applicationReleasePackager-vpggfqgq.js → applicationReleasePackager-esnrphw8.js} +40 -60
  10. package/buildBatch.proc.js +19 -24
  11. package/{capacitorApp-q3z0qht0.js → capacitorApp-1synz4en.js} +3 -4
  12. package/{cloud.command-4zwa5dsx.js → cloud.command-d7rqtzt9.js} +16 -26
  13. package/cloud.script-bkbpcr96.js +19 -0
  14. package/{code.command-468c9d7s.js → code.command-nn48xzej.js} +22 -37
  15. package/context.command-s3mcmvpa.js +48 -0
  16. package/context.runner-k99nb5pk.js +21 -0
  17. package/{dependencyScanner-0z2h2tks.js → dependencyScanner-ye2e6pdz.js} +2 -2
  18. package/{devTui-ffjsarqa.js → devTui-q7k7bakd.js} +5 -9
  19. package/fileSys-5ngz93ga.js +9 -0
  20. package/{guideline.command-vhw13pqr.js → guideline.command-sct4qnt5.js} +4 -5
  21. package/guidelines/conventions/conventions.instruction.md +5 -1
  22. package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
  23. package/incrementalBuilder.proc.js +30 -48
  24. package/{index-s5rhm04y.js → index-0bq14vr1.js} +1 -1
  25. package/{index-10dkrrww.js → index-13ffe9wp.js} +4 -4
  26. package/{index-srmay5jw.js → index-22d57v4c.js} +84 -67
  27. package/{index-53176s7j.js → index-31yr441d.js} +10 -17
  28. package/index-3hx1z96c.js +87 -0
  29. package/{index-4m929vvn.js → index-3sq321ak.js} +10 -18
  30. package/{index-bhtmj233.js → index-3t7g9e4r.js} +41 -78
  31. package/{index-q0y2jq9j.js → index-5b6tavv3.js} +6 -3
  32. package/{index-47pj3aee.js → index-5e0n4hqx.js} +11 -12
  33. package/{index-7ep8qtvp.js → index-5pc1qrbv.js} +5 -8
  34. package/{index-esk82rvk.js → index-8mna0947.js} +34 -71
  35. package/{index-sq2dzkzm.js → index-8sf7wmdr.js} +6 -6
  36. package/{index-crmeqnmf.js → index-9d9bgcx4.js} +283 -722
  37. package/{index-bwf965h6.js → index-ahemdr5n.js} +6 -6
  38. package/{index-ab0c38ea.js → index-as7xmyz8.js} +20 -20
  39. package/{index-bc88j1ry.js → index-axzjaqve.js} +94 -142
  40. package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
  41. package/{index-667w0yah.js → index-c6eggbee.js} +2 -5
  42. package/{index-a1w6934z.js → index-ddxvdd1p.js} +169 -305
  43. package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
  44. package/{index-22xtgmhn.js → index-dzf3r49a.js} +1 -1
  45. package/{index-89hy31kf.js → index-fgq75haa.js} +172 -287
  46. package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
  47. package/{index-hwkygn9s.js → index-khpfpcsd.js} +302 -33
  48. package/{index-vqx8bdxz.js → index-mxav6j3c.js} +78 -231
  49. package/{index-2446k7b4.js → index-myhc3c1j.js} +512 -588
  50. package/{index-3jrp517k.js → index-nv5976x3.js} +45 -128
  51. package/{index-zqgj2rt2.js → index-przybvy5.js} +69 -147
  52. package/{index-n3cv0tm4.js → index-smme4r47.js} +1 -1
  53. package/{index-qdgzsnhg.js → index-w2zdcw3k.js} +110 -231
  54. package/{index-14zrtgfa.js → index-wa5jbxj1.js} +6 -39
  55. package/{index-bftkz6cp.js → index-ww4z397j.js} +198 -555
  56. package/{index-kwaq3n9n.js → index-xqjwd384.js} +4 -7
  57. package/{index-txr7dj2g.js → index-xqpzbab5.js} +106 -240
  58. package/{index-e4v6vhxq.js → index-xsjh6nzh.js} +178 -165
  59. package/{index-18zybgkc.js → index-ygn77a5w.js} +47 -99
  60. package/{index-9d6nvkz2.js → index-ztp3e73t.js} +79 -35
  61. package/index.js +23 -24
  62. package/{library.command-cqr175dy.js → library.command-1gx04jgn.js} +4 -5
  63. package/{localRegistry.command-49z55qqz.js → localRegistry.command-zndxj1q6.js} +21 -42
  64. package/{module.command-9p8mm3b0.js → module.command-3waddk95.js} +6 -7
  65. package/{package.command-wxyz909t.js → package.command-zrc7br1y.js} +5 -6
  66. package/package.json +2 -2
  67. package/{page.command-gsrsfqqs.js → page.command-vpjgardh.js} +4 -5
  68. package/{primitive.command-ns1mptje.js → primitive.command-sz84tk4t.js} +9 -20
  69. package/{prompter-1f8d9pcc.js → prompter-ptaa3nk0.js} +2 -2
  70. package/{quality.command-e76k2q9k.js → quality.command-g869hafs.js} +129 -363
  71. package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
  72. package/{repair.command-pkrsm3cw.js → repair.command-chsnjvvv.js} +11 -35
  73. package/{scalar.command-0cpt3fc8.js → scalar.command-2v21newx.js} +5 -6
  74. package/skills/akan-code/SKILL.md +12 -4
  75. package/{subspace.command-fktpwp0g.js → subspace.command-ckcbwfp1.js} +39 -58
  76. package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +3 -3
  77. package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +3 -3
  78. package/templates/client.ts +7 -30
  79. package/templates/lib/__lib/lib.dictionary.ts +0 -2
  80. package/templates/lib/__lib/lib.document.ts +0 -2
  81. package/templates/lib/sig.ts +8 -30
  82. package/templates/server.ts +0 -2
  83. package/{tunnel.command-d5jy9gk8.js → tunnel.command-kd2yr4fx.js} +5 -6
  84. package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
  85. package/typecheck.proc.js +1 -1
  86. package/workflow.command-44252cqv.js +79 -0
  87. package/{workspace.command-gv84eh1p.js → workspace.command-fqcztt5p.js} +72 -107
  88. package/TunnelShare-2j6s511d.js +0 -9
  89. package/cloud.script-fwx3vb34.js +0 -20
  90. package/context.command-dsnw0jby.js +0 -80
  91. package/context.runner-rs4rj15d.js +0 -22
  92. package/devTuiView-1q1mdgrv.js +0 -9
  93. package/getDirname-dr3jz1xg.js +0 -7
  94. package/index-6wwzs1bc.js +0 -7
  95. package/workflow.command-6tkcysmx.js +0 -105
@@ -7,24 +7,25 @@ import {
7
7
  isScannedRootEntry,
8
8
  AppExecutor,
9
9
  LibExecutor
10
- } from "./index-crmeqnmf.js";
10
+ } from "./index-9d9bgcx4.js";
11
11
  import {
12
- FileSys
13
- } from "./index-q0y2jq9j.js";
12
+ FileSys2
13
+ } from "./index-5b6tavv3.js";
14
14
  import {
15
15
  collectRecipeSources2,
16
16
  scanRecipes2,
17
17
  findInlineRecipeDuplicates2
18
- } from "./index-by5gpp8x.js";
18
+ } from "./index-hj6w4ka1.js";
19
19
  import {
20
+ workflowPathsForPlan,
20
21
  workflowRunArtifactPath,
21
22
  workflowSyncDir
22
- } from "./index-2446k7b4.js";
23
+ } from "./index-myhc3c1j.js";
23
24
 
24
25
  // pkgs/@akanjs/devkit/akanContext.ts
25
26
  import { readdir } from "fs/promises";
26
27
  import path from "path";
27
- import { capitalize } from "akanjs/common";
28
+ import { capitalize, isRecord } from "akanjs/common";
28
29
  var guidelineResourceUri = (name) => `akan://guidelines/${name}`;
29
30
  var staticResourceList = [
30
31
  { uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
@@ -52,16 +53,13 @@ var akanMcpInstallConfigPaths = {
52
53
  var cursorWorkspaceFolder = "$" + "{workspaceFolder}";
53
54
  var claudeProjectDir = "$CLAUDE_PROJECT_DIR";
54
55
  var akanMcpCommand = (mode, { cd } = {}) => cd ? `cd "${cd}" && akan mcp --mode ${mode}` : `akan mcp --mode ${mode}`;
55
- var createAkanCursorMcpServer = (mode = "readonly") => ({
56
+ var bashMcpServer = (mode, cd) => ({
56
57
  type: "stdio",
57
58
  command: "bash",
58
- args: ["-lc", akanMcpCommand(mode, { cd: cursorWorkspaceFolder })]
59
- });
60
- var createAkanClaudeMcpServer = (mode = "readonly") => ({
61
- type: "stdio",
62
- command: "bash",
63
- args: ["-lc", akanMcpCommand(mode, { cd: claudeProjectDir })]
59
+ args: ["-lc", akanMcpCommand(mode, { cd })]
64
60
  });
61
+ var createAkanCursorMcpServer = (mode = "readonly") => bashMcpServer(mode, cursorWorkspaceFolder);
62
+ var createAkanClaudeMcpServer = (mode = "readonly") => bashMcpServer(mode, claudeProjectDir);
65
63
  var createAkanMcpServer = (target, mode = "readonly") => target === "cursor" ? createAkanCursorMcpServer(mode) : createAkanClaudeMcpServer(mode);
66
64
  var akanCursorMcpServer = createAkanCursorMcpServer();
67
65
  var codexMcpServerTableHeader = "[mcp_servers.akan]";
@@ -164,41 +162,13 @@ var moduleShapeFiles = (module) => {
164
162
  ];
165
163
  };
166
164
  var constantFieldNames = (content) => [...content.matchAll(/\b([A-Za-z_$][\w$]*)\s*:\s*field\(/g)].map((match) => match[1]).filter(Boolean);
167
- var safeReadDir = async (dirPath) => {
168
- try {
169
- return (await readdir(dirPath, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
170
- } catch {
171
- return [];
172
- }
173
- };
174
- var safeReadText = async (filePath) => {
175
- try {
176
- return await FileSys.readText(filePath);
177
- } catch {
178
- return null;
179
- }
180
- };
181
- var safeReadJson = async (filePath) => {
182
- try {
183
- return await FileSys.readJson(filePath);
184
- } catch {
185
- return null;
186
- }
187
- };
188
- var isWorkflowPlan = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1 && ("mode" in value) && value.mode === "plan";
189
- var isWorkflowApplyReport = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1 && ("mode" in value) && (value.mode === "apply" || value.mode === "dry-run");
165
+ var safeReadDir = async (dirPath) => (await readdir(dirPath, { withFileTypes: true }).catch(() => [])).sort((a, b) => a.name.localeCompare(b.name));
166
+ var safeReadText = (filePath) => FileSys2.readText(filePath).catch(() => null);
167
+ var safeReadJson = (filePath) => FileSys2.readJson(filePath).catch(() => null);
168
+ var isWorkflowPlan = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1 && ("mode" in value) && value.mode === "plan" && ("inputs" in value) && isRecord(value.inputs) && ("predictedChanges" in value) && Array.isArray(value.predictedChanges) && value.predictedChanges.every((change) => isRecord(change) && typeof change.target === "string");
169
+ var isPathList = (value) => Array.isArray(value) && value.every((file) => isRecord(file) && typeof file.path === "string");
170
+ var isWorkflowApplyReport = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1 && ("mode" in value) && (value.mode === "apply" || value.mode === "dry-run") && ("changedFiles" in value) && isPathList(value.changedFiles) && ("generatedFiles" in value) && isPathList(value.generatedFiles) && ("plan" in value) && isWorkflowPlan(value.plan);
190
171
  var isWorkflowRunArtifact = (value) => typeof value === "object" && value !== null && ("schemaVersion" in value) && value.schemaVersion === 1;
191
- var planInputString = (plan, key) => {
192
- const value = plan.inputs[key];
193
- return typeof value === "string" ? value : "";
194
- };
195
- var expandWorkflowTarget = (target, plan) => {
196
- const app = planInputString(plan, "app");
197
- const module = planInputString(plan, "module");
198
- const moduleClass = module ? capitalize(module) : "<Module>";
199
- return target.replace(/^\*\//, app ? `apps/${app}/` : "").replaceAll("<module>", module || "<module>").replaceAll("<Module>", moduleClass);
200
- };
201
- var workflowPathsForPlan = (plan) => plan.predictedChanges.map((change) => expandWorkflowTarget(change.target, plan));
202
172
  var workflowPathsForArtifact = (artifact) => {
203
173
  if (isWorkflowPlan(artifact))
204
174
  return workflowPathsForPlan(artifact);
@@ -209,7 +179,7 @@ var workflowPathsForArtifact = (artifact) => {
209
179
  ...workflowPathsForPlan(artifact.plan)
210
180
  ];
211
181
  }
212
- if ("mode" in artifact && artifact.mode === "validate" && artifact.plan)
182
+ if ("mode" in artifact && artifact.mode === "validate" && isWorkflowPlan(artifact.plan))
213
183
  return workflowPathsForPlan(artifact.plan);
214
184
  return [];
215
185
  };
@@ -310,13 +280,13 @@ var getSysModules = async (workspace, sys, {
310
280
  const serviceName = entry.name.replace(/^_+/, "");
311
281
  if (moduleFilter && moduleFilter !== serviceName && moduleFilter !== entry.name)
312
282
  continue;
313
- if (!await FileSys.fileExists(path.join(libPath, entry.name, `${serviceName}.service.ts`)))
283
+ if (!await FileSys2.fileExists(path.join(libPath, entry.name, `${serviceName}.service.ts`)))
314
284
  continue;
315
285
  modules.push(await createModuleContext(workspace, sys, "service", entry.name, serviceName, includeAbstractContent));
316
286
  } else {
317
287
  if (moduleFilter && moduleFilter !== entry.name)
318
288
  continue;
319
- if (!await FileSys.fileExists(path.join(libPath, entry.name, `${entry.name}.constant.ts`)))
289
+ if (!await FileSys2.fileExists(path.join(libPath, entry.name, `${entry.name}.constant.ts`)))
320
290
  continue;
321
291
  modules.push(await createModuleContext(workspace, sys, "domain", entry.name, entry.name, includeAbstractContent));
322
292
  }
@@ -327,7 +297,7 @@ var getSysModules = async (workspace, sys, {
327
297
  continue;
328
298
  if (moduleFilter && moduleFilter !== entry.name)
329
299
  continue;
330
- if (!await FileSys.fileExists(path.join(scalarRoot, entry.name, `${entry.name}.constant.ts`)))
300
+ if (!await FileSys2.fileExists(path.join(scalarRoot, entry.name, `${entry.name}.constant.ts`)))
331
301
  continue;
332
302
  modules.push(await createModuleContext(workspace, sys, "scalar", entry.name, entry.name, includeAbstractContent));
333
303
  }
@@ -339,7 +309,7 @@ var getSysContext = async (workspace, type, name, options) => {
339
309
  type,
340
310
  name,
341
311
  path: `${type}s/${name}`,
342
- hasConfig: await FileSys.fileExists(path.join(sys.cwdPath, "akan.config.ts")),
312
+ hasConfig: await FileSys2.fileExists(path.join(sys.cwdPath, "akan.config.ts")),
343
313
  modules: await getSysModules(workspace, sys, {
344
314
  includeAbstractContent: options.includeAbstractContent,
345
315
  module: options.module
@@ -411,62 +381,46 @@ class AkanContextAnalyzer {
411
381
  repairAction("generated", "akan repair generated --app <app-or-lib>", "Refresh generated Akan files.", true),
412
382
  repairAction("format", "akan repair format --target <app-or-lib-or-pkg>", "Run the formatter/linter repair path.", true)
413
383
  ];
384
+ const report = (diagnostic, action) => {
385
+ diagnostics.push({ ...diagnostic, repairActions: [action] });
386
+ repairActions.push(action);
387
+ };
414
388
  for (const sys of [...context.apps, ...context.libs]) {
415
389
  const sysPath = path.join(workspace.workspaceRoot, sys.path);
416
390
  for (const entry of await safeReadDir(sysPath)) {
417
391
  if (!isScannedRootEntry(sys.type, entry.name))
418
392
  continue;
419
393
  const allowed = entry.isDirectory() ? rootAllowedDirs[sys.type].has(entry.name) : rootAllowedFiles[sys.type].has(entry.name);
420
- if (!allowed) {
421
- const action = repairAction("module-shape", `akan repair module-shape --app ${sys.name}`, `Review ${sys.type} root shape and remove or move the unknown entry.`, false);
422
- diagnostics.push({
394
+ if (!allowed)
395
+ report({
423
396
  severity: "error",
424
397
  code: `${sys.type}-root-unknown-entry`,
425
398
  path: `${sys.path}/${entry.name}`,
426
- message: `Unexpected ${entry.isDirectory() ? "folder" : "file"} in ${sys.type} root: ${sys.path}/${entry.name}`,
427
- repairActions: [action]
428
- });
429
- repairActions.push(action);
430
- }
399
+ message: `Unexpected ${entry.isDirectory() ? "folder" : "file"} in ${sys.type} root: ${sys.path}/${entry.name}`
400
+ }, repairAction("module-shape", `akan repair module-shape --app ${sys.name}`, `Review ${sys.type} root shape and remove or move the unknown entry.`, false));
431
401
  }
432
402
  }
433
403
  const agentDrift = await AkanContextAnalyzer.#agentGuideDrift(workspace);
434
- if (agentDrift) {
435
- const action = repairAction("generated", "akan agent install agents-md", agentDrift.hint, true);
436
- diagnostics.push({
437
- severity: "warning",
438
- code: agentDrift.code,
439
- path: "AGENTS.md",
440
- message: agentDrift.message,
441
- repairActions: [action]
442
- });
443
- repairActions.push(action);
444
- }
404
+ if (agentDrift)
405
+ report({ severity: "warning", code: agentDrift.code, path: "AGENTS.md", message: agentDrift.message }, repairAction("generated", "akan agent install agents-md", agentDrift.hint, true));
445
406
  for (const sys of [...context.apps, ...context.libs]) {
446
407
  for (const module of sys.modules) {
447
- if (!module.abstract.exists) {
448
- const action = repairAction("module-shape", `akan repair module-shape --app ${sys.name} --module ${module.name}`, "Create the missing module abstract or inspect required source files.", false);
449
- diagnostics.push({
408
+ const moduleShapeCommand = `akan repair module-shape --app ${sys.name} --module ${module.name}`;
409
+ if (!module.abstract.exists)
410
+ report({
450
411
  severity: strict ? "error" : "warning",
451
412
  code: "module-abstract-missing",
452
413
  path: module.abstract.path,
453
- message: `${capitalize(module.kind)} module ${sys.name}:${module.name} should include ${module.abstract.path}`,
454
- repairActions: [action]
455
- });
456
- repairActions.push(action);
457
- }
414
+ message: `${capitalize(module.kind)} module ${sys.name}:${module.name} should include ${module.abstract.path}`
415
+ }, repairAction("module-shape", moduleShapeCommand, "Create the missing module abstract or inspect required source files.", false));
458
416
  const missingFiles = moduleShapeFiles(module).filter((filename) => !module.files.includes(filename));
459
- if (missingFiles.length) {
460
- const action = repairAction("module-shape", `akan repair module-shape --app ${sys.name} --module ${module.name}`, "Review missing required module source files.", false);
461
- diagnostics.push({
417
+ if (missingFiles.length)
418
+ report({
462
419
  severity: "error",
463
420
  code: "module-shape-invalid",
464
421
  path: module.path,
465
- message: `${capitalize(module.kind)} module ${sys.name}:${module.name} is missing required files: ${missingFiles.join(", ")}`,
466
- repairActions: [action]
467
- });
468
- repairActions.push(action);
469
- }
422
+ message: `${capitalize(module.kind)} module ${sys.name}:${module.name} is missing required files: ${missingFiles.join(", ")}`
423
+ }, repairAction("module-shape", moduleShapeCommand, "Review missing required module source files.", false));
470
424
  if (module.kind !== "service" && module.files.includes(`${module.name}.dictionary.ts`)) {
471
425
  const constantPath = path.join(workspace.workspaceRoot, module.path, `${module.name}.constant.ts`);
472
426
  const dictionaryPath = path.join(workspace.workspaceRoot, module.path, `${module.name}.dictionary.ts`);
@@ -478,15 +432,12 @@ class AkanContextAnalyzer {
478
432
  for (const fieldName of constantFieldNames(constantContent)) {
479
433
  if (new RegExp(`\\b${fieldName}\\s*:`).test(dictionaryContent))
480
434
  continue;
481
- const action = repairAction("dictionary", `akan repair dictionary --app ${sys.name} --module ${module.name}`, "Add missing dictionary labels for source constant fields.", false);
482
- diagnostics.push({
435
+ report({
483
436
  severity: "warning",
484
437
  code: "dictionary-label-missing",
485
438
  path: `${module.path}/${module.name}.dictionary.ts`,
486
- message: `Dictionary labels for ${sys.name}:${module.name}.${fieldName} were not found.`,
487
- repairActions: [action]
488
- });
489
- repairActions.push(action);
439
+ message: `Dictionary labels for ${sys.name}:${module.name}.${fieldName} were not found.`
440
+ }, repairAction("dictionary", `akan repair dictionary --app ${sys.name} --module ${module.name}`, "Add missing dictionary labels for source constant fields.", false));
490
441
  }
491
442
  }
492
443
  }
@@ -554,19 +505,16 @@ class AkanContextAnalyzer {
554
505
  const pushIndexDiagnostic = (indexPath, missing, stale, repairCommand) => {
555
506
  if (missing.length === 0 && stale.length === 0)
556
507
  return;
557
- const action = repairAction("generated", repairCommand, "Regenerate the recipe index from the scanned recipes.", true);
558
508
  const parts = [
559
509
  missing.length > 0 ? `${missing.length} declared but unlisted (${missing.slice(0, 5).join(", ")})` : "",
560
510
  stale.length > 0 ? `${stale.length} listed but gone (${stale.slice(0, 5).join(", ")})` : ""
561
511
  ].filter(Boolean);
562
- diagnostics.push({
512
+ report({
563
513
  severity: "error",
564
514
  code: "recipe-index-stale",
565
515
  path: indexPath,
566
- message: `${indexPath} recipe index is out of date \u2014 ${parts.join("; ")}. Agents read this list as authoritative.`,
567
- repairActions: [action]
568
- });
569
- repairActions.push(action);
516
+ message: `${indexPath} recipe index is out of date \u2014 ${parts.join("; ")}. Agents read this list as authoritative.`
517
+ }, repairAction("generated", repairCommand, "Regenerate the recipe index from the scanned recipes.", true));
570
518
  };
571
519
  const frameworkDeclared = declaredByImport.get("akanjs/ui") ?? new Set;
572
520
  if (frameworkDeclared.size > 0) {
@@ -1,4 +1,8 @@
1
1
  // @bun
2
+ import {
3
+ ConfigLock
4
+ } from "./index-3hx1z96c.js";
5
+
2
6
  // pkgs/@akanjs/devkit/codeAgent/agent/SubagentPool.ts
3
7
  import { codeAgentReadOnlyBuiltins } from "akanjs/common";
4
8
  import { Type } from "typebox";
@@ -19,11 +23,11 @@ class SubagentPool2 {
19
23
  static defaultKind = "explore";
20
24
  #options;
21
25
  #children = new Map;
22
- #running = 0;
23
- #spent = 0;
26
+ #spend;
24
27
  #ticker = null;
25
28
  constructor(options) {
26
29
  this.#options = options;
30
+ this.#spend = options.spend ?? { tokens: 0, running: 0 };
27
31
  }
28
32
  static extensionFor(options) {
29
33
  if (!options.parent.tools.subagent)
@@ -52,7 +56,7 @@ class SubagentPool2 {
52
56
  const refusal = this.#refuse();
53
57
  if (refusal)
54
58
  return { content: [{ type: "text", text: refusal }], details: undefined, isError: true };
55
- this.#running += 1;
59
+ this.#spend.running += 1;
56
60
  this.#children.set(id, { kind, description: params.description, startedAt: Date.now() });
57
61
  this.#report();
58
62
  this.#options.onNotice?.(`${kind} sub-agent \xB7 ${params.description}`);
@@ -60,7 +64,7 @@ class SubagentPool2 {
60
64
  const text = await this.#run(id, kind, params.prompt, signal);
61
65
  return { content: [{ type: "text", text }], details: undefined };
62
66
  } finally {
63
- this.#running -= 1;
67
+ this.#spend.running -= 1;
64
68
  this.#children.delete(id);
65
69
  this.#report();
66
70
  }
@@ -71,9 +75,9 @@ class SubagentPool2 {
71
75
  const budget = this.#options.parent.tools.subagent;
72
76
  if (!budget)
73
77
  return "Sub-agents are disabled by this profile.";
74
- if (this.#running >= budget.maxConcurrent)
75
- return `Too many sub-agents are already running (limit ${budget.maxConcurrent}). Wait for one to finish.`;
76
- if (this.#spent >= budget.budget)
78
+ if (this.#spend.running >= budget.maxConcurrent)
79
+ return `Too many sub-agents are already running (limit ${budget.maxConcurrent} at once, counted across the whole task tree). ${this.#children.size ? "Wait for one of yours to finish, or do" : "Do"} this part yourself.`;
80
+ if (this.#spend.tokens >= budget.budget)
77
81
  return `The sub-agent token budget (${budget.budget}) is spent. Do the rest of this work yourself.`;
78
82
  return;
79
83
  }
@@ -112,7 +116,7 @@ class SubagentPool2 {
112
116
  }
113
117
  }
114
118
  async#run(id, kind, prompt, signal) {
115
- const { CodeAgent } = await import("./CodeAgent-6cm97kay.js");
119
+ const { CodeAgent } = await import("./CodeAgent-awv258wb.js");
116
120
  const budget = this.#options.parent.tools.subagent;
117
121
  const child = SubagentPool2.childOf(this.#options.parent, kind);
118
122
  const agent = await CodeAgent.create({
@@ -120,28 +124,43 @@ class SubagentPool2 {
120
124
  cwd: this.#options.cwd,
121
125
  profile: child,
122
126
  apps: [],
123
- depth: this.#options.depth + 1
127
+ depth: this.#options.depth + 1,
128
+ subagentSpend: this.#spend
124
129
  });
125
130
  const running = this.#children.get(id);
126
131
  if (running)
127
132
  running.agent = agent;
128
- const abort = () => void agent.abort();
133
+ let stopped = false;
134
+ const abort = () => {
135
+ stopped = true;
136
+ agent.abort();
137
+ };
129
138
  signal?.addEventListener("abort", abort, { once: true });
139
+ if (signal?.aborted)
140
+ stopped = true;
141
+ let finished = false;
130
142
  try {
131
143
  let answer = "";
132
144
  agent.on((event) => {
133
145
  if (event.type === "message" && event.role === "assistant")
134
146
  answer = event.text;
147
+ if (event.type === "turn_start" && stopped)
148
+ agent.abort();
135
149
  });
136
- await agent.prompt(prompt);
137
- await agent.waitForIdle();
138
- this.#spent += agent.tokensUsed;
139
- const ceiling = budget ? budget.budget : 0;
140
- this.#options.onNotice?.(`${kind} sub-agent finished, ${agent.tokensUsed} tokens (${this.#spent} of ${ceiling} spent)`);
150
+ if (!stopped) {
151
+ await agent.prompt(prompt);
152
+ await agent.waitForIdle();
153
+ }
154
+ finished = true;
141
155
  return answer.length > maxResultChars ? `${answer.slice(0, maxResultChars)}
142
156
  \u2026(truncated)` : answer || "(no answer)";
143
157
  } finally {
144
158
  signal?.removeEventListener("abort", abort);
159
+ const tokens = agent.tokensUsed;
160
+ this.#spend.tokens += tokens;
161
+ const outcome = stopped ? "stopped" : finished ? "finished" : "failed";
162
+ const ceiling = budget ? budget.budget : 0;
163
+ this.#options.onNotice?.(`${kind} sub-agent ${outcome}, ${tokens} tokens (${this.#spend.tokens} of ${ceiling} spent)`);
145
164
  agent.dispose();
146
165
  }
147
166
  }
@@ -207,8 +226,9 @@ class McpServerConfig {
207
226
  `);
208
227
  return McpServerConfig.#refOf(name, entry);
209
228
  }
210
- static remove(workspaceRoot, name) {
211
- for (const { scope } of [...McpServerConfig.files(workspaceRoot)].reverse()) {
229
+ static remove(workspaceRoot, name, only) {
230
+ const candidates = McpServerConfig.files(workspaceRoot).filter(({ scope }) => !only || scope === only);
231
+ for (const { scope } of candidates.reverse()) {
212
232
  const { file, key, map } = McpServerConfig.#parse(workspaceRoot, scope);
213
233
  if (!(name in map))
214
234
  continue;
@@ -270,6 +290,9 @@ class McpTokenStore {
270
290
  static file() {
271
291
  return akanCodePaths2.mcpAuthFile();
272
292
  }
293
+ static lockFile() {
294
+ return `${McpTokenStore.file()}.lock`;
295
+ }
273
296
  static read(name) {
274
297
  return McpTokenStore.#all()[name];
275
298
  }
@@ -539,30 +562,54 @@ class McpOAuthLoopback {
539
562
 
540
563
  // pkgs/@akanjs/devkit/codeAgent/tools/McpSignIn.ts
541
564
  class McpSignIn {
565
+ static #refreshing = new Map;
542
566
  static async token(ref, onNotice) {
543
567
  const stored = McpTokenStore.read(ref.name);
544
568
  if (!stored)
545
569
  return;
546
570
  if (!McpTokenStore.isExpired(stored))
547
571
  return stored.accessToken;
572
+ return await McpSignIn.#refreshOnce(ref, stored, onNotice);
573
+ }
574
+ static async retryToken(ref, refused, onNotice) {
575
+ const stored = McpTokenStore.read(ref.name);
576
+ if (!stored)
577
+ return;
578
+ if (stored.accessToken !== refused && !McpTokenStore.isExpired(stored))
579
+ return stored.accessToken;
580
+ return await McpSignIn.#refreshOnce(ref, stored, onNotice);
581
+ }
582
+ static async#refreshOnce(ref, stored, onNotice) {
583
+ const key = `${ref.name}
584
+ ${stored.refreshToken}`;
585
+ let pending = McpSignIn.#refreshing.get(key);
586
+ if (!pending) {
587
+ pending = McpSignIn.#refreshed(ref, stored, onNotice).finally(() => McpSignIn.#refreshing.delete(key));
588
+ McpSignIn.#refreshing.set(key, pending);
589
+ }
590
+ return await pending;
591
+ }
592
+ static async#refreshed(ref, stored, onNotice) {
548
593
  if (!stored.refreshToken)
549
594
  return;
550
595
  try {
551
- const server = {
552
- issuer: stored.issuer,
553
- authorizationEndpoint: "",
554
- tokenEndpoint: stored.tokenEndpoint,
555
- resource: stored.resource
556
- };
557
- const tokens = await McpOAuth.refresh(server, stored);
558
- McpTokenStore.write(ref.name, {
559
- ...stored,
560
- accessToken: tokens.accessToken,
561
- ...tokens.refreshToken ? { refreshToken: tokens.refreshToken } : {},
562
- ...tokens.expiresAt ? { expiresAt: tokens.expiresAt } : {},
563
- ...tokens.scope ? { scope: tokens.scope } : {}
596
+ return await ConfigLock.run(McpTokenStore.lockFile(), async () => {
597
+ const current = McpTokenStore.read(ref.name);
598
+ if (!current)
599
+ return;
600
+ if (current.accessToken !== stored.accessToken && !McpTokenStore.isExpired(current))
601
+ return current.accessToken;
602
+ const server = {
603
+ issuer: current.issuer,
604
+ authorizationEndpoint: "",
605
+ tokenEndpoint: current.tokenEndpoint,
606
+ resource: current.resource
607
+ };
608
+ const tokens = await McpOAuth.refresh(server, current);
609
+ const { expiresAt: _spent, ...grant } = current;
610
+ McpTokenStore.write(ref.name, { ...grant, ...tokens });
611
+ return tokens.accessToken;
564
612
  });
565
- return tokens.accessToken;
566
613
  } catch (error) {
567
614
  onNotice?.(`MCP server "${ref.name}" needs signing in again \u2014 ${String(error)}`);
568
615
  return;
@@ -597,10 +644,7 @@ class McpSignIn {
597
644
  clientId: client.clientId,
598
645
  ...client.clientSecret ? { clientSecret: client.clientSecret } : {},
599
646
  redirectUri,
600
- accessToken: tokens.accessToken,
601
- ...tokens.refreshToken ? { refreshToken: tokens.refreshToken } : {},
602
- ...tokens.expiresAt ? { expiresAt: tokens.expiresAt } : {},
603
- ...tokens.scope ? { scope: tokens.scope } : {}
647
+ ...tokens
604
648
  };
605
649
  McpTokenStore.write(ref.name, auth);
606
650
  return auth;
package/index.js CHANGED
@@ -4,35 +4,34 @@ import {
4
4
  getTargetMetas,
5
5
  getTargetCommandNames,
6
6
  runCommands
7
- } from "./index-qdgzsnhg.js";
8
- import"./index-q0y2jq9j.js";
9
- import"./index-crmeqnmf.js";
10
- import"./index-6wwzs1bc.js";
7
+ } from "./index-w2zdcw3k.js";
8
+ import"./index-5b6tavv3.js";
9
+ import"./index-9d9bgcx4.js";
11
10
 
12
11
  // pkgs/@akanjs/cli/commandManifest.ts
13
12
  import path from "path";
14
13
 
15
14
  // pkgs/@akanjs/cli/commandModules.ts
16
15
  var commandModules = {
17
- workspace: async () => (await import("./workspace.command-gv84eh1p.js")).WorkspaceCommand,
18
- agent: async () => (await import("./agent.command-e0wpbbyg.js")).AgentCommand,
19
- code: async () => (await import("./code.command-468c9d7s.js")).CodeCommand,
20
- application: async () => (await import("./application.command-8wyxqc8q.js")).ApplicationCommand,
21
- library: async () => (await import("./library.command-cqr175dy.js")).LibraryCommand,
22
- localRegistry: async () => (await import("./localRegistry.command-49z55qqz.js")).LocalRegistryCommand,
23
- package: async () => (await import("./package.command-wxyz909t.js")).PackageCommand,
24
- module: async () => (await import("./module.command-9p8mm3b0.js")).ModuleCommand,
25
- page: async () => (await import("./page.command-gsrsfqqs.js")).PageCommand,
26
- context: async () => (await import("./context.command-dsnw0jby.js")).ContextCommand,
27
- cloud: async () => (await import("./cloud.command-4zwa5dsx.js")).CloudCommand,
28
- subspace: async () => (await import("./subspace.command-fktpwp0g.js")).SubspaceCommand,
29
- guideline: async () => (await import("./guideline.command-vhw13pqr.js")).GuidelineCommand,
30
- scalar: async () => (await import("./scalar.command-0cpt3fc8.js")).ScalarCommand,
31
- primitive: async () => (await import("./primitive.command-ns1mptje.js")).PrimitiveCommand,
32
- quality: async () => (await import("./quality.command-e76k2q9k.js")).QualityCommand,
33
- repair: async () => (await import("./repair.command-pkrsm3cw.js")).RepairCommand,
34
- workflow: async () => (await import("./workflow.command-6tkcysmx.js")).WorkflowCommand,
35
- tunnel: async () => (await import("./tunnel.command-d5jy9gk8.js")).TunnelCommand
16
+ workspace: async () => (await import("./workspace.command-fqcztt5p.js")).WorkspaceCommand,
17
+ agent: async () => (await import("./agent.command-1s9ag7sb.js")).AgentCommand,
18
+ code: async () => (await import("./code.command-nn48xzej.js")).CodeCommand,
19
+ application: async () => (await import("./application.command-49hwy6va.js")).ApplicationCommand,
20
+ library: async () => (await import("./library.command-1gx04jgn.js")).LibraryCommand,
21
+ localRegistry: async () => (await import("./localRegistry.command-zndxj1q6.js")).LocalRegistryCommand,
22
+ package: async () => (await import("./package.command-zrc7br1y.js")).PackageCommand,
23
+ module: async () => (await import("./module.command-3waddk95.js")).ModuleCommand,
24
+ page: async () => (await import("./page.command-vpjgardh.js")).PageCommand,
25
+ context: async () => (await import("./context.command-s3mcmvpa.js")).ContextCommand,
26
+ cloud: async () => (await import("./cloud.command-d7rqtzt9.js")).CloudCommand,
27
+ subspace: async () => (await import("./subspace.command-ckcbwfp1.js")).SubspaceCommand,
28
+ guideline: async () => (await import("./guideline.command-sct4qnt5.js")).GuidelineCommand,
29
+ scalar: async () => (await import("./scalar.command-2v21newx.js")).ScalarCommand,
30
+ primitive: async () => (await import("./primitive.command-sz84tk4t.js")).PrimitiveCommand,
31
+ quality: async () => (await import("./quality.command-g869hafs.js")).QualityCommand,
32
+ repair: async () => (await import("./repair.command-chsnjvvv.js")).RepairCommand,
33
+ workflow: async () => (await import("./workflow.command-44252cqv.js")).WorkflowCommand,
34
+ tunnel: async () => (await import("./tunnel.command-kd2yr4fx.js")).TunnelCommand
36
35
  };
37
36
  var commandModuleIds = Object.keys(commandModules);
38
37
 
@@ -70,4 +69,4 @@ class CommandManifest {
70
69
  // pkgs/@akanjs/cli/index.ts
71
70
  var ids = CommandManifest.resolve(await CommandManifest.read(), process.argv) ?? commandModuleIds;
72
71
  var commands = await Promise.all(ids.map(async (id) => await commandModules[id]()));
73
- runCommands(...commands);
72
+ await runCommands(...commands);
@@ -3,13 +3,12 @@ import {
3
3
  Lib,
4
4
  Workspace,
5
5
  command
6
- } from "./index-qdgzsnhg.js";
7
- import"./index-q0y2jq9j.js";
8
- import"./index-crmeqnmf.js";
9
- import"./index-6wwzs1bc.js";
6
+ } from "./index-w2zdcw3k.js";
7
+ import"./index-5b6tavv3.js";
8
+ import"./index-9d9bgcx4.js";
10
9
  import {
11
10
  LibraryScript
12
- } from "./index-7ep8qtvp.js";
11
+ } from "./index-5pc1qrbv.js";
13
12
 
14
13
  // pkgs/@akanjs/cli/library/library.command.ts
15
14
  class LibraryCommand extends command("library", [LibraryScript], ({ public: target }) => ({