@unbrained/pm-cli 2026.3.12 → 2026.5.1-2
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/.agents/pm/extensions/.managed-extensions.json +42 -0
- package/.agents/pm/extensions/beads/index.js +109 -0
- package/.agents/pm/extensions/beads/manifest.json +7 -0
- package/{dist/cli/commands/beads.js → .agents/pm/extensions/beads/runtime.js} +31 -21
- package/.agents/pm/extensions/beads/runtime.ts +702 -0
- package/.agents/pm/extensions/todos/index.js +126 -0
- package/.agents/pm/extensions/todos/manifest.json +7 -0
- package/{dist/extensions/builtins/todos/import-export.js → .agents/pm/extensions/todos/runtime.js} +39 -29
- package/.agents/pm/extensions/todos/runtime.ts +568 -0
- package/AGENTS.md +196 -92
- package/CHANGELOG.md +404 -0
- package/CODE_OF_CONDUCT.md +42 -0
- package/CONTRIBUTING.md +144 -0
- package/PRD.md +512 -164
- package/README.md +1053 -2
- package/SECURITY.md +51 -0
- package/dist/cli/commands/activity.d.ts +5 -0
- package/dist/cli/commands/activity.js +66 -3
- package/dist/cli/commands/activity.js.map +1 -1
- package/dist/cli/commands/aggregate.d.ts +54 -0
- package/dist/cli/commands/aggregate.js +181 -0
- package/dist/cli/commands/aggregate.js.map +1 -0
- package/dist/cli/commands/append.js +4 -1
- package/dist/cli/commands/append.js.map +1 -1
- package/dist/cli/commands/calendar.d.ts +109 -0
- package/dist/cli/commands/calendar.js +797 -0
- package/dist/cli/commands/calendar.js.map +1 -0
- package/dist/cli/commands/claim.d.ts +5 -1
- package/dist/cli/commands/claim.js +42 -21
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.d.ts +1 -0
- package/dist/cli/commands/close.js +54 -5
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/comments-audit.d.ts +91 -0
- package/dist/cli/commands/comments-audit.js +195 -0
- package/dist/cli/commands/comments-audit.js.map +1 -0
- package/dist/cli/commands/comments.d.ts +1 -0
- package/dist/cli/commands/comments.js +70 -21
- package/dist/cli/commands/comments.js.map +1 -1
- package/dist/cli/commands/completion.d.ts +10 -4
- package/dist/cli/commands/completion.js +1184 -137
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/config.d.ts +35 -3
- package/dist/cli/commands/config.js +968 -13
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/context.d.ts +86 -0
- package/dist/cli/commands/context.js +299 -0
- package/dist/cli/commands/context.js.map +1 -0
- package/dist/cli/commands/contracts.d.ts +78 -0
- package/dist/cli/commands/contracts.js +920 -0
- package/dist/cli/commands/contracts.js.map +1 -0
- package/dist/cli/commands/create.d.ts +48 -14
- package/dist/cli/commands/create.js +1331 -160
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/dedupe-audit.d.ts +81 -0
- package/dist/cli/commands/dedupe-audit.js +330 -0
- package/dist/cli/commands/dedupe-audit.js.map +1 -0
- package/dist/cli/commands/deps.d.ts +52 -0
- package/dist/cli/commands/deps.js +204 -0
- package/dist/cli/commands/deps.js.map +1 -0
- package/dist/cli/commands/docs.d.ts +19 -0
- package/dist/cli/commands/docs.js +212 -13
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/extension.d.ts +122 -0
- package/dist/cli/commands/extension.js +1850 -0
- package/dist/cli/commands/extension.js.map +1 -0
- package/dist/cli/commands/files.d.ts +52 -1
- package/dist/cli/commands/files.js +455 -13
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/gc.d.ts +11 -1
- package/dist/cli/commands/gc.js +89 -11
- package/dist/cli/commands/gc.js.map +1 -1
- package/dist/cli/commands/get.d.ts +13 -0
- package/dist/cli/commands/get.js +35 -3
- package/dist/cli/commands/get.js.map +1 -1
- package/dist/cli/commands/health.d.ts +10 -2
- package/dist/cli/commands/health.js +774 -23
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/history.d.ts +20 -0
- package/dist/cli/commands/history.js +152 -6
- package/dist/cli/commands/history.js.map +1 -1
- package/dist/cli/commands/index.d.ts +16 -3
- package/dist/cli/commands/index.js +16 -3
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -2
- package/dist/cli/commands/init.js +137 -5
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/learnings.d.ts +17 -0
- package/dist/cli/commands/learnings.js +129 -0
- package/dist/cli/commands/learnings.js.map +1 -0
- package/dist/cli/commands/list.d.ts +29 -1
- package/dist/cli/commands/list.js +289 -53
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/normalize.d.ts +51 -0
- package/dist/cli/commands/normalize.js +298 -0
- package/dist/cli/commands/normalize.js.map +1 -0
- package/dist/cli/commands/notes.d.ts +17 -0
- package/dist/cli/commands/notes.js +129 -0
- package/dist/cli/commands/notes.js.map +1 -0
- package/dist/cli/commands/reindex.d.ts +1 -0
- package/dist/cli/commands/reindex.js +208 -32
- package/dist/cli/commands/reindex.js.map +1 -1
- package/dist/cli/commands/restore.js +164 -30
- package/dist/cli/commands/restore.js.map +1 -1
- package/dist/cli/commands/search.d.ts +14 -1
- package/dist/cli/commands/search.js +475 -81
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/stats.js +26 -10
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/commands/templates.d.ts +26 -0
- package/dist/cli/commands/templates.js +179 -0
- package/dist/cli/commands/templates.js.map +1 -0
- package/dist/cli/commands/test-all.d.ts +19 -1
- package/dist/cli/commands/test-all.js +161 -13
- package/dist/cli/commands/test-all.js.map +1 -1
- package/dist/cli/commands/test-runs.d.ts +63 -0
- package/dist/cli/commands/test-runs.js +179 -0
- package/dist/cli/commands/test-runs.js.map +1 -0
- package/dist/cli/commands/test.d.ts +75 -1
- package/dist/cli/commands/test.js +1360 -41
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update-many.d.ts +57 -0
- package/dist/cli/commands/update-many.js +631 -0
- package/dist/cli/commands/update-many.js.map +1 -0
- package/dist/cli/commands/update.d.ts +30 -0
- package/dist/cli/commands/update.js +1393 -84
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +30 -0
- package/dist/cli/commands/validate.js +1151 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/error-guidance.d.ts +33 -0
- package/dist/cli/error-guidance.js +337 -0
- package/dist/cli/error-guidance.js.map +1 -0
- package/dist/cli/extension-command-options.d.ts +1 -0
- package/dist/cli/extension-command-options.js +92 -0
- package/dist/cli/extension-command-options.js.map +1 -1
- package/dist/cli/help-content.d.ts +20 -0
- package/dist/cli/help-content.js +543 -0
- package/dist/cli/help-content.js.map +1 -0
- package/dist/cli/main.js +3625 -445
- package/dist/cli/main.js.map +1 -1
- package/dist/core/extensions/index.d.ts +13 -1
- package/dist/core/extensions/index.js +108 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/item-fields.d.ts +2 -0
- package/dist/core/extensions/item-fields.js +79 -0
- package/dist/core/extensions/item-fields.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +322 -9
- package/dist/core/extensions/loader.js +911 -20
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runtime-registrations.d.ts +5 -0
- package/dist/core/extensions/runtime-registrations.js +51 -0
- package/dist/core/extensions/runtime-registrations.js.map +1 -0
- package/dist/core/history/history-stream-policy.d.ts +20 -0
- package/dist/core/history/history-stream-policy.js +53 -0
- package/dist/core/history/history-stream-policy.js.map +1 -0
- package/dist/core/history/history.js +90 -1
- package/dist/core/history/history.js.map +1 -1
- package/dist/core/item/id.js +4 -1
- package/dist/core/item/id.js.map +1 -1
- package/dist/core/item/index.d.ts +1 -0
- package/dist/core/item/index.js +1 -0
- package/dist/core/item/index.js.map +1 -1
- package/dist/core/item/item-format.d.ts +11 -5
- package/dist/core/item/item-format.js +507 -24
- package/dist/core/item/item-format.js.map +1 -1
- package/dist/core/item/parent-reference-policy.d.ts +6 -0
- package/dist/core/item/parent-reference-policy.js +32 -0
- package/dist/core/item/parent-reference-policy.js.map +1 -0
- package/dist/core/item/parse.d.ts +5 -0
- package/dist/core/item/parse.js +216 -19
- package/dist/core/item/parse.js.map +1 -1
- package/dist/core/item/sprint-release-format.d.ts +6 -0
- package/dist/core/item/sprint-release-format.js +33 -0
- package/dist/core/item/sprint-release-format.js.map +1 -0
- package/dist/core/item/status.d.ts +3 -0
- package/dist/core/item/status.js +24 -0
- package/dist/core/item/status.js.map +1 -0
- package/dist/core/item/type-registry.d.ts +37 -0
- package/dist/core/item/type-registry.js +706 -0
- package/dist/core/item/type-registry.js.map +1 -0
- package/dist/core/lock/lock.d.ts +1 -1
- package/dist/core/lock/lock.js +101 -12
- package/dist/core/lock/lock.js.map +1 -1
- package/dist/core/output/command-aware.d.ts +1 -0
- package/dist/core/output/command-aware.js +394 -0
- package/dist/core/output/command-aware.js.map +1 -0
- package/dist/core/output/output.d.ts +3 -0
- package/dist/core/output/output.js +124 -6
- package/dist/core/output/output.js.map +1 -1
- package/dist/core/schema/runtime-field-filters.d.ts +3 -0
- package/dist/core/schema/runtime-field-filters.js +39 -0
- package/dist/core/schema/runtime-field-filters.js.map +1 -0
- package/dist/core/schema/runtime-field-values.d.ts +8 -0
- package/dist/core/schema/runtime-field-values.js +154 -0
- package/dist/core/schema/runtime-field-values.js.map +1 -0
- package/dist/core/schema/runtime-schema.d.ts +68 -0
- package/dist/core/schema/runtime-schema.js +554 -0
- package/dist/core/schema/runtime-schema.js.map +1 -0
- package/dist/core/search/cache.d.ts +13 -1
- package/dist/core/search/cache.js +123 -14
- package/dist/core/search/cache.js.map +1 -1
- package/dist/core/search/semantic-defaults.d.ts +6 -0
- package/dist/core/search/semantic-defaults.js +120 -0
- package/dist/core/search/semantic-defaults.js.map +1 -0
- package/dist/core/search/vector-stores.js +3 -1
- package/dist/core/search/vector-stores.js.map +1 -1
- package/dist/core/shared/command-types.d.ts +2 -0
- package/dist/core/shared/conflict-markers.d.ts +7 -0
- package/dist/core/shared/conflict-markers.js +27 -0
- package/dist/core/shared/conflict-markers.js.map +1 -0
- package/dist/core/shared/constants.d.ts +15 -4
- package/dist/core/shared/constants.js +141 -1
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/errors.d.ts +10 -1
- package/dist/core/shared/errors.js +3 -1
- package/dist/core/shared/errors.js.map +1 -1
- package/dist/core/shared/text-normalization.d.ts +4 -0
- package/dist/core/shared/text-normalization.js +33 -0
- package/dist/core/shared/text-normalization.js.map +1 -0
- package/dist/core/shared/time.d.ts +1 -2
- package/dist/core/shared/time.js +98 -11
- package/dist/core/shared/time.js.map +1 -1
- package/dist/core/store/index.d.ts +1 -0
- package/dist/core/store/index.js +1 -0
- package/dist/core/store/index.js.map +1 -1
- package/dist/core/store/item-format-migration.d.ts +9 -0
- package/dist/core/store/item-format-migration.js +87 -0
- package/dist/core/store/item-format-migration.js.map +1 -0
- package/dist/core/store/item-store.d.ts +13 -4
- package/dist/core/store/item-store.js +238 -51
- package/dist/core/store/item-store.js.map +1 -1
- package/dist/core/store/paths.d.ts +21 -3
- package/dist/core/store/paths.js +59 -4
- package/dist/core/store/paths.js.map +1 -1
- package/dist/core/store/settings.d.ts +14 -1
- package/dist/core/store/settings.js +463 -7
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/consent.d.ts +2 -0
- package/dist/core/telemetry/consent.js +79 -0
- package/dist/core/telemetry/consent.js.map +1 -0
- package/dist/core/telemetry/runtime.d.ts +38 -0
- package/dist/core/telemetry/runtime.js +733 -0
- package/dist/core/telemetry/runtime.js.map +1 -0
- package/dist/core/test/background-runs.d.ts +117 -0
- package/dist/core/test/background-runs.js +760 -0
- package/dist/core/test/background-runs.js.map +1 -0
- package/dist/core/test/item-test-run-tracking.d.ts +9 -0
- package/dist/core/test/item-test-run-tracking.js +50 -0
- package/dist/core/test/item-test-run-tracking.js.map +1 -0
- package/dist/sdk/cli-contracts.d.ts +92 -0
- package/dist/sdk/cli-contracts.js +2357 -0
- package/dist/sdk/cli-contracts.js.map +1 -0
- package/dist/sdk/index.d.ts +34 -0
- package/dist/sdk/index.js +23 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/types.d.ts +197 -3
- package/dist/types.js +48 -1
- package/dist/types.js.map +1 -1
- package/docs/ARCHITECTURE.md +368 -39
- package/docs/EXTENSIONS.md +454 -49
- package/docs/RELEASING.md +70 -19
- package/docs/SDK.md +123 -0
- package/docs/examples/starter-extension/README.md +48 -0
- package/docs/examples/starter-extension/index.js +191 -0
- package/docs/examples/starter-extension/manifest.json +17 -0
- package/docs/examples/starter-extension/package.json +10 -0
- package/package.json +41 -14
- package/.pi/extensions/pm-cli/index.ts +0 -778
- package/dist/cli/commands/beads.d.ts +0 -16
- package/dist/cli/commands/beads.js.map +0 -1
- package/dist/cli/commands/install.d.ts +0 -18
- package/dist/cli/commands/install.js +0 -87
- package/dist/cli/commands/install.js.map +0 -1
- package/dist/core/extensions/builtins.d.ts +0 -3
- package/dist/core/extensions/builtins.js +0 -47
- package/dist/core/extensions/builtins.js.map +0 -1
- package/dist/extensions/builtins/beads/index.d.ts +0 -8
- package/dist/extensions/builtins/beads/index.js +0 -33
- package/dist/extensions/builtins/beads/index.js.map +0 -1
- package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
- package/dist/extensions/builtins/todos/import-export.js.map +0 -1
- package/dist/extensions/builtins/todos/index.d.ts +0 -8
- package/dist/extensions/builtins/todos/index.js +0 -38
- package/dist/extensions/builtins/todos/index.js.map +0 -1
|
@@ -0,0 +1,920 @@
|
|
|
1
|
+
import { EXIT_CODE, SETTINGS_DEFAULTS } from "../../core/shared/constants.js";
|
|
2
|
+
import { PmCliError } from "../../core/shared/errors.js";
|
|
3
|
+
import { activateExtensions, getActiveExtensionRegistrations, loadExtensions } from "../../core/extensions/index.js";
|
|
4
|
+
import { pathExists } from "../../core/fs/fs-utils.js";
|
|
5
|
+
import { commandOptionFlagLabel, resolveCommandOptionPolicyState, resolveItemTypeRegistry } from "../../core/item/type-registry.js";
|
|
6
|
+
import { resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, } from "../../core/schema/runtime-schema.js";
|
|
7
|
+
import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
|
|
8
|
+
import { readSettings } from "../../core/store/settings.js";
|
|
9
|
+
import { ACTIVITY_COMMANDER_STRING_OPTION_CONTRACTS, ACTIVITY_FLAG_CONTRACTS, AGGREGATE_FLAG_CONTRACTS, APPEND_FLAG_CONTRACTS, CALENDAR_COMMANDER_STRING_OPTION_CONTRACTS, CALENDAR_FLAG_CONTRACTS, CLAIM_FLAG_CONTRACTS, CLOSE_TASK_FLAG_CONTRACTS, COMMENTS_FLAG_CONTRACTS, COMMENTS_AUDIT_FLAG_CONTRACTS, CLOSE_FLAG_CONTRACTS, COMPLETION_FLAG_CONTRACTS, CONFIG_FLAG_CONTRACTS, CONTRACTS_FLAG_CONTRACTS, CONTEXT_COMMANDER_STRING_OPTION_CONTRACTS, CONTEXT_FLAG_CONTRACTS, CREATE_COMMANDER_REPEATABLE_OPTION_CONTRACTS, CREATE_COMMANDER_STRING_OPTION_CONTRACTS, CREATE_FLAG_CONTRACTS, DELETE_FLAG_CONTRACTS, DEPS_FLAG_CONTRACTS, DEDUPE_AUDIT_FLAG_CONTRACTS, DOCS_FLAG_CONTRACTS, EXTENSION_FLAG_CONTRACTS, FILES_FLAG_CONTRACTS, GC_FLAG_CONTRACTS, GLOBAL_FLAG_CONTRACTS, HEALTH_FLAG_CONTRACTS, HISTORY_FLAG_CONTRACTS, LEARNINGS_FLAG_CONTRACTS, LIST_COMMANDER_STRING_OPTION_CONTRACTS, LIST_FILTER_FLAG_CONTRACTS, NORMALIZE_FLAG_CONTRACTS, NOTES_FLAG_CONTRACTS, PM_CORE_COMMAND_NAMES, PM_TOOL_ACTIONS, PM_TOOL_PARAMETERS_SCHEMA, REINDEX_FLAG_CONTRACTS, RELEASE_FLAG_CONTRACTS, RESTORE_FLAG_CONTRACTS, SEARCH_COMMANDER_STRING_OPTION_CONTRACTS, SEARCH_FLAG_CONTRACTS, START_TASK_FLAG_CONTRACTS, PAUSE_TASK_FLAG_CONTRACTS, TEST_ALL_FLAG_CONTRACTS, TEST_FLAG_CONTRACTS, TEST_RUNS_FLAG_CONTRACTS, UPDATE_COMMANDER_REPEATABLE_OPTION_CONTRACTS, UPDATE_COMMANDER_STRING_OPTION_CONTRACTS, UPDATE_FLAG_CONTRACTS, UPDATE_MANY_FLAG_CONTRACTS, VALIDATE_FLAG_CONTRACTS, withFlagAliasMetadata, } from "../../sdk/cli-contracts.js";
|
|
10
|
+
const LIST_COMMAND_NAMES = new Set([
|
|
11
|
+
"list",
|
|
12
|
+
"list-all",
|
|
13
|
+
"list-draft",
|
|
14
|
+
"list-open",
|
|
15
|
+
"list-in-progress",
|
|
16
|
+
"list-blocked",
|
|
17
|
+
"list-closed",
|
|
18
|
+
"list-canceled",
|
|
19
|
+
]);
|
|
20
|
+
const EXTENSION_ACTION_COMMAND_PATHS = {
|
|
21
|
+
"beads-import": "beads import",
|
|
22
|
+
"todos-import": "todos import",
|
|
23
|
+
"todos-export": "todos export",
|
|
24
|
+
};
|
|
25
|
+
function resolveActionCommandPath(action) {
|
|
26
|
+
const extensionCommandPath = EXTENSION_ACTION_COMMAND_PATHS[action];
|
|
27
|
+
if (extensionCommandPath) {
|
|
28
|
+
return normalizeCommandPath(extensionCommandPath);
|
|
29
|
+
}
|
|
30
|
+
if (PM_CORE_COMMAND_NAMES.includes(action)) {
|
|
31
|
+
return normalizeCommandPath(action);
|
|
32
|
+
}
|
|
33
|
+
if (action.startsWith("extension-")) {
|
|
34
|
+
return normalizeCommandPath(`extension ${action.slice("extension-".length)}`);
|
|
35
|
+
}
|
|
36
|
+
if (action.startsWith("test-runs-")) {
|
|
37
|
+
return normalizeCommandPath(`test-runs ${action.slice("test-runs-".length)}`);
|
|
38
|
+
}
|
|
39
|
+
if (action.startsWith("templates-")) {
|
|
40
|
+
return normalizeCommandPath(`templates ${action.slice("templates-".length)}`);
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
function actionDescriptorMatchesSelectedCommand(descriptor, selectedCommand) {
|
|
45
|
+
if (descriptor.command_path === null) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const commandPath = normalizeCommandPath(descriptor.command_path);
|
|
49
|
+
if (commandPath === selectedCommand) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
return commandPath.startsWith(`${selectedCommand} `);
|
|
53
|
+
}
|
|
54
|
+
function resolveScopedCommandsFromActionDescriptors(descriptors, commandCatalog) {
|
|
55
|
+
const commandSet = new Set(commandCatalog);
|
|
56
|
+
const scoped = new Set();
|
|
57
|
+
for (const descriptor of descriptors) {
|
|
58
|
+
if (!descriptor.command_path) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const commandPath = normalizeCommandPath(descriptor.command_path);
|
|
62
|
+
const tokens = commandPath.split(" ").filter((entry) => entry.length > 0);
|
|
63
|
+
if (tokens.length === 0) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
for (let end = tokens.length; end > 0; end -= 1) {
|
|
67
|
+
const candidate = tokens.slice(0, end).join(" ");
|
|
68
|
+
if (!commandSet.has(candidate)) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
scoped.add(candidate);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return [...scoped].sort((left, right) => left.localeCompare(right));
|
|
76
|
+
}
|
|
77
|
+
function normalizeToken(value) {
|
|
78
|
+
if (typeof value !== "string") {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const trimmed = value.trim().toLowerCase();
|
|
82
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
83
|
+
}
|
|
84
|
+
function extractActionBranches(schema) {
|
|
85
|
+
const oneOf = schema.oneOf;
|
|
86
|
+
if (!Array.isArray(oneOf)) {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
return oneOf.filter((entry) => typeof entry === "object" && entry !== null);
|
|
90
|
+
}
|
|
91
|
+
function filterSchemaByAction(schema, action) {
|
|
92
|
+
if (!action) {
|
|
93
|
+
return { ...schema };
|
|
94
|
+
}
|
|
95
|
+
const branches = extractActionBranches(schema);
|
|
96
|
+
const filtered = branches.filter((entry) => {
|
|
97
|
+
const properties = entry.properties;
|
|
98
|
+
if (typeof properties !== "object" || properties === null) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const actionProperty = properties.action;
|
|
102
|
+
if (typeof actionProperty !== "object" || actionProperty === null) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return actionProperty.const === action;
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
...schema,
|
|
109
|
+
oneOf: filtered,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function filterSchemaByActions(schema, actions) {
|
|
113
|
+
const branches = extractActionBranches(schema);
|
|
114
|
+
const filtered = branches.filter((entry) => {
|
|
115
|
+
const properties = entry.properties;
|
|
116
|
+
if (typeof properties !== "object" || properties === null) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
const actionProperty = properties.action;
|
|
120
|
+
if (typeof actionProperty !== "object" || actionProperty === null) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
const actionConst = actionProperty.const;
|
|
124
|
+
return typeof actionConst === "string" && actions.has(actionConst);
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
...schema,
|
|
128
|
+
oneOf: filtered,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function normalizeCommandPath(value) {
|
|
132
|
+
return value
|
|
133
|
+
.trim()
|
|
134
|
+
.toLowerCase()
|
|
135
|
+
.split(/\s+/)
|
|
136
|
+
.filter((entry) => entry.length > 0)
|
|
137
|
+
.join(" ");
|
|
138
|
+
}
|
|
139
|
+
function normalizeActionNameFromCommand(commandPath) {
|
|
140
|
+
return commandPath.replace(/\s+/g, "-");
|
|
141
|
+
}
|
|
142
|
+
function toOptionalTrimmedString(value) {
|
|
143
|
+
if (typeof value !== "string") {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const trimmed = value.trim();
|
|
147
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
148
|
+
}
|
|
149
|
+
function normalizeStringList(values) {
|
|
150
|
+
if (!Array.isArray(values)) {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
const normalized = [];
|
|
154
|
+
const seen = new Set();
|
|
155
|
+
for (const value of values) {
|
|
156
|
+
const trimmed = toOptionalTrimmedString(value);
|
|
157
|
+
if (!trimmed || seen.has(trimmed)) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
seen.add(trimmed);
|
|
161
|
+
normalized.push(trimmed);
|
|
162
|
+
}
|
|
163
|
+
return normalized;
|
|
164
|
+
}
|
|
165
|
+
function toExtensionFlagContract(definition) {
|
|
166
|
+
const longName = toOptionalTrimmedString(definition.long);
|
|
167
|
+
const shortName = toOptionalTrimmedString(definition.short);
|
|
168
|
+
const normalizedLong = longName && longName.startsWith("--") && longName.length > 2 ? longName : null;
|
|
169
|
+
const normalizedShort = shortName && shortName.startsWith("-") && !shortName.startsWith("--") ? shortName : null;
|
|
170
|
+
const flag = normalizedLong ?? normalizedShort;
|
|
171
|
+
if (!flag) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const contract = { flag };
|
|
175
|
+
if (normalizedShort && normalizedLong) {
|
|
176
|
+
contract.short = normalizedShort;
|
|
177
|
+
}
|
|
178
|
+
return contract;
|
|
179
|
+
}
|
|
180
|
+
function collectExtensionFlagContractsByCommand(registrations) {
|
|
181
|
+
const grouped = new Map();
|
|
182
|
+
for (const registration of registrations) {
|
|
183
|
+
const commandPath = normalizeCommandPath(registration.target_command);
|
|
184
|
+
if (commandPath.length === 0) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const bucket = grouped.get(commandPath) ?? {
|
|
188
|
+
flags: [],
|
|
189
|
+
sources: [],
|
|
190
|
+
dedupe: new Set(),
|
|
191
|
+
sourceDedupe: new Set(),
|
|
192
|
+
};
|
|
193
|
+
const sourceKey = `${registration.layer}:${registration.name}`;
|
|
194
|
+
if (!bucket.sourceDedupe.has(sourceKey)) {
|
|
195
|
+
bucket.sourceDedupe.add(sourceKey);
|
|
196
|
+
bucket.sources.push({
|
|
197
|
+
layer: registration.layer,
|
|
198
|
+
name: registration.name,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
for (const definition of registration.flags) {
|
|
202
|
+
const contract = toExtensionFlagContract(definition);
|
|
203
|
+
if (!contract) {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
const key = `${contract.flag}|${contract.short ?? ""}`;
|
|
207
|
+
if (bucket.dedupe.has(key)) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
bucket.dedupe.add(key);
|
|
211
|
+
bucket.flags.push(contract);
|
|
212
|
+
}
|
|
213
|
+
grouped.set(commandPath, bucket);
|
|
214
|
+
}
|
|
215
|
+
const normalized = new Map();
|
|
216
|
+
for (const [commandPath, bucket] of grouped.entries()) {
|
|
217
|
+
normalized.set(commandPath, {
|
|
218
|
+
flags: bucket.flags,
|
|
219
|
+
sources: bucket.sources.sort((left, right) => {
|
|
220
|
+
const layerOrder = left.layer.localeCompare(right.layer);
|
|
221
|
+
if (layerOrder !== 0) {
|
|
222
|
+
return layerOrder;
|
|
223
|
+
}
|
|
224
|
+
return left.name.localeCompare(right.name);
|
|
225
|
+
}),
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return normalized;
|
|
229
|
+
}
|
|
230
|
+
function collectExtensionCommandContracts(runtimeProbe) {
|
|
231
|
+
const flagsByCommand = collectExtensionFlagContractsByCommand(runtimeProbe.flagRegistrations);
|
|
232
|
+
const definitionsByCommand = new Map();
|
|
233
|
+
for (const definition of runtimeProbe.commandDefinitions) {
|
|
234
|
+
const command = normalizeCommandPath(definition.command);
|
|
235
|
+
if (command.length === 0) {
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
const action = toOptionalTrimmedString(definition.action) ?? normalizeActionNameFromCommand(command);
|
|
239
|
+
const args = Array.isArray(definition.arguments)
|
|
240
|
+
? definition.arguments
|
|
241
|
+
.map((argument) => {
|
|
242
|
+
const name = toOptionalTrimmedString(argument.name);
|
|
243
|
+
if (!name) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
name,
|
|
248
|
+
required: argument.required === true,
|
|
249
|
+
variadic: argument.variadic === true,
|
|
250
|
+
description: toOptionalTrimmedString(argument.description),
|
|
251
|
+
};
|
|
252
|
+
})
|
|
253
|
+
.filter((argument) => argument !== null)
|
|
254
|
+
: [];
|
|
255
|
+
definitionsByCommand.set(command, {
|
|
256
|
+
command,
|
|
257
|
+
action,
|
|
258
|
+
source: {
|
|
259
|
+
layer: definition.layer,
|
|
260
|
+
name: definition.name,
|
|
261
|
+
},
|
|
262
|
+
description: toOptionalTrimmedString(definition.description),
|
|
263
|
+
intent: toOptionalTrimmedString(definition.intent),
|
|
264
|
+
arguments: args,
|
|
265
|
+
flags: flagsByCommand.get(command)?.flags ?? [],
|
|
266
|
+
examples: normalizeStringList(definition.examples),
|
|
267
|
+
failure_hints: normalizeStringList(definition.failure_hints),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
const extensionCommands = new Set();
|
|
271
|
+
for (const command of runtimeProbe.handlers) {
|
|
272
|
+
extensionCommands.add(normalizeCommandPath(command));
|
|
273
|
+
}
|
|
274
|
+
for (const command of definitionsByCommand.keys()) {
|
|
275
|
+
extensionCommands.add(command);
|
|
276
|
+
}
|
|
277
|
+
for (const command of flagsByCommand.keys()) {
|
|
278
|
+
extensionCommands.add(command);
|
|
279
|
+
}
|
|
280
|
+
const contracts = [];
|
|
281
|
+
for (const command of [...extensionCommands].sort((left, right) => left.localeCompare(right))) {
|
|
282
|
+
const definition = definitionsByCommand.get(command);
|
|
283
|
+
if (definition) {
|
|
284
|
+
contracts.push({
|
|
285
|
+
...definition,
|
|
286
|
+
flags: definition.flags.length > 0 ? definition.flags : flagsByCommand.get(command)?.flags ?? [],
|
|
287
|
+
});
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
contracts.push({
|
|
291
|
+
command,
|
|
292
|
+
action: normalizeActionNameFromCommand(command),
|
|
293
|
+
source: null,
|
|
294
|
+
description: null,
|
|
295
|
+
intent: null,
|
|
296
|
+
arguments: [],
|
|
297
|
+
flags: flagsByCommand.get(command)?.flags ?? [],
|
|
298
|
+
examples: [],
|
|
299
|
+
failure_hints: [],
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return contracts;
|
|
303
|
+
}
|
|
304
|
+
function extensionSchemaPropertyNameFromFlag(flag) {
|
|
305
|
+
const normalized = flag.flag.replace(/^-+/, "").trim();
|
|
306
|
+
if (normalized.length === 0) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
const camelCased = normalized.replace(/-([a-z0-9])/g, (_match, char) => char.toUpperCase());
|
|
310
|
+
const cleaned = camelCased.replace(/[^a-zA-Z0-9]/g, "");
|
|
311
|
+
return cleaned.length > 0 ? cleaned : null;
|
|
312
|
+
}
|
|
313
|
+
function buildExtensionActionSchemaBranch(contract) {
|
|
314
|
+
const properties = {
|
|
315
|
+
action: {
|
|
316
|
+
type: "string",
|
|
317
|
+
const: contract.action,
|
|
318
|
+
description: contract.intent ?? contract.description ?? `Invoke extension command '${contract.command}'.`,
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
const required = ["action"];
|
|
322
|
+
for (const argument of contract.arguments) {
|
|
323
|
+
if (argument.variadic) {
|
|
324
|
+
properties[argument.name] = {
|
|
325
|
+
type: "array",
|
|
326
|
+
items: { type: "string" },
|
|
327
|
+
description: argument.description ?? `Variadic argument '${argument.name}' for extension action '${contract.action}'.`,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
properties[argument.name] = {
|
|
332
|
+
type: "string",
|
|
333
|
+
description: argument.description ?? `Argument '${argument.name}' for extension action '${contract.action}'.`,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
if (argument.required) {
|
|
337
|
+
required.push(argument.name);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
for (const flag of contract.flags) {
|
|
341
|
+
const propertyName = extensionSchemaPropertyNameFromFlag(flag);
|
|
342
|
+
if (!propertyName || properties[propertyName] !== undefined) {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
const isBooleanFlag = !flag.flag.includes(" ");
|
|
346
|
+
properties[propertyName] = {
|
|
347
|
+
type: isBooleanFlag ? ["boolean", "string"] : "string",
|
|
348
|
+
description: `Extension option '${flag.flag}' for action '${contract.action}'.`,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
type: "object",
|
|
353
|
+
properties,
|
|
354
|
+
required,
|
|
355
|
+
additionalProperties: true,
|
|
356
|
+
"x-extension-source": contract.source,
|
|
357
|
+
"x-extension-command": contract.command,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
async function resolveRuntimeExtensionActionProbe(global) {
|
|
361
|
+
if (global.noExtensions) {
|
|
362
|
+
return {
|
|
363
|
+
handlers: new Set(),
|
|
364
|
+
disabledReason: "extensions_disabled",
|
|
365
|
+
commandDefinitions: [],
|
|
366
|
+
flagRegistrations: [],
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
const pmRoot = resolvePmRoot(process.cwd(), global.path);
|
|
370
|
+
if (!(await pathExists(getSettingsPath(pmRoot)))) {
|
|
371
|
+
return {
|
|
372
|
+
handlers: new Set(),
|
|
373
|
+
disabledReason: null,
|
|
374
|
+
commandDefinitions: [],
|
|
375
|
+
flagRegistrations: [],
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
try {
|
|
379
|
+
const settings = await readSettings(pmRoot);
|
|
380
|
+
const loadResult = await loadExtensions({
|
|
381
|
+
pmRoot,
|
|
382
|
+
settings,
|
|
383
|
+
cwd: process.cwd(),
|
|
384
|
+
noExtensions: false,
|
|
385
|
+
});
|
|
386
|
+
const activationResult = await activateExtensions({
|
|
387
|
+
...loadResult,
|
|
388
|
+
loaded: loadResult.loaded,
|
|
389
|
+
});
|
|
390
|
+
const handlers = new Set(activationResult.commands.handlers.map((entry) => normalizeCommandPath(entry.command)));
|
|
391
|
+
return {
|
|
392
|
+
handlers,
|
|
393
|
+
disabledReason: null,
|
|
394
|
+
commandDefinitions: activationResult.registrations.commands,
|
|
395
|
+
flagRegistrations: activationResult.registrations.flags,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
return {
|
|
400
|
+
handlers: new Set(),
|
|
401
|
+
disabledReason: "extension_runtime_probe_failed",
|
|
402
|
+
commandDefinitions: [],
|
|
403
|
+
flagRegistrations: [],
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function collectActionContractDescriptors(extensionContracts) {
|
|
408
|
+
const descriptors = new Map();
|
|
409
|
+
for (const action of PM_TOOL_ACTIONS) {
|
|
410
|
+
const extensionCommandPath = EXTENSION_ACTION_COMMAND_PATHS[action];
|
|
411
|
+
const commandPath = resolveActionCommandPath(action);
|
|
412
|
+
descriptors.set(action, {
|
|
413
|
+
action,
|
|
414
|
+
provider: extensionCommandPath ? "extension" : "core",
|
|
415
|
+
requires_extension: extensionCommandPath !== undefined,
|
|
416
|
+
command_path: commandPath,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
for (const contract of extensionContracts) {
|
|
420
|
+
if (descriptors.has(contract.action)) {
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
descriptors.set(contract.action, {
|
|
424
|
+
action: contract.action,
|
|
425
|
+
provider: "extension",
|
|
426
|
+
requires_extension: true,
|
|
427
|
+
command_path: normalizeCommandPath(contract.command),
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
return [...descriptors.values()].sort((left, right) => left.action.localeCompare(right.action));
|
|
431
|
+
}
|
|
432
|
+
function resolveActionAvailability(descriptor, runtimeProbe) {
|
|
433
|
+
if (descriptor.provider === "core" && !descriptor.requires_extension) {
|
|
434
|
+
return {
|
|
435
|
+
action: descriptor.action,
|
|
436
|
+
invocable: true,
|
|
437
|
+
available: true,
|
|
438
|
+
requires_extension: false,
|
|
439
|
+
provider: "core",
|
|
440
|
+
disabled_reason: null,
|
|
441
|
+
command_path: descriptor.command_path,
|
|
442
|
+
cli_exposed: descriptor.command_path !== null,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
const commandPath = descriptor.command_path ? normalizeCommandPath(descriptor.command_path) : "";
|
|
446
|
+
const extensionCommandAvailable = commandPath.length > 0 && runtimeProbe.handlers.has(commandPath);
|
|
447
|
+
const invocable = runtimeProbe.disabledReason === null && extensionCommandAvailable;
|
|
448
|
+
return {
|
|
449
|
+
action: descriptor.action,
|
|
450
|
+
invocable,
|
|
451
|
+
available: invocable,
|
|
452
|
+
requires_extension: true,
|
|
453
|
+
provider: "extension",
|
|
454
|
+
disabled_reason: invocable ? null : runtimeProbe.disabledReason ?? "extension_command_not_registered",
|
|
455
|
+
command_path: descriptor.command_path,
|
|
456
|
+
cli_exposed: extensionCommandAvailable,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function resolveCoreCommandFlags(command) {
|
|
460
|
+
if (command === "config") {
|
|
461
|
+
return CONFIG_FLAG_CONTRACTS;
|
|
462
|
+
}
|
|
463
|
+
if (command === "extension") {
|
|
464
|
+
return EXTENSION_FLAG_CONTRACTS;
|
|
465
|
+
}
|
|
466
|
+
if (command === "create") {
|
|
467
|
+
return CREATE_FLAG_CONTRACTS;
|
|
468
|
+
}
|
|
469
|
+
if (command === "update") {
|
|
470
|
+
return UPDATE_FLAG_CONTRACTS;
|
|
471
|
+
}
|
|
472
|
+
if (command === "update-many") {
|
|
473
|
+
return UPDATE_MANY_FLAG_CONTRACTS;
|
|
474
|
+
}
|
|
475
|
+
if (command === "normalize") {
|
|
476
|
+
return NORMALIZE_FLAG_CONTRACTS;
|
|
477
|
+
}
|
|
478
|
+
if (command === "calendar" || command === "cal") {
|
|
479
|
+
return CALENDAR_FLAG_CONTRACTS;
|
|
480
|
+
}
|
|
481
|
+
if (command === "context" || command === "ctx") {
|
|
482
|
+
return CONTEXT_FLAG_CONTRACTS;
|
|
483
|
+
}
|
|
484
|
+
if (command === "search") {
|
|
485
|
+
return SEARCH_FLAG_CONTRACTS;
|
|
486
|
+
}
|
|
487
|
+
if (command === "aggregate") {
|
|
488
|
+
return AGGREGATE_FLAG_CONTRACTS;
|
|
489
|
+
}
|
|
490
|
+
if (command === "dedupe-audit") {
|
|
491
|
+
return DEDUPE_AUDIT_FLAG_CONTRACTS;
|
|
492
|
+
}
|
|
493
|
+
if (command === "deps") {
|
|
494
|
+
return DEPS_FLAG_CONTRACTS;
|
|
495
|
+
}
|
|
496
|
+
if (command === "reindex") {
|
|
497
|
+
return REINDEX_FLAG_CONTRACTS;
|
|
498
|
+
}
|
|
499
|
+
if (command === "history") {
|
|
500
|
+
return HISTORY_FLAG_CONTRACTS;
|
|
501
|
+
}
|
|
502
|
+
if (command === "restore") {
|
|
503
|
+
return RESTORE_FLAG_CONTRACTS;
|
|
504
|
+
}
|
|
505
|
+
if (command === "delete") {
|
|
506
|
+
return DELETE_FLAG_CONTRACTS;
|
|
507
|
+
}
|
|
508
|
+
if (command === "close") {
|
|
509
|
+
return CLOSE_FLAG_CONTRACTS;
|
|
510
|
+
}
|
|
511
|
+
if (command === "append") {
|
|
512
|
+
return APPEND_FLAG_CONTRACTS;
|
|
513
|
+
}
|
|
514
|
+
if (command === "claim") {
|
|
515
|
+
return CLAIM_FLAG_CONTRACTS;
|
|
516
|
+
}
|
|
517
|
+
if (command === "release") {
|
|
518
|
+
return RELEASE_FLAG_CONTRACTS;
|
|
519
|
+
}
|
|
520
|
+
if (command === "start-task") {
|
|
521
|
+
return START_TASK_FLAG_CONTRACTS;
|
|
522
|
+
}
|
|
523
|
+
if (command === "pause-task") {
|
|
524
|
+
return PAUSE_TASK_FLAG_CONTRACTS;
|
|
525
|
+
}
|
|
526
|
+
if (command === "close-task") {
|
|
527
|
+
return CLOSE_TASK_FLAG_CONTRACTS;
|
|
528
|
+
}
|
|
529
|
+
if (command === "comments") {
|
|
530
|
+
return COMMENTS_FLAG_CONTRACTS;
|
|
531
|
+
}
|
|
532
|
+
if (command === "notes") {
|
|
533
|
+
return NOTES_FLAG_CONTRACTS;
|
|
534
|
+
}
|
|
535
|
+
if (command === "learnings") {
|
|
536
|
+
return LEARNINGS_FLAG_CONTRACTS;
|
|
537
|
+
}
|
|
538
|
+
if (command === "files") {
|
|
539
|
+
return FILES_FLAG_CONTRACTS;
|
|
540
|
+
}
|
|
541
|
+
if (command === "docs") {
|
|
542
|
+
return DOCS_FLAG_CONTRACTS;
|
|
543
|
+
}
|
|
544
|
+
if (command === "test") {
|
|
545
|
+
return TEST_FLAG_CONTRACTS;
|
|
546
|
+
}
|
|
547
|
+
if (command === "test-all") {
|
|
548
|
+
return TEST_ALL_FLAG_CONTRACTS;
|
|
549
|
+
}
|
|
550
|
+
if (command === "test-runs") {
|
|
551
|
+
return TEST_RUNS_FLAG_CONTRACTS;
|
|
552
|
+
}
|
|
553
|
+
if (command === "gc") {
|
|
554
|
+
return GC_FLAG_CONTRACTS;
|
|
555
|
+
}
|
|
556
|
+
if (command === "validate") {
|
|
557
|
+
return VALIDATE_FLAG_CONTRACTS;
|
|
558
|
+
}
|
|
559
|
+
if (command === "comments-audit") {
|
|
560
|
+
return COMMENTS_AUDIT_FLAG_CONTRACTS;
|
|
561
|
+
}
|
|
562
|
+
if (command === "health") {
|
|
563
|
+
return HEALTH_FLAG_CONTRACTS;
|
|
564
|
+
}
|
|
565
|
+
if (command === "contracts") {
|
|
566
|
+
return CONTRACTS_FLAG_CONTRACTS;
|
|
567
|
+
}
|
|
568
|
+
if (command === "completion") {
|
|
569
|
+
return COMPLETION_FLAG_CONTRACTS;
|
|
570
|
+
}
|
|
571
|
+
if (command === "activity") {
|
|
572
|
+
return ACTIVITY_FLAG_CONTRACTS;
|
|
573
|
+
}
|
|
574
|
+
if (LIST_COMMAND_NAMES.has(command)) {
|
|
575
|
+
return LIST_FILTER_FLAG_CONTRACTS;
|
|
576
|
+
}
|
|
577
|
+
return GLOBAL_FLAG_CONTRACTS;
|
|
578
|
+
}
|
|
579
|
+
function normalizeCommandForRuntimeFieldFlags(command) {
|
|
580
|
+
if (LIST_COMMAND_NAMES.has(command)) {
|
|
581
|
+
return "list";
|
|
582
|
+
}
|
|
583
|
+
if (command === "cal") {
|
|
584
|
+
return "calendar";
|
|
585
|
+
}
|
|
586
|
+
if (command === "ctx") {
|
|
587
|
+
return "context";
|
|
588
|
+
}
|
|
589
|
+
if (command === "update-many") {
|
|
590
|
+
return "update";
|
|
591
|
+
}
|
|
592
|
+
return command;
|
|
593
|
+
}
|
|
594
|
+
function toRuntimeLongFlagToken(token) {
|
|
595
|
+
const trimmed = token.trim();
|
|
596
|
+
if (!trimmed) {
|
|
597
|
+
return null;
|
|
598
|
+
}
|
|
599
|
+
if (trimmed.startsWith("--")) {
|
|
600
|
+
return trimmed;
|
|
601
|
+
}
|
|
602
|
+
if (trimmed.startsWith("-")) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
return `--${trimmed}`;
|
|
606
|
+
}
|
|
607
|
+
function toRuntimeShortFlagToken(token) {
|
|
608
|
+
const trimmed = token.trim();
|
|
609
|
+
if (!trimmed) {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
if (trimmed.startsWith("--")) {
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
if (trimmed.startsWith("-")) {
|
|
616
|
+
return trimmed;
|
|
617
|
+
}
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
function buildRuntimeFieldFlagContracts(fieldRegistry) {
|
|
621
|
+
const buckets = new Map();
|
|
622
|
+
for (const definition of fieldRegistry.definitions) {
|
|
623
|
+
const primaryFlag = toRuntimeLongFlagToken(definition.cli_flag);
|
|
624
|
+
if (!primaryFlag) {
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
const shortAlias = definition.cli_aliases.map((alias) => toRuntimeShortFlagToken(alias)).find((alias) => alias !== null);
|
|
628
|
+
const longAliases = definition.cli_aliases
|
|
629
|
+
.map((alias) => toRuntimeLongFlagToken(alias))
|
|
630
|
+
.filter((alias) => alias !== null && alias !== primaryFlag);
|
|
631
|
+
for (const command of definition.commands) {
|
|
632
|
+
const bucket = buckets.get(command) ?? { flags: [], seen: new Set() };
|
|
633
|
+
const primaryContract = shortAlias ? { flag: primaryFlag, short: shortAlias } : { flag: primaryFlag };
|
|
634
|
+
const primaryKey = `${primaryContract.flag}|${primaryContract.short ?? ""}`;
|
|
635
|
+
if (!bucket.seen.has(primaryKey)) {
|
|
636
|
+
bucket.seen.add(primaryKey);
|
|
637
|
+
bucket.flags.push(primaryContract);
|
|
638
|
+
}
|
|
639
|
+
for (const alias of longAliases) {
|
|
640
|
+
const key = `${alias}|`;
|
|
641
|
+
if (bucket.seen.has(key)) {
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
bucket.seen.add(key);
|
|
645
|
+
bucket.flags.push({ flag: alias });
|
|
646
|
+
}
|
|
647
|
+
buckets.set(command, bucket);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
const result = new Map();
|
|
651
|
+
for (const [command, bucket] of buckets.entries()) {
|
|
652
|
+
result.set(command, withFlagAliasMetadata(bucket.flags));
|
|
653
|
+
}
|
|
654
|
+
return result;
|
|
655
|
+
}
|
|
656
|
+
function mergeFlagContracts(primary, secondary) {
|
|
657
|
+
const merged = [];
|
|
658
|
+
const seen = new Set();
|
|
659
|
+
for (const contract of [...primary, ...secondary]) {
|
|
660
|
+
const key = `${contract.flag}|${contract.short ?? ""}`;
|
|
661
|
+
if (seen.has(key)) {
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
seen.add(key);
|
|
665
|
+
merged.push(contract);
|
|
666
|
+
}
|
|
667
|
+
return withFlagAliasMetadata(merged);
|
|
668
|
+
}
|
|
669
|
+
function buildCommandFlagSurface(commands, extensionFlagMap, runtimeFieldFlagMap) {
|
|
670
|
+
return commands
|
|
671
|
+
.map((command) => {
|
|
672
|
+
const isCoreCommand = PM_CORE_COMMAND_NAMES.includes(command);
|
|
673
|
+
const coreFlags = isCoreCommand ? resolveCoreCommandFlags(command) : [];
|
|
674
|
+
const runtimeFlags = runtimeFieldFlagMap.get(normalizeCommandForRuntimeFieldFlags(command)) ?? [];
|
|
675
|
+
const extensionFlags = extensionFlagMap.get(command);
|
|
676
|
+
const coreWithRuntime = mergeFlagContracts(coreFlags, runtimeFlags);
|
|
677
|
+
const flags = mergeFlagContracts(coreWithRuntime, extensionFlags?.flags ?? []);
|
|
678
|
+
const provider = coreFlags.length > 0 && (extensionFlags?.flags.length ?? 0) > 0
|
|
679
|
+
? "mixed"
|
|
680
|
+
: isCoreCommand
|
|
681
|
+
? "core"
|
|
682
|
+
: "extension";
|
|
683
|
+
return {
|
|
684
|
+
command,
|
|
685
|
+
flags,
|
|
686
|
+
provider,
|
|
687
|
+
extension_sources: extensionFlags?.sources,
|
|
688
|
+
};
|
|
689
|
+
})
|
|
690
|
+
.sort((left, right) => left.command.localeCompare(right.command));
|
|
691
|
+
}
|
|
692
|
+
function buildCommanderAliasSurface() {
|
|
693
|
+
return {
|
|
694
|
+
create_string_options: CREATE_COMMANDER_STRING_OPTION_CONTRACTS,
|
|
695
|
+
create_repeatable_options: CREATE_COMMANDER_REPEATABLE_OPTION_CONTRACTS,
|
|
696
|
+
update_string_options: UPDATE_COMMANDER_STRING_OPTION_CONTRACTS,
|
|
697
|
+
update_repeatable_options: UPDATE_COMMANDER_REPEATABLE_OPTION_CONTRACTS,
|
|
698
|
+
list_string_options: LIST_COMMANDER_STRING_OPTION_CONTRACTS,
|
|
699
|
+
search_string_options: SEARCH_COMMANDER_STRING_OPTION_CONTRACTS,
|
|
700
|
+
calendar_string_options: CALENDAR_COMMANDER_STRING_OPTION_CONTRACTS,
|
|
701
|
+
context_string_options: CONTEXT_COMMANDER_STRING_OPTION_CONTRACTS,
|
|
702
|
+
activity_string_options: ACTIVITY_COMMANDER_STRING_OPTION_CONTRACTS,
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
function resolveCreateRequiredOptionContract(typeDefinition, createMode) {
|
|
706
|
+
const baseRequiredOptions = new Set(["title", "description", "type"]);
|
|
707
|
+
if (createMode === "strict") {
|
|
708
|
+
for (const field of typeDefinition.required_create_fields) {
|
|
709
|
+
baseRequiredOptions.add(field);
|
|
710
|
+
}
|
|
711
|
+
for (const field of typeDefinition.required_create_repeatables) {
|
|
712
|
+
baseRequiredOptions.add(field);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
const policyState = resolveCommandOptionPolicyState(typeDefinition, "create", baseRequiredOptions);
|
|
716
|
+
const requiredOptionKeys = [...new Set(policyState.required)].sort((left, right) => left.localeCompare(right));
|
|
717
|
+
const requiredFlags = [...new Set(requiredOptionKeys.map((option) => commandOptionFlagLabel("create", option)))].sort((left, right) => left.localeCompare(right));
|
|
718
|
+
const requiredTypeOptions = [...new Set(typeDefinition.options.filter((option) => option.required === true).map((option) => option.key))].sort((left, right) => left.localeCompare(right));
|
|
719
|
+
return {
|
|
720
|
+
required_option_keys: requiredOptionKeys,
|
|
721
|
+
required_flags: requiredFlags,
|
|
722
|
+
required_type_options: requiredTypeOptions,
|
|
723
|
+
policy_errors: [...new Set(policyState.errors)].sort((left, right) => left.localeCompare(right)),
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function buildCreateRequiredOptionContracts(typeRegistry) {
|
|
727
|
+
const byTypeStrict = {};
|
|
728
|
+
const byTypeProgressive = {};
|
|
729
|
+
for (const typeName of [...typeRegistry.types].sort((left, right) => left.localeCompare(right))) {
|
|
730
|
+
const typeDefinition = typeRegistry.by_type[typeName];
|
|
731
|
+
byTypeStrict[typeName] = resolveCreateRequiredOptionContract(typeDefinition, "strict");
|
|
732
|
+
byTypeProgressive[typeName] = resolveCreateRequiredOptionContract(typeDefinition, "progressive");
|
|
733
|
+
}
|
|
734
|
+
return {
|
|
735
|
+
default_create_mode: "strict",
|
|
736
|
+
by_create_mode: {
|
|
737
|
+
strict: {
|
|
738
|
+
by_type: byTypeStrict,
|
|
739
|
+
},
|
|
740
|
+
progressive: {
|
|
741
|
+
by_type: byTypeProgressive,
|
|
742
|
+
},
|
|
743
|
+
},
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
function attachCreateRequiredOptionContracts(schema, metadata) {
|
|
747
|
+
const branches = extractActionBranches(schema);
|
|
748
|
+
if (branches.length === 0) {
|
|
749
|
+
return schema;
|
|
750
|
+
}
|
|
751
|
+
let touched = false;
|
|
752
|
+
const enrichedBranches = branches.map((branch) => {
|
|
753
|
+
const properties = branch.properties;
|
|
754
|
+
if (typeof properties !== "object" || properties === null) {
|
|
755
|
+
return branch;
|
|
756
|
+
}
|
|
757
|
+
const actionProperty = properties.action;
|
|
758
|
+
if (typeof actionProperty !== "object" || actionProperty === null) {
|
|
759
|
+
return branch;
|
|
760
|
+
}
|
|
761
|
+
if (actionProperty.const !== "create") {
|
|
762
|
+
return branch;
|
|
763
|
+
}
|
|
764
|
+
touched = true;
|
|
765
|
+
return {
|
|
766
|
+
...branch,
|
|
767
|
+
"x-create-required-options": metadata,
|
|
768
|
+
};
|
|
769
|
+
});
|
|
770
|
+
if (!touched) {
|
|
771
|
+
return schema;
|
|
772
|
+
}
|
|
773
|
+
return {
|
|
774
|
+
...schema,
|
|
775
|
+
oneOf: enrichedBranches,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
export async function runContracts(options, global) {
|
|
779
|
+
const selectedAction = normalizeToken(options.action);
|
|
780
|
+
const selectedCommand = normalizeToken(options.command);
|
|
781
|
+
const schemaOnly = options.schemaOnly === true;
|
|
782
|
+
const flagsOnly = options.flagsOnly === true;
|
|
783
|
+
const availabilityOnly = options.availabilityOnly === true;
|
|
784
|
+
const runtimeOnly = options.runtimeOnly === true;
|
|
785
|
+
const projectionFlagsEnabled = [schemaOnly, flagsOnly, availabilityOnly].filter((value) => value).length;
|
|
786
|
+
if (projectionFlagsEnabled > 1) {
|
|
787
|
+
throw new PmCliError("Choose only one projection flag: --schema-only, --flags-only, or --availability-only.", EXIT_CODE.USAGE);
|
|
788
|
+
}
|
|
789
|
+
const pmRoot = resolvePmRoot(process.cwd(), global.path);
|
|
790
|
+
let settings = structuredClone(SETTINGS_DEFAULTS);
|
|
791
|
+
try {
|
|
792
|
+
settings = await readSettings(pmRoot);
|
|
793
|
+
}
|
|
794
|
+
catch {
|
|
795
|
+
settings = structuredClone(SETTINGS_DEFAULTS);
|
|
796
|
+
}
|
|
797
|
+
const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
|
|
798
|
+
const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
|
|
799
|
+
const runtimeFieldRegistry = resolveRuntimeFieldRegistry(settings.schema);
|
|
800
|
+
const runtimeFieldFlagMap = buildRuntimeFieldFlagContracts(runtimeFieldRegistry);
|
|
801
|
+
const createRequiredOptionContracts = buildCreateRequiredOptionContracts(typeRegistry);
|
|
802
|
+
const runtimeProbe = await resolveRuntimeExtensionActionProbe(global);
|
|
803
|
+
const extensionContracts = collectExtensionCommandContracts(runtimeProbe);
|
|
804
|
+
const extensionFlagMap = collectExtensionFlagContractsByCommand(runtimeProbe.flagRegistrations);
|
|
805
|
+
const actionDescriptors = collectActionContractDescriptors(extensionContracts);
|
|
806
|
+
const actionNames = new Set(actionDescriptors.map((entry) => entry.action));
|
|
807
|
+
if (selectedAction && !actionNames.has(selectedAction)) {
|
|
808
|
+
throw new PmCliError(`Unknown action: "${options.action}".`, EXIT_CODE.USAGE);
|
|
809
|
+
}
|
|
810
|
+
const commandCatalog = [...new Set([...PM_CORE_COMMAND_NAMES, ...extensionContracts.map((entry) => entry.command)])]
|
|
811
|
+
.map((entry) => normalizeCommandPath(entry))
|
|
812
|
+
.filter((entry) => entry.length > 0)
|
|
813
|
+
.sort((left, right) => left.localeCompare(right));
|
|
814
|
+
const commandNames = new Set(commandCatalog);
|
|
815
|
+
if (selectedCommand && !commandNames.has(selectedCommand)) {
|
|
816
|
+
throw new PmCliError(`Unknown command: "${options.command}".`, EXIT_CODE.USAGE);
|
|
817
|
+
}
|
|
818
|
+
const commandScopedDescriptors = selectedCommand
|
|
819
|
+
? actionDescriptors.filter((descriptor) => actionDescriptorMatchesSelectedCommand(descriptor, selectedCommand))
|
|
820
|
+
: actionDescriptors;
|
|
821
|
+
if (selectedCommand &&
|
|
822
|
+
selectedAction &&
|
|
823
|
+
!commandScopedDescriptors.some((descriptor) => descriptor.action === selectedAction)) {
|
|
824
|
+
throw new PmCliError(`Action "${options.action}" is not mapped to command "${options.command}" in contracts output.`, EXIT_CODE.USAGE);
|
|
825
|
+
}
|
|
826
|
+
const schema = PM_TOOL_PARAMETERS_SCHEMA;
|
|
827
|
+
const schemaBranches = extractActionBranches(schema);
|
|
828
|
+
const schemaActionSet = new Set(schemaBranches
|
|
829
|
+
.map((entry) => {
|
|
830
|
+
const properties = entry.properties;
|
|
831
|
+
if (typeof properties !== "object" || properties === null) {
|
|
832
|
+
return null;
|
|
833
|
+
}
|
|
834
|
+
const actionProperty = properties.action;
|
|
835
|
+
if (typeof actionProperty !== "object" || actionProperty === null) {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
const actionConst = actionProperty.const;
|
|
839
|
+
return typeof actionConst === "string" ? actionConst : null;
|
|
840
|
+
})
|
|
841
|
+
.filter((entry) => entry !== null));
|
|
842
|
+
const extensionBranches = extensionContracts
|
|
843
|
+
.filter((contract) => !schemaActionSet.has(contract.action))
|
|
844
|
+
.map((contract) => buildExtensionActionSchemaBranch(contract));
|
|
845
|
+
const mergedSchema = extensionBranches.length > 0
|
|
846
|
+
? {
|
|
847
|
+
...schema,
|
|
848
|
+
oneOf: [...schemaBranches, ...extensionBranches],
|
|
849
|
+
}
|
|
850
|
+
: schema;
|
|
851
|
+
const scopedActionDescriptors = selectedAction
|
|
852
|
+
? commandScopedDescriptors.filter((descriptor) => descriptor.action === selectedAction)
|
|
853
|
+
: commandScopedDescriptors;
|
|
854
|
+
const allActionAvailability = scopedActionDescriptors.map((descriptor) => resolveActionAvailability(descriptor, runtimeProbe));
|
|
855
|
+
const actionAvailability = runtimeOnly && !selectedAction ? allActionAvailability.filter((entry) => entry.invocable) : allActionAvailability;
|
|
856
|
+
const actions = actionAvailability.map((entry) => entry.action);
|
|
857
|
+
let filteredSchema = selectedAction
|
|
858
|
+
? filterSchemaByAction(mergedSchema, selectedAction)
|
|
859
|
+
: selectedCommand
|
|
860
|
+
? filterSchemaByActions(mergedSchema, new Set(scopedActionDescriptors.map((descriptor) => descriptor.action)))
|
|
861
|
+
: mergedSchema;
|
|
862
|
+
if (runtimeOnly && !selectedAction) {
|
|
863
|
+
filteredSchema = filterSchemaByActions(filteredSchema, new Set(actions));
|
|
864
|
+
}
|
|
865
|
+
const includeSchemaSurface = !flagsOnly && !availabilityOnly;
|
|
866
|
+
if (includeSchemaSurface) {
|
|
867
|
+
filteredSchema = attachCreateRequiredOptionContracts(filteredSchema, createRequiredOptionContracts);
|
|
868
|
+
}
|
|
869
|
+
const commands = selectedCommand !== undefined
|
|
870
|
+
? [selectedCommand]
|
|
871
|
+
: selectedAction
|
|
872
|
+
? resolveScopedCommandsFromActionDescriptors(scopedActionDescriptors, commandCatalog)
|
|
873
|
+
: commandCatalog;
|
|
874
|
+
const extensionCommandContracts = selectedCommand
|
|
875
|
+
? extensionContracts.filter((entry) => entry.command === selectedCommand)
|
|
876
|
+
: selectedAction
|
|
877
|
+
? extensionContracts.filter((entry) => commands.includes(normalizeCommandPath(entry.command)))
|
|
878
|
+
: extensionContracts;
|
|
879
|
+
const result = {
|
|
880
|
+
schema_version: typeof mergedSchema["x-schema-version"] === "string" ? mergedSchema["x-schema-version"] : null,
|
|
881
|
+
schema_id: typeof mergedSchema.$id === "string" ? mergedSchema.$id : null,
|
|
882
|
+
selected: {
|
|
883
|
+
action: selectedAction ?? null,
|
|
884
|
+
command: selectedCommand ?? null,
|
|
885
|
+
schema_only: schemaOnly,
|
|
886
|
+
flags_only: flagsOnly,
|
|
887
|
+
availability_only: availabilityOnly,
|
|
888
|
+
runtime_only: runtimeOnly,
|
|
889
|
+
command_scoped: selectedCommand !== undefined,
|
|
890
|
+
},
|
|
891
|
+
commands,
|
|
892
|
+
runtime_schema: {
|
|
893
|
+
statuses: statusRegistry.definitions.map((definition) => definition.id),
|
|
894
|
+
open_status: statusRegistry.open_status,
|
|
895
|
+
close_status: statusRegistry.close_status,
|
|
896
|
+
canceled_status: statusRegistry.canceled_status,
|
|
897
|
+
types: [...typeRegistry.types],
|
|
898
|
+
fields_by_command: Object.fromEntries([...runtimeFieldRegistry.command_to_fields.entries()].map(([command, definitions]) => [
|
|
899
|
+
command,
|
|
900
|
+
[...new Set(definitions.map((definition) => `--${definition.cli_flag}`))].sort((left, right) => left.localeCompare(right)),
|
|
901
|
+
])),
|
|
902
|
+
},
|
|
903
|
+
};
|
|
904
|
+
if (!flagsOnly) {
|
|
905
|
+
result.actions = actions;
|
|
906
|
+
result.action_availability = actionAvailability;
|
|
907
|
+
}
|
|
908
|
+
if (includeSchemaSurface) {
|
|
909
|
+
result.schema = filteredSchema;
|
|
910
|
+
result.extension_commands = extensionCommandContracts;
|
|
911
|
+
}
|
|
912
|
+
if (!schemaOnly && !availabilityOnly) {
|
|
913
|
+
result.command_flags = buildCommandFlagSurface(commands, extensionFlagMap, runtimeFieldFlagMap);
|
|
914
|
+
}
|
|
915
|
+
if (!schemaOnly && !flagsOnly && !availabilityOnly) {
|
|
916
|
+
result.commander_aliases = buildCommanderAliasSurface();
|
|
917
|
+
}
|
|
918
|
+
return result;
|
|
919
|
+
}
|
|
920
|
+
//# sourceMappingURL=contracts.js.map
|