@north-light/crouter 0.3.163 → 0.3.165

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 (167) hide show
  1. package/dist/build-root.d.ts +6 -6
  2. package/dist/build-root.js +12 -13
  3. package/dist/builtin-memory/00-runtime-base.md +3 -4
  4. package/dist/builtin-memory/01-spine/01-no-manager.md +1 -1
  5. package/dist/builtin-memory/02-lifecycle/00-terminal.md +2 -0
  6. package/dist/builtin-memory/04-orchestration-kernel.md +16 -18
  7. package/dist/builtin-memory/05-kinds/advisor/00-base.md +0 -2
  8. package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +3 -9
  9. package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -3
  10. package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +2 -10
  11. package/dist/builtin-memory/05-kinds/explore/00-base.md +2 -2
  12. package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +0 -2
  13. package/dist/builtin-memory/05-kinds/general/00-base.md +3 -5
  14. package/dist/builtin-memory/05-kinds/general/01-orchestrator.md +0 -4
  15. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -3
  16. package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +12 -0
  17. package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +0 -2
  18. package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +0 -2
  19. package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +0 -2
  20. package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +1 -1
  21. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +0 -2
  22. package/dist/builtin-memory/05-kinds/review/00-base.md +0 -2
  23. package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -3
  24. package/dist/builtin-memory/05-kinds/spec/00-base.md +1 -1
  25. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +2 -4
  26. package/dist/builtin-memory/05-kinds/spec/requirements.md +1 -1
  27. package/dist/builtin-memory/advisor/council.md +40 -0
  28. package/dist/builtin-memory/design.md +8 -11
  29. package/dist/builtin-memory/development.md +6 -9
  30. package/dist/builtin-memory/internal/INDEX.md +5 -5
  31. package/dist/builtin-memory/internal/agent-shaping.md +5 -7
  32. package/dist/builtin-memory/internal/examples/imessage-assistant.md +3 -3
  33. package/dist/builtin-memory/internal/marketplaces.md +13 -14
  34. package/dist/builtin-memory/internal/memory-loading.md +45 -0
  35. package/dist/builtin-memory/internal/nodes-and-canvas.md +4 -4
  36. package/dist/builtin-memory/internal/plugins.md +61 -45
  37. package/dist/builtin-memory/planning.md +4 -7
  38. package/dist/builtin-memory/spec.md +9 -12
  39. package/dist/builtin-memory/wedged-child-on-runaway-bash.md +8 -22
  40. package/dist/cli.js +1 -1
  41. package/dist/clients/attach/__tests__/attach-keybindings.test.js +17 -4
  42. package/dist/clients/attach/__tests__/context-message.test.js +31 -20
  43. package/dist/clients/attach/__tests__/crtr-output-coverage.test.js +1 -1
  44. package/dist/clients/attach/__tests__/crtr-output.test.js +39 -30
  45. package/dist/clients/attach/__tests__/edit-diff.test.js +21 -20
  46. package/dist/clients/attach/render/chat-view.d.ts +20 -20
  47. package/dist/clients/attach/render/chat-view.js +88 -89
  48. package/dist/clients/attach/render/{frozen-history.d.ts → condensed-history.d.ts} +1 -18
  49. package/dist/clients/attach/render/condensed-history.js +60 -0
  50. package/dist/clients/attach/render/context-message.js +9 -14
  51. package/dist/clients/attach/render/crtr-output.d.ts +2 -1
  52. package/dist/clients/attach/render/crtr-output.js +4 -4
  53. package/dist/clients/attach/render/edit-diff.d.ts +21 -6
  54. package/dist/clients/attach/render/edit-diff.js +90 -91
  55. package/dist/clients/attach/render/tool-calls.d.ts +14 -18
  56. package/dist/clients/attach/render/tool-calls.js +66 -41
  57. package/dist/clients/attach/session/bindings.d.ts +5 -3
  58. package/dist/clients/attach/session/bindings.js +7 -13
  59. package/dist/clients/attach/session/keys.d.ts +2 -0
  60. package/dist/clients/attach/session/keys.js +36 -37
  61. package/dist/clients/attach/session/profile-files.d.ts +8 -0
  62. package/dist/clients/attach/session/profile-files.js +157 -0
  63. package/dist/clients/attach/viewer.js +530 -528
  64. package/dist/commands/memory/lint.js +1 -1
  65. package/dist/commands/memory/write.js +1 -1
  66. package/dist/commands/node.js +2 -2
  67. package/dist/commands/pkg/plugin-inspect.js +6 -7
  68. package/dist/commands/pkg/plugin-manage.d.ts +1 -1
  69. package/dist/commands/pkg/plugin-manage.js +131 -19
  70. package/dist/commands/pkg/plugin.js +2 -2
  71. package/dist/commands/pkg.js +6 -11
  72. package/dist/commands/profile/env.js +3 -3
  73. package/dist/commands/sys/config.js +17 -76
  74. package/dist/commands/sys/doctor.js +5 -91
  75. package/dist/commands/sys/setup-wizard.d.ts +9 -11
  76. package/dist/commands/sys/setup-wizard.js +47 -81
  77. package/dist/core/__tests__/base-worker-prompt.test.js +18 -21
  78. package/dist/core/__tests__/command-plugins-surfaces.test.js +39 -5
  79. package/dist/core/__tests__/command-plugins.test.js +36 -16
  80. package/dist/core/__tests__/review-model-floor.test.js +2 -2
  81. package/dist/core/__tests__/tmux-surface.test.js +10 -1
  82. package/dist/core/command-manifests/manifest.d.ts +24 -0
  83. package/dist/core/{configured-clis → command-manifests}/manifest.js +21 -25
  84. package/dist/core/command-manifests/registry.d.ts +1 -2
  85. package/dist/core/command-manifests/registry.js +2 -2
  86. package/dist/core/command-manifests/schema.d.ts +11 -13
  87. package/dist/core/command-manifests/schema.js +53 -192
  88. package/dist/core/command-plugins/compose.d.ts +0 -6
  89. package/dist/core/command-plugins/compose.js +28 -75
  90. package/dist/core/command-plugins/discovery.d.ts +25 -58
  91. package/dist/core/command-plugins/discovery.js +152 -259
  92. package/dist/core/command-plugins/endpoint.d.ts +24 -0
  93. package/dist/core/command-plugins/endpoint.js +48 -0
  94. package/dist/core/command-plugins/store.d.ts +16 -0
  95. package/dist/core/command-plugins/store.js +64 -0
  96. package/dist/core/command-plugins/{adapter.d.ts → transport/exec-invoke.d.ts} +3 -3
  97. package/dist/core/command-plugins/{adapter.js → transport/exec-invoke.js} +4 -4
  98. package/dist/core/{configured-clis/fetch.d.ts → command-plugins/transport/http-fetch.d.ts} +9 -18
  99. package/dist/core/{configured-clis/fetch.js → command-plugins/transport/http-fetch.js} +15 -35
  100. package/dist/core/{configured-clis/invoker.d.ts → command-plugins/transport/http-invoke.d.ts} +7 -7
  101. package/dist/core/{configured-clis/invoker.js → command-plugins/transport/http-invoke.js} +21 -23
  102. package/dist/core/command.d.ts +8 -9
  103. package/dist/core/command.js +6 -9
  104. package/dist/core/config.js +6 -10
  105. package/dist/core/env-name.d.ts +6 -0
  106. package/dist/core/env-name.js +9 -0
  107. package/dist/core/io.d.ts +1 -1
  108. package/dist/core/keybindings/__tests__/resolve.test.js +40 -3
  109. package/dist/core/keybindings/attach-control.d.ts +37 -0
  110. package/dist/core/keybindings/attach-control.js +38 -0
  111. package/dist/core/keybindings/catalog.d.ts +5 -4
  112. package/dist/core/keybindings/catalog.js +16 -8
  113. package/dist/core/keybindings/index.d.ts +1 -0
  114. package/dist/core/keybindings/index.js +1 -0
  115. package/dist/core/keybindings/types.d.ts +1 -1
  116. package/dist/core/preview-registry.js +41 -74
  117. package/dist/core/runtime/bearings.d.ts +2 -5
  118. package/dist/core/runtime/bearings.js +2 -5
  119. package/dist/core/runtime/front-door.d.ts +1 -1
  120. package/dist/core/runtime/front-door.js +2 -2
  121. package/dist/core/runtime/kickoff.d.ts +3 -3
  122. package/dist/core/runtime/kickoff.js +4 -3
  123. package/dist/core/runtime/situational-context.d.ts +1 -1
  124. package/dist/core/runtime/situational-context.js +1 -1
  125. package/dist/core/runtime/spawn.js +9 -9
  126. package/dist/core/runtime/tmux.js +29 -2
  127. package/dist/core/scope.d.ts +0 -5
  128. package/dist/core/scope.js +0 -10
  129. package/dist/core/user-settings.d.ts +193 -0
  130. package/dist/core/user-settings.js +252 -0
  131. package/dist/index.d.ts +4 -0
  132. package/dist/index.js +3 -0
  133. package/dist/pi-extensions/canvas-stophook.js +3 -2
  134. package/dist/pi-extensions/canvas-tool-guide.js +4 -1
  135. package/dist/shared/generated-context.d.ts +34 -0
  136. package/dist/shared/generated-context.js +98 -0
  137. package/dist/types.d.ts +23 -16
  138. package/dist/types.js +3 -14
  139. package/dist/web-client/assets/{index-NIuSCOHM.js → index-BMTOGuOZ.js} +19 -19
  140. package/dist/web-client/assets/index-DvA6Zw-R.css +2 -0
  141. package/dist/web-client/index.html +2 -2
  142. package/dist/web-client/sw.js +1 -1
  143. package/docs/public-api.md +1 -0
  144. package/package.json +2 -2
  145. package/runtime.lock.json +6 -6
  146. package/dist/builtin-memory/05-kinds/product/00-base.md +0 -25
  147. package/dist/builtin-memory/05-kinds/product/01-orchestrator.md +0 -15
  148. package/dist/builtin-memory/05-kinds/product/teardown.md +0 -15
  149. package/dist/builtin-memory/internal/workflow-codification.md +0 -82
  150. package/dist/builtin-memory/product.md +0 -80
  151. package/dist/clients/attach/render/frozen-history.js +0 -100
  152. package/dist/commands/pkg/cli-inspect.d.ts +0 -17
  153. package/dist/commands/pkg/cli-inspect.js +0 -190
  154. package/dist/commands/pkg/cli-manage.d.ts +0 -3
  155. package/dist/commands/pkg/cli-manage.js +0 -206
  156. package/dist/commands/pkg/cli.d.ts +0 -1
  157. package/dist/commands/pkg/cli.js +0 -14
  158. package/dist/core/configured-clis/cache.d.ts +0 -16
  159. package/dist/core/configured-clis/cache.js +0 -57
  160. package/dist/core/configured-clis/compose.d.ts +0 -14
  161. package/dist/core/configured-clis/compose.js +0 -60
  162. package/dist/core/configured-clis/discovery.d.ts +0 -47
  163. package/dist/core/configured-clis/discovery.js +0 -173
  164. package/dist/core/configured-clis/manifest.d.ts +0 -24
  165. package/dist/core/configured-clis/registration.d.ts +0 -40
  166. package/dist/core/configured-clis/registration.js +0 -201
  167. package/dist/web-client/assets/index-CqLKj8Xu.css +0 -2
@@ -1,80 +0,0 @@
1
- ---
2
- kind: knowledge
3
- when-and-why-to-read: When running a product-discovery effort, shaping a product roadmap, or deciding how to stage problem discovery, competitive teardown, and experience definition, this knowledge should be read so the real user need is tested before solution commitment and downstream specification starts from one evidence-grounded direction.
4
- short-form: Use when running a product-discovery effort or shaping a product roadmap. Covers the three-stage DISCOVER→GROUND→DEFINE methodology, the Mom Test discovery discipline, the four-risks ownership boundary vs the downstream spec, parallel teardown delegation, and what a finished product brief contains.
5
- system-prompt-visibility: name
6
- file-read-visibility: none
7
- gate:
8
- kind:
9
- imatches: '^product($|/)'
10
- needs-refinement: true
11
- ---
12
-
13
- ## The Three Stages
14
-
15
- A product-discovery effort runs in this order: **DISCOVER** → **GROUND** → **DEFINE**. GROUND and DEFINE interleave (you ground to inform the definition), but you do not commit a product direction in DEFINE until DISCOVER has cleared its gate. Each stage has a gate; you do not commit the next until the current one is met.
16
-
17
- ### Stage 1 — Discover (problem-space)
18
-
19
- Discover is where you find the real need. A client arrives with a solution in their mouth and a problem in their gut; your job is to reach the problem. Treat the request as a hypothesis, not an order — work the **job-to-be-done**: what the user is hiring this product to accomplish (functional, emotional, and social dimensions), for whom, in what triggering moment, and what they do today instead and why it falls short.
20
-
21
- Run discovery with `crtr human ask` using the **Mom Test discipline**: ask about real, specific past behavior and concrete pain ("walk me through the last time you hit this"), never pitch your idea, and never ask hypothetical "would you use…" questions — they invite politeness, not truth. Real pain is validated by current workarounds, emotional language, and evidence of prior spend, not hypothetical enthusiasm. Earn every question: answer what you can yourself by tearing down existing products and reading the codebase first; only judgment-bearing, genuinely unresolved questions reach the human.
22
-
23
- Write each core need as a **JTBD statement** — `verb + object + context` ("minimize the time to capture a thought on the go") or `When [situation], I want to [motivation], so I can [outcome]` — across all three dimensions (functional, emotional, social); the emotional and social dimensions are the ones teams skip and are exactly what feed the experience work in Define. Structure the discovery output as an **opportunity solution tree** (Torres): one measurable **outcome** at the root, the **opportunities** (unmet needs/pains, sourced from real evidence) beneath it, and candidate **solutions** each tied to a specific opportunity, with the riskiest **assumptions** to test hanging off them. The tree's whole job is to forbid jumping from the outcome straight to a solution and to force more than one branch — it kills the single-track tunnel vision that order-taking produces.
24
-
25
- The request and the real job often diverge. When the asked-for feature does not serve the underlying job, say so and steer — building exactly what was asked when it won't meet the need is the central failure this role exists to prevent.
26
-
27
- Gate: the client confirms you have the real problem and the users right — restate the job without correction, and the requested feature is either validated as serving it or consciously redirected.
28
-
29
- ### Stage 2 — Ground (competitive)
30
-
31
- Before committing a direction, study how comparable products solve the same job. This is not a feature survey — it is a teardown of the *experience*: interaction patterns, what each product gets right (borrow), where it fails its users (avoid), and where a new product could beat it (differentiate).
32
-
33
- Delegate one `product/teardown` child per comparable product and run them in parallel; each studies one product deeply against the job-to-be-done and returns a verdict. Integrate the teardowns yourself into a single **positioning stance** — borrow / avoid / differentiate — never a concatenation and never a copy. Inspiration becomes a defensible direction only when you can say why you are borrowing or rejecting each pattern *for this job*.
34
-
35
- Treat competitor patterns as hypotheses, not proven-optimal truth — their design may never have been tested. Do not chase feature parity; it is easily copied and commoditizes you. Instead find the **market orthodoxy** (what every comparable product does the same way), locate the customer-satisfaction gap that orthodoxy leaves open, and pick an opposite dimension that matters to a specific segment. Express the result as a positioning statement: **"Unlike [competitor], [product] provides [durable outcome] because [verifiable reason to believe]."** The reason must rest on something that *compounds* (proprietary data, domain depth, a unique posture), not a UI tweak or a vague "easier to use" claim.
36
-
37
- Gate: a positioning stance exists that names what you will borrow, what you will avoid, and how you will differentiate — on a dimension that compounds.
38
-
39
- ### Stage 3 — Define (experience)
40
-
41
- Define commits the opinionated product direction. It produces: the **use cases** the product serves; **3–7 experience principles** (opinionated, prioritized — "instant over configurable", not platitudes); the **emotional target** ("using this should feel like…"); a **user journey** with its moments of truth — where the product must delight and where it must not fail; and a **product vision + North Star** that names the one outcome the product optimizes. Be opinionated: a definition that lists options without a recommendation has not done the consulting.
42
-
43
- Gate: the client aligns on the product direction and the experience — the feel, the use cases, and the vision.
44
-
45
- ---
46
-
47
- ## The Four Risks — What This Role Owns
48
-
49
- Every product idea carries four risks (Cagan): **value** (will anyone want it), **usability** (can they use it), **feasibility** (can we build it), **viability** (does it work for the business — brand, legal, economics). This role **owns value, usability, and experience**: discovering them and defining for them is the job. It **flags viability** when it surfaces (a direction that risks the brand, a legal exposure, an economics problem) but does not adjudicate it. It **defers feasibility** entirely to engineering — never let "is this buildable" narrow the product direction during discovery; that is the downstream spec and design work, and pre-empting it trades a clean problem for a brittle answer.
50
-
51
- Discovery exists to attack these risks *cheaply and early* — with the assumption inventory and small tests, not engineering cycles. Treat the opening problem statement as a set of unproven hypotheses: categorize the claims (behavioral / emotional / economic), rank them by risk, and surface the riskiest first — the ranked inventory is the explicit baton of what still needs validating.
52
-
53
- ---
54
-
55
- ## The Boundary With Spec — Where the Baton Passes
56
-
57
- This role stops at **the right product to build and how it should feel and look.** It does NOT write acceptance criteria, EARS requirements, user stories, API or data models, or pixel-level UI. Those belong to the downstream `spec` (buildable behavior, interfaces, edge cases) and `design` (architecture, UI structure) kinds.
58
-
59
- The baton handed to spec is four things: the **validated problem** (job, users, pain), the **experiential direction** (use cases, experience principles, emotional target, journey), the **competitive grounding** (positioning stance), and the **ranked open assumptions** the spec stage must resolve. A clean baton is a sharp *problem and direction*, not a half-written solution — pre-deciding the spec's job hands it an answer to verify instead of a problem to specify.
60
-
61
- ---
62
-
63
- ## What a Finished Product Brief Contains
64
-
65
- A product brief is lightweight, living, and decision-driving — not a heavy PRD. It is finished when a spec writer could derive what to build from it without re-discovering the user. It contains:
66
-
67
- - **Validated problem / opportunity** — the real job-to-be-done (functional, emotional, social), who has it, the pain, and what they do today.
68
- - **Use cases** — the concrete situations the product serves, in the user's terms.
69
- - **Experience definition** — 3–7 opinionated experience principles, the emotional target, and a user journey with its moments of truth (delight points and must-not-fail points).
70
- - **Competitive grounding + positioning** — what comparable products teach, and the borrow / avoid / differentiate stance.
71
- - **Product vision + North Star** — the one outcome the product optimizes, and the direction it implies.
72
- - **Ranked open assumptions** — the value/usability/experience bets the brief is making, risk-ranked, for the next stages to resolve.
73
-
74
- A brief that types the request back as a plan, lists options without a recommendation, or smuggles in acceptance criteria and UI specs is not finished. Surface unresolved discovery as ranked assumptions, never as silent guesses.
75
-
76
- ---
77
-
78
- ## Roadmap Shape for a Product Effort
79
-
80
- The goal section states the product being discovered and for whom. Scope assumptions record the audience and the job in scope and what is explicitly not. `## Strategy / phases` holds exactly three phases: Discover (gate: client confirms the real problem + users), Ground (gate: positioning stance exists), Define (gate: client aligns on direction + experience). The current phase carries a one-line status; completed phases are deleted, not summarized. Human-confirmed decisions and teardown findings fold into context files (`context/product-brief-*.md`, teardown reports), not the roadmap.
@@ -1,100 +0,0 @@
1
- // frozen-history.ts — condensed, frozen rendering of a node's OLD cycles.
2
- //
3
- // A node that has yielded several times carries every prior cycle in its welcome
4
- // snapshot (cycleAwareMessages, session-cycles.ts), and the viewer used to build a
5
- // live component for each message in all of them. Measured across six real
6
- // sessions (2788 entries, rendered at width 120 with tool output collapsed):
7
- //
8
- // tool calls + results 20448 lines (62.9%) 1376 ms (69%) of build time
9
- // user 6078 lines (18.7%) 431 ms
10
- // assistant prose 5960 lines (18.3%) 202 ms
11
- //
12
- // So the tool traffic of cycles you are no longer working in dominates both the
13
- // transcript's line count and the cost of attaching to it. Cycles older than the
14
- // trailing `live_cycles` (config, default 2) are therefore CONDENSED — reduced to
15
- // the cycle dividers plus whichever messages `condensed_history` (config, default
16
- // `none`) admits — and FROZEN: rendered once into a flat `string[]` that is handed
17
- // back verbatim on every subsequent frame.
18
- //
19
- // Freezing means the block never re-wraps. Widening the pane leaves the old lines
20
- // short (harmless); narrowing CLIPS them at the right edge rather than reflowing,
21
- // because emitting a line wider than the pane would desync pi-tui's line
22
- // accounting against the terminal's own wrapping and garble everything below it.
23
- //
24
- // The full detail of a condensed cycle is never lost — it is in the node's session
25
- // file, and `/tree` still navigates the real branches.
26
- import { sliceByColumn } from '@earendil-works/pi-tui';
27
- import { CRTR_CYCLE_DIVIDER_CUSTOM_TYPE } from '../../../core/runtime/session-cycles.js';
28
- /** Roles admitted by each `condensed_history` mode. `toolResult`,
29
- * `bashExecution`, and every non-divider `custom` message (crtr output,
30
- * injected context blocks) are never kept, nor are the tool-call components an
31
- * assistant message would otherwise spawn — only its prose. The cycle dividers
32
- * survive every mode, so `none` leaves the seams and nothing else. */
33
- const ROLES_BY_MODE = {
34
- none: new Set(),
35
- user: new Set(['user']),
36
- agent: new Set(['assistant', 'compactionSummary', 'branchSummary']),
37
- both: new Set(['user', 'assistant', 'compactionSummary', 'branchSummary']),
38
- };
39
- export function isCycleDivider(message) {
40
- return message.role === 'custom' && message.customType === CRTR_CYCLE_DIVIDER_CUSTOM_TYPE;
41
- }
42
- /** Does this message survive condensation into the frozen block? */
43
- export function keepWhenCondensed(message, mode) {
44
- if (isCycleDivider(message))
45
- return true;
46
- return (ROLES_BY_MODE[mode] ?? ROLES_BY_MODE.none).has(message.role ?? '');
47
- }
48
- /**
49
- * Index into `messages` at which the LIVE (fully rendered) region begins.
50
- *
51
- * The snapshot is `[cycle 0][divider][cycle 1][divider]…[current cycle]`, so a
52
- * transcript with D dividers holds D+1 cycles. Keeping the trailing
53
- * `liveCycles` of them means everything up to and including divider
54
- * `D - liveCycles` is condensed. Returns 0 — condense nothing — when the node
55
- * has not yielded often enough to have older cycles, so a fresh or
56
- * single-yield node renders exactly as it always did.
57
- */
58
- export function liveRegionStart(messages, liveCycles) {
59
- const keep = Math.max(1, Math.floor(liveCycles));
60
- const dividers = [];
61
- for (let i = 0; i < messages.length; i++) {
62
- if (isCycleDivider(messages[i]))
63
- dividers.push(i);
64
- }
65
- const cycles = dividers.length + 1;
66
- if (cycles <= keep)
67
- return 0;
68
- // The last divider that closes a condensed cycle; the live region opens just
69
- // after it (the divider itself stays in the frozen block as the seam).
70
- return dividers[cycles - keep - 1] + 1;
71
- }
72
- /**
73
- * A settled block of pre-rendered transcript lines. Renders in O(1) at the width
74
- * it was frozen at, and clips (never reflows) when the pane is narrower. Ctrl+O /
75
- * Ctrl+T do not reach it: it holds no components to expand, only text.
76
- */
77
- export class FrozenHistoryComponent {
78
- lines;
79
- frozenWidth;
80
- /** Last clip result, so a stable narrow pane clips once rather than per frame. */
81
- clipped;
82
- constructor(lines, frozenWidth) {
83
- this.lines = lines;
84
- this.frozenWidth = frozenWidth;
85
- }
86
- get lineCount() {
87
- return this.lines.length;
88
- }
89
- /** Nothing to recompute — the block is text, already laid out. */
90
- invalidate() { }
91
- render(width) {
92
- if (width >= this.frozenWidth)
93
- return this.lines;
94
- if (this.clipped?.width === width)
95
- return this.clipped.lines;
96
- const lines = this.lines.map((line) => sliceByColumn(line, 0, width, true));
97
- this.clipped = { width, lines };
98
- return lines;
99
- }
100
- }
@@ -1,17 +0,0 @@
1
- import { type ConfiguredCliRegistration } from '../../core/configured-clis/registration.js';
2
- import type { CommandRegistrySnapshot } from '../../core/command-manifests/registry.js';
3
- /** Whether a registration's STORED manifest reads as present. Mirrors the
4
- * discovery classifier exactly (§3.3): a missing/metadata-mismatched/unreadable
5
- * manifest, or one whose bytes do not parse as JSON, reads as `absent`; a
6
- * parseable manifest — even one that later fails §4 validation — is `stored`.
7
- * Never fetches. */
8
- export declare function configuredCliManifestStored(registration: ConfiguredCliRegistration): boolean;
9
- /** The stored-manifest state string for a registration. */
10
- export declare function configuredCliManifestState(registration: ConfiguredCliRegistration): 'stored' | 'absent';
11
- export declare const cliList: import("../../core/command.js").LeafDef;
12
- /** Build the show/refresh report body for one registration from the unified
13
- * snapshot: its stored-manifest state, every command it currently contributes
14
- * (each with its full mount path and subtree), and every validation/collision
15
- * issue attributed to it. Zero network. */
16
- export declare function configuredCliReport(registration: ConfiguredCliRegistration, snapshot: CommandRegistrySnapshot): Record<string, unknown>;
17
- export declare const cliShow: import("../../core/command.js").LeafDef;
@@ -1,190 +0,0 @@
1
- import { defineLeaf } from '../../core/command.js';
2
- import { notFound } from '../../core/errors.js';
3
- import { paginate } from '../../core/pagination.js';
4
- import { resolveScopeArg } from '../../core/scope.js';
5
- import { SUBTREE_NAMES } from '../../build-root.js';
6
- import { listConfiguredCliRegistrations, resolveConfiguredCli, } from '../../core/configured-clis/registration.js';
7
- import { isCacheMetadataValid, readConfiguredCliCacheManifest } from '../../core/configured-clis/cache.js';
8
- import { buildExternalCommandSnapshot } from '../../core/configured-clis/discovery.js';
9
- // ---------------------------------------------------------------------------
10
- // Shared inspection helpers (zero network — read stored manifest bytes only)
11
- // ---------------------------------------------------------------------------
12
- /** Whether a registration's STORED manifest reads as present. Mirrors the
13
- * discovery classifier exactly (§3.3): a missing/metadata-mismatched/unreadable
14
- * manifest, or one whose bytes do not parse as JSON, reads as `absent`; a
15
- * parseable manifest — even one that later fails §4 validation — is `stored`.
16
- * Never fetches. */
17
- export function configuredCliManifestStored(registration) {
18
- if (!isCacheMetadataValid(registration))
19
- return false;
20
- const bytes = readConfiguredCliCacheManifest(registration);
21
- if (bytes === null)
22
- return false;
23
- try {
24
- JSON.parse(Buffer.from(bytes).toString('utf8'));
25
- return true;
26
- }
27
- catch {
28
- return false; // unparseable → reads as absent
29
- }
30
- }
31
- /** The stored-manifest state string for a registration. */
32
- export function configuredCliManifestState(registration) {
33
- return configuredCliManifestStored(registration) ? 'stored' : 'absent';
34
- }
35
- /** The core top-level subtree names — the closed set a remote may never mount
36
- * onto or shadow. Passed to the unified snapshot as `reservedCoreNames`. */
37
- function reservedCoreNames() {
38
- return new Set(SUBTREE_NAMES);
39
- }
40
- /** Every full command path (space-joined tokens) in a contributed node's
41
- * subtree, starting at the node itself — the top-level mount path plus every
42
- * descendant. e.g. `["device", "device reboot", "device status"]`. */
43
- function enumerateCommandPaths(node, prefix) {
44
- const here = [...prefix, node.name];
45
- const out = [here.join(' ')];
46
- if (node.kind === 'branch') {
47
- for (const child of node.children)
48
- out.push(...enumerateCommandPaths(child, here));
49
- }
50
- return out;
51
- }
52
- /** The accepted top-level command names a registration currently contributes,
53
- * read from THE unified collision-resolved snapshot (a collided command is
54
- * dropped and appears only in issues). */
55
- function contributedTopLevel(snapshot, name) {
56
- return snapshot.contributions
57
- .filter((c) => c.contributor.kind === 'configured-cli' && c.contributor.name === name)
58
- .map((c) => c.node.name)
59
- .sort((a, b) => a.localeCompare(b));
60
- }
61
- /** Serialize a single configured-CLI issue to the received/expected/next shape. */
62
- function issueOut(issue) {
63
- return {
64
- code: issue.code,
65
- ...(issue.path !== undefined ? { path: issue.path } : {}),
66
- message: issue.message,
67
- received: issue.received,
68
- expected: issue.expected,
69
- next: issue.next,
70
- };
71
- }
72
- // ---------------------------------------------------------------------------
73
- // list
74
- // ---------------------------------------------------------------------------
75
- export const cliList = defineLeaf({
76
- name: 'list',
77
- description: 'list registered configured CLIs',
78
- whenToUse: 'enumerating configured-CLI registrations across scopes with endpoint, scope, stored-manifest state, and the top-level command(s) each currently contributes',
79
- help: {
80
- name: 'pkg cli list',
81
- summary: 'list registered configured CLIs (zero network)',
82
- params: [
83
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project', 'all'], required: false, constraint: 'Default: all.' },
84
- { kind: 'flag', name: 'limit', type: 'int', required: false, default: 50, constraint: 'Default 50, max 200.' },
85
- { kind: 'flag', name: 'cursor', type: 'string', required: false, constraint: 'Opaque token from next_cursor. Omit on first call.' },
86
- ],
87
- output: [
88
- { name: 'items', type: 'object[]', required: true, constraint: 'Each: {name, endpoint, scope, manifest_state, top_level_commands}. manifest_state is "stored" or "absent". top_level_commands are the accepted top-level command names from the unified snapshot (empty when absent, invalid, or collided). Sorted by scope (project first) then name ascending.' },
89
- { name: 'next_cursor', type: 'string | null', required: true, constraint: 'null means no more items.' },
90
- { name: 'total', type: 'integer | null', required: true, constraint: 'Exact count.' },
91
- ],
92
- outputKind: 'object',
93
- effects: ['None. Read-only. Reads stored manifests only — never fetches, never revalidates.'],
94
- },
95
- run: async (input) => {
96
- const scopeInput = input['scope'];
97
- const limitRaw = input['limit'];
98
- const limit = limitRaw !== undefined ? Math.min(Math.max(1, limitRaw), 200) : 50;
99
- const cursor = input['cursor'];
100
- let scopeFilter;
101
- if (scopeInput !== undefined) {
102
- const resolved = resolveScopeArg(scopeInput);
103
- if (resolved !== 'all')
104
- scopeFilter = resolved;
105
- }
106
- const snapshot = buildExternalCommandSnapshot(reservedCoreNames());
107
- const all = listConfiguredCliRegistrations()
108
- .filter((r) => scopeFilter === undefined || r.scope === scopeFilter)
109
- .sort((a, b) => {
110
- if (a.scope === 'project' && b.scope !== 'project')
111
- return -1;
112
- if (a.scope !== 'project' && b.scope === 'project')
113
- return 1;
114
- return a.name.localeCompare(b.name);
115
- });
116
- const result = paginate(all, { limit, cursor: cursor !== undefined ? cursor : undefined }, { defaultLimit: 50, maxLimit: 200, keyOf: (r) => `${r.scope}:${r.name}`, total: 'count' });
117
- return {
118
- items: result.items.map((r) => ({
119
- name: r.name,
120
- endpoint: r.endpoint,
121
- scope: r.scope,
122
- manifest_state: configuredCliManifestState(r),
123
- top_level_commands: contributedTopLevel(snapshot, r.name),
124
- })),
125
- next_cursor: result.next_cursor,
126
- total: result.total,
127
- };
128
- },
129
- });
130
- // ---------------------------------------------------------------------------
131
- // show
132
- // ---------------------------------------------------------------------------
133
- /** Build the show/refresh report body for one registration from the unified
134
- * snapshot: its stored-manifest state, every command it currently contributes
135
- * (each with its full mount path and subtree), and every validation/collision
136
- * issue attributed to it. Zero network. */
137
- export function configuredCliReport(registration, snapshot) {
138
- const commands = snapshot.contributions
139
- .filter((c) => c.contributor.kind === 'configured-cli' && c.contributor.name === registration.name)
140
- .map((c) => ({
141
- command: c.node.name,
142
- paths: enumerateCommandPaths(c.node, []),
143
- }))
144
- .sort((a, b) => a.command.localeCompare(b.command));
145
- const issues = snapshot.issues
146
- .filter((i) => i.contributor.kind === 'configured-cli' && i.contributor.name === registration.name)
147
- .map(issueOut);
148
- return {
149
- name: registration.name,
150
- scope: registration.scope,
151
- endpoint: registration.endpoint,
152
- manifest_state: configuredCliManifestState(registration),
153
- commands,
154
- issues,
155
- };
156
- }
157
- export const cliShow = defineLeaf({
158
- name: 'show',
159
- description: 'inventory one configured CLI',
160
- whenToUse: 'reading one configured-CLI registration in detail: resolved endpoint, whether a manifest is stored, every command it currently contributes with full mount path and subtree, and every current validation/collision issue',
161
- help: {
162
- name: 'pkg cli show',
163
- summary: 'inventory one configured CLI from its stored manifest (zero network)',
164
- params: [
165
- { kind: 'positional', name: 'name', type: 'string', required: true, constraint: 'Registration name.' },
166
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'Narrows resolution. Default: the effective registration (project outranks user).' },
167
- ],
168
- output: [
169
- { name: 'name', type: 'string', required: true, constraint: 'Registration name.' },
170
- { name: 'scope', type: 'string', required: true, constraint: 'Scope the registration lives in.' },
171
- { name: 'endpoint', type: 'string', required: true, constraint: 'Resolved manifest endpoint URL.' },
172
- { name: 'manifest_state', type: 'string', required: true, constraint: '"stored" or "absent". Absent is a valid inventory state (register-time fetch failed), not an error.' },
173
- { name: 'commands', type: 'object[]', required: true, constraint: 'Every accepted command this CLI contributes. Each: {command (top-level mount name), paths (every full command path in its subtree, space-joined)}. Empty when the manifest is absent, invalid, or collided.' },
174
- { name: 'issues', type: 'object[]', required: true, constraint: 'Every current validation/collision issue for this CLI, from the unified snapshot. Each: {code, path?, message, received, expected, next}.' },
175
- ],
176
- outputKind: 'object',
177
- effects: ['None. Read-only. Serves the stored manifest — never fetches, never revalidates.'],
178
- },
179
- run: async (input) => {
180
- const name = input['name'];
181
- const scopeInput = input['scope'];
182
- const scope = scopeInput !== undefined ? resolveScopeArg(scopeInput) : undefined;
183
- const registration = resolveConfiguredCli(name, scope);
184
- if (registration === null) {
185
- throw notFound(`configured CLI not found: ${name}`);
186
- }
187
- const snapshot = buildExternalCommandSnapshot(reservedCoreNames());
188
- return configuredCliReport(registration, snapshot);
189
- },
190
- });
@@ -1,3 +0,0 @@
1
- export declare const cliRegister: import("../../core/command.js").LeafDef;
2
- export declare const cliRemove: import("../../core/command.js").LeafDef;
3
- export declare const cliRefresh: import("../../core/command.js").LeafDef;
@@ -1,206 +0,0 @@
1
- import { defineLeaf } from '../../core/command.js';
2
- import { notFound, usage } from '../../core/errors.js';
3
- import { resolveScopeArg, requireScopeRoot, ensureProjectScopeRoot, } from '../../core/scope.js';
4
- import { updateConfig, ensureScopeInitialized, readConfig } from '../../core/config.js';
5
- import { SUBTREE_NAMES } from '../../build-root.js';
6
- import { resolveConfiguredCli, normalizeEndpoint, validateRegistrationName, validateEndpoint, validateEnvVarName, } from '../../core/configured-clis/registration.js';
7
- import { removeConfiguredCliCache } from '../../core/configured-clis/cache.js';
8
- import { registerFetchConfiguredCli, refreshConfiguredCli } from '../../core/configured-clis/fetch.js';
9
- import { buildExternalCommandSnapshot } from '../../core/configured-clis/discovery.js';
10
- import { configuredCliManifestState, configuredCliReport } from './cli-inspect.js';
11
- /** Resolve the target scope for `register`. Spec default is **user** (register
12
- * declares a remote surface; it does not install a local artifact). Only
13
- * user/project are valid. */
14
- function resolveRegisterScope(scopeInput) {
15
- if (scopeInput === undefined)
16
- return 'user';
17
- const resolved = resolveScopeArg(scopeInput);
18
- if (resolved === 'all' || resolved === 'builtin') {
19
- throw usage('scope must be "user" or "project"');
20
- }
21
- return resolved;
22
- }
23
- export const cliRegister = defineLeaf({
24
- name: 'register',
25
- description: 'register a configured CLI and load its manifest',
26
- whenToUse: 'declaring a configured CLI — a remote command surface defined by a manifest endpoint and executed as declarative HTTP. Records {name, endpoint, auth-env} to scope config and fetches-and-stores the manifest. Re-run on every guest boot to reload the manifest: a byte-identical re-register is an idempotent record but still re-fetches. To change an existing endpoint/auth-env, `remove` first.',
27
- help: {
28
- name: 'pkg cli register',
29
- summary: 'register a configured CLI and fetch its manifest',
30
- params: [
31
- { kind: 'flag', name: 'name', type: 'string', required: true, constraint: 'Registration name (kebab-case, unique among this scope\'s configured-CLI registrations). A local handle — NOT a command name; the top-level command(s) a CLI contributes are named by its manifest mounts.' },
32
- { kind: 'flag', name: 'endpoint', type: 'string', required: true, constraint: 'Absolute https:// URL crtr GETs to fetch the manifest (http:// permitted for loopback hosts only — local dev). Its origin is the default REST base for leaf calls. No credentials or fragment.' },
33
- { kind: 'flag', name: 'auth-env', type: 'string', required: false, constraint: 'Name of an env var holding a bearer token (e.g. NL_CORE_TOKEN). crtr reads process.env[NAME] at fetch/invocation time and sends Authorization: Bearer. Omit for an unauthenticated endpoint. The credential is never stored.' },
34
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'Default: user.' },
35
- ],
36
- output: [
37
- { name: 'name', type: 'string', required: true, constraint: 'Registration name.' },
38
- { name: 'endpoint', type: 'string', required: true, constraint: 'Normalized manifest endpoint URL as stored.' },
39
- { name: 'auth_env', type: 'string', required: false, constraint: 'Configured auth env var name. Absent when unauthenticated.' },
40
- { name: 'scope', type: 'string', required: true, constraint: 'Scope the registration was written to.' },
41
- { name: 'manifest_state', type: 'string', required: true, constraint: '"stored" (fetch succeeded, or a prior manifest was preserved) or "absent" (fetch failed and nothing was stored).' },
42
- { name: 'unchanged', type: 'boolean', required: false, constraint: 'True when the record already existed identically (idempotent re-register). The manifest was still re-fetched.' },
43
- ],
44
- outputKind: 'object',
45
- effects: [
46
- 'Writes configuredClis.<name> to the scope config.json (atomic, lock-guarded), then performs exactly one authenticated GET of the endpoint and stores the returned bytes as the manifest (replacing any prior one on success).',
47
- 'A byte-identical re-register (same endpoint + auth-env) skips the config write but still re-fetches and replaces the stored manifest — the guest-boot reload path.',
48
- 'A fetch failure (network / non-2xx) preserves any prior stored manifest and exits success with a stderr diagnostic suggesting `pkg cli refresh <name>`. A named-but-unset auth env, a differing endpoint/auth-env for an existing name, or an invalid name/endpoint fails before writing or fetching.',
49
- ],
50
- },
51
- run: async (input) => {
52
- const name = input['name']?.trim();
53
- const endpointRaw = input['endpoint'];
54
- const authEnvVar = input['authEnv'];
55
- const scopeInput = input['scope'];
56
- // ---- Validate inputs (a failure writes nothing and fetches nothing) ----
57
- const nameCheck = validateRegistrationName(name);
58
- if (!nameCheck.isValid) {
59
- throw usage(`invalid --name: ${nameCheck.errors.join('; ')}`);
60
- }
61
- const endpointCheck = validateEndpoint(endpointRaw);
62
- if (!endpointCheck.isValid) {
63
- throw usage(`invalid --endpoint: ${endpointCheck.errors.join('; ')}`);
64
- }
65
- if (authEnvVar !== undefined) {
66
- const envCheck = validateEnvVarName(authEnvVar);
67
- if (!envCheck.isValid) {
68
- throw usage(`invalid --auth-env: ${envCheck.errors.join('; ')}`);
69
- }
70
- }
71
- const endpoint = normalizeEndpoint(endpointRaw);
72
- const scope = resolveRegisterScope(scopeInput);
73
- if (scope === 'project')
74
- ensureProjectScopeRoot();
75
- ensureScopeInitialized(scope, requireScopeRoot(scope));
76
- // ---- Resolve any existing same-scope registration (idempotent / conflict) ----
77
- const existing = readConfig(scope).configuredClis[name];
78
- let unchanged = false;
79
- if (existing !== undefined) {
80
- const sameEndpoint = normalizeEndpoint(existing.endpoint) === endpoint;
81
- const sameAuth = (existing.authEnvVar ?? undefined) === (authEnvVar ?? undefined);
82
- if (sameEndpoint && sameAuth) {
83
- unchanged = true; // idempotent record — still re-fetch below
84
- }
85
- else {
86
- throw usage(`configured CLI "${name}" already registered in ${scope} scope with ` +
87
- `endpoint=${existing.endpoint}` +
88
- `${existing.authEnvVar !== undefined ? ` auth-env=${existing.authEnvVar}` : ' (no auth-env)'}. ` +
89
- `Run \`crtr pkg cli remove ${name} --scope ${scope}\` first to change it.`);
90
- }
91
- }
92
- // ---- Auth-env precondition: a named-but-unset var fails usage before any
93
- // fetch AND before any config write (a usage error mutates nothing). ----
94
- if (authEnvVar !== undefined && !process.env[authEnvVar]) {
95
- throw usage(`auth env var "${authEnvVar}" is required but not set or empty — export it before registering. ` +
96
- `crtr never prompts, mints, or refreshes a token.`);
97
- }
98
- // ---- Record the registration (skip the write when byte-identical) ----
99
- if (!unchanged) {
100
- updateConfig(scope, (cfg) => {
101
- cfg.configuredClis[name] = {
102
- endpoint,
103
- ...(authEnvVar !== undefined ? { authEnvVar } : {}),
104
- };
105
- });
106
- }
107
- const registration = resolveConfiguredCli(name, scope);
108
- // ---- One authenticated fetch-and-store (register always fetches) ----
109
- const result = await registerFetchConfiguredCli(registration);
110
- if (result.status !== 200) {
111
- if (result.status === 'auth_env_missing') {
112
- // Precondition re-check above should have caught this; fail loud.
113
- throw usage(result.message);
114
- }
115
- // Network / non-2xx: registration stands, prior manifest preserved,
116
- // exit success with a one-line stderr diagnostic + refresh remedy.
117
- process.stderr.write(`crtr: configured CLI "${registration.name}": ${result.message}\n`);
118
- process.stderr.write(`next: run \`crtr pkg cli refresh ${registration.name}\` once the endpoint is reachable\n`);
119
- }
120
- return {
121
- name: registration.name,
122
- endpoint: registration.endpoint,
123
- ...(registration.authEnvVar !== undefined ? { auth_env: registration.authEnvVar } : {}),
124
- scope: registration.scope,
125
- manifest_state: configuredCliManifestState(registration),
126
- ...(unchanged ? { unchanged: true } : {}),
127
- };
128
- },
129
- });
130
- export const cliRemove = defineLeaf({
131
- name: 'remove',
132
- description: 'remove a configured CLI registration and its stored manifest',
133
- whenToUse: 'deregistering a configured CLI: deletes its config entry and its stored manifest directory. Takes effect on the next invocation with no restart',
134
- help: {
135
- name: 'pkg cli remove',
136
- summary: 'remove a configured CLI registration and its stored manifest',
137
- params: [
138
- { kind: 'positional', name: 'name', type: 'string', required: true, constraint: 'Registration name to remove.' },
139
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'Narrows resolution. Default: the effective registration (project outranks user).' },
140
- ],
141
- output: [
142
- { name: 'removed', type: 'boolean', required: true, constraint: 'Always true (a miss throws not_found).' },
143
- { name: 'name', type: 'string', required: true, constraint: 'Registration name removed.' },
144
- { name: 'scope', type: 'string', required: true, constraint: 'Scope the registration was removed from.' },
145
- ],
146
- outputKind: 'object',
147
- effects: ['Deletes configuredClis.<name> from the scope config.json, then removes <scopeRoot>/configured-clis/<name>/. Config is authoritative — removed first.'],
148
- },
149
- run: async (input) => {
150
- const name = input['name'];
151
- const scopeInput = input['scope'];
152
- const scope = scopeInput !== undefined ? resolveScopeArg(scopeInput) : undefined;
153
- const registration = resolveConfiguredCli(name, scope);
154
- if (registration === null) {
155
- throw notFound(`configured CLI not found: ${name}`);
156
- }
157
- // Config is authoritative: delete the entry first so a crash between steps
158
- // can only leave an inert orphan store, never an active registration that
159
- // reported removed.
160
- updateConfig(registration.scope, (cfg) => {
161
- delete cfg.configuredClis[name];
162
- });
163
- removeConfiguredCliCache(registration);
164
- return { removed: true, name: registration.name, scope: registration.scope };
165
- },
166
- });
167
- export const cliRefresh = defineLeaf({
168
- name: 'refresh',
169
- description: 'refetch and replace a configured CLI manifest',
170
- whenToUse: 'pulling a backend manifest change into an already-stored CLI: unconditionally refetches and replaces the stored manifest, then reports the accepted command surface and issues. The only way to update a stored manifest short of a re-register',
171
- help: {
172
- name: 'pkg cli refresh',
173
- summary: 'refetch and replace a configured CLI manifest, report the surface',
174
- params: [
175
- { kind: 'positional', name: 'name', type: 'string', required: true, constraint: 'Registration name to refresh.' },
176
- { kind: 'flag', name: 'scope', type: 'enum', choices: ['user', 'project'], required: false, constraint: 'Narrows resolution. Default: the effective registration (project outranks user).' },
177
- ],
178
- output: [
179
- { name: 'name', type: 'string', required: true, constraint: 'Registration name.' },
180
- { name: 'scope', type: 'string', required: true, constraint: 'Scope the registration lives in.' },
181
- { name: 'endpoint', type: 'string', required: true, constraint: 'Resolved manifest endpoint URL.' },
182
- { name: 'manifest_state', type: 'string', required: true, constraint: '"stored" after a successful refresh.' },
183
- { name: 'commands', type: 'object[]', required: true, constraint: 'Every accepted command after the refresh. Each: {command, paths}. Empty when the new manifest is invalid or collided.' },
184
- { name: 'issues', type: 'object[]', required: true, constraint: 'Every current validation/collision issue. Each: {code, path?, message, received, expected, next}.' },
185
- ],
186
- outputKind: 'object',
187
- effects: [
188
- 'Performs one unconditional authenticated GET of the endpoint and replaces the stored manifest with the returned bytes on success.',
189
- 'On failure (network / non-2xx / named-but-unset auth env) it fails loud and KEEPS the previously stored manifest — the command still composes from it.',
190
- ],
191
- },
192
- run: async (input) => {
193
- const name = input['name'];
194
- const scopeInput = input['scope'];
195
- const scope = scopeInput !== undefined ? resolveScopeArg(scopeInput) : undefined;
196
- const registration = resolveConfiguredCli(name, scope);
197
- if (registration === null) {
198
- throw notFound(`configured CLI not found: ${name}`);
199
- }
200
- // Unconditional fetch-and-replace. Throws on failure (auth→usage,
201
- // unreachable→network, protocol→general), preserving the old manifest.
202
- await refreshConfiguredCli(registration);
203
- const snapshot = buildExternalCommandSnapshot(new Set(SUBTREE_NAMES));
204
- return configuredCliReport(registration, snapshot);
205
- },
206
- });
@@ -1 +0,0 @@
1
- export declare const cliBranch: import("../../core/command.js").BranchDef;
@@ -1,14 +0,0 @@
1
- import { defineBranch } from '../../core/command.js';
2
- import { cliRegister, cliRemove, cliRefresh } from './cli-manage.js';
3
- import { cliList, cliShow } from './cli-inspect.js';
4
- export const cliBranch = defineBranch({
5
- name: 'cli',
6
- description: 'register and manage configured CLIs',
7
- whenToUse: 'working with configured CLIs: a command surface whose tree is defined by a remote manifest and executed as declarative HTTP (definition + HTTP, never remote code). Register one against a manifest endpoint, remove, list, show, or refresh it. Use `pkg plugin` for local plugins that ship an executable, and `pkg market` for marketplace sources.',
8
- help: {
9
- name: 'pkg cli',
10
- summary: 'configured-CLI lifecycle and inspection',
11
- model: 'A configured CLI is the CLI analogue of an MCP client: crtr fetches a manifest (an extension of the command-plugin schema) from a remote endpoint, stores it locally, renders native -h help from it, and runs each leaf as a declarative REST call. No remote code — the trust surface is definition + HTTP. Registration records {name, endpoint, auth-env NAME} in scope config and stores the fetched manifest; the credential itself is never stored. The stored manifest is authoritative with zero freshness checks — it reloads only on a re-register or an explicit refresh.',
12
- },
13
- children: [cliRegister, cliRemove, cliList, cliShow, cliRefresh],
14
- });