@north-light/api 0.0.0 → 0.3.414

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 (247) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +66 -2
  3. package/dist/api/__tests__/error-codes.test.d.ts +1 -0
  4. package/dist/api/__tests__/error-codes.test.js +79 -0
  5. package/dist/api/__tests__/integration/client.test.d.ts +1 -0
  6. package/dist/api/__tests__/integration/client.test.js +276 -0
  7. package/dist/api/client.d.ts +501 -0
  8. package/dist/api/client.js +1281 -0
  9. package/dist/api/command-manifest/index.d.ts +3 -0
  10. package/dist/api/command-manifest/index.js +3 -0
  11. package/dist/api/command-manifest/manifest.d.ts +51 -0
  12. package/dist/api/command-manifest/manifest.js +332 -0
  13. package/dist/api/command-manifest/result.d.ts +25 -0
  14. package/dist/api/command-manifest/result.js +97 -0
  15. package/dist/api/command-manifest/schema.d.ts +28 -0
  16. package/dist/api/command-manifest/schema.js +856 -0
  17. package/dist/api/dto/analytics.d.ts +184 -0
  18. package/dist/api/dto/analytics.js +3 -0
  19. package/dist/api/dto/attach.d.ts +22 -0
  20. package/dist/api/dto/attach.js +13 -0
  21. package/dist/api/dto/bash-jobs.d.ts +24 -0
  22. package/dist/api/dto/bash-jobs.js +9 -0
  23. package/dist/api/dto/bash.d.ts +17 -0
  24. package/dist/api/dto/bash.js +1 -0
  25. package/dist/api/dto/broker-ops.d.ts +187 -0
  26. package/dist/api/dto/broker-ops.js +6 -0
  27. package/dist/api/dto/broker-signals.d.ts +25 -0
  28. package/dist/api/dto/broker-signals.js +1 -0
  29. package/dist/api/dto/broker.d.ts +86 -0
  30. package/dist/api/dto/broker.js +20 -0
  31. package/dist/api/dto/canvas.d.ts +359 -0
  32. package/dist/api/dto/canvas.js +2 -0
  33. package/dist/api/dto/chat-inventory.d.ts +56 -0
  34. package/dist/api/dto/chat-inventory.js +11 -0
  35. package/dist/api/dto/common.d.ts +29 -0
  36. package/dist/api/dto/common.js +15 -0
  37. package/dist/api/dto/config.d.ts +46 -0
  38. package/dist/api/dto/config.js +3 -0
  39. package/dist/api/dto/crons.d.ts +158 -0
  40. package/dist/api/dto/crons.js +10 -0
  41. package/dist/api/dto/custom-objects.d.ts +66 -0
  42. package/dist/api/dto/custom-objects.js +1 -0
  43. package/dist/api/dto/delivery.d.ts +71 -0
  44. package/dist/api/dto/delivery.js +7 -0
  45. package/dist/api/dto/docs.d.ts +135 -0
  46. package/dist/api/dto/docs.js +8 -0
  47. package/dist/api/dto/files.d.ts +21 -0
  48. package/dist/api/dto/files.js +1 -0
  49. package/dist/api/dto/focus.d.ts +24 -0
  50. package/dist/api/dto/focus.js +10 -0
  51. package/dist/api/dto/grants.d.ts +28 -0
  52. package/dist/api/dto/grants.js +1 -0
  53. package/dist/api/dto/health.d.ts +116 -0
  54. package/dist/api/dto/health.js +2 -0
  55. package/dist/api/dto/human-requests.d.ts +113 -0
  56. package/dist/api/dto/human-requests.js +4 -0
  57. package/dist/api/dto/human.d.ts +28 -0
  58. package/dist/api/dto/human.js +4 -0
  59. package/dist/api/dto/inbox.d.ts +273 -0
  60. package/dist/api/dto/inbox.js +4 -0
  61. package/dist/api/dto/lifecycle.d.ts +88 -0
  62. package/dist/api/dto/lifecycle.js +3 -0
  63. package/dist/api/dto/limits.d.ts +29 -0
  64. package/dist/api/dto/limits.js +2 -0
  65. package/dist/api/dto/mail.d.ts +44 -0
  66. package/dist/api/dto/mail.js +1 -0
  67. package/dist/api/dto/messages.d.ts +104 -0
  68. package/dist/api/dto/messages.js +2 -0
  69. package/dist/api/dto/model-config.d.ts +25 -0
  70. package/dist/api/dto/model-config.js +1 -0
  71. package/dist/api/dto/modelauth.d.ts +132 -0
  72. package/dist/api/dto/modelauth.js +4 -0
  73. package/dist/api/dto/node-events.d.ts +65 -0
  74. package/dist/api/dto/node-events.js +4 -0
  75. package/dist/api/dto/node-outcomes.d.ts +88 -0
  76. package/dist/api/dto/node-outcomes.js +2 -0
  77. package/dist/api/dto/node-records.d.ts +35 -0
  78. package/dist/api/dto/node-records.js +5 -0
  79. package/dist/api/dto/nodes.d.ts +371 -0
  80. package/dist/api/dto/nodes.js +3 -0
  81. package/dist/api/dto/objects.d.ts +172 -0
  82. package/dist/api/dto/objects.js +5 -0
  83. package/dist/api/dto/profiles.d.ts +117 -0
  84. package/dist/api/dto/profiles.js +4 -0
  85. package/dist/api/dto/recovery.d.ts +104 -0
  86. package/dist/api/dto/recovery.js +1 -0
  87. package/dist/api/dto/reports.d.ts +95 -0
  88. package/dist/api/dto/reports.js +2 -0
  89. package/dist/api/dto/review-comments.d.ts +146 -0
  90. package/dist/api/dto/review-comments.js +5 -0
  91. package/dist/api/dto/reviews.d.ts +113 -0
  92. package/dist/api/dto/reviews.js +5 -0
  93. package/dist/api/dto/run-events.d.ts +295 -0
  94. package/dist/api/dto/run-events.js +6 -0
  95. package/dist/api/dto/structured-requests.d.ts +64 -0
  96. package/dist/api/dto/structured-requests.js +5 -0
  97. package/dist/api/dto/subscriptions.d.ts +14 -0
  98. package/dist/api/dto/subscriptions.js +2 -0
  99. package/dist/api/dto/worktree.d.ts +55 -0
  100. package/dist/api/dto/worktree.js +6 -0
  101. package/dist/api/error-codes.d.ts +259 -0
  102. package/dist/api/error-codes.js +56 -0
  103. package/dist/api/errors.d.ts +47 -0
  104. package/dist/api/errors.js +66 -0
  105. package/dist/api/index.d.ts +48 -0
  106. package/dist/api/index.js +45 -0
  107. package/dist/api/long-poll.d.ts +59 -0
  108. package/dist/api/long-poll.js +67 -0
  109. package/dist/api/node-transport.d.ts +18 -0
  110. package/dist/api/node-transport.js +105 -0
  111. package/dist/api/plugin-manifest-schema.d.ts +233 -0
  112. package/dist/api/plugin-manifest-schema.js +23 -0
  113. package/dist/api/routes.d.ts +164 -0
  114. package/dist/api/routes.js +197 -0
  115. package/dist/api/runtime-version.d.ts +31 -0
  116. package/dist/api/runtime-version.js +50 -0
  117. package/dist/core/asset-root.d.ts +7 -0
  118. package/dist/core/asset-root.js +18 -0
  119. package/dist/core/canvas/boot-id.d.ts +6 -0
  120. package/dist/core/canvas/boot-id.js +26 -0
  121. package/dist/core/canvas/paths.d.ts +72 -0
  122. package/dist/core/canvas/paths.js +163 -0
  123. package/dist/core/canvas/pid.d.ts +391 -0
  124. package/dist/core/canvas/pid.js +948 -0
  125. package/dist/core/command-plugins/bundle.d.ts +149 -0
  126. package/dist/core/command-plugins/bundle.js +588 -0
  127. package/dist/core/command-plugins/endpoint.d.ts +24 -0
  128. package/dist/core/command-plugins/endpoint.js +51 -0
  129. package/dist/core/config.d.ts +233 -0
  130. package/dist/core/config.js +1120 -0
  131. package/dist/core/env-name.d.ts +6 -0
  132. package/dist/core/env-name.js +9 -0
  133. package/dist/core/errors.d.ts +38 -0
  134. package/dist/core/errors.js +90 -0
  135. package/dist/core/events/emit.d.ts +6 -0
  136. package/dist/core/events/emit.js +42 -0
  137. package/dist/core/events/envelope.d.ts +2 -0
  138. package/dist/core/events/envelope.js +84 -0
  139. package/dist/core/events/errors.d.ts +4 -0
  140. package/dist/core/events/errors.js +69 -0
  141. package/dist/core/events/operation-id.d.ts +4 -0
  142. package/dist/core/events/operation-id.js +24 -0
  143. package/dist/core/events/serialize.d.ts +4 -0
  144. package/dist/core/events/serialize.js +199 -0
  145. package/dist/core/events/source.d.ts +16 -0
  146. package/dist/core/events/source.js +31 -0
  147. package/dist/core/events/types.d.ts +68 -0
  148. package/dist/core/events/types.js +11 -0
  149. package/dist/core/exclusive-lock.d.ts +34 -0
  150. package/dist/core/exclusive-lock.js +197 -0
  151. package/dist/core/fs-utils.d.ts +44 -0
  152. package/dist/core/fs-utils.js +208 -0
  153. package/dist/core/help.d.ts +309 -0
  154. package/dist/core/help.js +406 -0
  155. package/dist/core/human/page-catalog.d.ts +57 -0
  156. package/dist/core/human/page-catalog.js +172 -0
  157. package/dist/core/installed-plugins.d.ts +2 -0
  158. package/dist/core/installed-plugins.js +79 -0
  159. package/dist/core/io.d.ts +122 -0
  160. package/dist/core/io.js +373 -0
  161. package/dist/core/keybindings/attach-control.d.ts +49 -0
  162. package/dist/core/keybindings/attach-control.js +42 -0
  163. package/dist/core/keybindings/catalog.d.ts +18 -0
  164. package/dist/core/keybindings/catalog.js +257 -0
  165. package/dist/core/keybindings/types.d.ts +42 -0
  166. package/dist/core/keybindings/types.js +1 -0
  167. package/dist/core/layout.d.ts +34 -0
  168. package/dist/core/layout.js +106 -0
  169. package/dist/core/locked-file.d.ts +27 -0
  170. package/dist/core/locked-file.js +118 -0
  171. package/dist/core/log.d.ts +9 -0
  172. package/dist/core/log.js +89 -0
  173. package/dist/core/manifest.d.ts +5 -0
  174. package/dist/core/manifest.js +15 -0
  175. package/dist/core/plugin-env.d.ts +8 -0
  176. package/dist/core/plugin-env.js +31 -0
  177. package/dist/core/plugin-extensions.d.ts +29 -0
  178. package/dist/core/plugin-extensions.js +191 -0
  179. package/dist/core/plugin-swap-lock.d.ts +9 -0
  180. package/dist/core/plugin-swap-lock.js +31 -0
  181. package/dist/core/preview-result-path.d.ts +4 -0
  182. package/dist/core/preview-result-path.js +26 -0
  183. package/dist/core/profiles/env-store.d.ts +22 -0
  184. package/dist/core/profiles/env-store.js +163 -0
  185. package/dist/core/profiles/fuzzy-match.d.ts +19 -0
  186. package/dist/core/profiles/fuzzy-match.js +92 -0
  187. package/dist/core/profiles/manifest.d.ts +120 -0
  188. package/dist/core/profiles/manifest.js +529 -0
  189. package/dist/core/rate-limit-scope.d.ts +25 -0
  190. package/dist/core/rate-limit-scope.js +64 -0
  191. package/dist/core/render.d.ts +12 -0
  192. package/dist/core/render.js +138 -0
  193. package/dist/core/resolver.d.ts +14 -0
  194. package/dist/core/resolver.js +111 -0
  195. package/dist/core/runtime/branded-host.d.ts +55 -0
  196. package/dist/core/runtime/branded-host.js +485 -0
  197. package/dist/core/runtime/broker/daemon-ops.d.ts +65 -0
  198. package/dist/core/runtime/broker/daemon-ops.js +177 -0
  199. package/dist/core/runtime/broker/signal-stream.d.ts +30 -0
  200. package/dist/core/runtime/broker/signal-stream.js +149 -0
  201. package/dist/core/scope.d.ts +32 -0
  202. package/dist/core/scope.js +184 -0
  203. package/dist/core/scoped-state/db.d.ts +17 -0
  204. package/dist/core/scoped-state/db.js +247 -0
  205. package/dist/core/scoped-state/migrate.d.ts +8 -0
  206. package/dist/core/scoped-state/migrate.js +187 -0
  207. package/dist/core/scoped-state/paths.d.ts +9 -0
  208. package/dist/core/scoped-state/paths.js +27 -0
  209. package/dist/core/scoped-state/profiles.d.ts +27 -0
  210. package/dist/core/scoped-state/profiles.js +93 -0
  211. package/dist/core/scoped-state/providers.d.ts +24 -0
  212. package/dist/core/scoped-state/providers.js +19 -0
  213. package/dist/core/scoped-state/schema.d.ts +6 -0
  214. package/dist/core/scoped-state/schema.js +43 -0
  215. package/dist/core/scoped-state/settings.d.ts +28 -0
  216. package/dist/core/scoped-state/settings.js +83 -0
  217. package/dist/core/spaces/open-beneath.d.ts +71 -0
  218. package/dist/core/spaces/open-beneath.js +581 -0
  219. package/dist/core/sqlite-statements.d.ts +4 -0
  220. package/dist/core/sqlite-statements.js +17 -0
  221. package/dist/core/subscription-state.d.ts +121 -0
  222. package/dist/core/subscription-state.js +287 -0
  223. package/dist/core/user-settings.d.ts +377 -0
  224. package/dist/core/user-settings.js +458 -0
  225. package/dist/daemon/broker-signals/bus.d.ts +30 -0
  226. package/dist/daemon/broker-signals/bus.js +87 -0
  227. package/dist/daemon/manage.d.ts +176 -0
  228. package/dist/daemon/manage.js +664 -0
  229. package/dist/daemon/pidfile.d.ts +8 -0
  230. package/dist/daemon/pidfile.js +37 -0
  231. package/dist/daemon/startup-policy.d.ts +1 -0
  232. package/dist/daemon/startup-policy.js +1 -0
  233. package/dist/native/linux.d.ts +29 -0
  234. package/dist/native/linux.js +20 -0
  235. package/dist/shared/env.d.ts +116 -0
  236. package/dist/shared/env.js +271 -0
  237. package/dist/shared/generated-context.d.ts +83 -0
  238. package/dist/shared/generated-context.js +235 -0
  239. package/dist/shared/inbox-entry-body.d.ts +22 -0
  240. package/dist/shared/inbox-entry-body.js +116 -0
  241. package/dist/shared/predicates.d.ts +2 -0
  242. package/dist/shared/predicates.js +4 -0
  243. package/dist/shared/working-activity.d.ts +9 -0
  244. package/dist/shared/working-activity.js +27 -0
  245. package/dist/types.d.ts +562 -0
  246. package/dist/types.js +186 -0
  247. package/package.json +46 -5
@@ -0,0 +1,138 @@
1
+ // Default stdout rendering: the result a leaf returns is written FOR the model
2
+ // to act on, not as data to parse. Output is a continuation of the agent's
3
+ // prompt — PLAIN MARKDOWN, no XML wrapper. Scalars list as `- name: value`
4
+ // bullets in output-schema order, prose fields render as paragraphs, and arrays
5
+ // become a count lead-in plus a markdown table (objects) or bullets (scalars).
6
+ // The raw JSON object is still available behind the `--json` global for tooling.
7
+ //
8
+ // A leaf may hand `defineLeaf` a bespoke `render(result)` for instruction-shaped
9
+ // output that leads with the outcome (see `node new`, `push`).
10
+ // Everything else falls through to the schema-driven generic renderer here, so
11
+ // every command obeys the markdown paradigm without a hand-written renderer.
12
+ // `renderError` is the one sanctioned exception: a failure is a different domain
13
+ // from a result, so it keeps its `<error>` block.
14
+ // Field names whose value is prose the agent reads, not a scalar it keys on —
15
+ // these always render as their own paragraph, never as a `- name: value` bullet.
16
+ const PROSE_FIELDS = new Set([
17
+ 'follow_up', 'digest', 'message', 'next', 'result', 'content', 'body', 'guide',
18
+ 'summary', 'note', 'reason', 'detail', 'details', 'hint', 'instruction',
19
+ 'instructions', 'prompt', 'roadmap', 'report', 'answer', 'response', 'text',
20
+ ]);
21
+ /** Minimal attribute-value sanitization: values here are controlled (ids,
22
+ * statuses, counts), so collapse quotes rather than entity-escape. */
23
+ function attrEsc(s) {
24
+ return String(s).replace(/"/g, "'").replace(/\n/g, ' ');
25
+ }
26
+ function scalarStr(v) {
27
+ if (v === null || v === undefined)
28
+ return '';
29
+ if (Array.isArray(v))
30
+ return v.map(scalarStr).join(', ');
31
+ if (typeof v === 'object')
32
+ return JSON.stringify(v);
33
+ return String(v);
34
+ }
35
+ function fencedJson(value) {
36
+ const json = JSON.stringify(value, null, 2);
37
+ let fence = '```';
38
+ while (json.includes(fence))
39
+ fence += '`';
40
+ return `${fence}json\n${json}\n${fence}`;
41
+ }
42
+ /** A string field is prose when it is named as such, spans lines, or is long
43
+ * enough that it reads as a sentence rather than an identifier. */
44
+ function isProse(name, v) {
45
+ if (typeof v !== 'string')
46
+ return false;
47
+ if (PROSE_FIELDS.has(name))
48
+ return true;
49
+ return v.includes('\n') || v.length > 80;
50
+ }
51
+ /** Keep a value safe inside a markdown table cell: pipes would split columns,
52
+ * newlines would break the row. */
53
+ function cellEsc(v) {
54
+ return scalarStr(v).replace(/\|/g, '\\|').replace(/\n/g, ' ');
55
+ }
56
+ /** An array renders as a count lead-in followed by the collection: a markdown
57
+ * table when every element is an object, plain bullets otherwise. */
58
+ function renderArray(name, arr) {
59
+ if (arr.length === 0)
60
+ return `0 ${name}.`;
61
+ const lead = `${arr.length} ${name}:`;
62
+ const allObjects = arr.every((x) => x !== null && typeof x === 'object' && !Array.isArray(x));
63
+ if (allObjects) {
64
+ const rows = arr;
65
+ const cols = [];
66
+ for (const r of rows)
67
+ for (const k of Object.keys(r))
68
+ if (!cols.includes(k))
69
+ cols.push(k);
70
+ const head = `| ${cols.join(' | ')} |`;
71
+ const sep = `| ${cols.map(() => '---').join(' | ')} |`;
72
+ const body = rows.map((r) => `| ${cols.map((c) => cellEsc(r[c])).join(' | ')} |`).join('\n');
73
+ return `${lead}\n\n${head}\n${sep}\n${body}`;
74
+ }
75
+ const items = arr.map((x) => `- ${scalarStr(x)}`).join('\n');
76
+ return `${lead}\n${items}`;
77
+ }
78
+ /** Schema-driven fallback: turn a result object into agent-ready plain markdown.
79
+ * Field order follows the leaf's declared output schema; any extra keys append
80
+ * after. Scalars (and nested objects) list as `- name: value` bullets, prose
81
+ * fields render as paragraphs, and arrays become a count lead-in plus a table
82
+ * or bullets. No root tag — the result is read as a continuation of the prompt. */
83
+ export function renderResult(result, help) {
84
+ const order = help.output.map((f) => f.name);
85
+ for (const k of Object.keys(result))
86
+ if (!order.includes(k))
87
+ order.push(k);
88
+ const bullets = [];
89
+ const proseFields = [];
90
+ const arrays = [];
91
+ for (const name of order) {
92
+ const v = result[name];
93
+ if (v === undefined || v === null)
94
+ continue;
95
+ if (Array.isArray(v)) {
96
+ arrays.push(renderArray(name, v));
97
+ continue;
98
+ }
99
+ if (isProse(name, v)) {
100
+ proseFields.push({ name, text: v });
101
+ continue;
102
+ }
103
+ // Scalars and nested objects alike list as a bullet (objects via compact JSON).
104
+ bullets.push(`- ${name}: ${scalarStr(v)}`);
105
+ }
106
+ const parts = [];
107
+ if (bullets.length > 0)
108
+ parts.push(bullets.join('\n'));
109
+ // Label prose only when more than one block would otherwise blur together.
110
+ const labelProse = proseFields.length > 1;
111
+ for (const { name, text } of proseFields) {
112
+ parts.push(labelProse ? `**${name}:** ${text}` : text);
113
+ }
114
+ for (const block of arrays)
115
+ parts.push(block);
116
+ return parts.join('\n\n');
117
+ }
118
+ /** Render a structured failure as an instruction-shaped block: what broke, what
119
+ * was received, and the recovery road sign — the same recovery info the JSON
120
+ * payload carries, shaped for the model to act on. */
121
+ export function renderError(p) {
122
+ const lines = [p.message];
123
+ if (p.received !== undefined && p.received !== null && p.received !== '') {
124
+ lines.push(`received: ${scalarStr(p.received)}`);
125
+ }
126
+ if (p.field !== undefined)
127
+ lines.push(`field: ${p.field}`);
128
+ // Its own labeled line: a transport status is a fact about the call, not about
129
+ // the value the caller supplied.
130
+ if (p.http_status !== undefined)
131
+ lines.push(`http status: ${p.http_status}`);
132
+ if ('primaryCompleted' in p && p.primaryCompleted === true) {
133
+ lines.push('primaryCompleted: true');
134
+ lines.push(`Primary result (the command already completed):\n${fencedJson(p.result)}`);
135
+ }
136
+ lines.push(`Next: ${p.next}`);
137
+ return `<error code="${attrEsc(p.error)}">\n${lines.join('\n')}\n</error>`;
138
+ }
@@ -0,0 +1,14 @@
1
+ import type { InstalledMarketplace, InstalledPlugin, Scope } from '../types.js';
2
+ export { listInstalledPluginsInRoot } from './installed-plugins.js';
3
+ export declare function listInstalledPlugins(scope: Scope): InstalledPlugin[];
4
+ export declare function listAllPlugins(): InstalledPlugin[];
5
+ export declare function findPluginByName(name: string, scope?: Scope): InstalledPlugin | null;
6
+ export interface ParsedSkillQualifier {
7
+ scope?: Scope;
8
+ segments: string[];
9
+ }
10
+ export declare function parseSkillQualifier(raw: string): ParsedSkillQualifier;
11
+ export declare function listInstalledMarketplaces(scope: Exclude<Scope, 'builtin'>): InstalledMarketplace[];
12
+ export declare function listAllMarketplaces(): InstalledMarketplace[];
13
+ export declare function findMarketplaceByName(name: string, scope?: Exclude<Scope, 'builtin'>): InstalledMarketplace | null;
14
+ export declare function scopeRootsLabel(): string;
@@ -0,0 +1,111 @@
1
+ import { join } from 'node:path';
2
+ import { readConfig } from './config.js';
3
+ import { listDirs, pathExists } from './fs-utils.js';
4
+ import { readMarketplaceManifest } from './manifest.js';
5
+ import { InputError } from './io.js';
6
+ import { marketplacesDir, projectScopeRoot, scopeRoot, userScopeRoot, } from './scope.js';
7
+ // Moved to installed-plugins.ts (a leaf module below config.ts) so
8
+ // `readMergedLaunchConfig` can layer plugin-declared kinds without an import
9
+ // cycle; re-exported here for this module's existing callers.
10
+ export { listInstalledPluginsInRoot } from './installed-plugins.js';
11
+ import { listInstalledPluginsInRoot } from './installed-plugins.js';
12
+ export function listInstalledPlugins(scope) {
13
+ // The builtin scope has no scopeRoot, so this returns [] — builtin content is
14
+ // the shipped documents, not plugins.
15
+ const root = scopeRoot(scope);
16
+ if (!root)
17
+ return [];
18
+ return listInstalledPluginsInRoot(scope, root);
19
+ }
20
+ export function listAllPlugins() {
21
+ const scopes = [];
22
+ if (projectScopeRoot())
23
+ scopes.push('project');
24
+ scopes.push('user');
25
+ scopes.push('builtin');
26
+ return scopes.flatMap(listInstalledPlugins);
27
+ }
28
+ export function findPluginByName(name, scope) {
29
+ if (scope) {
30
+ return listInstalledPlugins(scope).find((p) => p.name === name) ?? null;
31
+ }
32
+ for (const s of ['project', 'user', 'builtin'].filter((sc) => sc === 'project' ? projectScopeRoot() !== null : true)) {
33
+ const match = listInstalledPlugins(s).find((p) => p.name === name);
34
+ if (match)
35
+ return match;
36
+ }
37
+ return null;
38
+ }
39
+ const SCOPE_QUALIFIERS = new Set(['user', 'project']);
40
+ // Accepted identifier forms:
41
+ // <name> — bare name; scope-root first, then plugins
42
+ // <plugin>/<name> — explicit plugin (plugin may contain slashes)
43
+ // <scope>/<name> — scope-root in a specific scope
44
+ // <scope>/<plugin>/<name> — fully qualified
45
+ export function parseSkillQualifier(raw) {
46
+ if (raw.includes(':')) {
47
+ const suggested = raw.replace(/:/g, '/');
48
+ throw new InputError({
49
+ error: 'invalid_qualifier',
50
+ message: "mixed separators ':' and '/' no longer supported; use slashes throughout",
51
+ received: raw,
52
+ field: 'name',
53
+ next: `Use ${suggested}.`,
54
+ });
55
+ }
56
+ const segments = raw.split('/');
57
+ if (SCOPE_QUALIFIERS.has(segments[0])) {
58
+ const scope = segments[0];
59
+ return { scope, segments: segments.slice(1) };
60
+ }
61
+ return { segments };
62
+ }
63
+ export function listInstalledMarketplaces(scope) {
64
+ const dir = marketplacesDir(scope);
65
+ if (!dir || !pathExists(dir))
66
+ return [];
67
+ const cfg = readConfig(scope);
68
+ const out = [];
69
+ for (const name of listDirs(dir)) {
70
+ const root = join(dir, name);
71
+ const manifest = readMarketplaceManifest(root);
72
+ if (!manifest)
73
+ continue;
74
+ const entry = cfg.marketplaces[name];
75
+ const url = entry && entry.url !== undefined ? entry.url : '';
76
+ const ref = entry && entry.ref !== undefined ? entry.ref : 'main';
77
+ out.push({
78
+ name,
79
+ scope,
80
+ root,
81
+ manifest,
82
+ url,
83
+ ref,
84
+ });
85
+ }
86
+ return out;
87
+ }
88
+ export function listAllMarketplaces() {
89
+ const scopes = [];
90
+ if (projectScopeRoot())
91
+ scopes.push('project');
92
+ scopes.push('user');
93
+ return scopes.flatMap(listInstalledMarketplaces);
94
+ }
95
+ export function findMarketplaceByName(name, scope) {
96
+ if (scope) {
97
+ return listInstalledMarketplaces(scope).find((m) => m.name === name) ?? null;
98
+ }
99
+ for (const s of ['project', 'user']) {
100
+ if (s === 'project' && !projectScopeRoot())
101
+ continue;
102
+ const found = listInstalledMarketplaces(s).find((m) => m.name === name);
103
+ if (found)
104
+ return found;
105
+ }
106
+ return null;
107
+ }
108
+ export function scopeRootsLabel() {
109
+ const proj = projectScopeRoot();
110
+ return proj ? `project=${proj}, user=${userScopeRoot()}` : `user=${userScopeRoot()}`;
111
+ }
@@ -0,0 +1,55 @@
1
+ /** Machine-global host dir in this process owner’s HOME. Only the daemon reconciles it; agents do not install the branded host. Deliberately NOT under `CRTR_HOME` (tests override
2
+ * that to an isolated temp): the branded binary is a per-machine artifact keyed
3
+ * to the installed node, shared across every canvas home. */
4
+ export declare function brandedHostDir(): string;
5
+ export declare function brandedHostBin(): string;
6
+ /** macOS keys FDA grants on the Mach-O cdhash. A real developer identity
7
+ * keeps that hash stable across branded-host rebuilds; ad-hoc signing is the
8
+ * portable default for machines without a local signing certificate. */
9
+ export declare function codesignIdentitiesForBrandedHost(opts?: {
10
+ configured?: string | null;
11
+ discovered?: string | null;
12
+ }): string[];
13
+ export declare function signBrandedHostArtifacts(binPath: string, libnodePath: string | null, sign?: (path: string) => void): void;
14
+ export declare function brandedHostWorks(binPath: string, timeoutMs?: number): boolean;
15
+ /** Ensure the branded host binary exists and matches the live node; return its
16
+ * absolute path. Idempotent and self-healing. Throws on a genuine build failure
17
+ * (disk full / permissions); hostExecPath() turns that into a logged fallback to
18
+ * a real node so a broken host never blocks launching. */
19
+ export declare function ensureBrandedHost(opts?: {
20
+ execPath?: string;
21
+ }): string;
22
+ /** Find a working, ABI-compatible, non-branded `node` to rebuild from. Blocking:
23
+ * for CLI / explicit reconcile only, never the daemon's event loop (use
24
+ * findRealNodeAsync there). Returns null when none works. */
25
+ export declare function findRealNode(): string | null;
26
+ /** Non-blocking findRealNode for the daemon's event loop. */
27
+ export declare function findRealNodeAsync(): Promise<string | null>;
28
+ /** Forget remembered host health (tests). */
29
+ export declare function resetBrandedHostHealthCache(): void;
30
+ /** The node to exec for a short-lived helper child (forked worker, bash
31
+ * supervisor, probe). Outside the branded host this is `process.execPath`
32
+ * untouched. Inside it, a host that no longer starts (dyld cannot resolve a
33
+ * moved Homebrew dependency) would abort every child, so a real node is used
34
+ * instead. Never blocks: it returns the last known answer and refreshes it in
35
+ * the background. A fork that still dies calls recheckChildNode() to learn the
36
+ * truth at once. */
37
+ export declare function childNodeExecPath(execPath?: string): string;
38
+ /** Re-probe the host now (after a child died) and return the node to retry on;
39
+ * equals `execPath` when the host is fine or no real node exists. */
40
+ export declare function recheckChildNode(execPath?: string): Promise<string>;
41
+ /** Like childNodeExecPath(), but first awaits a probe no older than `maxAgeMs`
42
+ * (coalesced with any probe in flight). Use it right before a fork whose death
43
+ * would lose work (a broker, a bash job, the inventory child) so a host broken
44
+ * since the last probe is caught before the exec, not after. The probe is a
45
+ * non-blocking `node -e ''`; outside the branded host this costs nothing. */
46
+ export declare function freshChildNodeExecPath(execPath?: string, maxAgeMs?: number): Promise<string>;
47
+ /** hostExecPath() for async launchers: inside the host it is verified fresh
48
+ * rather than taken from the cache. */
49
+ export declare function hostExecPathFresh(): Promise<string>;
50
+ /** The path the engine (broker / daemon) should be launched from. On macOS in a
51
+ * compiled (production) build this is the validated branded host; otherwise —
52
+ * non-darwin (TCC is macOS-only), source/tsx (dev + the test suite: never copy
53
+ * 70 MB into the real ~/.crouter), or the explicit `CRTR_BRANDED_HOST=0`
54
+ * opt-out — it is the live node. */
55
+ export declare function hostExecPath(): string;