arkgate 4.8.7 → 4.8.9

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 (59) hide show
  1. package/CHANGELOG.md +92 -3
  2. package/README.md +41 -6
  3. package/bin/ark-check-runtime.mjs +22 -0
  4. package/bin/ark-dashboard.mjs +423 -0
  5. package/bin/ark-layer-match.mjs +25 -10
  6. package/bin/ark.mjs +51 -3
  7. package/bin/lib/agent-homes.mjs +1 -1
  8. package/bin/lib/analysis-engine.mjs +8 -8
  9. package/bin/lib/ark-order-sensors.mjs +103 -3
  10. package/bin/lib/config-extras.mjs +1 -0
  11. package/bin/lib/contract-smells.mjs +12 -6
  12. package/bin/lib/doctor-human.mjs +32 -7
  13. package/bin/lib/doctor-next-actions.mjs +21 -2
  14. package/bin/lib/gate-files.mjs +108 -22
  15. package/bin/lib/managed-upgrade.mjs +9 -1
  16. package/bin/lib/upgrade-command.mjs +17 -4
  17. package/dist/{configTypes-0eHpocR3.d.ts → configTypes-j7so8B4O.d.ts} +12 -0
  18. package/dist/{diagnosticCatalog-wDAH08gH.d.ts → diagnosticCatalog-BrkOiwCk.d.ts} +3 -3
  19. package/dist/eslint/index.cjs +5 -5
  20. package/dist/eslint/index.d.ts +6 -4
  21. package/dist/eslint/index.js +5 -5
  22. package/dist/index.cjs +30 -30
  23. package/dist/index.d.ts +13 -4
  24. package/dist/index.js +31 -31
  25. package/dist/nestjs/index.cjs +5 -5
  26. package/dist/nestjs/index.d.ts +3 -3
  27. package/dist/nestjs/index.js +5 -5
  28. package/dist/order/index.cjs +1 -1
  29. package/dist/order/index.d.ts +6 -2
  30. package/dist/order/index.js +1 -1
  31. package/dist/runtime/index.cjs +15 -15
  32. package/dist/runtime/index.d.ts +6 -6
  33. package/dist/runtime/index.js +15 -15
  34. package/dist/{types-BK47clMl.d.ts → types-Djbs3KjE.d.ts} +1 -1
  35. package/dist/{types-CwZ_oz1N.d.ts → types-tGhZUiGX.d.ts} +106 -2
  36. package/docs/README.md +13 -4
  37. package/docs/agent-guide.md +38 -2
  38. package/docs/ai-gates.md +13 -1
  39. package/docs/arkorder.md +41 -8
  40. package/docs/configuration.md +47 -12
  41. package/docs/develop.md +17 -8
  42. package/docs/enthusiast/README.md +13 -2
  43. package/docs/package-surface.md +20 -6
  44. package/docs/product-voice.md +25 -2
  45. package/docs/use.md +11 -3
  46. package/package.json +3 -1
  47. package/schemas/ark.config.schema.json +9 -0
  48. package/server.json +2 -2
  49. package/templates/agent-skills/README.md +1 -1
  50. package/templates/agent-skills/ark-adopt/SKILL.md +1 -0
  51. package/templates/agent-skills/ark-autopilot/SKILL.md +1 -1
  52. package/templates/agent-skills/ark-contract/SKILL.md +1 -1
  53. package/templates/agent-skills/ark-explore/SKILL.md +2 -2
  54. package/templates/agent-skills/ark-place/SKILL.md +1 -0
  55. package/templates/skills/ark-adopt.md +1 -0
  56. package/templates/skills/ark-autopilot.md +1 -1
  57. package/templates/skills/ark-contract.md +1 -1
  58. package/templates/skills/ark-explore.md +2 -2
  59. package/templates/skills/ark-place.md +1 -0
@@ -362,15 +362,27 @@ export function crossSliceEdgeAllowed(allowedCrossSlice, fromSlice, toSlice) {
362
362
  * Fail-closed stays fail-closed: absent evidence denies. What changed in 4.8.4
363
363
  * is what counts as evidence — a declared shared root, or a declared directed
364
364
  * cross-slice edge, is the repo telling us its design, so it is no longer
365
- * "unclassifiable". Order: no paths → no slice folders → a side that is neither
366
- * in a slice nor declared shared same slice declared cross edge → deny.
365
+ * "unclassifiable". Order: no fromPath → no slice folders → intent (no toPath):
366
+ * shared-root allow / slice fail-closed a side that is neither in a slice nor
367
+ * declared shared → same slice → declared cross edge → deny.
368
+ *
369
+ * Intent/event names are not files. Callers pass fromPath only and must not
370
+ * invent a toPath (that would mis-slice). A declared shared root is classified
371
+ * the same way as on import edges.
367
372
  */
368
373
  export function peerIsolationDecision(input) {
369
- if (!input.fromPath || !input.toPath)
374
+ if (!input.fromPath)
370
375
  return { denied: true, reason: 'missing-path' };
371
376
  if (input.folderCount <= 0)
372
377
  return { denied: true, reason: 'no-slice-folders' };
373
378
  const fromClassified = Boolean(input.fromSlice) || input.fromShared === true;
379
+ if (!input.toPath) {
380
+ if (!fromClassified)
381
+ return { denied: true, reason: 'unclassifiable-path' };
382
+ if (!input.fromSlice)
383
+ return { denied: false };
384
+ return { denied: true, reason: 'missing-path' };
385
+ }
374
386
  const toClassified = Boolean(input.toSlice) || input.toShared === true;
375
387
  if (!fromClassified || !toClassified)
376
388
  return { denied: true, reason: 'unclassifiable-path' };
@@ -387,8 +399,9 @@ export function peerIsolationDecision(input) {
387
399
  /**
388
400
  * Boolean face of {@link peerIsolationDecision}, kept for parity consumers.
389
401
  *
390
- * Fail-closed: missing path, no classifiable folders, or unclassifiable either
391
- * side → deny. Same-slice allow (return false). Cross-slice deny unless the
402
+ * Fail-closed: missing fromPath, no classifiable folders, or unclassifiable
403
+ * either side → deny. Intent refs (no toPath) allow only a declared shared
404
+ * root. Same-slice → allow (return false). Cross-slice → deny unless the
392
405
  * rule declared that directed edge.
393
406
  */
394
407
  export function peerIsolationMustDeny(input) {
@@ -426,9 +439,11 @@ export function peerIsolationDenyExplanation(reason, context) {
426
439
  * Same-layer is always allowed (historical short-circuit).
427
440
  * - `peerIsolation: true` + `allowed: false`: deny only when importer and importee
428
441
  * resolve to **different** slice ids (same or cross layer). Same-slice → allow.
429
- * Missing paths, no slice folders, or unclassifiable slices **fail-closed**
430
- * (deny): isolation is configured, so insufficient evidence must not silently
431
- * allow a possible cross-slice edge.
442
+ * File imports pass fromPath + toPath. Intent references pass fromPath only.
443
+ * A declared shared root is classified (no denial). Missing fromPath, no slice
444
+ * folders, or unclassifiable slices → **fail-closed** (deny): isolation is
445
+ * configured, so insufficient evidence must not silently allow a possible
446
+ * cross-slice edge.
432
447
  */
433
448
  export function findDeniedEdgeRule(rules, from, to, options) {
434
449
  return findDeniedEdgeDecision(rules, from, to, options)?.rule;
@@ -448,8 +463,8 @@ export function findDeniedEdgeDecision(rules, from, to, options) {
448
463
  const fromPath = options?.fromPath;
449
464
  const toPath = options?.toPath;
450
465
  const folders = resolveSliceFolders(rule, from, options?.layers);
451
- const fromSlice = fromPath && toPath ? sliceIdForPath(fromPath, folders) : undefined;
452
- const toSlice = fromPath && toPath ? sliceIdForPath(toPath, folders) : undefined;
466
+ const fromSlice = fromPath ? sliceIdForPath(fromPath, folders) : undefined;
467
+ const toSlice = toPath ? sliceIdForPath(toPath, folders) : undefined;
453
468
  const decision = peerIsolationDecision({
454
469
  fromPath,
455
470
  toPath,
package/bin/ark.mjs CHANGED
@@ -39,6 +39,36 @@ import { setupUsage, setupUsageAll, upgradeUsage } from './lib/first-run-help.mj
39
39
 
40
40
  const here = path.dirname(fileURLToPath(import.meta.url));
41
41
  const arkCheck = path.join(here, 'ark-check.mjs');
42
+ const arkDashboard = path.join(here, 'ark-dashboard.mjs');
43
+ const dashboardHelp = `arkgate dashboard (alias ark dashboard) — observability TUI.
44
+ Usage: arkgate dashboard [--url <snapshot-url>] [--interval <ms>]
45
+ Polls an ArkRun inspector; it does not start the kernel.`;
46
+
47
+ function withDashboardHelp(text, detailed) {
48
+ if (detailed) {
49
+ return text
50
+ .replace(
51
+ ' arkgate agents-md [--root',
52
+ ' arkgate dashboard [--url <snapshot-url>] [--interval <ms>]\n arkgate agents-md [--root'
53
+ )
54
+ .replace(
55
+ ' agents-md Version-matched',
56
+ ' dashboard ANSI observability TUI against a running ArkRun inspector (spawns ark-dashboard).\n agents-md Version-matched'
57
+ );
58
+ }
59
+ return text.replace(
60
+ ' arkgate-check --doctor status — one next step\n',
61
+ ' arkgate-check --doctor status — one next step\n arkgate dashboard observability TUI (inspector)\n'
62
+ );
63
+ }
64
+
65
+ function runDashboard(passthroughArgs) {
66
+ const result = spawnSync(process.execPath, [arkDashboard, ...passthroughArgs], {
67
+ stdio: 'inherit',
68
+ encoding: 'utf8',
69
+ });
70
+ return result.status ?? 1;
71
+ }
42
72
 
43
73
  /**
44
74
  * Day-zero architecture picture: freeze origin under `.ark/reports/` as soon as
@@ -93,6 +123,7 @@ function parseArgs(argv) {
93
123
  help: false,
94
124
  all: false,
95
125
  version: false,
126
+ passthrough: [],
96
127
  };
97
128
 
98
129
  const requireValue = (flag, index) => {
@@ -147,7 +178,14 @@ function parseArgs(argv) {
147
178
  else if (arg === '--help' || arg === '-h' || arg === 'help') args.help = true;
148
179
  else if (arg === '--all') args.all = true;
149
180
  else if (arg === '--version' || arg === '-V') args.version = true;
150
- else if (!arg.startsWith('-') && args.command === undefined) args.command = arg;
181
+ else if (!arg.startsWith('-') && args.command === undefined) {
182
+ args.command = arg;
183
+ // Dashboard owns its flags (--url/--interval); pass the rest through untouched.
184
+ if (arg === 'dashboard') {
185
+ args.passthrough = argv.slice(i + 1);
186
+ break;
187
+ }
188
+ }
151
189
  else throw new Error(`Unknown argument: ${arg}. Run arkgate --help for usage.`);
152
190
  }
153
191
 
@@ -782,11 +820,21 @@ async function main() {
782
820
  console.log(upgradeUsage());
783
821
  return 0;
784
822
  }
823
+ if (args.command === 'dashboard' && args.passthrough.some((arg) => ['--help', '-h', 'help'].includes(arg))) {
824
+ console.log(dashboardHelp);
825
+ return 0;
826
+ }
785
827
  if (args.help || !args.command) {
786
- console.log(args.all ? setupUsageAll() : setupUsage());
828
+ console.log(
829
+ withDashboardHelp(args.all ? setupUsageAll() : setupUsage(), Boolean(args.all))
830
+ );
787
831
  return 0;
788
832
  }
789
833
 
834
+ if (args.command === 'dashboard') {
835
+ return runDashboard(args.passthrough);
836
+ }
837
+
790
838
  if (args.requireWriteHook && !['start', 'init'].includes(args.command)) {
791
839
  console.error('--require-write-hook is supported by ark start and ark init.');
792
840
  return 2;
@@ -913,7 +961,7 @@ async function main() {
913
961
  }
914
962
 
915
963
  console.error(`Unknown command: ${args.command}`);
916
- console.error(setupUsage());
964
+ console.error(withDashboardHelp(setupUsage(), false));
917
965
  return 2;
918
966
  }
919
967
 
@@ -108,7 +108,7 @@ function usesDefaultHome(spec, env, homeDir) {
108
108
 
109
109
  function skillsDirFor(host, env = process.env) {
110
110
  const spec = HOSTS[host];
111
- return path.join(resolveHomeDir(spec, env), 'skills');
111
+ return path.join(resolveHomeDir(spec, env, os.homedir()), 'skills');
112
112
  }
113
113
 
114
114
  function readHomeCatalogFloor(skillsDir) {