open-multi-agent-kit 1.0.0 → 1.2.0

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 (244) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/README.md +2 -2
  3. package/dist/cli/help.d.ts.map +1 -1
  4. package/dist/cli/help.js +1 -0
  5. package/dist/cli/help.js.map +1 -1
  6. package/dist/coordination/awareness.d.ts +32 -0
  7. package/dist/coordination/awareness.d.ts.map +1 -0
  8. package/dist/coordination/awareness.js +55 -0
  9. package/dist/coordination/awareness.js.map +1 -0
  10. package/dist/coordination/broker.d.ts +79 -0
  11. package/dist/coordination/broker.d.ts.map +1 -0
  12. package/dist/coordination/broker.js +195 -0
  13. package/dist/coordination/broker.js.map +1 -0
  14. package/dist/coordination/index.d.ts +16 -0
  15. package/dist/coordination/index.d.ts.map +1 -0
  16. package/dist/coordination/index.js +16 -0
  17. package/dist/coordination/index.js.map +1 -0
  18. package/dist/coordination/integration.d.ts +59 -0
  19. package/dist/coordination/integration.d.ts.map +1 -0
  20. package/dist/coordination/integration.js +126 -0
  21. package/dist/coordination/integration.js.map +1 -0
  22. package/dist/coordination/operation.d.ts +106 -0
  23. package/dist/coordination/operation.d.ts.map +1 -0
  24. package/dist/coordination/operation.js +179 -0
  25. package/dist/coordination/operation.js.map +1 -0
  26. package/dist/coordination/resource.d.ts +33 -0
  27. package/dist/coordination/resource.d.ts.map +1 -0
  28. package/dist/coordination/resource.js +89 -0
  29. package/dist/coordination/resource.js.map +1 -0
  30. package/dist/coordination/session.d.ts +74 -0
  31. package/dist/coordination/session.d.ts.map +1 -0
  32. package/dist/coordination/session.js +143 -0
  33. package/dist/coordination/session.js.map +1 -0
  34. package/dist/coordination/types.d.ts +68 -0
  35. package/dist/coordination/types.d.ts.map +1 -0
  36. package/dist/coordination/types.js +26 -0
  37. package/dist/coordination/types.js.map +1 -0
  38. package/dist/core/agent-session.d.ts.map +1 -1
  39. package/dist/core/agent-session.js +28 -7
  40. package/dist/core/agent-session.js.map +1 -1
  41. package/dist/core/compaction/control-state.d.ts +41 -0
  42. package/dist/core/compaction/control-state.d.ts.map +1 -0
  43. package/dist/core/compaction/control-state.js +85 -0
  44. package/dist/core/compaction/control-state.js.map +1 -0
  45. package/dist/core/compaction/fallback.d.ts +60 -0
  46. package/dist/core/compaction/fallback.d.ts.map +1 -0
  47. package/dist/core/compaction/fallback.js +117 -0
  48. package/dist/core/compaction/fallback.js.map +1 -0
  49. package/dist/core/compaction/index.d.ts +2 -0
  50. package/dist/core/compaction/index.d.ts.map +1 -1
  51. package/dist/core/compaction/index.js +2 -0
  52. package/dist/core/compaction/index.js.map +1 -1
  53. package/dist/core/context-budget-headroom-candidates.d.ts +16 -1
  54. package/dist/core/context-budget-headroom-candidates.d.ts.map +1 -1
  55. package/dist/core/context-budget-headroom-candidates.js +31 -13
  56. package/dist/core/context-budget-headroom-candidates.js.map +1 -1
  57. package/dist/core/context-budget-headroom-types.d.ts +7 -1
  58. package/dist/core/context-budget-headroom-types.d.ts.map +1 -1
  59. package/dist/core/context-budget-headroom-types.js +0 -1
  60. package/dist/core/context-budget-headroom-types.js.map +1 -1
  61. package/dist/core/context-budget-headroom.d.ts +10 -0
  62. package/dist/core/context-budget-headroom.d.ts.map +1 -1
  63. package/dist/core/context-budget-headroom.js +11 -2
  64. package/dist/core/context-budget-headroom.js.map +1 -1
  65. package/dist/core/context-budget-v2-global-pass.d.ts +21 -0
  66. package/dist/core/context-budget-v2-global-pass.d.ts.map +1 -0
  67. package/dist/core/context-budget-v2-global-pass.js +203 -0
  68. package/dist/core/context-budget-v2-global-pass.js.map +1 -0
  69. package/dist/core/context-budget-v2-planned-items.d.ts +12 -0
  70. package/dist/core/context-budget-v2-planned-items.d.ts.map +1 -1
  71. package/dist/core/context-budget-v2-planned-items.js +21 -2
  72. package/dist/core/context-budget-v2-planned-items.js.map +1 -1
  73. package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
  74. package/dist/core/context-budget-v2-planner.js +18 -19
  75. package/dist/core/context-budget-v2-planner.js.map +1 -1
  76. package/dist/core/context-budget-v2-scoring.d.ts +7 -1
  77. package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
  78. package/dist/core/context-budget-v2-scoring.js.map +1 -1
  79. package/dist/core/context-budget-v2-selection.d.ts +3 -0
  80. package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
  81. package/dist/core/context-budget-v2-selection.js +6 -2
  82. package/dist/core/context-budget-v2-selection.js.map +1 -1
  83. package/dist/core/context-budget-v2-types.d.ts +6 -1
  84. package/dist/core/context-budget-v2-types.d.ts.map +1 -1
  85. package/dist/core/context-budget-v2-types.js +6 -1
  86. package/dist/core/context-budget-v2-types.js.map +1 -1
  87. package/dist/core/provider-default-models.d.ts +1 -0
  88. package/dist/core/provider-default-models.d.ts.map +1 -1
  89. package/dist/core/provider-default-models.js +1 -0
  90. package/dist/core/provider-default-models.js.map +1 -1
  91. package/dist/core/provider-display-names.d.ts.map +1 -1
  92. package/dist/core/provider-display-names.js +1 -0
  93. package/dist/core/provider-display-names.js.map +1 -1
  94. package/dist/core/reasoning-router-resolver.d.ts +7 -0
  95. package/dist/core/reasoning-router-resolver.d.ts.map +1 -1
  96. package/dist/core/reasoning-router-resolver.js +21 -3
  97. package/dist/core/reasoning-router-resolver.js.map +1 -1
  98. package/dist/core/reasoning-router-v4.d.ts +8 -5
  99. package/dist/core/reasoning-router-v4.d.ts.map +1 -1
  100. package/dist/core/reasoning-router-v4.js +8 -5
  101. package/dist/core/reasoning-router-v4.js.map +1 -1
  102. package/dist/core/session-compaction-service.d.ts +15 -0
  103. package/dist/core/session-compaction-service.d.ts.map +1 -1
  104. package/dist/core/session-compaction-service.js +17 -4
  105. package/dist/core/session-compaction-service.js.map +1 -1
  106. package/dist/core/todo-runtime-state.d.ts +12 -0
  107. package/dist/core/todo-runtime-state.d.ts.map +1 -1
  108. package/dist/core/todo-runtime-state.js +23 -0
  109. package/dist/core/todo-runtime-state.js.map +1 -1
  110. package/dist/index.d.ts +2 -0
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +2 -0
  113. package/dist/index.js.map +1 -1
  114. package/dist/metacognition/calibration-selective.d.ts +78 -0
  115. package/dist/metacognition/calibration-selective.d.ts.map +1 -0
  116. package/dist/metacognition/calibration-selective.js +161 -0
  117. package/dist/metacognition/calibration-selective.js.map +1 -0
  118. package/dist/metacognition/calibration.d.ts +62 -0
  119. package/dist/metacognition/calibration.d.ts.map +1 -0
  120. package/dist/metacognition/calibration.js +122 -0
  121. package/dist/metacognition/calibration.js.map +1 -0
  122. package/dist/metacognition/checkpoint.d.ts +60 -0
  123. package/dist/metacognition/checkpoint.d.ts.map +1 -0
  124. package/dist/metacognition/checkpoint.js +57 -0
  125. package/dist/metacognition/checkpoint.js.map +1 -0
  126. package/dist/metacognition/context7.d.ts +48 -0
  127. package/dist/metacognition/context7.d.ts.map +1 -0
  128. package/dist/metacognition/context7.js +154 -0
  129. package/dist/metacognition/context7.js.map +1 -0
  130. package/dist/metacognition/decision.d.ts +44 -0
  131. package/dist/metacognition/decision.d.ts.map +1 -0
  132. package/dist/metacognition/decision.js +111 -0
  133. package/dist/metacognition/decision.js.map +1 -0
  134. package/dist/metacognition/evaluation.d.ts +73 -0
  135. package/dist/metacognition/evaluation.d.ts.map +1 -0
  136. package/dist/metacognition/evaluation.js +97 -0
  137. package/dist/metacognition/evaluation.js.map +1 -0
  138. package/dist/metacognition/index.d.ts +31 -0
  139. package/dist/metacognition/index.d.ts.map +1 -0
  140. package/dist/metacognition/index.js +31 -0
  141. package/dist/metacognition/index.js.map +1 -0
  142. package/dist/metacognition/knowledge-action.d.ts +43 -0
  143. package/dist/metacognition/knowledge-action.d.ts.map +1 -0
  144. package/dist/metacognition/knowledge-action.js +60 -0
  145. package/dist/metacognition/knowledge-action.js.map +1 -0
  146. package/dist/metacognition/knowledge.d.ts +84 -0
  147. package/dist/metacognition/knowledge.d.ts.map +1 -0
  148. package/dist/metacognition/knowledge.js +165 -0
  149. package/dist/metacognition/knowledge.js.map +1 -0
  150. package/dist/metacognition/obligations.d.ts +82 -0
  151. package/dist/metacognition/obligations.d.ts.map +1 -0
  152. package/dist/metacognition/obligations.js +139 -0
  153. package/dist/metacognition/obligations.js.map +1 -0
  154. package/dist/metacognition/observation-validity.d.ts +83 -0
  155. package/dist/metacognition/observation-validity.d.ts.map +1 -0
  156. package/dist/metacognition/observation-validity.js +118 -0
  157. package/dist/metacognition/observation-validity.js.map +1 -0
  158. package/dist/metacognition/observe.d.ts +45 -0
  159. package/dist/metacognition/observe.d.ts.map +1 -0
  160. package/dist/metacognition/observe.js +59 -0
  161. package/dist/metacognition/observe.js.map +1 -0
  162. package/dist/metacognition/policy.d.ts +53 -0
  163. package/dist/metacognition/policy.d.ts.map +1 -0
  164. package/dist/metacognition/policy.js +155 -0
  165. package/dist/metacognition/policy.js.map +1 -0
  166. package/dist/metacognition/predictions.d.ts +78 -0
  167. package/dist/metacognition/predictions.d.ts.map +1 -0
  168. package/dist/metacognition/predictions.js +181 -0
  169. package/dist/metacognition/predictions.js.map +1 -0
  170. package/dist/metacognition/retrieval.d.ts +53 -0
  171. package/dist/metacognition/retrieval.d.ts.map +1 -0
  172. package/dist/metacognition/retrieval.js +170 -0
  173. package/dist/metacognition/retrieval.js.map +1 -0
  174. package/dist/metacognition/risk.d.ts +48 -0
  175. package/dist/metacognition/risk.d.ts.map +1 -0
  176. package/dist/metacognition/risk.js +165 -0
  177. package/dist/metacognition/risk.js.map +1 -0
  178. package/dist/metacognition/route-economics.d.ts +95 -0
  179. package/dist/metacognition/route-economics.d.ts.map +1 -0
  180. package/dist/metacognition/route-economics.js +110 -0
  181. package/dist/metacognition/route-economics.js.map +1 -0
  182. package/dist/metacognition/runtime-bridge.d.ts +54 -0
  183. package/dist/metacognition/runtime-bridge.d.ts.map +1 -0
  184. package/dist/metacognition/runtime-bridge.js +140 -0
  185. package/dist/metacognition/runtime-bridge.js.map +1 -0
  186. package/dist/metacognition/skills.d.ts +42 -0
  187. package/dist/metacognition/skills.d.ts.map +1 -0
  188. package/dist/metacognition/skills.js +220 -0
  189. package/dist/metacognition/skills.js.map +1 -0
  190. package/dist/metacognition/state.d.ts +110 -0
  191. package/dist/metacognition/state.d.ts.map +1 -0
  192. package/dist/metacognition/state.js +52 -0
  193. package/dist/metacognition/state.js.map +1 -0
  194. package/dist/metacognition/validation.d.ts +19 -0
  195. package/dist/metacognition/validation.d.ts.map +1 -0
  196. package/dist/metacognition/validation.js +58 -0
  197. package/dist/metacognition/validation.js.map +1 -0
  198. package/dist/metacognition/verification.d.ts +93 -0
  199. package/dist/metacognition/verification.d.ts.map +1 -0
  200. package/dist/metacognition/verification.js +132 -0
  201. package/dist/metacognition/verification.js.map +1 -0
  202. package/dist/metacognition/verifier.d.ts +49 -0
  203. package/dist/metacognition/verifier.d.ts.map +1 -0
  204. package/dist/metacognition/verifier.js +88 -0
  205. package/dist/metacognition/verifier.js.map +1 -0
  206. package/dist/observation/identity.d.ts +14 -0
  207. package/dist/observation/identity.d.ts.map +1 -0
  208. package/dist/observation/identity.js +29 -0
  209. package/dist/observation/identity.js.map +1 -0
  210. package/dist/observation/index.d.ts +13 -0
  211. package/dist/observation/index.d.ts.map +1 -0
  212. package/dist/observation/index.js +13 -0
  213. package/dist/observation/index.js.map +1 -0
  214. package/dist/observation/observe-mode.d.ts +46 -0
  215. package/dist/observation/observe-mode.d.ts.map +1 -0
  216. package/dist/observation/observe-mode.js +83 -0
  217. package/dist/observation/observe-mode.js.map +1 -0
  218. package/dist/observation/store.d.ts +53 -0
  219. package/dist/observation/store.d.ts.map +1 -0
  220. package/dist/observation/store.js +126 -0
  221. package/dist/observation/store.js.map +1 -0
  222. package/dist/observation/types.d.ts +72 -0
  223. package/dist/observation/types.d.ts.map +1 -0
  224. package/dist/observation/types.js +9 -0
  225. package/dist/observation/types.js.map +1 -0
  226. package/dist/observation/view.d.ts +39 -0
  227. package/dist/observation/view.d.ts.map +1 -0
  228. package/dist/observation/view.js +173 -0
  229. package/dist/observation/view.js.map +1 -0
  230. package/docs/metacognition.md +51 -0
  231. package/docs/model-catalog-refresh.md +59 -0
  232. package/docs/providers.md +53 -0
  233. package/docs/runtime-algorithms.md +107 -3
  234. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  235. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  236. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  237. package/examples/extensions/gondolin/package-lock.json +2 -2
  238. package/examples/extensions/gondolin/package.json +1 -1
  239. package/examples/extensions/sandbox/package-lock.json +2 -2
  240. package/examples/extensions/sandbox/package.json +1 -1
  241. package/examples/extensions/with-deps/package-lock.json +2 -2
  242. package/examples/extensions/with-deps/package.json +1 -1
  243. package/npm-shrinkwrap.json +18 -18
  244. package/package.json +6 -6
package/CHANGELOG.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [1.2.0] - 2026-09-20
4
+
5
+ ### Added
6
+
7
+ - Parallel-session coordination kernel (`coordination/`): an admission broker that keeps a possibly-live effect's resource claims held until a trusted supervisor confirms termination — expiry, cancellation and authority restart are authorization events, not termination proofs — plus prefix-based claim conflict algebra, a publisher that admits a candidate only when its read versions, parent revision and receipt binding all still match, generation-tagged session lifecycle that discards a late init from a superseded generation and retains the handle when close fails, an operation lifecycle whose dispatch consumes a recorded observation rather than a re-interpreted instruction and re-evaluates the permit at the dispatch boundary, and conservative change-invalidation and frontier admission helpers.
8
+ - Metacognition evidence primitives: finite-sample Clopper–Pearson risk bounds for automation gating (a point estimate never widens scope; zero trials is absent evidence, not zero risk), probability calibration with temperature scaling, Brier/log-loss/ECE reported with bin occupancy, a selective-execution gate that reports coverage beside risk and leaves risk undefined when nothing was admitted, observation validity that separates time decay from the change indicator and lets explicit age and generation bounds override the decay score, state packing that returns `incomplete-state` instead of silently dropping required evidence, cost- and latency-aware route selection with safety as a hard filter outside the utility, and three-valued verification where `unknown` is never negated into `true` and evidence level is labelled by the strongest witness actually held.
4
9
 
5
10
  ## [1.0.0] - 2026-09-18
6
11
 
package/README.md CHANGED
@@ -47,7 +47,7 @@ OMK stores user configuration under `~/.omk/agent/` and project configuration un
47
47
  Install `omk-book-to-skill` to compile documents into reusable skills without adding Python extractors to OMK core:
48
48
 
49
49
  ```bash
50
- omk install npm:omk-book-to-skill@1.0.0
50
+ omk install npm:omk-book-to-skill@1.2.0
51
51
  ```
52
52
 
53
53
  It provides compile, update, and verification commands plus a local SHA-256 provenance manifest. See [Book to Skill](https://github.com/dmae97/omk/blob/main/packages/coding-agent/docs/book-to-skill.md).
@@ -258,7 +258,7 @@ npm test
258
258
 
259
259
  See [Development](https://github.com/dmae97/omk/blob/main/packages/coding-agent/docs/development.md) and [CONTRIBUTING.md](https://github.com/dmae97/omk/blob/main/CONTRIBUTING.md).
260
260
 
261
- Release notes: [v1.0.0](https://github.com/dmae97/omk/blob/main/.github/RELEASE_NOTES_v1.0.0.md).
261
+ Release notes: [v1.2.0](https://github.com/dmae97/omk/blob/main/.github/RELEASE_NOTES_v1.2.0.md).
262
262
 
263
263
  ## License
264
264
 
@@ -1 +1 @@
1
- {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,wBAAgB,SAAS,CAAC,cAAc,CAAC,EAAE,aAAa,EAAE,GAAG,IAAI,CAkMhE","sourcesContent":["import chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR, ENV_SESSION_DIR } from \"../config.ts\";\nimport type { ExtensionFlag } from \"../core/extensions/types.ts\";\n\nexport function printHelp(extensionFlags?: ExtensionFlag[]): void {\n\tlet extensionFlagsText = \"\";\n\tif (extensionFlags && extensionFlags.length > 0) {\n\t\textensionFlagsText = `\\n${chalk.bold(\"Extension CLI Flags:\")}\\n${extensionFlags\n\t\t\t.map((flag) => {\n\t\t\t\tconst value = flag.type === \"string\" ? \" <value>\" : \"\";\n\t\t\t\tconst description = flag.description ?? `Registered by ${flag.extensionPath}`;\n\t\t\t\treturn ` --${flag.name}${value}`.padEnd(30) + description;\n\t\t\t})\n\t\t\t.join(\"\\n\")}\\n`;\n\t}\n\t// CLI help is intentional stdout, not application debug logging.\n\t// pi-lens-ignore: no-console-except-error\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Commands:\")}\n ${APP_NAME} init --global [--dry-run] Create missing user context documents without overwriting settings\n ${APP_NAME} install <source> [-l] Install extension source and add to settings\n ${APP_NAME} remove <source> [-l] Remove extension source from settings\n ${APP_NAME} uninstall <source> [-l] Alias for remove\n ${APP_NAME} update [source|self|omk] Update OMK and installed extensions\n ${APP_NAME} list List installed extensions from settings\n ${APP_NAME} package doctor <source> Diagnose omk/pi manifest and runtime compatibility as JSON\n ${APP_NAME} config Open TUI to enable/disable package resources\n ${APP_NAME} quota Manage CodexBar quota connector and summaries\n ${APP_NAME} provider doctor <id> Diagnose a provider as sanitized JSON (--probe-model adds an\n opt-in Level-2 generative probe that may incur provider costs)\n ${APP_NAME} session doctor Inspect or safely repair one session (--session, --repair, --dry-run)\n ${APP_NAME} doctor resources [--json] [--report] Inspect current pressure or aggregate local observations\n ${APP_NAME} doctor adaptorch [--json] Verify ADAPTORCH_API_KEY reaches the AdaptOrch API (0 ok, 1 unset, 2 failed)\n ${APP_NAME} router-feedback compile-bias Compile this repository's bounded router bias snapshot\n ${APP_NAME} <command> --help Show help for install/remove/uninstall/update/list\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <pattern> Model pattern or ID (supports \"provider/id\" and optional \":<thinking>\")\n --model-contract <file> Pin an optional JSON model/effort/output dispatch policy\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt (can be used multiple times)\n --mode <mode> Output mode: text (default), json, rpc, or acp (conversation-only)\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path|id> Use specific session file or partial UUID\n --session-id <id> Use exact project session ID, creating it if missing\n --fork <path|id> Fork specific session file or partial UUID into a new session\n --session-dir <dir> Directory for session storage and lookup\n --no-session Don't save session (ephemeral)\n --name, -n <name> Set session display name\n --models <patterns> Comma-separated model patterns for Ctrl+P cycling\n Supports globs (anthropic/*, *sonnet*) and fuzzy matching\n --no-tools, -nt Disable all tools by default (built-in and extension)\n --no-builtin-tools, -nbt Disable built-in tools by default but keep extension/custom tools enabled\n --tools, -t <tools> Comma-separated allowlist of tool names to enable\n Applies to built-in, extension, and custom tools\n --exclude-tools, -xt <tools> Comma-separated denylist of tool names to disable\n Applies to built-in, extension, and custom tools\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh, max, ultra\n --extension, -e <path> Load an extension file (can be used multiple times)\n --no-extensions, -ne Disable extension discovery (explicit -e paths still work)\n --skill <path> Load a skill file or directory (can be used multiple times)\n --no-skills, -ns Disable skills discovery and loading\n --prompt-template <path> Load a prompt template file or directory (can be used multiple times)\n --no-prompt-templates, -np Disable prompt template discovery and loading\n --theme <path> Load a theme file or directory (can be used multiple times)\n --no-themes Disable theme discovery and loading\n --no-context-files, -nc Disable AGENTS.md and CLAUDE.md discovery and loading\n --export <file> Export session file to HTML and exit\n --list-models [search] List available models (with optional fuzzy search)\n --verbose Force verbose startup (overrides quietStartup setting)\n --offline Disable startup network operations (same as OMK_OFFLINE=1)\n --help, -h Show this help\n --version, -v Show version number\n\nExtensions can register additional flags (e.g., --plan from plan-mode extension).${extensionFlagsText}\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Start a named session\n ${APP_NAME} --name \"Refactor auth module\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Use model with provider prefix (no --provider needed)\n ${APP_NAME} --model openai/gpt-4o \"Help me refactor this code\"\n\n # Use model with thinking level shorthand\n ${APP_NAME} --model sonnet:high \"Solve this complex problem\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Limit to a specific provider with glob pattern\n ${APP_NAME} --models \"github-copilot/*\"\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Disable one tool while keeping the rest available\n ${APP_NAME} --exclude-tools ask_question\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n ANT_LING_API_KEY - Ant Ling API key\n OPENAI_API_KEY - OpenAI GPT API key\n AZURE_OPENAI_API_KEY - Azure OpenAI API key\n AZURE_OPENAI_BASE_URL - Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)\n AZURE_OPENAI_RESOURCE_NAME - Azure OpenAI resource name (alternative to base URL)\n AZURE_OPENAI_API_VERSION - Azure OpenAI API version (default: v1)\n AZURE_OPENAI_DEPLOYMENT_NAME_MAP - Azure OpenAI model=deployment map (comma-separated)\n DEEPSEEK_API_KEY - DeepSeek API key\n DEVIN_API_KEY - Devin CLI subscription session token (or /login devin)\n NVIDIA_API_KEY - NVIDIA NIM API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n FIREWORKS_API_KEY - Fireworks API key\n TOGETHER_API_KEY - Together AI API key\n OPENROUTER_API_KEY - OpenRouter API key\n AI_GATEWAY_API_KEY - Vercel AI Gateway API key\n ZAI_API_KEY - ZAI API key\n ZAI_CODING_CN_API_KEY - ZAI Coding Plan API key (China)\n MISTRAL_API_KEY - Mistral API key\n MINIMAX_API_KEY - MiniMax API key\n MOONSHOT_API_KEY - Moonshot AI API key\n META_API_KEY - Meta Model API key (Muse Spark); META_MODEL_API_KEY/MODEL_API_KEY also read\n OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key\n KIMI_API_KEY - Kimi For Coding API key\n CLOUDFLARE_API_KEY - Cloudflare API token (Workers AI and AI Gateway)\n CLOUDFLARE_ACCOUNT_ID - Cloudflare account id (required for both)\n CLOUDFLARE_GATEWAY_ID - Cloudflare AI Gateway slug (required for AI Gateway)\n XIAOMI_API_KEY - Xiaomi MiMo API key (api.xiaomimimo.com billing)\n XIAOMI_TOKEN_PLAN_CN_API_KEY - Xiaomi MiMo Token Plan API key (China region)\n XIAOMI_TOKEN_PLAN_AMS_API_KEY - Xiaomi MiMo Token Plan API key (Amsterdam region)\n XIAOMI_TOKEN_PLAN_SGP_API_KEY - Xiaomi MiMo Token Plan API key (Singapore region)\n ZYLOO_API_KEY - Zyloo API key\n AWS_PROFILE - AWS profile for Amazon Bedrock\n AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock\n AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock\n AWS_BEARER_TOKEN_BEDROCK - Bedrock API key (bearer token)\n AWS_REGION - AWS region for Amazon Bedrock (e.g., us-east-1)\n ${ENV_AGENT_DIR.padEnd(32)} - Config directory (default: ~/${CONFIG_DIR_NAME}/agent)\n ${ENV_SESSION_DIR.padEnd(32)} - Session storage directory (overridden by --session-dir)\n OMK_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)\n OMK_TOOL_SCHEDULER - Tool scheduler override: dag-v2 or waves-v1 rollback\n OMK_OFFLINE - Disable startup network operations when set to 1/true/yes\n OMK_TELEMETRY - Override install telemetry when set to 1/true/yes or 0/false/no\n OMK_SHARE_VIEWER_URL - Base URL for /share command (default: https://omk.dev/session/)\n ADAPTORCH_API_KEY - AdaptOrch API key (optional; enables the doctor adaptorch check)\n ADAPTORCH_API_URL - AdaptOrch API base URL (default: https://api.adaptorch.com)\n\n${chalk.bold(\"Built-in Tool Names:\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,wBAAgB,SAAS,CAAC,cAAc,CAAC,EAAE,aAAa,EAAE,GAAG,IAAI,CAmMhE","sourcesContent":["import chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR, ENV_SESSION_DIR } from \"../config.ts\";\nimport type { ExtensionFlag } from \"../core/extensions/types.ts\";\n\nexport function printHelp(extensionFlags?: ExtensionFlag[]): void {\n\tlet extensionFlagsText = \"\";\n\tif (extensionFlags && extensionFlags.length > 0) {\n\t\textensionFlagsText = `\\n${chalk.bold(\"Extension CLI Flags:\")}\\n${extensionFlags\n\t\t\t.map((flag) => {\n\t\t\t\tconst value = flag.type === \"string\" ? \" <value>\" : \"\";\n\t\t\t\tconst description = flag.description ?? `Registered by ${flag.extensionPath}`;\n\t\t\t\treturn ` --${flag.name}${value}`.padEnd(30) + description;\n\t\t\t})\n\t\t\t.join(\"\\n\")}\\n`;\n\t}\n\t// CLI help is intentional stdout, not application debug logging.\n\t// pi-lens-ignore: no-console-except-error\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Commands:\")}\n ${APP_NAME} init --global [--dry-run] Create missing user context documents without overwriting settings\n ${APP_NAME} install <source> [-l] Install extension source and add to settings\n ${APP_NAME} remove <source> [-l] Remove extension source from settings\n ${APP_NAME} uninstall <source> [-l] Alias for remove\n ${APP_NAME} update [source|self|omk] Update OMK and installed extensions\n ${APP_NAME} list List installed extensions from settings\n ${APP_NAME} package doctor <source> Diagnose omk/pi manifest and runtime compatibility as JSON\n ${APP_NAME} config Open TUI to enable/disable package resources\n ${APP_NAME} quota Manage CodexBar quota connector and summaries\n ${APP_NAME} provider doctor <id> Diagnose a provider as sanitized JSON (--probe-model adds an\n opt-in Level-2 generative probe that may incur provider costs)\n ${APP_NAME} session doctor Inspect or safely repair one session (--session, --repair, --dry-run)\n ${APP_NAME} doctor resources [--json] [--report] Inspect current pressure or aggregate local observations\n ${APP_NAME} doctor adaptorch [--json] Verify ADAPTORCH_API_KEY reaches the AdaptOrch API (0 ok, 1 unset, 2 failed)\n ${APP_NAME} router-feedback compile-bias Compile this repository's bounded router bias snapshot\n ${APP_NAME} <command> --help Show help for install/remove/uninstall/update/list\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <pattern> Model pattern or ID (supports \"provider/id\" and optional \":<thinking>\")\n --model-contract <file> Pin an optional JSON model/effort/output dispatch policy\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt (can be used multiple times)\n --mode <mode> Output mode: text (default), json, rpc, or acp (conversation-only)\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path|id> Use specific session file or partial UUID\n --session-id <id> Use exact project session ID, creating it if missing\n --fork <path|id> Fork specific session file or partial UUID into a new session\n --session-dir <dir> Directory for session storage and lookup\n --no-session Don't save session (ephemeral)\n --name, -n <name> Set session display name\n --models <patterns> Comma-separated model patterns for Ctrl+P cycling\n Supports globs (anthropic/*, *sonnet*) and fuzzy matching\n --no-tools, -nt Disable all tools by default (built-in and extension)\n --no-builtin-tools, -nbt Disable built-in tools by default but keep extension/custom tools enabled\n --tools, -t <tools> Comma-separated allowlist of tool names to enable\n Applies to built-in, extension, and custom tools\n --exclude-tools, -xt <tools> Comma-separated denylist of tool names to disable\n Applies to built-in, extension, and custom tools\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh, max, ultra\n --extension, -e <path> Load an extension file (can be used multiple times)\n --no-extensions, -ne Disable extension discovery (explicit -e paths still work)\n --skill <path> Load a skill file or directory (can be used multiple times)\n --no-skills, -ns Disable skills discovery and loading\n --prompt-template <path> Load a prompt template file or directory (can be used multiple times)\n --no-prompt-templates, -np Disable prompt template discovery and loading\n --theme <path> Load a theme file or directory (can be used multiple times)\n --no-themes Disable theme discovery and loading\n --no-context-files, -nc Disable AGENTS.md and CLAUDE.md discovery and loading\n --export <file> Export session file to HTML and exit\n --list-models [search] List available models (with optional fuzzy search)\n --verbose Force verbose startup (overrides quietStartup setting)\n --offline Disable startup network operations (same as OMK_OFFLINE=1)\n --help, -h Show this help\n --version, -v Show version number\n\nExtensions can register additional flags (e.g., --plan from plan-mode extension).${extensionFlagsText}\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Start a named session\n ${APP_NAME} --name \"Refactor auth module\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Use model with provider prefix (no --provider needed)\n ${APP_NAME} --model openai/gpt-4o \"Help me refactor this code\"\n\n # Use model with thinking level shorthand\n ${APP_NAME} --model sonnet:high \"Solve this complex problem\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Limit to a specific provider with glob pattern\n ${APP_NAME} --models \"github-copilot/*\"\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Disable one tool while keeping the rest available\n ${APP_NAME} --exclude-tools ask_question\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n ANT_LING_API_KEY - Ant Ling API key\n OPENAI_API_KEY - OpenAI GPT API key\n AZURE_OPENAI_API_KEY - Azure OpenAI API key\n AZURE_OPENAI_BASE_URL - Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)\n AZURE_OPENAI_RESOURCE_NAME - Azure OpenAI resource name (alternative to base URL)\n AZURE_OPENAI_API_VERSION - Azure OpenAI API version (default: v1)\n AZURE_OPENAI_DEPLOYMENT_NAME_MAP - Azure OpenAI model=deployment map (comma-separated)\n DEEPSEEK_API_KEY - DeepSeek API key\n DEVIN_API_KEY - Devin CLI subscription session token (or /login devin)\n NVIDIA_API_KEY - NVIDIA NIM API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n FIREWORKS_API_KEY - Fireworks API key\n TOGETHER_API_KEY - Together AI API key\n OPENROUTER_API_KEY - OpenRouter API key\n AI_GATEWAY_API_KEY - Vercel AI Gateway API key\n ZAI_API_KEY - ZAI API key\n ZAI_CODING_CN_API_KEY - ZAI Coding Plan API key (China)\n MISTRAL_API_KEY - Mistral API key\n MINIMAX_API_KEY - MiniMax API key\n MOONSHOT_API_KEY - Moonshot AI API key\n META_API_KEY - Meta Model API key (Muse Spark); META_MODEL_API_KEY/MODEL_API_KEY also read\n OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key\n KIMI_API_KEY - Kimi For Coding API key\n WORKBUDDY_API_KEY - WorkBuddy (Tencent CodeBuddy) plan key\n CLOUDFLARE_API_KEY - Cloudflare API token (Workers AI and AI Gateway)\n CLOUDFLARE_ACCOUNT_ID - Cloudflare account id (required for both)\n CLOUDFLARE_GATEWAY_ID - Cloudflare AI Gateway slug (required for AI Gateway)\n XIAOMI_API_KEY - Xiaomi MiMo API key (api.xiaomimimo.com billing)\n XIAOMI_TOKEN_PLAN_CN_API_KEY - Xiaomi MiMo Token Plan API key (China region)\n XIAOMI_TOKEN_PLAN_AMS_API_KEY - Xiaomi MiMo Token Plan API key (Amsterdam region)\n XIAOMI_TOKEN_PLAN_SGP_API_KEY - Xiaomi MiMo Token Plan API key (Singapore region)\n ZYLOO_API_KEY - Zyloo API key\n AWS_PROFILE - AWS profile for Amazon Bedrock\n AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock\n AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock\n AWS_BEARER_TOKEN_BEDROCK - Bedrock API key (bearer token)\n AWS_REGION - AWS region for Amazon Bedrock (e.g., us-east-1)\n ${ENV_AGENT_DIR.padEnd(32)} - Config directory (default: ~/${CONFIG_DIR_NAME}/agent)\n ${ENV_SESSION_DIR.padEnd(32)} - Session storage directory (overridden by --session-dir)\n OMK_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)\n OMK_TOOL_SCHEDULER - Tool scheduler override: dag-v2 or waves-v1 rollback\n OMK_OFFLINE - Disable startup network operations when set to 1/true/yes\n OMK_TELEMETRY - Override install telemetry when set to 1/true/yes or 0/false/no\n OMK_SHARE_VIEWER_URL - Base URL for /share command (default: https://omk.dev/session/)\n ADAPTORCH_API_KEY - AdaptOrch API key (optional; enables the doctor adaptorch check)\n ADAPTORCH_API_URL - AdaptOrch API base URL (default: https://api.adaptorch.com)\n\n${chalk.bold(\"Built-in Tool Names:\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
package/dist/cli/help.js CHANGED
@@ -162,6 +162,7 @@ ${chalk.bold("Environment Variables:")}
162
162
  META_API_KEY - Meta Model API key (Muse Spark); META_MODEL_API_KEY/MODEL_API_KEY also read
163
163
  OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key
164
164
  KIMI_API_KEY - Kimi For Coding API key
165
+ WORKBUDDY_API_KEY - WorkBuddy (Tencent CodeBuddy) plan key
165
166
  CLOUDFLARE_API_KEY - Cloudflare API token (Workers AI and AI Gateway)
166
167
  CLOUDFLARE_ACCOUNT_ID - Cloudflare account id (required for both)
167
168
  CLOUDFLARE_GATEWAY_ID - Cloudflare AI Gateway slug (required for AI Gateway)
@@ -1 +1 @@
1
- {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGzF,MAAM,UAAU,SAAS,CAAC,cAAgC,EAAQ;IACjE,IAAI,kBAAkB,GAAG,EAAE,CAAC;IAC5B,IAAI,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjD,kBAAkB,GAAG,KAAK,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,cAAc;aAC7E,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,iBAAiB,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9E,OAAO,OAAO,IAAI,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC;QAAA,CAC3D,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IACD,iEAAiE;IACjE,0CAA0C;IAC1C,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;;EAElC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;IAClB,QAAQ;;EAEV,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;IACrB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;;IAER,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;;EAEV,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mFA0C2D,kBAAkB;;EAEnG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;;IAErB,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ,eAAe,eAAe;IACtC,QAAQ;;EAEV,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA0ClC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,mCAAmC,eAAe;IAC1E,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;;;;;;;;;EAS5B,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC;;;;;;;;CAQnC,CAAC,CAAC;AAAA,CACF","sourcesContent":["import chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR, ENV_SESSION_DIR } from \"../config.ts\";\nimport type { ExtensionFlag } from \"../core/extensions/types.ts\";\n\nexport function printHelp(extensionFlags?: ExtensionFlag[]): void {\n\tlet extensionFlagsText = \"\";\n\tif (extensionFlags && extensionFlags.length > 0) {\n\t\textensionFlagsText = `\\n${chalk.bold(\"Extension CLI Flags:\")}\\n${extensionFlags\n\t\t\t.map((flag) => {\n\t\t\t\tconst value = flag.type === \"string\" ? \" <value>\" : \"\";\n\t\t\t\tconst description = flag.description ?? `Registered by ${flag.extensionPath}`;\n\t\t\t\treturn ` --${flag.name}${value}`.padEnd(30) + description;\n\t\t\t})\n\t\t\t.join(\"\\n\")}\\n`;\n\t}\n\t// CLI help is intentional stdout, not application debug logging.\n\t// pi-lens-ignore: no-console-except-error\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Commands:\")}\n ${APP_NAME} init --global [--dry-run] Create missing user context documents without overwriting settings\n ${APP_NAME} install <source> [-l] Install extension source and add to settings\n ${APP_NAME} remove <source> [-l] Remove extension source from settings\n ${APP_NAME} uninstall <source> [-l] Alias for remove\n ${APP_NAME} update [source|self|omk] Update OMK and installed extensions\n ${APP_NAME} list List installed extensions from settings\n ${APP_NAME} package doctor <source> Diagnose omk/pi manifest and runtime compatibility as JSON\n ${APP_NAME} config Open TUI to enable/disable package resources\n ${APP_NAME} quota Manage CodexBar quota connector and summaries\n ${APP_NAME} provider doctor <id> Diagnose a provider as sanitized JSON (--probe-model adds an\n opt-in Level-2 generative probe that may incur provider costs)\n ${APP_NAME} session doctor Inspect or safely repair one session (--session, --repair, --dry-run)\n ${APP_NAME} doctor resources [--json] [--report] Inspect current pressure or aggregate local observations\n ${APP_NAME} doctor adaptorch [--json] Verify ADAPTORCH_API_KEY reaches the AdaptOrch API (0 ok, 1 unset, 2 failed)\n ${APP_NAME} router-feedback compile-bias Compile this repository's bounded router bias snapshot\n ${APP_NAME} <command> --help Show help for install/remove/uninstall/update/list\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <pattern> Model pattern or ID (supports \"provider/id\" and optional \":<thinking>\")\n --model-contract <file> Pin an optional JSON model/effort/output dispatch policy\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt (can be used multiple times)\n --mode <mode> Output mode: text (default), json, rpc, or acp (conversation-only)\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path|id> Use specific session file or partial UUID\n --session-id <id> Use exact project session ID, creating it if missing\n --fork <path|id> Fork specific session file or partial UUID into a new session\n --session-dir <dir> Directory for session storage and lookup\n --no-session Don't save session (ephemeral)\n --name, -n <name> Set session display name\n --models <patterns> Comma-separated model patterns for Ctrl+P cycling\n Supports globs (anthropic/*, *sonnet*) and fuzzy matching\n --no-tools, -nt Disable all tools by default (built-in and extension)\n --no-builtin-tools, -nbt Disable built-in tools by default but keep extension/custom tools enabled\n --tools, -t <tools> Comma-separated allowlist of tool names to enable\n Applies to built-in, extension, and custom tools\n --exclude-tools, -xt <tools> Comma-separated denylist of tool names to disable\n Applies to built-in, extension, and custom tools\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh, max, ultra\n --extension, -e <path> Load an extension file (can be used multiple times)\n --no-extensions, -ne Disable extension discovery (explicit -e paths still work)\n --skill <path> Load a skill file or directory (can be used multiple times)\n --no-skills, -ns Disable skills discovery and loading\n --prompt-template <path> Load a prompt template file or directory (can be used multiple times)\n --no-prompt-templates, -np Disable prompt template discovery and loading\n --theme <path> Load a theme file or directory (can be used multiple times)\n --no-themes Disable theme discovery and loading\n --no-context-files, -nc Disable AGENTS.md and CLAUDE.md discovery and loading\n --export <file> Export session file to HTML and exit\n --list-models [search] List available models (with optional fuzzy search)\n --verbose Force verbose startup (overrides quietStartup setting)\n --offline Disable startup network operations (same as OMK_OFFLINE=1)\n --help, -h Show this help\n --version, -v Show version number\n\nExtensions can register additional flags (e.g., --plan from plan-mode extension).${extensionFlagsText}\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Start a named session\n ${APP_NAME} --name \"Refactor auth module\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Use model with provider prefix (no --provider needed)\n ${APP_NAME} --model openai/gpt-4o \"Help me refactor this code\"\n\n # Use model with thinking level shorthand\n ${APP_NAME} --model sonnet:high \"Solve this complex problem\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Limit to a specific provider with glob pattern\n ${APP_NAME} --models \"github-copilot/*\"\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Disable one tool while keeping the rest available\n ${APP_NAME} --exclude-tools ask_question\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n ANT_LING_API_KEY - Ant Ling API key\n OPENAI_API_KEY - OpenAI GPT API key\n AZURE_OPENAI_API_KEY - Azure OpenAI API key\n AZURE_OPENAI_BASE_URL - Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)\n AZURE_OPENAI_RESOURCE_NAME - Azure OpenAI resource name (alternative to base URL)\n AZURE_OPENAI_API_VERSION - Azure OpenAI API version (default: v1)\n AZURE_OPENAI_DEPLOYMENT_NAME_MAP - Azure OpenAI model=deployment map (comma-separated)\n DEEPSEEK_API_KEY - DeepSeek API key\n DEVIN_API_KEY - Devin CLI subscription session token (or /login devin)\n NVIDIA_API_KEY - NVIDIA NIM API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n FIREWORKS_API_KEY - Fireworks API key\n TOGETHER_API_KEY - Together AI API key\n OPENROUTER_API_KEY - OpenRouter API key\n AI_GATEWAY_API_KEY - Vercel AI Gateway API key\n ZAI_API_KEY - ZAI API key\n ZAI_CODING_CN_API_KEY - ZAI Coding Plan API key (China)\n MISTRAL_API_KEY - Mistral API key\n MINIMAX_API_KEY - MiniMax API key\n MOONSHOT_API_KEY - Moonshot AI API key\n META_API_KEY - Meta Model API key (Muse Spark); META_MODEL_API_KEY/MODEL_API_KEY also read\n OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key\n KIMI_API_KEY - Kimi For Coding API key\n CLOUDFLARE_API_KEY - Cloudflare API token (Workers AI and AI Gateway)\n CLOUDFLARE_ACCOUNT_ID - Cloudflare account id (required for both)\n CLOUDFLARE_GATEWAY_ID - Cloudflare AI Gateway slug (required for AI Gateway)\n XIAOMI_API_KEY - Xiaomi MiMo API key (api.xiaomimimo.com billing)\n XIAOMI_TOKEN_PLAN_CN_API_KEY - Xiaomi MiMo Token Plan API key (China region)\n XIAOMI_TOKEN_PLAN_AMS_API_KEY - Xiaomi MiMo Token Plan API key (Amsterdam region)\n XIAOMI_TOKEN_PLAN_SGP_API_KEY - Xiaomi MiMo Token Plan API key (Singapore region)\n ZYLOO_API_KEY - Zyloo API key\n AWS_PROFILE - AWS profile for Amazon Bedrock\n AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock\n AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock\n AWS_BEARER_TOKEN_BEDROCK - Bedrock API key (bearer token)\n AWS_REGION - AWS region for Amazon Bedrock (e.g., us-east-1)\n ${ENV_AGENT_DIR.padEnd(32)} - Config directory (default: ~/${CONFIG_DIR_NAME}/agent)\n ${ENV_SESSION_DIR.padEnd(32)} - Session storage directory (overridden by --session-dir)\n OMK_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)\n OMK_TOOL_SCHEDULER - Tool scheduler override: dag-v2 or waves-v1 rollback\n OMK_OFFLINE - Disable startup network operations when set to 1/true/yes\n OMK_TELEMETRY - Override install telemetry when set to 1/true/yes or 0/false/no\n OMK_SHARE_VIEWER_URL - Base URL for /share command (default: https://omk.dev/session/)\n ADAPTORCH_API_KEY - AdaptOrch API key (optional; enables the doctor adaptorch check)\n ADAPTORCH_API_URL - AdaptOrch API base URL (default: https://api.adaptorch.com)\n\n${chalk.bold(\"Built-in Tool Names:\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGzF,MAAM,UAAU,SAAS,CAAC,cAAgC,EAAQ;IACjE,IAAI,kBAAkB,GAAG,EAAE,CAAC;IAC5B,IAAI,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjD,kBAAkB,GAAG,KAAK,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,cAAc;aAC7E,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,iBAAiB,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9E,OAAO,OAAO,IAAI,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC;QAAA,CAC3D,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IACD,iEAAiE;IACjE,0CAA0C;IAC1C,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;;EAElC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;IAClB,QAAQ;;EAEV,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;IACrB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;;IAER,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;;EAEV,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mFA0C2D,kBAAkB;;EAEnG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;;IAErB,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ;;;IAGR,QAAQ,eAAe,eAAe;IACtC,QAAQ;;EAEV,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2ClC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,mCAAmC,eAAe;IAC1E,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;;;;;;;;;EAS5B,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC;;;;;;;;CAQnC,CAAC,CAAC;AAAA,CACF","sourcesContent":["import chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR, ENV_SESSION_DIR } from \"../config.ts\";\nimport type { ExtensionFlag } from \"../core/extensions/types.ts\";\n\nexport function printHelp(extensionFlags?: ExtensionFlag[]): void {\n\tlet extensionFlagsText = \"\";\n\tif (extensionFlags && extensionFlags.length > 0) {\n\t\textensionFlagsText = `\\n${chalk.bold(\"Extension CLI Flags:\")}\\n${extensionFlags\n\t\t\t.map((flag) => {\n\t\t\t\tconst value = flag.type === \"string\" ? \" <value>\" : \"\";\n\t\t\t\tconst description = flag.description ?? `Registered by ${flag.extensionPath}`;\n\t\t\t\treturn ` --${flag.name}${value}`.padEnd(30) + description;\n\t\t\t})\n\t\t\t.join(\"\\n\")}\\n`;\n\t}\n\t// CLI help is intentional stdout, not application debug logging.\n\t// pi-lens-ignore: no-console-except-error\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Commands:\")}\n ${APP_NAME} init --global [--dry-run] Create missing user context documents without overwriting settings\n ${APP_NAME} install <source> [-l] Install extension source and add to settings\n ${APP_NAME} remove <source> [-l] Remove extension source from settings\n ${APP_NAME} uninstall <source> [-l] Alias for remove\n ${APP_NAME} update [source|self|omk] Update OMK and installed extensions\n ${APP_NAME} list List installed extensions from settings\n ${APP_NAME} package doctor <source> Diagnose omk/pi manifest and runtime compatibility as JSON\n ${APP_NAME} config Open TUI to enable/disable package resources\n ${APP_NAME} quota Manage CodexBar quota connector and summaries\n ${APP_NAME} provider doctor <id> Diagnose a provider as sanitized JSON (--probe-model adds an\n opt-in Level-2 generative probe that may incur provider costs)\n ${APP_NAME} session doctor Inspect or safely repair one session (--session, --repair, --dry-run)\n ${APP_NAME} doctor resources [--json] [--report] Inspect current pressure or aggregate local observations\n ${APP_NAME} doctor adaptorch [--json] Verify ADAPTORCH_API_KEY reaches the AdaptOrch API (0 ok, 1 unset, 2 failed)\n ${APP_NAME} router-feedback compile-bias Compile this repository's bounded router bias snapshot\n ${APP_NAME} <command> --help Show help for install/remove/uninstall/update/list\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <pattern> Model pattern or ID (supports \"provider/id\" and optional \":<thinking>\")\n --model-contract <file> Pin an optional JSON model/effort/output dispatch policy\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt (can be used multiple times)\n --mode <mode> Output mode: text (default), json, rpc, or acp (conversation-only)\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path|id> Use specific session file or partial UUID\n --session-id <id> Use exact project session ID, creating it if missing\n --fork <path|id> Fork specific session file or partial UUID into a new session\n --session-dir <dir> Directory for session storage and lookup\n --no-session Don't save session (ephemeral)\n --name, -n <name> Set session display name\n --models <patterns> Comma-separated model patterns for Ctrl+P cycling\n Supports globs (anthropic/*, *sonnet*) and fuzzy matching\n --no-tools, -nt Disable all tools by default (built-in and extension)\n --no-builtin-tools, -nbt Disable built-in tools by default but keep extension/custom tools enabled\n --tools, -t <tools> Comma-separated allowlist of tool names to enable\n Applies to built-in, extension, and custom tools\n --exclude-tools, -xt <tools> Comma-separated denylist of tool names to disable\n Applies to built-in, extension, and custom tools\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh, max, ultra\n --extension, -e <path> Load an extension file (can be used multiple times)\n --no-extensions, -ne Disable extension discovery (explicit -e paths still work)\n --skill <path> Load a skill file or directory (can be used multiple times)\n --no-skills, -ns Disable skills discovery and loading\n --prompt-template <path> Load a prompt template file or directory (can be used multiple times)\n --no-prompt-templates, -np Disable prompt template discovery and loading\n --theme <path> Load a theme file or directory (can be used multiple times)\n --no-themes Disable theme discovery and loading\n --no-context-files, -nc Disable AGENTS.md and CLAUDE.md discovery and loading\n --export <file> Export session file to HTML and exit\n --list-models [search] List available models (with optional fuzzy search)\n --verbose Force verbose startup (overrides quietStartup setting)\n --offline Disable startup network operations (same as OMK_OFFLINE=1)\n --help, -h Show this help\n --version, -v Show version number\n\nExtensions can register additional flags (e.g., --plan from plan-mode extension).${extensionFlagsText}\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Start a named session\n ${APP_NAME} --name \"Refactor auth module\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Use model with provider prefix (no --provider needed)\n ${APP_NAME} --model openai/gpt-4o \"Help me refactor this code\"\n\n # Use model with thinking level shorthand\n ${APP_NAME} --model sonnet:high \"Solve this complex problem\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Limit to a specific provider with glob pattern\n ${APP_NAME} --models \"github-copilot/*\"\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Disable one tool while keeping the rest available\n ${APP_NAME} --exclude-tools ask_question\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n ANT_LING_API_KEY - Ant Ling API key\n OPENAI_API_KEY - OpenAI GPT API key\n AZURE_OPENAI_API_KEY - Azure OpenAI API key\n AZURE_OPENAI_BASE_URL - Azure OpenAI/Cognitive Services base URL (e.g. https://{resource}.openai.azure.com)\n AZURE_OPENAI_RESOURCE_NAME - Azure OpenAI resource name (alternative to base URL)\n AZURE_OPENAI_API_VERSION - Azure OpenAI API version (default: v1)\n AZURE_OPENAI_DEPLOYMENT_NAME_MAP - Azure OpenAI model=deployment map (comma-separated)\n DEEPSEEK_API_KEY - DeepSeek API key\n DEVIN_API_KEY - Devin CLI subscription session token (or /login devin)\n NVIDIA_API_KEY - NVIDIA NIM API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n FIREWORKS_API_KEY - Fireworks API key\n TOGETHER_API_KEY - Together AI API key\n OPENROUTER_API_KEY - OpenRouter API key\n AI_GATEWAY_API_KEY - Vercel AI Gateway API key\n ZAI_API_KEY - ZAI API key\n ZAI_CODING_CN_API_KEY - ZAI Coding Plan API key (China)\n MISTRAL_API_KEY - Mistral API key\n MINIMAX_API_KEY - MiniMax API key\n MOONSHOT_API_KEY - Moonshot AI API key\n META_API_KEY - Meta Model API key (Muse Spark); META_MODEL_API_KEY/MODEL_API_KEY also read\n OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key\n KIMI_API_KEY - Kimi For Coding API key\n WORKBUDDY_API_KEY - WorkBuddy (Tencent CodeBuddy) plan key\n CLOUDFLARE_API_KEY - Cloudflare API token (Workers AI and AI Gateway)\n CLOUDFLARE_ACCOUNT_ID - Cloudflare account id (required for both)\n CLOUDFLARE_GATEWAY_ID - Cloudflare AI Gateway slug (required for AI Gateway)\n XIAOMI_API_KEY - Xiaomi MiMo API key (api.xiaomimimo.com billing)\n XIAOMI_TOKEN_PLAN_CN_API_KEY - Xiaomi MiMo Token Plan API key (China region)\n XIAOMI_TOKEN_PLAN_AMS_API_KEY - Xiaomi MiMo Token Plan API key (Amsterdam region)\n XIAOMI_TOKEN_PLAN_SGP_API_KEY - Xiaomi MiMo Token Plan API key (Singapore region)\n ZYLOO_API_KEY - Zyloo API key\n AWS_PROFILE - AWS profile for Amazon Bedrock\n AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock\n AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock\n AWS_BEARER_TOKEN_BEDROCK - Bedrock API key (bearer token)\n AWS_REGION - AWS region for Amazon Bedrock (e.g., us-east-1)\n ${ENV_AGENT_DIR.padEnd(32)} - Config directory (default: ~/${CONFIG_DIR_NAME}/agent)\n ${ENV_SESSION_DIR.padEnd(32)} - Session storage directory (overridden by --session-dir)\n OMK_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)\n OMK_TOOL_SCHEDULER - Tool scheduler override: dag-v2 or waves-v1 rollback\n OMK_OFFLINE - Disable startup network operations when set to 1/true/yes\n OMK_TELEMETRY - Override install telemetry when set to 1/true/yes or 0/false/no\n OMK_SHARE_VIEWER_URL - Base URL for /share command (default: https://omk.dev/session/)\n ADAPTORCH_API_KEY - AdaptOrch API key (optional; enables the doctor adaptorch check)\n ADAPTORCH_API_URL - AdaptOrch API base URL (default: https://api.adaptorch.com)\n\n${chalk.bold(\"Built-in Tool Names:\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Change awareness: what a change invalidates, and who may proceed next.
3
+ *
4
+ * Both functions are deliberately conservative. Invalidation treats an
5
+ * unmapped dependent as affected, because "we have no edge for it" is not
6
+ * evidence that it is unaffected. Frontier admission lets an unrelated
7
+ * follower pass a blocked leader, but never lets a later request that
8
+ * conflicts with an older waiting one jump ahead of it.
9
+ */
10
+ import type { ResourceClaim } from "./types.ts";
11
+ export interface WaitingRequest {
12
+ readonly requestId: string;
13
+ readonly claims: readonly ResourceClaim[];
14
+ }
15
+ /**
16
+ * Transitive closure over reverse dependencies.
17
+ *
18
+ * `unknownDependents` are nodes whose dependencies could not be resolved; they
19
+ * join the affected set rather than being assumed safe. Reaching a fixpoint
20
+ * terminates on cycles because the set only grows and is bounded by the graph.
21
+ */
22
+ export declare function invalidate(dependencies: Readonly<Record<string, readonly string[]>>, changed: readonly string[], unknownDependents?: readonly string[]): Set<string>;
23
+ /**
24
+ * Requests admissible right now, in queue order.
25
+ *
26
+ * A request is admitted only when it conflicts neither with the active claims
27
+ * nor with any earlier waiting request. Accumulating earlier claims — whether
28
+ * or not they were admitted — is what stops a stream of later readers from
29
+ * starving an older writer. Capacity fairness is not modelled here.
30
+ */
31
+ export declare function admissibleFrontier(waiting: readonly WaitingRequest[], active: readonly ResourceClaim[]): string[];
32
+ //# sourceMappingURL=awareness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/coordination/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,EACzD,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,iBAAiB,GAAE,SAAS,MAAM,EAAO,GACvC,GAAG,CAAC,MAAM,CAAC,CAab;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,EAAE,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,EAAE,CAYjH","sourcesContent":["/**\n * Change awareness: what a change invalidates, and who may proceed next.\n *\n * Both functions are deliberately conservative. Invalidation treats an\n * unmapped dependent as affected, because \"we have no edge for it\" is not\n * evidence that it is unaffected. Frontier admission lets an unrelated\n * follower pass a blocked leader, but never lets a later request that\n * conflicts with an older waiting one jump ahead of it.\n */\n\nimport { claimSetsConflict } from \"./resource.ts\";\nimport type { ResourceClaim } from \"./types.ts\";\n\nexport interface WaitingRequest {\n\treadonly requestId: string;\n\treadonly claims: readonly ResourceClaim[];\n}\n\n/**\n * Transitive closure over reverse dependencies.\n *\n * `unknownDependents` are nodes whose dependencies could not be resolved; they\n * join the affected set rather than being assumed safe. Reaching a fixpoint\n * terminates on cycles because the set only grows and is bounded by the graph.\n */\nexport function invalidate(\n\tdependencies: Readonly<Record<string, readonly string[]>>,\n\tchanged: readonly string[],\n\tunknownDependents: readonly string[] = [],\n): Set<string> {\n\tconst affected = new Set<string>([...changed, ...unknownDependents]);\n\tfor (;;) {\n\t\tlet grew = false;\n\t\tfor (const [node, deps] of Object.entries(dependencies)) {\n\t\t\tif (affected.has(node)) continue;\n\t\t\tif (deps.some((dep) => affected.has(dep))) {\n\t\t\t\taffected.add(node);\n\t\t\t\tgrew = true;\n\t\t\t}\n\t\t}\n\t\tif (!grew) return affected;\n\t}\n}\n\n/**\n * Requests admissible right now, in queue order.\n *\n * A request is admitted only when it conflicts neither with the active claims\n * nor with any earlier waiting request. Accumulating earlier claims — whether\n * or not they were admitted — is what stops a stream of later readers from\n * starving an older writer. Capacity fairness is not modelled here.\n */\nexport function admissibleFrontier(waiting: readonly WaitingRequest[], active: readonly ResourceClaim[]): string[] {\n\tconst chosen: string[] = [];\n\tconst reserved: ResourceClaim[] = [...active];\n\tconst earlier: ResourceClaim[] = [];\n\tfor (const request of waiting) {\n\t\tif (!claimSetsConflict(request.claims, reserved) && !claimSetsConflict(request.claims, earlier)) {\n\t\t\tchosen.push(request.requestId);\n\t\t\treserved.push(...request.claims);\n\t\t}\n\t\tearlier.push(...request.claims);\n\t}\n\treturn chosen;\n}\n"]}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Change awareness: what a change invalidates, and who may proceed next.
3
+ *
4
+ * Both functions are deliberately conservative. Invalidation treats an
5
+ * unmapped dependent as affected, because "we have no edge for it" is not
6
+ * evidence that it is unaffected. Frontier admission lets an unrelated
7
+ * follower pass a blocked leader, but never lets a later request that
8
+ * conflicts with an older waiting one jump ahead of it.
9
+ */
10
+ import { claimSetsConflict } from "./resource.js";
11
+ /**
12
+ * Transitive closure over reverse dependencies.
13
+ *
14
+ * `unknownDependents` are nodes whose dependencies could not be resolved; they
15
+ * join the affected set rather than being assumed safe. Reaching a fixpoint
16
+ * terminates on cycles because the set only grows and is bounded by the graph.
17
+ */
18
+ export function invalidate(dependencies, changed, unknownDependents = []) {
19
+ const affected = new Set([...changed, ...unknownDependents]);
20
+ for (;;) {
21
+ let grew = false;
22
+ for (const [node, deps] of Object.entries(dependencies)) {
23
+ if (affected.has(node))
24
+ continue;
25
+ if (deps.some((dep) => affected.has(dep))) {
26
+ affected.add(node);
27
+ grew = true;
28
+ }
29
+ }
30
+ if (!grew)
31
+ return affected;
32
+ }
33
+ }
34
+ /**
35
+ * Requests admissible right now, in queue order.
36
+ *
37
+ * A request is admitted only when it conflicts neither with the active claims
38
+ * nor with any earlier waiting request. Accumulating earlier claims — whether
39
+ * or not they were admitted — is what stops a stream of later readers from
40
+ * starving an older writer. Capacity fairness is not modelled here.
41
+ */
42
+ export function admissibleFrontier(waiting, active) {
43
+ const chosen = [];
44
+ const reserved = [...active];
45
+ const earlier = [];
46
+ for (const request of waiting) {
47
+ if (!claimSetsConflict(request.claims, reserved) && !claimSetsConflict(request.claims, earlier)) {
48
+ chosen.push(request.requestId);
49
+ reserved.push(...request.claims);
50
+ }
51
+ earlier.push(...request.claims);
52
+ }
53
+ return chosen;
54
+ }
55
+ //# sourceMappingURL=awareness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"awareness.js","sourceRoot":"","sources":["../../src/coordination/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAQlD;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACzB,YAAyD,EACzD,OAA0B,EAC1B,iBAAiB,GAAsB,EAAE,EAC3B;IACd,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,OAAO,EAAE,GAAG,iBAAiB,CAAC,CAAC,CAAC;IACrE,SAAS,CAAC;QACT,IAAI,IAAI,GAAG,KAAK,CAAC;QACjB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YACzD,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS;YACjC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAC3C,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACnB,IAAI,GAAG,IAAI,CAAC;YACb,CAAC;QACF,CAAC;QACD,IAAI,CAAC,IAAI;YAAE,OAAO,QAAQ,CAAC;IAC5B,CAAC;AAAA,CACD;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAkC,EAAE,MAAgC,EAAY;IAClH,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAoB,CAAC,GAAG,MAAM,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;YACjG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC/B,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd","sourcesContent":["/**\n * Change awareness: what a change invalidates, and who may proceed next.\n *\n * Both functions are deliberately conservative. Invalidation treats an\n * unmapped dependent as affected, because \"we have no edge for it\" is not\n * evidence that it is unaffected. Frontier admission lets an unrelated\n * follower pass a blocked leader, but never lets a later request that\n * conflicts with an older waiting one jump ahead of it.\n */\n\nimport { claimSetsConflict } from \"./resource.ts\";\nimport type { ResourceClaim } from \"./types.ts\";\n\nexport interface WaitingRequest {\n\treadonly requestId: string;\n\treadonly claims: readonly ResourceClaim[];\n}\n\n/**\n * Transitive closure over reverse dependencies.\n *\n * `unknownDependents` are nodes whose dependencies could not be resolved; they\n * join the affected set rather than being assumed safe. Reaching a fixpoint\n * terminates on cycles because the set only grows and is bounded by the graph.\n */\nexport function invalidate(\n\tdependencies: Readonly<Record<string, readonly string[]>>,\n\tchanged: readonly string[],\n\tunknownDependents: readonly string[] = [],\n): Set<string> {\n\tconst affected = new Set<string>([...changed, ...unknownDependents]);\n\tfor (;;) {\n\t\tlet grew = false;\n\t\tfor (const [node, deps] of Object.entries(dependencies)) {\n\t\t\tif (affected.has(node)) continue;\n\t\t\tif (deps.some((dep) => affected.has(dep))) {\n\t\t\t\taffected.add(node);\n\t\t\t\tgrew = true;\n\t\t\t}\n\t\t}\n\t\tif (!grew) return affected;\n\t}\n}\n\n/**\n * Requests admissible right now, in queue order.\n *\n * A request is admitted only when it conflicts neither with the active claims\n * nor with any earlier waiting request. Accumulating earlier claims — whether\n * or not they were admitted — is what stops a stream of later readers from\n * starving an older writer. Capacity fairness is not modelled here.\n */\nexport function admissibleFrontier(waiting: readonly WaitingRequest[], active: readonly ResourceClaim[]): string[] {\n\tconst chosen: string[] = [];\n\tconst reserved: ResourceClaim[] = [...active];\n\tconst earlier: ResourceClaim[] = [];\n\tfor (const request of waiting) {\n\t\tif (!claimSetsConflict(request.claims, reserved) && !claimSetsConflict(request.claims, earlier)) {\n\t\t\tchosen.push(request.requestId);\n\t\t\treserved.push(...request.claims);\n\t\t}\n\t\tearlier.push(...request.claims);\n\t}\n\treturn chosen;\n}\n"]}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * In-process admission broker for parallel sessions.
3
+ *
4
+ * Safety property: a grant that may still own a live external effect keeps
5
+ * holding its claims. Expiry, cancellation and authority restart are
6
+ * authorization events; only a trusted supervisor reporting termination frees
7
+ * the claims. Treating a lapsed deadline as "the effect stopped" is exactly how
8
+ * two sessions end up writing the same path.
9
+ *
10
+ * Bounded reference semantics: a single trusted state machine, canonical claim
11
+ * keys, and every shared effect crossing this broker. No IPC, no OS fencing,
12
+ * no persistence — those belong to the supervisor this broker reports to.
13
+ */
14
+ import type { EffectState, GrantToken, ResourceClaim, Sequence } from "./types.ts";
15
+ export interface AdmissionBrokerOptions {
16
+ /** Total admissible weight of concurrently active grants. */
17
+ readonly capacity: number;
18
+ }
19
+ export interface AcquireInput {
20
+ readonly sessionId: string;
21
+ readonly incarnation: Sequence | string;
22
+ readonly claims: readonly ResourceClaim[];
23
+ readonly now: number;
24
+ readonly ttl: number;
25
+ readonly weight?: number;
26
+ }
27
+ export interface StartInput {
28
+ readonly token: GrantToken;
29
+ readonly now: number;
30
+ /** Claims the operation actually resolved to after approval hooks. */
31
+ readonly actualClaims: readonly ResourceClaim[];
32
+ }
33
+ export declare class AdmissionBroker {
34
+ private readonly capacity;
35
+ private authorityEpoch;
36
+ private grantCounter;
37
+ private readonly incarnations;
38
+ private readonly grants;
39
+ constructor(options: AdmissionBrokerOptions);
40
+ /**
41
+ * Announce a session incarnation. Re-registering does not free the previous
42
+ * incarnation's grants: a restarted session cannot assume its predecessor's
43
+ * effects stopped.
44
+ */
45
+ register(sessionId: string): Sequence;
46
+ /** Grants still holding their claims, including quarantined ones. */
47
+ private activeGrants;
48
+ acquire(input: AcquireInput): GrantToken | null;
49
+ /** Resolve a token that is still authoritative for new action. */
50
+ private authoritative;
51
+ /** Resolve a token for settlement only; accepts superseded epochs. */
52
+ private settleable;
53
+ /**
54
+ * Bind an effect to its reservation. The actual claims must equal the
55
+ * reserved set exactly — an approval hook that widened scope has to be
56
+ * re-admitted, not silently allowed to run under the old grant.
57
+ */
58
+ start(input: StartInput): boolean;
59
+ /**
60
+ * Apply lapsed authorization deadlines. A reservation that never started is
61
+ * released; a running effect is quarantined and keeps its claims.
62
+ */
63
+ expire(now: number): void;
64
+ /** Withdraw authorization. Requested cancellation is not observed termination. */
65
+ cancel(token: GrantToken): boolean;
66
+ /**
67
+ * Trusted supervisor event: this exact effect is gone. Accepted for
68
+ * superseded epochs so a restarted authority can still settle what the
69
+ * previous one started, never to authorize new work.
70
+ */
71
+ confirmTerminated(token: GrantToken): boolean;
72
+ /** Fence the authority. Live effects stay quarantined until confirmed. */
73
+ restart(): void;
74
+ stateOf(token: GrantToken): EffectState | undefined;
75
+ claimsOf(token: GrantToken): readonly ResourceClaim[];
76
+ /** Invariant: active grants fit capacity and never pairwise conflict. */
77
+ isSafe(): boolean;
78
+ }
79
+ //# sourceMappingURL=broker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.d.ts","sourceRoot":"","sources":["../../src/coordination/broker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAYnF,MAAM,WAAW,sBAAsB;IACtC,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,QAAQ,CAAC,YAAY,EAAE,SAAS,aAAa,EAAE,CAAC;CAChD;AAQD,qBAAa,eAAe;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,cAAc,CAA2B;IACjD,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA+B;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IAEnD,YAAY,OAAO,EAAE,sBAAsB,EAG1C;IAED;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAOpC;IAED,qEAAqE;IACrE,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,UAAU,GAAG,IAAI,CAuC9C;IAED,kEAAkE;IAClE,OAAO,CAAC,aAAa;IASrB,sEAAsE;IACtE,OAAO,CAAC,UAAU;IAMlB;;;;OAIG;IACH,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAShC;IAED;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAOxB;IAED,kFAAkF;IAClF,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAKjC;IAED;;;;OAIG;IACH,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAM5C;IAED,0EAA0E;IAC1E,OAAO,IAAI,IAAI,CAKd;IAED,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,CAGlD;IAED,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,aAAa,EAAE,CAGpD;IAED,yEAAyE;IACzE,MAAM,IAAI,OAAO,CAShB;CACD","sourcesContent":["/**\n * In-process admission broker for parallel sessions.\n *\n * Safety property: a grant that may still own a live external effect keeps\n * holding its claims. Expiry, cancellation and authority restart are\n * authorization events; only a trusted supervisor reporting termination frees\n * the claims. Treating a lapsed deadline as \"the effect stopped\" is exactly how\n * two sessions end up writing the same path.\n *\n * Bounded reference semantics: a single trusted state machine, canonical claim\n * keys, and every shared effect crossing this broker. No IPC, no OS fencing,\n * no persistence — those belong to the supervisor this broker reports to.\n */\n\nimport { claimSetsConflict, sameClaimSet } from \"./resource.ts\";\nimport type { EffectState, GrantToken, ResourceClaim, Sequence } from \"./types.ts\";\nimport { nextSequence, SETTLED_EFFECT_STATES, sequence } from \"./types.ts\";\n\ninterface Grant {\n\treadonly token: GrantToken;\n\treadonly claims: readonly ResourceClaim[];\n\treadonly weight: number;\n\tstate: EffectState;\n\t/** True once an external effect may exist. Never inferred from the clock. */\n\teffectLive: boolean;\n}\n\nexport interface AdmissionBrokerOptions {\n\t/** Total admissible weight of concurrently active grants. */\n\treadonly capacity: number;\n}\n\nexport interface AcquireInput {\n\treadonly sessionId: string;\n\treadonly incarnation: Sequence | string;\n\treadonly claims: readonly ResourceClaim[];\n\treadonly now: number;\n\treadonly ttl: number;\n\treadonly weight?: number;\n}\n\nexport interface StartInput {\n\treadonly token: GrantToken;\n\treadonly now: number;\n\t/** Claims the operation actually resolved to after approval hooks. */\n\treadonly actualClaims: readonly ResourceClaim[];\n}\n\nfunction assertNonNegativeInteger(value: number, label: string): void {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n\t\tthrow new TypeError(`${label} must be a nonnegative safe integer`);\n\t}\n}\n\nexport class AdmissionBroker {\n\tprivate readonly capacity: number;\n\tprivate authorityEpoch: Sequence = sequence(\"1\");\n\tprivate grantCounter: Sequence = sequence(\"0\");\n\tprivate readonly incarnations = new Map<string, Sequence>();\n\tprivate readonly grants = new Map<string, Grant>();\n\n\tconstructor(options: AdmissionBrokerOptions) {\n\t\tassertNonNegativeInteger(options.capacity, \"capacity\");\n\t\tthis.capacity = options.capacity;\n\t}\n\n\t/**\n\t * Announce a session incarnation. Re-registering does not free the previous\n\t * incarnation's grants: a restarted session cannot assume its predecessor's\n\t * effects stopped.\n\t */\n\tregister(sessionId: string): Sequence {\n\t\tif (typeof sessionId !== \"string\" || sessionId.length === 0) {\n\t\t\tthrow new TypeError(\"sessionId must be a non-empty string\");\n\t\t}\n\t\tconst next = nextSequence(this.incarnations.get(sessionId) ?? sequence(\"0\"));\n\t\tthis.incarnations.set(sessionId, next);\n\t\treturn next;\n\t}\n\n\t/** Grants still holding their claims, including quarantined ones. */\n\tprivate activeGrants(): Grant[] {\n\t\treturn [...this.grants.values()].filter((g) => !SETTLED_EFFECT_STATES.has(g.state));\n\t}\n\n\tacquire(input: AcquireInput): GrantToken | null {\n\t\tassertNonNegativeInteger(input.now, \"now\");\n\t\tconst weight = input.weight ?? 1;\n\t\tassertNonNegativeInteger(weight, \"weight\");\n\t\tif (!Number.isSafeInteger(input.ttl) || input.ttl <= 0) {\n\t\t\tthrow new TypeError(\"ttl must be a positive safe integer\");\n\t\t}\n\t\tconst incarnation = sequence(input.incarnation);\n\t\tif (this.incarnations.get(input.sessionId) !== incarnation) {\n\t\t\tthrow new TypeError(\"stale session incarnation\");\n\t\t}\n\t\tif (input.claims.length === 0) {\n\t\t\tthrow new TypeError(\"an unknown scope must not be admitted as an empty scope\");\n\t\t}\n\n\t\t// Settle lapsed authorizations first; this never evicts a live effect.\n\t\tthis.expire(input.now);\n\t\tconst active = this.activeGrants();\n\t\tconst used = active.reduce((sum, g) => sum + g.weight, 0);\n\t\tif (weight + used > this.capacity) return null;\n\t\tconst claims = [...input.claims];\n\t\tif (active.some((g) => claimSetsConflict(claims, g.claims))) return null;\n\n\t\tthis.grantCounter = nextSequence(this.grantCounter);\n\t\tconst token: GrantToken = Object.freeze({\n\t\t\tauthorityEpoch: this.authorityEpoch,\n\t\t\tgrantSequence: this.grantCounter,\n\t\t\tsessionId: input.sessionId,\n\t\t\tsessionIncarnation: incarnation,\n\t\t\tauthorizationDeadline: input.now + input.ttl,\n\t\t});\n\t\tthis.grants.set(token.grantSequence, {\n\t\t\ttoken,\n\t\t\tclaims: Object.freeze(claims),\n\t\t\tweight,\n\t\t\tstate: \"reserved\",\n\t\t\teffectLive: false,\n\t\t});\n\t\treturn token;\n\t}\n\n\t/** Resolve a token that is still authoritative for new action. */\n\tprivate authoritative(token: GrantToken): Grant | undefined {\n\t\tconst grant = this.grants.get(token.grantSequence);\n\t\tif (grant === undefined || !sameToken(grant.token, token)) return undefined;\n\t\tif (token.authorityEpoch !== this.authorityEpoch) return undefined;\n\t\tif (this.incarnations.get(token.sessionId) !== token.sessionIncarnation) return undefined;\n\t\tif (SETTLED_EFFECT_STATES.has(grant.state)) return undefined;\n\t\treturn grant;\n\t}\n\n\t/** Resolve a token for settlement only; accepts superseded epochs. */\n\tprivate settleable(token: GrantToken): Grant | undefined {\n\t\tconst grant = this.grants.get(token.grantSequence);\n\t\tif (grant === undefined || !sameToken(grant.token, token)) return undefined;\n\t\treturn SETTLED_EFFECT_STATES.has(grant.state) ? undefined : grant;\n\t}\n\n\t/**\n\t * Bind an effect to its reservation. The actual claims must equal the\n\t * reserved set exactly — an approval hook that widened scope has to be\n\t * re-admitted, not silently allowed to run under the old grant.\n\t */\n\tstart(input: StartInput): boolean {\n\t\tassertNonNegativeInteger(input.now, \"now\");\n\t\tconst grant = this.authoritative(input.token);\n\t\tif (grant === undefined || grant.state !== \"reserved\") return false;\n\t\tif (input.now >= grant.token.authorizationDeadline) return false;\n\t\tif (!sameClaimSet(input.actualClaims, grant.claims)) return false;\n\t\tgrant.state = \"running\";\n\t\tgrant.effectLive = true;\n\t\treturn true;\n\t}\n\n\t/**\n\t * Apply lapsed authorization deadlines. A reservation that never started is\n\t * released; a running effect is quarantined and keeps its claims.\n\t */\n\texpire(now: number): void {\n\t\tassertNonNegativeInteger(now, \"now\");\n\t\tfor (const grant of this.activeGrants()) {\n\t\t\tif (now >= grant.token.authorizationDeadline) {\n\t\t\t\tgrant.state = grant.effectLive ? \"quarantined\" : \"cancelled\";\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Withdraw authorization. Requested cancellation is not observed termination. */\n\tcancel(token: GrantToken): boolean {\n\t\tconst grant = this.settleable(token);\n\t\tif (grant === undefined) return false;\n\t\tgrant.state = grant.effectLive ? \"quarantined\" : \"cancelled\";\n\t\treturn true;\n\t}\n\n\t/**\n\t * Trusted supervisor event: this exact effect is gone. Accepted for\n\t * superseded epochs so a restarted authority can still settle what the\n\t * previous one started, never to authorize new work.\n\t */\n\tconfirmTerminated(token: GrantToken): boolean {\n\t\tconst grant = this.settleable(token);\n\t\tif (grant === undefined) return false;\n\t\tgrant.effectLive = false;\n\t\tgrant.state = \"terminated\";\n\t\treturn true;\n\t}\n\n\t/** Fence the authority. Live effects stay quarantined until confirmed. */\n\trestart(): void {\n\t\tthis.authorityEpoch = nextSequence(this.authorityEpoch);\n\t\tfor (const grant of this.activeGrants()) {\n\t\t\tgrant.state = grant.effectLive ? \"quarantined\" : \"cancelled\";\n\t\t}\n\t}\n\n\tstateOf(token: GrantToken): EffectState | undefined {\n\t\tconst grant = this.grants.get(token.grantSequence);\n\t\treturn grant !== undefined && sameToken(grant.token, token) ? grant.state : undefined;\n\t}\n\n\tclaimsOf(token: GrantToken): readonly ResourceClaim[] {\n\t\tconst grant = this.grants.get(token.grantSequence);\n\t\treturn grant !== undefined && sameToken(grant.token, token) ? grant.claims : [];\n\t}\n\n\t/** Invariant: active grants fit capacity and never pairwise conflict. */\n\tisSafe(): boolean {\n\t\tconst active = this.activeGrants();\n\t\tif (active.reduce((sum, g) => sum + g.weight, 0) > this.capacity) return false;\n\t\tfor (const [index, grant] of active.entries()) {\n\t\t\tfor (const other of active.slice(index + 1)) {\n\t\t\t\tif (claimSetsConflict(grant.claims, other.claims)) return false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n}\n\nfunction sameToken(a: GrantToken, b: GrantToken): boolean {\n\treturn (\n\t\ta.authorityEpoch === b.authorityEpoch &&\n\t\ta.grantSequence === b.grantSequence &&\n\t\ta.sessionId === b.sessionId &&\n\t\ta.sessionIncarnation === b.sessionIncarnation &&\n\t\ta.authorizationDeadline === b.authorizationDeadline\n\t);\n}\n"]}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * In-process admission broker for parallel sessions.
3
+ *
4
+ * Safety property: a grant that may still own a live external effect keeps
5
+ * holding its claims. Expiry, cancellation and authority restart are
6
+ * authorization events; only a trusted supervisor reporting termination frees
7
+ * the claims. Treating a lapsed deadline as "the effect stopped" is exactly how
8
+ * two sessions end up writing the same path.
9
+ *
10
+ * Bounded reference semantics: a single trusted state machine, canonical claim
11
+ * keys, and every shared effect crossing this broker. No IPC, no OS fencing,
12
+ * no persistence — those belong to the supervisor this broker reports to.
13
+ */
14
+ import { claimSetsConflict, sameClaimSet } from "./resource.js";
15
+ import { nextSequence, SETTLED_EFFECT_STATES, sequence } from "./types.js";
16
+ function assertNonNegativeInteger(value, label) {
17
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
18
+ throw new TypeError(`${label} must be a nonnegative safe integer`);
19
+ }
20
+ }
21
+ export class AdmissionBroker {
22
+ capacity;
23
+ authorityEpoch = sequence("1");
24
+ grantCounter = sequence("0");
25
+ incarnations = new Map();
26
+ grants = new Map();
27
+ constructor(options) {
28
+ assertNonNegativeInteger(options.capacity, "capacity");
29
+ this.capacity = options.capacity;
30
+ }
31
+ /**
32
+ * Announce a session incarnation. Re-registering does not free the previous
33
+ * incarnation's grants: a restarted session cannot assume its predecessor's
34
+ * effects stopped.
35
+ */
36
+ register(sessionId) {
37
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
38
+ throw new TypeError("sessionId must be a non-empty string");
39
+ }
40
+ const next = nextSequence(this.incarnations.get(sessionId) ?? sequence("0"));
41
+ this.incarnations.set(sessionId, next);
42
+ return next;
43
+ }
44
+ /** Grants still holding their claims, including quarantined ones. */
45
+ activeGrants() {
46
+ return [...this.grants.values()].filter((g) => !SETTLED_EFFECT_STATES.has(g.state));
47
+ }
48
+ acquire(input) {
49
+ assertNonNegativeInteger(input.now, "now");
50
+ const weight = input.weight ?? 1;
51
+ assertNonNegativeInteger(weight, "weight");
52
+ if (!Number.isSafeInteger(input.ttl) || input.ttl <= 0) {
53
+ throw new TypeError("ttl must be a positive safe integer");
54
+ }
55
+ const incarnation = sequence(input.incarnation);
56
+ if (this.incarnations.get(input.sessionId) !== incarnation) {
57
+ throw new TypeError("stale session incarnation");
58
+ }
59
+ if (input.claims.length === 0) {
60
+ throw new TypeError("an unknown scope must not be admitted as an empty scope");
61
+ }
62
+ // Settle lapsed authorizations first; this never evicts a live effect.
63
+ this.expire(input.now);
64
+ const active = this.activeGrants();
65
+ const used = active.reduce((sum, g) => sum + g.weight, 0);
66
+ if (weight + used > this.capacity)
67
+ return null;
68
+ const claims = [...input.claims];
69
+ if (active.some((g) => claimSetsConflict(claims, g.claims)))
70
+ return null;
71
+ this.grantCounter = nextSequence(this.grantCounter);
72
+ const token = Object.freeze({
73
+ authorityEpoch: this.authorityEpoch,
74
+ grantSequence: this.grantCounter,
75
+ sessionId: input.sessionId,
76
+ sessionIncarnation: incarnation,
77
+ authorizationDeadline: input.now + input.ttl,
78
+ });
79
+ this.grants.set(token.grantSequence, {
80
+ token,
81
+ claims: Object.freeze(claims),
82
+ weight,
83
+ state: "reserved",
84
+ effectLive: false,
85
+ });
86
+ return token;
87
+ }
88
+ /** Resolve a token that is still authoritative for new action. */
89
+ authoritative(token) {
90
+ const grant = this.grants.get(token.grantSequence);
91
+ if (grant === undefined || !sameToken(grant.token, token))
92
+ return undefined;
93
+ if (token.authorityEpoch !== this.authorityEpoch)
94
+ return undefined;
95
+ if (this.incarnations.get(token.sessionId) !== token.sessionIncarnation)
96
+ return undefined;
97
+ if (SETTLED_EFFECT_STATES.has(grant.state))
98
+ return undefined;
99
+ return grant;
100
+ }
101
+ /** Resolve a token for settlement only; accepts superseded epochs. */
102
+ settleable(token) {
103
+ const grant = this.grants.get(token.grantSequence);
104
+ if (grant === undefined || !sameToken(grant.token, token))
105
+ return undefined;
106
+ return SETTLED_EFFECT_STATES.has(grant.state) ? undefined : grant;
107
+ }
108
+ /**
109
+ * Bind an effect to its reservation. The actual claims must equal the
110
+ * reserved set exactly — an approval hook that widened scope has to be
111
+ * re-admitted, not silently allowed to run under the old grant.
112
+ */
113
+ start(input) {
114
+ assertNonNegativeInteger(input.now, "now");
115
+ const grant = this.authoritative(input.token);
116
+ if (grant === undefined || grant.state !== "reserved")
117
+ return false;
118
+ if (input.now >= grant.token.authorizationDeadline)
119
+ return false;
120
+ if (!sameClaimSet(input.actualClaims, grant.claims))
121
+ return false;
122
+ grant.state = "running";
123
+ grant.effectLive = true;
124
+ return true;
125
+ }
126
+ /**
127
+ * Apply lapsed authorization deadlines. A reservation that never started is
128
+ * released; a running effect is quarantined and keeps its claims.
129
+ */
130
+ expire(now) {
131
+ assertNonNegativeInteger(now, "now");
132
+ for (const grant of this.activeGrants()) {
133
+ if (now >= grant.token.authorizationDeadline) {
134
+ grant.state = grant.effectLive ? "quarantined" : "cancelled";
135
+ }
136
+ }
137
+ }
138
+ /** Withdraw authorization. Requested cancellation is not observed termination. */
139
+ cancel(token) {
140
+ const grant = this.settleable(token);
141
+ if (grant === undefined)
142
+ return false;
143
+ grant.state = grant.effectLive ? "quarantined" : "cancelled";
144
+ return true;
145
+ }
146
+ /**
147
+ * Trusted supervisor event: this exact effect is gone. Accepted for
148
+ * superseded epochs so a restarted authority can still settle what the
149
+ * previous one started, never to authorize new work.
150
+ */
151
+ confirmTerminated(token) {
152
+ const grant = this.settleable(token);
153
+ if (grant === undefined)
154
+ return false;
155
+ grant.effectLive = false;
156
+ grant.state = "terminated";
157
+ return true;
158
+ }
159
+ /** Fence the authority. Live effects stay quarantined until confirmed. */
160
+ restart() {
161
+ this.authorityEpoch = nextSequence(this.authorityEpoch);
162
+ for (const grant of this.activeGrants()) {
163
+ grant.state = grant.effectLive ? "quarantined" : "cancelled";
164
+ }
165
+ }
166
+ stateOf(token) {
167
+ const grant = this.grants.get(token.grantSequence);
168
+ return grant !== undefined && sameToken(grant.token, token) ? grant.state : undefined;
169
+ }
170
+ claimsOf(token) {
171
+ const grant = this.grants.get(token.grantSequence);
172
+ return grant !== undefined && sameToken(grant.token, token) ? grant.claims : [];
173
+ }
174
+ /** Invariant: active grants fit capacity and never pairwise conflict. */
175
+ isSafe() {
176
+ const active = this.activeGrants();
177
+ if (active.reduce((sum, g) => sum + g.weight, 0) > this.capacity)
178
+ return false;
179
+ for (const [index, grant] of active.entries()) {
180
+ for (const other of active.slice(index + 1)) {
181
+ if (claimSetsConflict(grant.claims, other.claims))
182
+ return false;
183
+ }
184
+ }
185
+ return true;
186
+ }
187
+ }
188
+ function sameToken(a, b) {
189
+ return (a.authorityEpoch === b.authorityEpoch &&
190
+ a.grantSequence === b.grantSequence &&
191
+ a.sessionId === b.sessionId &&
192
+ a.sessionIncarnation === b.sessionIncarnation &&
193
+ a.authorizationDeadline === b.authorizationDeadline);
194
+ }
195
+ //# sourceMappingURL=broker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.js","sourceRoot":"","sources":["../../src/coordination/broker.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * In-process admission broker for parallel sessions.\n *\n * Safety property: a grant that may still own a live external effect keeps\n * holding its claims. Expiry, cancellation and authority restart are\n * authorization events; only a trusted supervisor reporting termination frees\n * the claims. Treating a lapsed deadline as \"the effect stopped\" is exactly how\n * two sessions end up writing the same path.\n *\n * Bounded reference semantics: a single trusted state machine, canonical claim\n * keys, and every shared effect crossing this broker. No IPC, no OS fencing,\n * no persistence — those belong to the supervisor this broker reports to.\n */\n\nimport { claimSetsConflict, sameClaimSet } from \"./resource.ts\";\nimport type { EffectState, GrantToken, ResourceClaim, Sequence } from \"./types.ts\";\nimport { nextSequence, SETTLED_EFFECT_STATES, sequence } from \"./types.ts\";\n\ninterface Grant {\n\treadonly token: GrantToken;\n\treadonly claims: readonly ResourceClaim[];\n\treadonly weight: number;\n\tstate: EffectState;\n\t/** True once an external effect may exist. Never inferred from the clock. */\n\teffectLive: boolean;\n}\n\nexport interface AdmissionBrokerOptions {\n\t/** Total admissible weight of concurrently active grants. */\n\treadonly capacity: number;\n}\n\nexport interface AcquireInput {\n\treadonly sessionId: string;\n\treadonly incarnation: Sequence | string;\n\treadonly claims: readonly ResourceClaim[];\n\treadonly now: number;\n\treadonly ttl: number;\n\treadonly weight?: number;\n}\n\nexport interface StartInput {\n\treadonly token: GrantToken;\n\treadonly now: number;\n\t/** Claims the operation actually resolved to after approval hooks. */\n\treadonly actualClaims: readonly ResourceClaim[];\n}\n\nfunction assertNonNegativeInteger(value: number, label: string): void {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n\t\tthrow new TypeError(`${label} must be a nonnegative safe integer`);\n\t}\n}\n\nexport class AdmissionBroker {\n\tprivate readonly capacity: number;\n\tprivate authorityEpoch: Sequence = sequence(\"1\");\n\tprivate grantCounter: Sequence = sequence(\"0\");\n\tprivate readonly incarnations = new Map<string, Sequence>();\n\tprivate readonly grants = new Map<string, Grant>();\n\n\tconstructor(options: AdmissionBrokerOptions) {\n\t\tassertNonNegativeInteger(options.capacity, \"capacity\");\n\t\tthis.capacity = options.capacity;\n\t}\n\n\t/**\n\t * Announce a session incarnation. Re-registering does not free the previous\n\t * incarnation's grants: a restarted session cannot assume its predecessor's\n\t * effects stopped.\n\t */\n\tregister(sessionId: string): Sequence {\n\t\tif (typeof sessionId !== \"string\" || sessionId.length === 0) {\n\t\t\tthrow new TypeError(\"sessionId must be a non-empty string\");\n\t\t}\n\t\tconst next = nextSequence(this.incarnations.get(sessionId) ?? sequence(\"0\"));\n\t\tthis.incarnations.set(sessionId, next);\n\t\treturn next;\n\t}\n\n\t/** Grants still holding their claims, including quarantined ones. */\n\tprivate activeGrants(): Grant[] {\n\t\treturn [...this.grants.values()].filter((g) => !SETTLED_EFFECT_STATES.has(g.state));\n\t}\n\n\tacquire(input: AcquireInput): GrantToken | null {\n\t\tassertNonNegativeInteger(input.now, \"now\");\n\t\tconst weight = input.weight ?? 1;\n\t\tassertNonNegativeInteger(weight, \"weight\");\n\t\tif (!Number.isSafeInteger(input.ttl) || input.ttl <= 0) {\n\t\t\tthrow new TypeError(\"ttl must be a positive safe integer\");\n\t\t}\n\t\tconst incarnation = sequence(input.incarnation);\n\t\tif (this.incarnations.get(input.sessionId) !== incarnation) {\n\t\t\tthrow new TypeError(\"stale session incarnation\");\n\t\t}\n\t\tif (input.claims.length === 0) {\n\t\t\tthrow new TypeError(\"an unknown scope must not be admitted as an empty scope\");\n\t\t}\n\n\t\t// Settle lapsed authorizations first; this never evicts a live effect.\n\t\tthis.expire(input.now);\n\t\tconst active = this.activeGrants();\n\t\tconst used = active.reduce((sum, g) => sum + g.weight, 0);\n\t\tif (weight + used > this.capacity) return null;\n\t\tconst claims = [...input.claims];\n\t\tif (active.some((g) => claimSetsConflict(claims, g.claims))) return null;\n\n\t\tthis.grantCounter = nextSequence(this.grantCounter);\n\t\tconst token: GrantToken = Object.freeze({\n\t\t\tauthorityEpoch: this.authorityEpoch,\n\t\t\tgrantSequence: this.grantCounter,\n\t\t\tsessionId: input.sessionId,\n\t\t\tsessionIncarnation: incarnation,\n\t\t\tauthorizationDeadline: input.now + input.ttl,\n\t\t});\n\t\tthis.grants.set(token.grantSequence, {\n\t\t\ttoken,\n\t\t\tclaims: Object.freeze(claims),\n\t\t\tweight,\n\t\t\tstate: \"reserved\",\n\t\t\teffectLive: false,\n\t\t});\n\t\treturn token;\n\t}\n\n\t/** Resolve a token that is still authoritative for new action. */\n\tprivate authoritative(token: GrantToken): Grant | undefined {\n\t\tconst grant = this.grants.get(token.grantSequence);\n\t\tif (grant === undefined || !sameToken(grant.token, token)) return undefined;\n\t\tif (token.authorityEpoch !== this.authorityEpoch) return undefined;\n\t\tif (this.incarnations.get(token.sessionId) !== token.sessionIncarnation) return undefined;\n\t\tif (SETTLED_EFFECT_STATES.has(grant.state)) return undefined;\n\t\treturn grant;\n\t}\n\n\t/** Resolve a token for settlement only; accepts superseded epochs. */\n\tprivate settleable(token: GrantToken): Grant | undefined {\n\t\tconst grant = this.grants.get(token.grantSequence);\n\t\tif (grant === undefined || !sameToken(grant.token, token)) return undefined;\n\t\treturn SETTLED_EFFECT_STATES.has(grant.state) ? undefined : grant;\n\t}\n\n\t/**\n\t * Bind an effect to its reservation. The actual claims must equal the\n\t * reserved set exactly — an approval hook that widened scope has to be\n\t * re-admitted, not silently allowed to run under the old grant.\n\t */\n\tstart(input: StartInput): boolean {\n\t\tassertNonNegativeInteger(input.now, \"now\");\n\t\tconst grant = this.authoritative(input.token);\n\t\tif (grant === undefined || grant.state !== \"reserved\") return false;\n\t\tif (input.now >= grant.token.authorizationDeadline) return false;\n\t\tif (!sameClaimSet(input.actualClaims, grant.claims)) return false;\n\t\tgrant.state = \"running\";\n\t\tgrant.effectLive = true;\n\t\treturn true;\n\t}\n\n\t/**\n\t * Apply lapsed authorization deadlines. A reservation that never started is\n\t * released; a running effect is quarantined and keeps its claims.\n\t */\n\texpire(now: number): void {\n\t\tassertNonNegativeInteger(now, \"now\");\n\t\tfor (const grant of this.activeGrants()) {\n\t\t\tif (now >= grant.token.authorizationDeadline) {\n\t\t\t\tgrant.state = grant.effectLive ? \"quarantined\" : \"cancelled\";\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Withdraw authorization. Requested cancellation is not observed termination. */\n\tcancel(token: GrantToken): boolean {\n\t\tconst grant = this.settleable(token);\n\t\tif (grant === undefined) return false;\n\t\tgrant.state = grant.effectLive ? \"quarantined\" : \"cancelled\";\n\t\treturn true;\n\t}\n\n\t/**\n\t * Trusted supervisor event: this exact effect is gone. Accepted for\n\t * superseded epochs so a restarted authority can still settle what the\n\t * previous one started, never to authorize new work.\n\t */\n\tconfirmTerminated(token: GrantToken): boolean {\n\t\tconst grant = this.settleable(token);\n\t\tif (grant === undefined) return false;\n\t\tgrant.effectLive = false;\n\t\tgrant.state = \"terminated\";\n\t\treturn true;\n\t}\n\n\t/** Fence the authority. Live effects stay quarantined until confirmed. */\n\trestart(): void {\n\t\tthis.authorityEpoch = nextSequence(this.authorityEpoch);\n\t\tfor (const grant of this.activeGrants()) {\n\t\t\tgrant.state = grant.effectLive ? \"quarantined\" : \"cancelled\";\n\t\t}\n\t}\n\n\tstateOf(token: GrantToken): EffectState | undefined {\n\t\tconst grant = this.grants.get(token.grantSequence);\n\t\treturn grant !== undefined && sameToken(grant.token, token) ? grant.state : undefined;\n\t}\n\n\tclaimsOf(token: GrantToken): readonly ResourceClaim[] {\n\t\tconst grant = this.grants.get(token.grantSequence);\n\t\treturn grant !== undefined && sameToken(grant.token, token) ? grant.claims : [];\n\t}\n\n\t/** Invariant: active grants fit capacity and never pairwise conflict. */\n\tisSafe(): boolean {\n\t\tconst active = this.activeGrants();\n\t\tif (active.reduce((sum, g) => sum + g.weight, 0) > this.capacity) return false;\n\t\tfor (const [index, grant] of active.entries()) {\n\t\t\tfor (const other of active.slice(index + 1)) {\n\t\t\t\tif (claimSetsConflict(grant.claims, other.claims)) return false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n}\n\nfunction sameToken(a: GrantToken, b: GrantToken): boolean {\n\treturn (\n\t\ta.authorityEpoch === b.authorityEpoch &&\n\t\ta.grantSequence === b.grantSequence &&\n\t\ta.sessionId === b.sessionId &&\n\t\ta.sessionIncarnation === b.sessionIncarnation &&\n\t\ta.authorizationDeadline === b.authorizationDeadline\n\t);\n}\n"]}