@north-light/crouter 0.3.164 → 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.
- package/dist/build-root.d.ts +6 -6
- package/dist/build-root.js +12 -13
- package/dist/builtin-memory/00-runtime-base.md +3 -4
- package/dist/builtin-memory/01-spine/01-no-manager.md +1 -1
- package/dist/builtin-memory/02-lifecycle/00-terminal.md +2 -0
- package/dist/builtin-memory/04-orchestration-kernel.md +16 -18
- package/dist/builtin-memory/05-kinds/advisor/00-base.md +0 -2
- package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +3 -9
- package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -3
- package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +2 -10
- package/dist/builtin-memory/05-kinds/explore/00-base.md +2 -2
- package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +0 -2
- package/dist/builtin-memory/05-kinds/general/00-base.md +3 -5
- package/dist/builtin-memory/05-kinds/general/01-orchestrator.md +0 -4
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -3
- package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +12 -0
- package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +0 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +0 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +0 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +0 -2
- package/dist/builtin-memory/05-kinds/review/00-base.md +0 -2
- package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -3
- package/dist/builtin-memory/05-kinds/spec/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +2 -4
- package/dist/builtin-memory/05-kinds/spec/requirements.md +1 -1
- package/dist/builtin-memory/advisor/council.md +40 -0
- package/dist/builtin-memory/design.md +8 -11
- package/dist/builtin-memory/development.md +6 -9
- package/dist/builtin-memory/internal/INDEX.md +4 -5
- package/dist/builtin-memory/internal/agent-shaping.md +5 -7
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +3 -3
- package/dist/builtin-memory/internal/marketplaces.md +13 -14
- package/dist/builtin-memory/internal/nodes-and-canvas.md +4 -4
- package/dist/builtin-memory/internal/plugins.md +61 -45
- package/dist/builtin-memory/planning.md +4 -7
- package/dist/builtin-memory/spec.md +9 -12
- package/dist/builtin-memory/wedged-child-on-runaway-bash.md +8 -22
- package/dist/cli.js +1 -1
- package/dist/clients/attach/__tests__/attach-keybindings.test.js +17 -4
- package/dist/clients/attach/__tests__/context-message.test.js +31 -20
- package/dist/clients/attach/__tests__/crtr-output.test.js +39 -30
- package/dist/clients/attach/render/chat-view.d.ts +20 -20
- package/dist/clients/attach/render/chat-view.js +42 -54
- package/dist/clients/attach/render/{frozen-history.d.ts → condensed-history.d.ts} +1 -18
- package/dist/clients/attach/render/condensed-history.js +60 -0
- package/dist/clients/attach/render/context-message.js +9 -14
- package/dist/clients/attach/session/bindings.d.ts +5 -3
- package/dist/clients/attach/session/bindings.js +7 -13
- package/dist/clients/attach/session/keys.d.ts +2 -0
- package/dist/clients/attach/session/keys.js +36 -37
- package/dist/clients/attach/session/profile-files.d.ts +8 -0
- package/dist/clients/attach/session/profile-files.js +157 -0
- package/dist/clients/attach/viewer.js +525 -525
- package/dist/commands/node.js +2 -2
- package/dist/commands/pkg/plugin-inspect.js +6 -7
- package/dist/commands/pkg/plugin-manage.d.ts +1 -1
- package/dist/commands/pkg/plugin-manage.js +131 -19
- package/dist/commands/pkg/plugin.js +2 -2
- package/dist/commands/pkg.js +6 -11
- package/dist/commands/profile/env.js +3 -3
- package/dist/commands/sys/config.js +17 -76
- package/dist/commands/sys/doctor.js +5 -91
- package/dist/commands/sys/setup-wizard.d.ts +9 -11
- package/dist/commands/sys/setup-wizard.js +47 -81
- package/dist/core/__tests__/base-worker-prompt.test.js +18 -21
- package/dist/core/__tests__/command-plugins-surfaces.test.js +39 -5
- package/dist/core/__tests__/command-plugins.test.js +36 -16
- package/dist/core/__tests__/review-model-floor.test.js +2 -2
- package/dist/core/__tests__/tmux-surface.test.js +10 -1
- package/dist/core/command-manifests/manifest.d.ts +24 -0
- package/dist/core/{configured-clis → command-manifests}/manifest.js +21 -25
- package/dist/core/command-manifests/registry.d.ts +1 -2
- package/dist/core/command-manifests/registry.js +2 -2
- package/dist/core/command-manifests/schema.d.ts +11 -13
- package/dist/core/command-manifests/schema.js +53 -192
- package/dist/core/command-plugins/compose.d.ts +0 -6
- package/dist/core/command-plugins/compose.js +28 -75
- package/dist/core/command-plugins/discovery.d.ts +25 -58
- package/dist/core/command-plugins/discovery.js +152 -259
- package/dist/core/command-plugins/endpoint.d.ts +24 -0
- package/dist/core/command-plugins/endpoint.js +48 -0
- package/dist/core/command-plugins/store.d.ts +16 -0
- package/dist/core/command-plugins/store.js +64 -0
- package/dist/core/command-plugins/{adapter.d.ts → transport/exec-invoke.d.ts} +3 -3
- package/dist/core/command-plugins/{adapter.js → transport/exec-invoke.js} +4 -4
- package/dist/core/{configured-clis/fetch.d.ts → command-plugins/transport/http-fetch.d.ts} +9 -18
- package/dist/core/{configured-clis/fetch.js → command-plugins/transport/http-fetch.js} +15 -35
- package/dist/core/{configured-clis/invoker.d.ts → command-plugins/transport/http-invoke.d.ts} +7 -7
- package/dist/core/{configured-clis/invoker.js → command-plugins/transport/http-invoke.js} +21 -23
- package/dist/core/command.d.ts +8 -9
- package/dist/core/command.js +6 -9
- package/dist/core/config.js +6 -10
- package/dist/core/env-name.d.ts +6 -0
- package/dist/core/env-name.js +9 -0
- package/dist/core/io.d.ts +1 -1
- package/dist/core/keybindings/__tests__/resolve.test.js +40 -3
- package/dist/core/keybindings/attach-control.d.ts +37 -0
- package/dist/core/keybindings/attach-control.js +38 -0
- package/dist/core/keybindings/catalog.d.ts +5 -4
- package/dist/core/keybindings/catalog.js +16 -8
- package/dist/core/keybindings/index.d.ts +1 -0
- package/dist/core/keybindings/index.js +1 -0
- package/dist/core/keybindings/types.d.ts +1 -1
- package/dist/core/preview-registry.js +41 -74
- package/dist/core/runtime/bearings.d.ts +2 -5
- package/dist/core/runtime/bearings.js +2 -5
- package/dist/core/runtime/front-door.d.ts +1 -1
- package/dist/core/runtime/front-door.js +2 -2
- package/dist/core/runtime/kickoff.d.ts +3 -3
- package/dist/core/runtime/kickoff.js +4 -3
- package/dist/core/runtime/situational-context.d.ts +1 -1
- package/dist/core/runtime/situational-context.js +1 -1
- package/dist/core/runtime/spawn.js +9 -9
- package/dist/core/runtime/tmux.js +29 -2
- package/dist/core/scope.d.ts +0 -5
- package/dist/core/scope.js +0 -10
- package/dist/core/user-settings.d.ts +193 -0
- package/dist/core/user-settings.js +252 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/pi-extensions/canvas-stophook.js +3 -2
- package/dist/shared/generated-context.d.ts +34 -0
- package/dist/shared/generated-context.js +98 -0
- package/dist/types.d.ts +23 -16
- package/dist/types.js +3 -14
- package/dist/web-client/assets/{index-NIuSCOHM.js → index-BMTOGuOZ.js} +19 -19
- package/dist/web-client/assets/index-DvA6Zw-R.css +2 -0
- package/dist/web-client/index.html +2 -2
- package/dist/web-client/sw.js +1 -1
- package/docs/public-api.md +1 -0
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/dist/builtin-memory/05-kinds/product/00-base.md +0 -25
- package/dist/builtin-memory/05-kinds/product/01-orchestrator.md +0 -15
- package/dist/builtin-memory/05-kinds/product/teardown.md +0 -15
- package/dist/builtin-memory/internal/workflow-codification.md +0 -82
- package/dist/builtin-memory/product.md +0 -80
- package/dist/clients/attach/render/frozen-history.js +0 -100
- package/dist/commands/pkg/cli-inspect.d.ts +0 -17
- package/dist/commands/pkg/cli-inspect.js +0 -190
- package/dist/commands/pkg/cli-manage.d.ts +0 -3
- package/dist/commands/pkg/cli-manage.js +0 -206
- package/dist/commands/pkg/cli.d.ts +0 -1
- package/dist/commands/pkg/cli.js +0 -14
- package/dist/core/configured-clis/cache.d.ts +0 -16
- package/dist/core/configured-clis/cache.js +0 -57
- package/dist/core/configured-clis/compose.d.ts +0 -14
- package/dist/core/configured-clis/compose.js +0 -60
- package/dist/core/configured-clis/discovery.d.ts +0 -47
- package/dist/core/configured-clis/discovery.js +0 -173
- package/dist/core/configured-clis/manifest.d.ts +0 -24
- package/dist/core/configured-clis/registration.d.ts +0 -40
- package/dist/core/configured-clis/registration.js +0 -201
- package/dist/web-client/assets/index-CqLKj8Xu.css +0 -2
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
// and leaf-dialect specialization for plugins vs configured CLIs.
|
|
3
|
-
//
|
|
4
|
-
// The descriptor vocabulary (DeclRootEntry, DeclBranch, DeclNode, InputParam,
|
|
5
|
-
// Field) is transport-neutral and reused by both plugins (local executable) and
|
|
6
|
-
// configured CLIs (remote HTTP). Leaves specialize into two strict dialects:
|
|
7
|
-
// PluginDeclLeaf requires only outputKind: 'object'; ConfiguredCliDeclLeaf
|
|
8
|
-
// requires only rest (and derives outputKind from rest.streaming).
|
|
1
|
+
// Unified command-manifest schema. Transport is the sole leaf-dialect discriminator.
|
|
9
2
|
// ---------------------------------------------------------------------------
|
|
10
3
|
// Validation helpers
|
|
11
4
|
// ---------------------------------------------------------------------------
|
|
@@ -15,15 +8,15 @@ const KEBAB = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
|
15
8
|
const BRANCH_KEYS = new Set([
|
|
16
9
|
'kind', 'name', 'description', 'whenToUse', 'tier', 'rootEntry', 'summary', 'model', 'children',
|
|
17
10
|
]);
|
|
18
|
-
/** Only
|
|
19
|
-
*
|
|
20
|
-
const
|
|
11
|
+
/** Only exec transport may declare `passthrough`; HTTP manifests keep
|
|
12
|
+
* BRANCH_KEYS, so a declared passthrough fails as an unknown key. */
|
|
13
|
+
const EXEC_BRANCH_KEYS = new Set([...BRANCH_KEYS, 'passthrough']);
|
|
21
14
|
const PASSTHROUGH_KEYS = new Set(['bin', 'installHint']);
|
|
22
15
|
const LEAF_KEYS_COMMON = new Set([
|
|
23
16
|
'kind', 'name', 'description', 'whenToUse', 'tier', 'summary', 'params', 'output', 'effects',
|
|
24
17
|
]);
|
|
25
|
-
const
|
|
26
|
-
const
|
|
18
|
+
const EXEC_LEAF_KEYS = new Set([...LEAF_KEYS_COMMON, 'outputKind']);
|
|
19
|
+
const HTTP_LEAF_KEYS = new Set([...LEAF_KEYS_COMMON, 'rest']);
|
|
27
20
|
const ROOT_ENTRY_KEYS = new Set(['concept', 'description', 'whenToUse']);
|
|
28
21
|
const FILE_ENCODINGS = new Set(['text', 'base64']);
|
|
29
22
|
const PARAM_KEYS_BY_KIND = {
|
|
@@ -342,107 +335,97 @@ function checkCommon(raw, path, issue) {
|
|
|
342
335
|
}
|
|
343
336
|
return true;
|
|
344
337
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
// ---------------------------------------------------------------------------
|
|
348
|
-
/** Validate a node for the plugin dialect (leaf must have outputKind: 'object'). */
|
|
349
|
-
export function validatePluginNode(raw, path, topLevel, issue) {
|
|
338
|
+
export function validateCommandNode(raw, path, topLevel, transport, issue) {
|
|
339
|
+
const pathString = path.join('.');
|
|
350
340
|
if (!isObject(raw)) {
|
|
351
|
-
issue('command_node_invalid',
|
|
341
|
+
issue('command_node_invalid', 'node must be an object', typeName(raw), 'a branch or leaf node object', 'Fix the node.', pathString);
|
|
352
342
|
return null;
|
|
353
343
|
}
|
|
354
344
|
const kind = raw['kind'];
|
|
355
345
|
if (kind === 'branch')
|
|
356
|
-
return
|
|
346
|
+
return validateBranch(raw, pathString, topLevel, transport, issue);
|
|
357
347
|
if (kind === 'leaf') {
|
|
358
348
|
if (topLevel) {
|
|
359
|
-
issue('command_node_invalid',
|
|
349
|
+
issue('command_node_invalid', 'top-level node must be a branch', 'leaf', 'a branch node with a rootEntry', 'Wrap the command in a top-level branch (noun) with a rootEntry.', `${pathString}.kind`);
|
|
360
350
|
return null;
|
|
361
351
|
}
|
|
362
|
-
return
|
|
352
|
+
return validateLeaf(raw, pathString, transport, issue);
|
|
363
353
|
}
|
|
364
|
-
issue('command_node_invalid',
|
|
354
|
+
issue('command_node_invalid', 'node kind must be "branch" or "leaf"', String(kind), 'branch | leaf', 'Set kind to branch or leaf.', `${pathString}.kind`);
|
|
365
355
|
return null;
|
|
366
356
|
}
|
|
367
|
-
function
|
|
368
|
-
if (!checkKeys(raw,
|
|
357
|
+
function validateBranch(raw, path, topLevel, transport, issue) {
|
|
358
|
+
if (!checkKeys(raw, transport === 'exec' ? EXEC_BRANCH_KEYS : BRANCH_KEYS, path, issue))
|
|
369
359
|
return null;
|
|
370
360
|
if (!checkCommon(raw, path, issue))
|
|
371
361
|
return null;
|
|
372
362
|
const hasRoot = raw['rootEntry'] !== undefined;
|
|
373
363
|
if (topLevel && !hasRoot) {
|
|
374
|
-
issue('command_node_invalid',
|
|
364
|
+
issue('command_node_invalid', 'top-level branch requires a rootEntry', '(missing)', 'a rootEntry { concept, description, whenToUse }', 'Add a rootEntry to the top-level branch.', `${path}.rootEntry`);
|
|
375
365
|
return null;
|
|
376
366
|
}
|
|
377
367
|
if (!topLevel && hasRoot) {
|
|
378
|
-
issue('command_node_invalid',
|
|
368
|
+
issue('command_node_invalid', 'nested branch must not declare a rootEntry', 'rootEntry', 'no rootEntry (only top-level branches carry one)', 'Remove rootEntry from the nested branch.', `${path}.rootEntry`);
|
|
379
369
|
return null;
|
|
380
370
|
}
|
|
381
371
|
let rootEntry;
|
|
382
372
|
if (hasRoot) {
|
|
383
|
-
const
|
|
384
|
-
if (
|
|
373
|
+
const validatedRootEntry = validateRootEntry(raw['rootEntry'], `${path}.rootEntry`, issue);
|
|
374
|
+
if (validatedRootEntry === null)
|
|
385
375
|
return null;
|
|
386
|
-
rootEntry =
|
|
376
|
+
rootEntry = validatedRootEntry;
|
|
387
377
|
}
|
|
388
378
|
if (typeof raw['summary'] !== 'string' || raw['summary'].length === 0) {
|
|
389
|
-
issue('command_node_invalid',
|
|
379
|
+
issue('command_node_invalid', 'branch summary must be a non-empty string', typeName(raw['summary']), 'a one-line summary string', 'Add a summary.', `${path}.summary`);
|
|
390
380
|
return null;
|
|
391
381
|
}
|
|
392
382
|
if (raw['model'] !== undefined && typeof raw['model'] !== 'string') {
|
|
393
|
-
issue('command_node_invalid',
|
|
383
|
+
issue('command_node_invalid', 'branch model must be a string', typeName(raw['model']), 'a string or omitted', 'Fix or remove model.', `${path}.model`);
|
|
394
384
|
return null;
|
|
395
385
|
}
|
|
396
386
|
let passthrough;
|
|
397
|
-
if (raw['passthrough'] !== undefined) {
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
387
|
+
if (transport === 'exec' && raw['passthrough'] !== undefined) {
|
|
388
|
+
const validated = validatePassthrough(raw['passthrough'], `${path}.passthrough`, issue);
|
|
389
|
+
if (validated === null)
|
|
400
390
|
return null;
|
|
401
|
-
passthrough =
|
|
391
|
+
passthrough = validated;
|
|
402
392
|
}
|
|
403
393
|
const children = raw['children'];
|
|
404
394
|
if (passthrough !== undefined) {
|
|
405
|
-
// A passthrough branch intercepts every argv token after it, so a child
|
|
406
|
-
// would be unreachable — declare the emptiness rather than implying it.
|
|
407
395
|
if (!Array.isArray(children) || children.length !== 0) {
|
|
408
|
-
issue('command_node_invalid',
|
|
396
|
+
issue('command_node_invalid', 'a passthrough branch must declare children: []', Array.isArray(children) ? `${children.length} children` : typeName(children), 'an empty children array', 'Set children to [] — a passthrough branch forwards all argv and can own no subcommands.', `${path}.children`);
|
|
409
397
|
return null;
|
|
410
398
|
}
|
|
411
399
|
}
|
|
412
|
-
else if (!Array.isArray(children)
|
|
413
|
-
issue('command_node_invalid',
|
|
400
|
+
else if (!Array.isArray(children)) {
|
|
401
|
+
issue('command_node_invalid', 'branch children must be an array', typeName(children), 'an array of branch/leaf nodes (may be empty for populated by mounts)', 'Fix children.', `${path}.children`);
|
|
414
402
|
return null;
|
|
415
403
|
}
|
|
416
404
|
const validated = [];
|
|
417
405
|
const childNames = new Set();
|
|
418
406
|
for (let i = 0; i < children.length; i++) {
|
|
419
|
-
const
|
|
420
|
-
if (
|
|
407
|
+
const child = validateCommandNode(children[i], [...path.split('.'), `children[${i}]`], false, transport, issue);
|
|
408
|
+
if (child === null)
|
|
421
409
|
return null;
|
|
422
|
-
if (childNames.has(
|
|
423
|
-
issue('command_node_invalid',
|
|
410
|
+
if (childNames.has(child.name)) {
|
|
411
|
+
issue('command_node_invalid', 'duplicate child name', child.name, 'unique child names within a branch', 'Rename the duplicate child.', `${path}.children[${i}].name`);
|
|
424
412
|
return null;
|
|
425
413
|
}
|
|
426
|
-
childNames.add(
|
|
427
|
-
validated.push(
|
|
414
|
+
childNames.add(child.name);
|
|
415
|
+
validated.push(child);
|
|
428
416
|
}
|
|
429
417
|
return {
|
|
430
|
-
kind: 'branch',
|
|
431
|
-
name: raw['name'],
|
|
432
|
-
description: raw['description'],
|
|
433
|
-
whenToUse: raw['whenToUse'],
|
|
418
|
+
kind: 'branch', name: raw['name'], description: raw['description'], whenToUse: raw['whenToUse'],
|
|
434
419
|
...(raw['tier'] !== undefined ? { tier: raw['tier'] } : {}),
|
|
435
|
-
...(rootEntry !== undefined ? { rootEntry } : {}),
|
|
436
|
-
summary: raw['summary'],
|
|
420
|
+
...(rootEntry !== undefined ? { rootEntry } : {}), summary: raw['summary'],
|
|
437
421
|
...(raw['model'] !== undefined ? { model: raw['model'] } : {}),
|
|
438
|
-
...(passthrough !== undefined ? { passthrough } : {}),
|
|
439
|
-
children: validated,
|
|
422
|
+
...(passthrough !== undefined ? { passthrough } : {}), children: validated,
|
|
440
423
|
};
|
|
441
424
|
}
|
|
442
425
|
/** `passthrough: { bin, installHint }` — both required non-empty strings. */
|
|
443
426
|
function validatePassthrough(raw, path, issue) {
|
|
444
427
|
if (!isObject(raw)) {
|
|
445
|
-
issue('command_node_invalid',
|
|
428
|
+
issue('command_node_invalid', 'passthrough must be an object', typeName(raw), 'an object { bin, installHint }', 'Fix or remove passthrough.', path);
|
|
446
429
|
return null;
|
|
447
430
|
}
|
|
448
431
|
if (!checkKeys(raw, PASSTHROUGH_KEYS, path, issue))
|
|
@@ -455,133 +438,21 @@ function validatePassthrough(raw, path, issue) {
|
|
|
455
438
|
}
|
|
456
439
|
return { bin: raw['bin'], installHint: raw['installHint'] };
|
|
457
440
|
}
|
|
458
|
-
function
|
|
459
|
-
if (!checkKeys(raw,
|
|
460
|
-
return null;
|
|
461
|
-
if (!checkCommon(raw, path, issue))
|
|
462
|
-
return null;
|
|
463
|
-
if (typeof raw['summary'] !== 'string' || raw['summary'].length === 0) {
|
|
464
|
-
issue('command_node_invalid', `leaf summary must be a non-empty string`, typeName(raw['summary']), 'a one-line summary string', 'Add a summary.', `${path}.summary`);
|
|
465
|
-
return null;
|
|
466
|
-
}
|
|
467
|
-
if (raw['outputKind'] !== 'object') {
|
|
468
|
-
issue('command_node_invalid', `leaf outputKind must be "object" in v1`, String(raw['outputKind']), 'exactly "object"', 'Set outputKind to "object".', `${path}.outputKind`);
|
|
469
|
-
return null;
|
|
470
|
-
}
|
|
471
|
-
const params = validateParams(raw['params'], `${path}.params`, issue);
|
|
472
|
-
if (params === null)
|
|
473
|
-
return null;
|
|
474
|
-
const output = validateOutput(raw['output'], `${path}.output`, issue);
|
|
475
|
-
if (output === null)
|
|
476
|
-
return null;
|
|
477
|
-
const effects = raw['effects'];
|
|
478
|
-
if (!Array.isArray(effects) || effects.length === 0 || !effects.every((e) => typeof e === 'string')) {
|
|
479
|
-
issue('command_node_invalid', `leaf effects must be a non-empty string array`, typeName(effects), 'a non-empty array of strings (["None. Read-only."] for read-only leaves)', 'Declare every persistent effect.', `${path}.effects`);
|
|
480
|
-
return null;
|
|
481
|
-
}
|
|
482
|
-
return {
|
|
483
|
-
kind: 'leaf',
|
|
484
|
-
name: raw['name'],
|
|
485
|
-
description: raw['description'],
|
|
486
|
-
whenToUse: raw['whenToUse'],
|
|
487
|
-
...(raw['tier'] !== undefined ? { tier: raw['tier'] } : {}),
|
|
488
|
-
summary: raw['summary'],
|
|
489
|
-
params,
|
|
490
|
-
output,
|
|
491
|
-
outputKind: 'object',
|
|
492
|
-
effects: effects,
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
/** Validate a node for the configured CLI dialect (leaf must have rest). */
|
|
496
|
-
export function validateConfiguredCliNode(raw, path, topLevel, issue) {
|
|
497
|
-
if (!isObject(raw)) {
|
|
498
|
-
issue('command_node_invalid', `node must be an object`, typeName(raw), 'a branch or leaf node object', 'Fix the node.', path);
|
|
499
|
-
return null;
|
|
500
|
-
}
|
|
501
|
-
const kind = raw['kind'];
|
|
502
|
-
if (kind === 'branch')
|
|
503
|
-
return validateConfiguredCliBranch(raw, path, topLevel, issue);
|
|
504
|
-
if (kind === 'leaf') {
|
|
505
|
-
if (topLevel) {
|
|
506
|
-
issue('command_node_invalid', `top-level node must be a branch`, 'leaf', 'a branch node with a rootEntry', 'Wrap the command in a top-level branch (noun) with a rootEntry.', `${path}.kind`);
|
|
507
|
-
return null;
|
|
508
|
-
}
|
|
509
|
-
return validateConfiguredCliLeaf(raw, path, issue);
|
|
510
|
-
}
|
|
511
|
-
issue('command_node_invalid', `node kind must be "branch" or "leaf"`, String(kind), 'branch | leaf', 'Set kind to branch or leaf.', `${path}.kind`);
|
|
512
|
-
return null;
|
|
513
|
-
}
|
|
514
|
-
function validateConfiguredCliBranch(raw, path, topLevel, issue) {
|
|
515
|
-
if (!checkKeys(raw, BRANCH_KEYS, path, issue))
|
|
441
|
+
function validateLeaf(raw, path, transport, issue) {
|
|
442
|
+
if (!checkKeys(raw, transport === 'exec' ? EXEC_LEAF_KEYS : HTTP_LEAF_KEYS, path, issue))
|
|
516
443
|
return null;
|
|
517
444
|
if (!checkCommon(raw, path, issue))
|
|
518
445
|
return null;
|
|
519
|
-
const hasRoot = raw['rootEntry'] !== undefined;
|
|
520
|
-
if (topLevel && !hasRoot) {
|
|
521
|
-
issue('command_node_invalid', `top-level branch requires a rootEntry`, '(missing)', 'a rootEntry { concept, description, whenToUse }', 'Add a rootEntry to the top-level branch.', `${path}.rootEntry`);
|
|
522
|
-
return null;
|
|
523
|
-
}
|
|
524
|
-
if (!topLevel && hasRoot) {
|
|
525
|
-
issue('command_node_invalid', `nested branch must not declare a rootEntry`, 'rootEntry', 'no rootEntry (only top-level branches carry one)', 'Remove rootEntry from the nested branch.', `${path}.rootEntry`);
|
|
526
|
-
return null;
|
|
527
|
-
}
|
|
528
|
-
let rootEntry;
|
|
529
|
-
if (hasRoot) {
|
|
530
|
-
const re = validateRootEntry(raw['rootEntry'], `${path}.rootEntry`, issue);
|
|
531
|
-
if (re === null)
|
|
532
|
-
return null;
|
|
533
|
-
rootEntry = re;
|
|
534
|
-
}
|
|
535
446
|
if (typeof raw['summary'] !== 'string' || raw['summary'].length === 0) {
|
|
536
|
-
issue('command_node_invalid',
|
|
447
|
+
issue('command_node_invalid', 'leaf summary must be a non-empty string', typeName(raw['summary']), 'a one-line summary string', 'Add a summary.', `${path}.summary`);
|
|
537
448
|
return null;
|
|
538
449
|
}
|
|
539
|
-
if (
|
|
540
|
-
issue('command_node_invalid',
|
|
541
|
-
return null;
|
|
542
|
-
}
|
|
543
|
-
const children = raw['children'];
|
|
544
|
-
if (!Array.isArray(children)) {
|
|
545
|
-
issue('command_node_invalid', `branch children must be an array`, typeName(children), 'an array of branch/leaf nodes (may be empty for populated by mounts)', 'Fix children.', `${path}.children`);
|
|
546
|
-
return null;
|
|
547
|
-
}
|
|
548
|
-
const validated = [];
|
|
549
|
-
const childNames = new Set();
|
|
550
|
-
for (let i = 0; i < children.length; i++) {
|
|
551
|
-
const c = validateConfiguredCliNode(children[i], `${path}.children[${i}]`, false, issue);
|
|
552
|
-
if (c === null)
|
|
553
|
-
return null;
|
|
554
|
-
if (childNames.has(c.name)) {
|
|
555
|
-
issue('command_node_invalid', `duplicate child name`, c.name, 'unique child names within a branch', 'Rename the duplicate child.', `${path}.children[${i}].name`);
|
|
556
|
-
return null;
|
|
557
|
-
}
|
|
558
|
-
childNames.add(c.name);
|
|
559
|
-
validated.push(c);
|
|
560
|
-
}
|
|
561
|
-
return {
|
|
562
|
-
kind: 'branch',
|
|
563
|
-
name: raw['name'],
|
|
564
|
-
description: raw['description'],
|
|
565
|
-
whenToUse: raw['whenToUse'],
|
|
566
|
-
...(raw['tier'] !== undefined ? { tier: raw['tier'] } : {}),
|
|
567
|
-
...(rootEntry !== undefined ? { rootEntry } : {}),
|
|
568
|
-
summary: raw['summary'],
|
|
569
|
-
...(raw['model'] !== undefined ? { model: raw['model'] } : {}),
|
|
570
|
-
children: validated,
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
function validateConfiguredCliLeaf(raw, path, issue) {
|
|
574
|
-
if (!checkKeys(raw, CONFIGURED_LEAF_KEYS, path, issue))
|
|
575
|
-
return null;
|
|
576
|
-
if (!checkCommon(raw, path, issue))
|
|
577
|
-
return null;
|
|
578
|
-
if (typeof raw['summary'] !== 'string' || raw['summary'].length === 0) {
|
|
579
|
-
issue('command_node_invalid', `leaf summary must be a non-empty string`, typeName(raw['summary']), 'a one-line summary string', 'Add a summary.', `${path}.summary`);
|
|
450
|
+
if (transport === 'exec' && raw['outputKind'] !== 'object') {
|
|
451
|
+
issue('command_node_invalid', 'leaf outputKind must be "object" in v1', String(raw['outputKind']), 'exactly "object"', 'Set outputKind to "object".', `${path}.outputKind`);
|
|
580
452
|
return null;
|
|
581
453
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
issue('command_node_invalid', `configured CLI leaf requires a rest mapping`, '(missing)', 'a rest object with method, path, and params', 'Add a rest mapping.', `${path}.rest`);
|
|
454
|
+
if (transport === 'http' && raw['rest'] === undefined) {
|
|
455
|
+
issue('command_node_invalid', 'HTTP leaf requires a rest mapping', '(missing)', 'a rest object with method, path, and params', 'Add a rest mapping.', `${path}.rest`);
|
|
585
456
|
return null;
|
|
586
457
|
}
|
|
587
458
|
const params = validateParams(raw['params'], `${path}.params`, issue);
|
|
@@ -591,26 +462,16 @@ function validateConfiguredCliLeaf(raw, path, issue) {
|
|
|
591
462
|
if (output === null)
|
|
592
463
|
return null;
|
|
593
464
|
const effects = raw['effects'];
|
|
594
|
-
if (!Array.isArray(effects) || effects.length === 0 || !effects.every((
|
|
595
|
-
issue('command_node_invalid',
|
|
465
|
+
if (!Array.isArray(effects) || effects.length === 0 || !effects.every((effect) => typeof effect === 'string')) {
|
|
466
|
+
issue('command_node_invalid', 'leaf effects must be a non-empty string array', typeName(effects), 'a non-empty array of strings (["None. Read-only."] for read-only leaves)', 'Declare every persistent effect.', `${path}.effects`);
|
|
596
467
|
return null;
|
|
597
468
|
}
|
|
598
|
-
|
|
469
|
+
const base = { kind: 'leaf', name: raw['name'], description: raw['description'], whenToUse: raw['whenToUse'],
|
|
470
|
+
...(raw['tier'] !== undefined ? { tier: raw['tier'] } : {}), summary: raw['summary'], params, output, effects: effects };
|
|
471
|
+
if (transport === 'exec')
|
|
472
|
+
return { ...base, outputKind: 'object' };
|
|
599
473
|
const rest = validateRestMapping(raw['rest'], path, params, issue);
|
|
600
|
-
|
|
601
|
-
return null;
|
|
602
|
-
return {
|
|
603
|
-
kind: 'leaf',
|
|
604
|
-
name: raw['name'],
|
|
605
|
-
description: raw['description'],
|
|
606
|
-
whenToUse: raw['whenToUse'],
|
|
607
|
-
...(raw['tier'] !== undefined ? { tier: raw['tier'] } : {}),
|
|
608
|
-
summary: raw['summary'],
|
|
609
|
-
params,
|
|
610
|
-
output,
|
|
611
|
-
effects: effects,
|
|
612
|
-
rest,
|
|
613
|
-
};
|
|
474
|
+
return rest === null ? null : { ...base, rest };
|
|
614
475
|
}
|
|
615
476
|
// ---------------------------------------------------------------------------
|
|
616
477
|
// REST mapping validation (§4.4)
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import type { BranchDef } from '../command.js';
|
|
2
2
|
import type { CommandRegistrySnapshot } from '../command-manifests/registry.js';
|
|
3
3
|
import type { ValidatedContribution } from './discovery.js';
|
|
4
|
-
/** Adapt legacy ValidatedContribution (plugin format) to transport-neutral
|
|
5
|
-
* CommandContribution. Returns a snapshot conforming to the unified registry
|
|
6
|
-
* contract, with an adaptLeaf callback that wraps executeExternalLeaf. */
|
|
7
4
|
export declare function adaptPluginContributions(contributions: ValidatedContribution[]): CommandRegistrySnapshot;
|
|
8
|
-
/** Map an accepted registry snapshot to real top-level BranchDefs, ready to
|
|
9
|
-
* concatenate beside core subtrees in `buildRoot()`. Consumes transport-neutral
|
|
10
|
-
* CommandContribution entries from a unified registry snapshot. */
|
|
11
5
|
export declare function composeExternalSubtrees(snapshot: CommandRegistrySnapshot): BranchDef[];
|
|
@@ -1,88 +1,41 @@
|
|
|
1
|
-
// Tree composer — adapt transport-neutral contributions into ordinary crtr
|
|
2
|
-
// BranchDef/LeafDef values via the SAME defineBranch/defineRoot path core uses,
|
|
3
|
-
// so external contributions get child-owned parent representations and the
|
|
4
|
-
// existing help renderer with no second help engine. External nodes are
|
|
5
|
-
// static-only (no dynamicState, no custom renderer); each leaf's run closure is
|
|
6
|
-
// supplied by the contribution's adaptLeaf callback. Composition is deterministic:
|
|
7
|
-
// contributions arrive already sorted by name from registry resolution.
|
|
8
1
|
import { defineBranch, defineLeaf } from '../command.js';
|
|
9
|
-
import { executeExternalLeaf } from './
|
|
10
|
-
|
|
11
|
-
* CommandContribution. Returns a snapshot conforming to the unified registry
|
|
12
|
-
* contract, with an adaptLeaf callback that wraps executeExternalLeaf. */
|
|
2
|
+
import { executeExternalLeaf } from './transport/exec-invoke.js';
|
|
3
|
+
import { invokeHttpLeaf } from './transport/http-invoke.js';
|
|
13
4
|
export function adaptPluginContributions(contributions) {
|
|
14
|
-
const adapted = contributions.map((vc) => ({
|
|
15
|
-
contributor: {
|
|
16
|
-
kind: 'plugin',
|
|
17
|
-
name: vc.plugin.name,
|
|
18
|
-
scope: vc.plugin.scope, // plugins are never builtin
|
|
19
|
-
},
|
|
20
|
-
node: vc.node,
|
|
21
|
-
adaptLeaf: (leaf, commandPath) => ({
|
|
22
|
-
outputKind: 'object',
|
|
23
|
-
run: async (input) => executeExternalLeaf({
|
|
24
|
-
plugin: vc.plugin,
|
|
25
|
-
// Discovery rejects a leaf-bearing manifest that omits `executable`,
|
|
26
|
-
// so a contribution reaching adaptLeaf always carries one.
|
|
27
|
-
executable: vc.executable,
|
|
28
|
-
commandPath: Array.from(commandPath),
|
|
29
|
-
output: leaf.output,
|
|
30
|
-
}, input),
|
|
31
|
-
}),
|
|
32
|
-
}));
|
|
33
5
|
return {
|
|
34
|
-
contributions:
|
|
6
|
+
contributions: contributions.map((contribution) => ({
|
|
7
|
+
contributor: { name: contribution.plugin.name, scope: contribution.plugin.scope },
|
|
8
|
+
node: contribution.node,
|
|
9
|
+
adaptLeaf: (leaf, commandPath) => {
|
|
10
|
+
const transport = contribution.transport;
|
|
11
|
+
if (transport.kind === 'exec')
|
|
12
|
+
return {
|
|
13
|
+
outputKind: 'object',
|
|
14
|
+
run: async (input) => executeExternalLeaf({ plugin: contribution.plugin, executable: transport.executable, commandPath: [...commandPath], output: leaf.output }, input),
|
|
15
|
+
};
|
|
16
|
+
const httpLeaf = leaf;
|
|
17
|
+
return {
|
|
18
|
+
outputKind: httpLeaf.rest.streaming === true ? 'jsonl' : 'object',
|
|
19
|
+
run: (input, context) => invokeHttpLeaf({
|
|
20
|
+
registration: { name: contribution.plugin.name, endpoint: transport.endpoint, ...(transport.authEnv !== undefined ? { authEnv: transport.authEnv } : {}) },
|
|
21
|
+
...(contribution.manifest?.baseUrl !== undefined ? { baseUrl: contribution.manifest.baseUrl } : {}),
|
|
22
|
+
...(contribution.manifest?.timeouts !== undefined ? { timeouts: contribution.manifest.timeouts } : {}),
|
|
23
|
+
params: httpLeaf.params, rest: httpLeaf.rest, output: httpLeaf.output, commandPath: [...commandPath],
|
|
24
|
+
}, input, context),
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
})),
|
|
35
28
|
issues: [],
|
|
36
29
|
};
|
|
37
30
|
}
|
|
38
|
-
/** Map an accepted registry snapshot to real top-level BranchDefs, ready to
|
|
39
|
-
* concatenate beside core subtrees in `buildRoot()`. Consumes transport-neutral
|
|
40
|
-
* CommandContribution entries from a unified registry snapshot. */
|
|
41
31
|
export function composeExternalSubtrees(snapshot) {
|
|
42
|
-
return snapshot.contributions.map((
|
|
32
|
+
return snapshot.contributions.map((contribution) => buildBranch(contribution, contribution.node, [contribution.node.name]));
|
|
43
33
|
}
|
|
44
34
|
function buildBranch(contribution, node, path) {
|
|
45
|
-
const rootEntry = node.rootEntry
|
|
46
|
-
|
|
47
|
-
concept: node.rootEntry.concept,
|
|
48
|
-
// Explicit field mapping: declarative description→desc, whenToUse→useWhen.
|
|
49
|
-
desc: node.rootEntry.description,
|
|
50
|
-
useWhen: node.rootEntry.whenToUse,
|
|
51
|
-
}
|
|
52
|
-
: undefined;
|
|
53
|
-
return defineBranch({
|
|
54
|
-
name: node.name,
|
|
55
|
-
description: node.description,
|
|
56
|
-
whenToUse: node.whenToUse,
|
|
57
|
-
...(node.tier !== undefined ? { tier: node.tier } : {}),
|
|
58
|
-
...(rootEntry !== undefined ? { rootEntry } : {}),
|
|
59
|
-
...(node.passthrough !== undefined ? { passthrough: node.passthrough } : {}),
|
|
60
|
-
help: {
|
|
61
|
-
name: path.join(' '),
|
|
62
|
-
summary: node.summary,
|
|
63
|
-
...(node.model !== undefined ? { model: node.model } : {}),
|
|
64
|
-
},
|
|
65
|
-
children: node.children.map((child) => child.kind === 'branch'
|
|
66
|
-
? buildBranch(contribution, child, [...path, child.name])
|
|
67
|
-
: buildLeaf(contribution, child, [...path, child.name])),
|
|
68
|
-
});
|
|
35
|
+
const rootEntry = node.rootEntry === undefined ? undefined : { concept: node.rootEntry.concept, desc: node.rootEntry.description, useWhen: node.rootEntry.whenToUse };
|
|
36
|
+
return defineBranch({ name: node.name, description: node.description, whenToUse: node.whenToUse, ...(node.tier !== undefined ? { tier: node.tier } : {}), ...(rootEntry !== undefined ? { rootEntry } : {}), help: { name: path.join(' '), summary: node.summary, ...(node.model !== undefined ? { model: node.model } : {}) }, ...(node.passthrough !== undefined ? { passthrough: node.passthrough } : {}), children: node.children.map((child) => child.kind === 'branch' ? buildBranch(contribution, child, [...path, child.name]) : buildLeaf(contribution, child, [...path, child.name])) });
|
|
69
37
|
}
|
|
70
38
|
function buildLeaf(contribution, node, path) {
|
|
71
|
-
// Use the contribution's adapter to get the outputKind and run implementation.
|
|
72
39
|
const adapted = contribution.adaptLeaf(node, path);
|
|
73
|
-
return defineLeaf({
|
|
74
|
-
name: node.name,
|
|
75
|
-
description: node.description,
|
|
76
|
-
whenToUse: node.whenToUse,
|
|
77
|
-
...(node.tier !== undefined ? { tier: node.tier } : {}),
|
|
78
|
-
help: {
|
|
79
|
-
name: path.join(' '),
|
|
80
|
-
summary: node.summary,
|
|
81
|
-
params: node.params,
|
|
82
|
-
output: node.output,
|
|
83
|
-
outputKind: adapted.outputKind,
|
|
84
|
-
effects: node.effects,
|
|
85
|
-
},
|
|
86
|
-
run: adapted.run,
|
|
87
|
-
});
|
|
40
|
+
return defineLeaf({ name: node.name, description: node.description, whenToUse: node.whenToUse, ...(node.tier !== undefined ? { tier: node.tier } : {}), help: { name: path.join(' '), summary: node.summary, params: node.params, output: node.output, outputKind: adapted.outputKind, effects: node.effects }, run: adapted.run });
|
|
88
41
|
}
|
|
@@ -1,74 +1,41 @@
|
|
|
1
|
-
import type { InstalledPlugin } from '../../types.js';
|
|
2
|
-
import { type
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { InstalledPlugin, PluginTransport } from '../../types.js';
|
|
2
|
+
import { type ValidatedCommandManifest } from '../command-manifests/manifest.js';
|
|
3
|
+
import type { CommandManifestIssue, DeclBranch as DeclBranchGeneric, DeclLeaf as DeclLeafGeneric } from '../command-manifests/schema.js';
|
|
4
|
+
import type { CommandRegistrySnapshot } from '../command-manifests/registry.js';
|
|
5
|
+
import type { HttpPluginManifestStore } from './store.js';
|
|
5
6
|
export interface CommandDiscoveryIssue extends CommandManifestIssue {
|
|
6
|
-
/** The offending plugin's name. */
|
|
7
7
|
plugin: string;
|
|
8
8
|
}
|
|
9
|
-
export type { DeclRootEntry } from '../command-manifests/schema.js';
|
|
10
|
-
export type
|
|
11
|
-
export type
|
|
12
|
-
export type
|
|
13
|
-
export type DeclNode = DeclBranchGeneric<PluginDeclLeaf> | PluginDeclLeaf;
|
|
14
|
-
/** One accepted top-level contribution: a validated branch node plus the
|
|
15
|
-
* plugin identity and canonical executable the adapter needs at run time. */
|
|
9
|
+
export type { DeclRootEntry, CommandIssueCode, TransportKind } from '../command-manifests/schema.js';
|
|
10
|
+
export type DeclLeaf = DeclLeafGeneric;
|
|
11
|
+
export type DeclBranch = DeclBranchGeneric<DeclLeafGeneric>;
|
|
12
|
+
export type DeclNode = DeclBranch | DeclLeaf;
|
|
16
13
|
export interface ValidatedContribution {
|
|
17
14
|
plugin: InstalledPlugin;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
executable?: string;
|
|
22
|
-
/** The validated top-level branch node (always kind 'branch'). */
|
|
23
|
-
node: DeclBranchGeneric<PluginDeclLeaf>;
|
|
15
|
+
transport: PluginTransport;
|
|
16
|
+
node: DeclBranchGeneric<DeclLeafGeneric>;
|
|
17
|
+
manifest: ValidatedCommandManifest;
|
|
24
18
|
}
|
|
25
|
-
/** Per-plugin validation result — the Phase 2 lifecycle entry point. Reports
|
|
26
|
-
* accepted contributions and every issue without executing the binary. */
|
|
27
19
|
export interface PluginCommandValidation {
|
|
28
20
|
plugin: InstalledPlugin;
|
|
29
|
-
/** Absolute path to the plugin's commands.json (whether or not it loaded). */
|
|
30
21
|
manifestPath: string;
|
|
31
|
-
|
|
32
|
-
executable?: string;
|
|
22
|
+
transport?: PluginTransport;
|
|
33
23
|
contributions: ValidatedContribution[];
|
|
34
24
|
issues: CommandDiscoveryIssue[];
|
|
25
|
+
absentStore?: boolean;
|
|
26
|
+
httpManifestStore?: HttpPluginManifestStore;
|
|
35
27
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
contributions: ValidatedContribution[];
|
|
40
|
-
/** Every discovery issue across all effective command plugins. */
|
|
41
|
-
issues: CommandDiscoveryIssue[];
|
|
28
|
+
export interface AbsentStoreHydration {
|
|
29
|
+
hydratedAny: boolean;
|
|
30
|
+
diagnostics: string[];
|
|
42
31
|
}
|
|
43
|
-
/** The effective, deduped set of enabled plugins that declare a command
|
|
44
|
-
* manifest, in scope-precedence order. Enumerated with existing machinery
|
|
45
|
-
* only: `projectScopeRoots()` (profile-widened, nearest-first) via
|
|
46
|
-
* `listInstalledPluginsInRoot('project', root)`, then user scope. Dedup is by
|
|
47
|
-
* plugin NAME across ALL copies (highest precedence wins) BEFORE the enabled
|
|
48
|
-
* filter — so a disabled higher-precedence copy suppresses lower-precedence
|
|
49
|
-
* copies of the same name. */
|
|
50
32
|
export declare function effectiveCommandPlugins(startDir?: string, profileId?: string | null): InstalledPlugin[];
|
|
51
|
-
|
|
52
|
-
* Each plugin validation includes its contributions and per-plugin issues;
|
|
53
|
-
* call resolveCommandRegistry (or a later unified collision handler) to
|
|
54
|
-
* produce the final snapshot with cross-plugin collision detection. */
|
|
33
|
+
export declare function validatePluginCommands(plugin: InstalledPlugin, reservedNames?: ReadonlySet<string>): PluginCommandValidation;
|
|
55
34
|
export declare function discoverPluginCommandCandidates(startDir?: string, profileId?: string | null): PluginCommandValidation[];
|
|
56
|
-
/** Validate every effective command plugin and compose an invocation-local
|
|
57
|
-
* registry snapshot. `reservedNames` are the core top-level subtree names —
|
|
58
|
-
* a contribution claiming one is silently skipped from the tree and recorded
|
|
59
|
-
* as a `command_collision` issue (core always wins). A plugin-vs-plugin
|
|
60
|
-
* top-level name collision drops all claimants with an issue. Accepted
|
|
61
|
-
* contributions are sorted by name for deterministic help/order. */
|
|
62
|
-
export declare function discoverCommandContributions(reservedNames: ReadonlySet<string>, startDir?: string, profileId?: string | null): CommandRegistrySnapshot;
|
|
63
|
-
/** Validate every effective command plugin, including the cross-plugin
|
|
64
|
-
* top-level name collision pass: a name claimed by more than one plugin is
|
|
65
|
-
* dropped from EVERY claimant's contributions and a `command_collision`
|
|
66
|
-
* issue is recorded on EACH claimant's validation, so per-plugin surfaces
|
|
67
|
-
* (`sys doctor`, `pkg plugin show`) see it too. This is the entry point for
|
|
68
|
-
* any surface that reports on mounted commands — the per-plugin
|
|
69
|
-
* `validatePluginCommands` cannot see other plugins' claims. */
|
|
70
35
|
export declare function validateEffectiveCommandPlugins(reservedNames: ReadonlySet<string>, startDir?: string, profileId?: string | null): PluginCommandValidation[];
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
36
|
+
export declare function discoverCommandContributions(reservedNames: ReadonlySet<string>, startDir?: string, profileId?: string | null): {
|
|
37
|
+
contributions: ValidatedContribution[];
|
|
38
|
+
issues: CommandDiscoveryIssue[];
|
|
39
|
+
};
|
|
40
|
+
export declare function buildExternalCommandSnapshot(reservedCoreNames: ReadonlySet<string>): CommandRegistrySnapshot;
|
|
41
|
+
export declare function hydrateAbsentHttpPlugins(): Promise<AbsentStoreHydration>;
|