@aefree/pi-plastic 0.7.6 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +48 -174
- package/docs/2026-10-06-development.md +101 -0
- package/docs/2026-10-06-diffs-and-patches.md +136 -0
- package/docs/2026-10-06-discovery.md +135 -0
- package/docs/2026-10-06-integrations.md +49 -0
- package/docs/2026-10-06-merging.md +153 -0
- package/docs/2026-10-06-safety-and-receipts.md +95 -0
- package/docs/2026-10-06-setup.md +101 -0
- package/docs/2026-10-06-shelvesets-and-reviews.md +113 -0
- package/docs/2026-10-06-status.md +116 -0
- package/docs/2026-10-06-tools-and-loading.md +64 -0
- package/docs/2026-10-06-workspace-operations.md +142 -0
- package/docs/README.md +65 -0
- package/extensions/bash-cm-diff-guard.ts +1 -1
- package/index.ts +4 -687
- package/package.json +10 -4
- package/skills/using-plastic/SKILL.md +11 -5
- package/skills/using-plastic/references/branch-management.md +5 -1
- package/skills/using-plastic/references/changeset-operations.md +9 -8
- package/skills/using-plastic/references/code-review-creation.md +25 -18
- package/skills/using-plastic/references/integration.md +9 -5
- package/skills/using-plastic/references/quick-reference.md +4 -4
- package/skills/using-plastic/references/reviewing-changes.md +10 -10
- package/skills/using-plastic/references/shelving.md +26 -11
- package/skills/using-plastic/references/troubleshooting.md +4 -4
- package/src/diff/local-snapshot.ts +74 -0
- package/src/diff/text.ts +187 -0
- package/src/domain/add-contract.ts +24 -0
- package/src/domain/branch-create-contract.ts +38 -0
- package/src/domain/branch-delete-contract.ts +15 -0
- package/src/domain/branches.ts +263 -0
- package/src/domain/checkin-contract.ts +70 -0
- package/src/domain/closeout-contract.ts +30 -0
- package/src/domain/copied-merge.ts +42 -0
- package/src/domain/diff-base-xml.ts +65 -0
- package/src/domain/diff-pending-xml.ts +34 -0
- package/src/domain/merge-output.ts +327 -0
- package/src/domain/paths.ts +253 -0
- package/src/domain/pending.ts +499 -0
- package/src/domain/removal-contract.ts +25 -0
- package/src/domain/revisions.ts +301 -0
- package/src/domain/server-merge-contract.ts +45 -0
- package/src/domain/server-merge-resolutions.ts +61 -0
- package/src/domain/status-xml.ts +122 -0
- package/src/domain/switch-contract.ts +60 -0
- package/src/domain/switch-policy.ts +95 -0
- package/src/domain/undo-contract.ts +24 -0
- package/src/domain/update-contract.ts +16 -0
- package/src/domain/workspace-merge-contract.ts +41 -0
- package/src/execution/add-command.ts +118 -0
- package/src/execution/branch-create-command.ts +118 -0
- package/src/execution/branch-list-command.ts +75 -0
- package/src/execution/checkin-command.ts +116 -0
- package/src/execution/cli-version.ts +31 -0
- package/src/execution/cm.ts +59 -0
- package/src/execution/code-review-find-command.ts +75 -0
- package/src/execution/context.ts +20 -0
- package/src/execution/diff-revisions-command.ts +74 -0
- package/src/execution/process.ts +260 -0
- package/src/execution/removal-command.ts +118 -0
- package/src/execution/server-merge-command.ts +92 -0
- package/src/execution/shelveset-list-command.ts +75 -0
- package/src/execution/status-command.ts +29 -0
- package/src/execution/status-xml-command.ts +72 -0
- package/src/execution/status-xml-limits.ts +1 -0
- package/src/execution/switch-command.ts +118 -0
- package/src/execution/test-seams.ts +10 -0
- package/src/execution/undo-command.ts +118 -0
- package/src/execution/update-command.ts +118 -0
- package/src/execution/workspace-list-command.ts +75 -0
- package/src/execution/workspace-merge-command.ts +118 -0
- package/src/operations/add-receipt.ts +37 -0
- package/src/operations/arguments.ts +3 -0
- package/src/operations/branch-create.ts +74 -0
- package/src/operations/branch-delete-receipt.ts +25 -0
- package/src/operations/branch-list.ts +94 -0
- package/src/operations/branch-reads.ts +94 -0
- package/src/operations/branches.ts +111 -0
- package/src/operations/checkin-receipt.ts +140 -0
- package/src/operations/checkin.ts +102 -0
- package/src/operations/closeout-receipt.ts +74 -0
- package/src/operations/closeout.ts +19 -0
- package/src/operations/code-review-find.ts +97 -0
- package/src/operations/consolidated-diff.ts +144 -0
- package/src/operations/diff-revisions.ts +157 -0
- package/src/operations/diff.ts +53 -0
- package/src/operations/merge.ts +26 -0
- package/src/operations/object-delete-receipt.ts +21 -0
- package/src/operations/object-write-receipt.ts +105 -0
- package/src/operations/patch-receipt.ts +96 -0
- package/src/operations/patch-support.ts +375 -0
- package/src/operations/patch.ts +25 -0
- package/src/operations/removal-receipt.ts +42 -0
- package/src/operations/reviews.ts +90 -0
- package/src/operations/server-merge.ts +130 -0
- package/src/operations/shelveset-list.ts +90 -0
- package/src/operations/shelvesets.ts +90 -0
- package/src/operations/status.ts +129 -0
- package/src/operations/switch-receipt.ts +85 -0
- package/src/operations/switch.ts +25 -0
- package/src/operations/undo-receipt.ts +37 -0
- package/src/operations/update-receipt.ts +35 -0
- package/src/operations/workspace-list.ts +92 -0
- package/src/operations/workspace-merge-receipt.ts +50 -0
- package/src/operations/workspace.ts +120 -0
- package/src/pi/add-output.ts +52 -0
- package/src/pi/arguments.ts +298 -0
- package/src/pi/branch-create-output.ts +83 -0
- package/src/pi/branch-delete-output.ts +46 -0
- package/src/pi/branch-list-output.ts +59 -0
- package/src/pi/branch-output.ts +63 -0
- package/src/pi/capability-diagnostics.ts +23 -0
- package/src/pi/checkin-output.ts +68 -0
- package/src/pi/closeout-output.ts +87 -0
- package/src/pi/code-review-find-output.ts +50 -0
- package/src/pi/diff-output.ts +66 -0
- package/src/pi/diff-revisions-output.ts +55 -0
- package/src/pi/object-delete-output.ts +15 -0
- package/src/pi/object-write-output.ts +54 -0
- package/src/pi/patch-output.ts +69 -0
- package/src/pi/register.ts +188 -0
- package/src/pi/removal-output.ts +59 -0
- package/src/pi/schemas.ts +146 -0
- package/src/pi/server-merge-output.ts +83 -0
- package/src/pi/shelveset-list-output.ts +50 -0
- package/src/pi/status-output.ts +149 -0
- package/src/pi/switch-output.ts +80 -0
- package/src/pi/tool-registry.ts +72 -0
- package/src/pi/undo-output.ts +52 -0
- package/src/pi/update-output.ts +48 -0
- package/src/pi/workspace-list-output.ts +53 -0
- package/src/pi/workspace-merge-output.ts +46 -0
- package/src/plastic-core.ts +14 -5775
- package/src/plastic-renderers.ts +102 -22
- package/src/plastic-tool-loading.ts +7 -12
- package/src/presentation/add-results.ts +5 -0
- package/src/presentation/branch-create.ts +7 -0
- package/src/presentation/branch-delete-results.ts +7 -0
- package/src/presentation/checkin-results.ts +14 -0
- package/src/presentation/closeout-results.ts +2 -0
- package/src/presentation/diff-results.ts +237 -0
- package/src/presentation/removal-results.ts +7 -0
- package/src/presentation/results.ts +84 -0
- package/src/presentation/switch-results.ts +7 -0
- package/src/presentation/undo-results.ts +5 -0
- package/src/presentation/update-results.ts +5 -0
- package/src/presentation/workspace-merge-results.ts +6 -0
package/index.ts
CHANGED
|
@@ -1,695 +1,12 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import {
|
|
4
|
-
import * as core from "./src/plastic-core";
|
|
5
|
-
import { renderPlasticCall, renderPlasticResult, renderPlasticSearchResult } from "./src/plastic-renderers";
|
|
6
|
-
import {
|
|
7
|
-
getEffectivePlasticToolOwnership,
|
|
8
|
-
getInitiallyInactivePlasticTools,
|
|
9
|
-
getPlasticToolLoadingMode,
|
|
10
|
-
getRestoredPlasticToolNames,
|
|
11
|
-
getUnknownExactPlasticToolNames,
|
|
12
|
-
isPlasticToolBrowseRequest,
|
|
13
|
-
PLASTIC_TOOL_BROWSE_TEXT,
|
|
14
|
-
PLASTIC_TOOL_SEARCH_NAME,
|
|
15
|
-
searchPlasticTools,
|
|
16
|
-
} from "./src/plastic-tool-loading";
|
|
3
|
+
import { registerPlasticTools } from "./src/pi/register";
|
|
17
4
|
|
|
18
|
-
|
|
19
|
-
kind: string;
|
|
20
|
-
values?: unknown;
|
|
21
|
-
inner?: unknown;
|
|
22
|
-
metadata?: {
|
|
23
|
-
optional?: boolean;
|
|
24
|
-
description?: string;
|
|
25
|
-
min?: number;
|
|
26
|
-
max?: number;
|
|
27
|
-
int?: boolean;
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type CoreTool = {
|
|
32
|
-
description?: string;
|
|
33
|
-
args?: Record<string, unknown>;
|
|
34
|
-
execute: (args: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
type ToolConfig = {
|
|
38
|
-
prepareArguments?: (args: unknown) => Record<string, unknown>;
|
|
39
|
-
};
|
|
5
|
+
export { __plasticCapabilityDiagnosticInternals } from "./src/pi/capability-diagnostics";
|
|
40
6
|
|
|
7
|
+
// Pi provenance belongs to the manifest entry, never the extracted adapter.
|
|
41
8
|
const EXTENSION_SOURCE_PATH = fileURLToPath(import.meta.url);
|
|
42
|
-
const EMPTY_PARAMETERS = Type.Object({});
|
|
43
|
-
const enumSchema = (values: readonly string[], description: string): TSchema =>
|
|
44
|
-
Type.Union(values.map((value) => Type.Literal(value)), { description });
|
|
45
|
-
|
|
46
|
-
const OUTPUT_FORMAT_SCHEMA = enumSchema(["text", "json"], "Output format. Defaults to text.");
|
|
47
|
-
const PENDING_CHANGES_SCHEMA = enumSchema(["shelve", "bring", "cancel"], "How to handle pending changes when switching branches.");
|
|
48
|
-
const MERGE_STRATEGY_SCHEMA = enumSchema(["auto", "source", "destination"], "Conflict resolution strategy.");
|
|
49
|
-
const COMPARISON_METHOD_SCHEMA = enumSchema(
|
|
50
|
-
["ignoreeol", "ignorewhitespaces", "ignoreeolandwhitespaces", "recognizeall"],
|
|
51
|
-
"Comparison method used for diff calculations.",
|
|
52
|
-
);
|
|
53
|
-
const REVIEW_TARGET_TYPE_SCHEMA = enumSchema(["branch", "changeset"], "Filter by review target type.");
|
|
54
|
-
const BRANCH_ORDER_BY_SCHEMA = enumSchema(["date", "branchname"], "Sort field for branch queries.");
|
|
55
|
-
const REVIEW_ORDER_BY_SCHEMA = enumSchema(["date", "modifieddate", "status"], "Sort field for review queries.");
|
|
56
|
-
|
|
57
|
-
const PLASTIC_EXPORTS = [
|
|
58
|
-
"status",
|
|
59
|
-
"update",
|
|
60
|
-
"add",
|
|
61
|
-
"checkin",
|
|
62
|
-
"undo",
|
|
63
|
-
"resolveDeleteChangeConflict",
|
|
64
|
-
"diff",
|
|
65
|
-
"patch",
|
|
66
|
-
"diffRevisions",
|
|
67
|
-
"diffFile",
|
|
68
|
-
"workspaceDiff",
|
|
69
|
-
"branchCreate",
|
|
70
|
-
"switchBranch",
|
|
71
|
-
"merge",
|
|
72
|
-
"mergeBranches",
|
|
73
|
-
"mergeToBranch",
|
|
74
|
-
"finalizeMerge",
|
|
75
|
-
"currentBranch",
|
|
76
|
-
"branchList",
|
|
77
|
-
"branchExists",
|
|
78
|
-
"branchDelete",
|
|
79
|
-
"shelvesetCreate",
|
|
80
|
-
"shelvesetApply",
|
|
81
|
-
"shelvesetDelete",
|
|
82
|
-
"shelvesetList",
|
|
83
|
-
"codeReviewCreate",
|
|
84
|
-
"codeReviewUpdate",
|
|
85
|
-
"codeReviewDelete",
|
|
86
|
-
"codeReviewFind",
|
|
87
|
-
"workspaceList",
|
|
88
|
-
] as const;
|
|
89
|
-
|
|
90
|
-
type PlasticExportName = (typeof PLASTIC_EXPORTS)[number];
|
|
91
|
-
|
|
92
|
-
const TOOL_CONFIG: Partial<Record<PlasticExportName, ToolConfig>> = {
|
|
93
|
-
status: {
|
|
94
|
-
prepareArguments(args) {
|
|
95
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
96
|
-
normalizeWorkdirAliases(input);
|
|
97
|
-
assignAlias(input, "includeRevId", ["include_rev_id"]);
|
|
98
|
-
assignAlias(input, "machineReadable", ["machine_readable", "machine"]);
|
|
99
|
-
assignAlias(input, "maxItems", ["max_items"]);
|
|
100
|
-
assignAlias(input, "includeRaw", ["include_raw"]);
|
|
101
|
-
return input;
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
update: {
|
|
105
|
-
prepareArguments(args) {
|
|
106
|
-
const input = normalizeArgs(args);
|
|
107
|
-
normalizeWorkdirAliases(input);
|
|
108
|
-
return input;
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
add: {
|
|
112
|
-
prepareArguments(args) {
|
|
113
|
-
const input = normalizeArgs(args);
|
|
114
|
-
normalizeWorkdirAliases(input);
|
|
115
|
-
promoteSinglePath(input);
|
|
116
|
-
assignAlias(input, "paths", ["items"]);
|
|
117
|
-
return input;
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
checkin: {
|
|
121
|
-
prepareArguments(args) {
|
|
122
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
123
|
-
normalizeWorkdirAliases(input);
|
|
124
|
-
assignAlias(input, "message", ["comment", "comments"]);
|
|
125
|
-
promoteSinglePath(input);
|
|
126
|
-
assignAlias(input, "paths", ["items", "files"]);
|
|
127
|
-
assignAlias(input, "applyChanged", ["apply_changed"]);
|
|
128
|
-
assignAlias(input, "includePrivate", ["include_private"]);
|
|
129
|
-
assignAlias(input, "includeAll", ["include_all"]);
|
|
130
|
-
assignAlias(input, "updateAfter", ["update_after"]);
|
|
131
|
-
return input;
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
undo: {
|
|
135
|
-
prepareArguments(args) {
|
|
136
|
-
const input = normalizeArgs(args);
|
|
137
|
-
normalizeWorkdirAliases(input);
|
|
138
|
-
promoteSinglePath(input);
|
|
139
|
-
assignAlias(input, "paths", ["items"]);
|
|
140
|
-
return input;
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
resolveDeleteChangeConflict: {
|
|
144
|
-
prepareArguments(args) {
|
|
145
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
146
|
-
normalizeWorkdirAliases(input);
|
|
147
|
-
promoteSinglePath(input);
|
|
148
|
-
assignAlias(input, "paths", ["items", "files"]);
|
|
149
|
-
assignAlias(input, "keepOnDisk", ["keep_on_disk", "keepOnDisk", "nodisk"]);
|
|
150
|
-
return input;
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
diff: {
|
|
154
|
-
prepareArguments(args) {
|
|
155
|
-
const input = normalizeArgs(args);
|
|
156
|
-
normalizeWorkdirAliases(input);
|
|
157
|
-
assignAlias(input, "repositoryPaths", ["repository_paths"]);
|
|
158
|
-
assignAlias(input, "dateFormat", ["date_format"]);
|
|
159
|
-
assignAlias(input, "comparisonMethod", ["comparison_method"]);
|
|
160
|
-
assignAlias(input, "fullPaths", ["full_paths"]);
|
|
161
|
-
return input;
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
patch: {
|
|
165
|
-
prepareArguments(args) {
|
|
166
|
-
const input = normalizeArgs(args);
|
|
167
|
-
normalizeWorkdirAliases(input);
|
|
168
|
-
assignAlias(input, "output", ["output_file", "outputFile"]);
|
|
169
|
-
assignAlias(input, "toolPath", ["tool_path", "tool"]);
|
|
170
|
-
return input;
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
diffRevisions: {
|
|
174
|
-
prepareArguments(args) {
|
|
175
|
-
const input = normalizeArgs(args);
|
|
176
|
-
normalizeWorkdirAliases(input);
|
|
177
|
-
assignAlias(input, "leftRevision", ["left_revision"]);
|
|
178
|
-
assignAlias(input, "rightRevision", ["right_revision"]);
|
|
179
|
-
assignAlias(input, "maxChars", ["max_chars"]);
|
|
180
|
-
return input;
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
diffFile: {
|
|
184
|
-
prepareArguments(args) {
|
|
185
|
-
const input = normalizeArgs(args);
|
|
186
|
-
normalizeWorkdirAliases(input);
|
|
187
|
-
assignAlias(input, "maxChars", ["max_chars"]);
|
|
188
|
-
return input;
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
workspaceDiff: {
|
|
192
|
-
prepareArguments(args) {
|
|
193
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
194
|
-
normalizeWorkdirAliases(input);
|
|
195
|
-
promoteSinglePath(input);
|
|
196
|
-
assignAlias(input, "paths", ["items", "files"]);
|
|
197
|
-
assignAlias(input, "allPending", ["all_pending"]);
|
|
198
|
-
assignAlias(input, "includePrivate", ["include_private"]);
|
|
199
|
-
assignAlias(input, "maxFiles", ["max_files"]);
|
|
200
|
-
assignAlias(input, "maxChars", ["max_chars"]);
|
|
201
|
-
return input;
|
|
202
|
-
},
|
|
203
|
-
},
|
|
204
|
-
branchCreate: {
|
|
205
|
-
prepareArguments(args) {
|
|
206
|
-
const input = normalizeArgs(args);
|
|
207
|
-
normalizeWorkdirAliases(input);
|
|
208
|
-
assignAlias(input, "commentsFile", ["comments_file"]);
|
|
209
|
-
return input;
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
switchBranch: {
|
|
213
|
-
prepareArguments(args) {
|
|
214
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
215
|
-
normalizeWorkdirAliases(input);
|
|
216
|
-
assignAlias(input, "pendingChanges", ["pending_changes"]);
|
|
217
|
-
return input;
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
merge: {
|
|
221
|
-
prepareArguments(args) {
|
|
222
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
223
|
-
normalizeWorkdirAliases(input);
|
|
224
|
-
assignAlias(input, "cherrypicking", ["cherry_picking", "cherryPicking"]);
|
|
225
|
-
return input;
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
mergeBranches: {
|
|
229
|
-
prepareArguments(args) {
|
|
230
|
-
return normalizeOutputFormatAlias(normalizeArgs(args));
|
|
231
|
-
},
|
|
232
|
-
},
|
|
233
|
-
mergeToBranch: {
|
|
234
|
-
prepareArguments(args) {
|
|
235
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
236
|
-
normalizeWorkdirAliases(input);
|
|
237
|
-
assignAlias(input, "source", ["sourceBranch", "source_branch", "branch"]);
|
|
238
|
-
assignAlias(input, "target", ["targetBranch", "target_branch", "destination", "destinationBranch", "destination_branch"]);
|
|
239
|
-
assignAlias(input, "cardRef", ["card", "cardCode", "card_code", "codecksCard", "codecks_card"]);
|
|
240
|
-
assignAlias(input, "updateTarget", ["update_target", "update"]);
|
|
241
|
-
assignAlias(input, "includePrivate", ["include_private"]);
|
|
242
|
-
return input;
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
finalizeMerge: {
|
|
246
|
-
prepareArguments(args) {
|
|
247
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
248
|
-
normalizeWorkdirAliases(input);
|
|
249
|
-
assignAlias(input, "source", ["mergeSource", "merge_source"]);
|
|
250
|
-
return input;
|
|
251
|
-
},
|
|
252
|
-
},
|
|
253
|
-
currentBranch: {
|
|
254
|
-
prepareArguments(args) {
|
|
255
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
256
|
-
normalizeWorkdirAliases(input);
|
|
257
|
-
return input;
|
|
258
|
-
},
|
|
259
|
-
},
|
|
260
|
-
branchList: {
|
|
261
|
-
prepareArguments(args) {
|
|
262
|
-
const input = normalizeArgs(args);
|
|
263
|
-
normalizeWorkdirAliases(input);
|
|
264
|
-
assignAlias(input, "nameLike", ["name_like"]);
|
|
265
|
-
assignAlias(input, "includeHidden", ["include_hidden"]);
|
|
266
|
-
assignAlias(input, "orderBy", ["order_by"]);
|
|
267
|
-
return input;
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
branchExists: {
|
|
271
|
-
prepareArguments(args) {
|
|
272
|
-
const input = normalizeArgs(args);
|
|
273
|
-
normalizeWorkdirAliases(input);
|
|
274
|
-
return input;
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
branchDelete: {
|
|
278
|
-
prepareArguments(args) {
|
|
279
|
-
const input = normalizeArgs(args);
|
|
280
|
-
normalizeWorkdirAliases(input);
|
|
281
|
-
assignAlias(input, "deleteChangesets", ["delete_changesets"]);
|
|
282
|
-
return input;
|
|
283
|
-
},
|
|
284
|
-
},
|
|
285
|
-
shelvesetCreate: {
|
|
286
|
-
prepareArguments(args) {
|
|
287
|
-
const input = normalizeArgs(args);
|
|
288
|
-
normalizeWorkdirAliases(input);
|
|
289
|
-
promoteSinglePath(input);
|
|
290
|
-
assignAlias(input, "paths", ["items"]);
|
|
291
|
-
assignAlias(input, "commentsFile", ["comments_file"]);
|
|
292
|
-
assignAlias(input, "summaryFormat", ["summary_format"]);
|
|
293
|
-
return input;
|
|
294
|
-
},
|
|
295
|
-
},
|
|
296
|
-
shelvesetApply: {
|
|
297
|
-
prepareArguments(args) {
|
|
298
|
-
const input = normalizeArgs(args);
|
|
299
|
-
normalizeWorkdirAliases(input);
|
|
300
|
-
assignAlias(input, "changePaths", ["change_paths"]);
|
|
301
|
-
assignAlias(input, "dontCheckout", ["dont_checkout"]);
|
|
302
|
-
assignAlias(input, "comparisonMethod", ["comparison_method"]);
|
|
303
|
-
return input;
|
|
304
|
-
},
|
|
305
|
-
},
|
|
306
|
-
shelvesetDelete: {
|
|
307
|
-
prepareArguments(args) {
|
|
308
|
-
const input = normalizeArgs(args);
|
|
309
|
-
normalizeWorkdirAliases(input);
|
|
310
|
-
return input;
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
shelvesetList: {
|
|
314
|
-
prepareArguments(args) {
|
|
315
|
-
const input = normalizeArgs(args);
|
|
316
|
-
normalizeWorkdirAliases(input);
|
|
317
|
-
assignAlias(input, "commentLike", ["comment_like"]);
|
|
318
|
-
assignAlias(input, "dateFrom", ["date_from"]);
|
|
319
|
-
assignAlias(input, "dateFormat", ["date_format"]);
|
|
320
|
-
return input;
|
|
321
|
-
},
|
|
322
|
-
},
|
|
323
|
-
codeReviewCreate: {
|
|
324
|
-
prepareArguments(args) {
|
|
325
|
-
const input = normalizeArgs(args);
|
|
326
|
-
normalizeWorkdirAliases(input);
|
|
327
|
-
assignAlias(input, "reviewId", ["id"]);
|
|
328
|
-
return input;
|
|
329
|
-
},
|
|
330
|
-
},
|
|
331
|
-
codeReviewUpdate: {
|
|
332
|
-
prepareArguments(args) {
|
|
333
|
-
const input = normalizeArgs(args);
|
|
334
|
-
normalizeWorkdirAliases(input);
|
|
335
|
-
assignAlias(input, "reviewId", ["review_id"]);
|
|
336
|
-
if (input.reviewId !== undefined && input.id === undefined) input.id = input.reviewId;
|
|
337
|
-
return input;
|
|
338
|
-
},
|
|
339
|
-
},
|
|
340
|
-
codeReviewDelete: {
|
|
341
|
-
prepareArguments(args) {
|
|
342
|
-
const input = normalizeArgs(args);
|
|
343
|
-
normalizeWorkdirAliases(input);
|
|
344
|
-
if (input.id !== undefined && input.ids === undefined) input.ids = [String(input.id)];
|
|
345
|
-
assignAlias(input, "ids", ["review_ids"]);
|
|
346
|
-
return input;
|
|
347
|
-
},
|
|
348
|
-
},
|
|
349
|
-
codeReviewFind: {
|
|
350
|
-
prepareArguments(args) {
|
|
351
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
352
|
-
normalizeWorkdirAliases(input);
|
|
353
|
-
assignAlias(input, "targetType", ["target_type"]);
|
|
354
|
-
assignAlias(input, "titleLike", ["title_like"]);
|
|
355
|
-
assignAlias(input, "orderBy", ["order_by"]);
|
|
356
|
-
assignAlias(input, "dateFormat", ["date_format"]);
|
|
357
|
-
assignAlias(input, "output", ["output_format", "response_format"]);
|
|
358
|
-
return input;
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
workspaceList: {
|
|
362
|
-
prepareArguments(args) {
|
|
363
|
-
const input = normalizeOutputFormatAlias(normalizeArgs(args));
|
|
364
|
-
normalizeWorkdirAliases(input);
|
|
365
|
-
assignAlias(input, "output", ["output_format", "response_format"]);
|
|
366
|
-
return input;
|
|
367
|
-
},
|
|
368
|
-
},
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
function toToolName(exportName: string): string {
|
|
372
|
-
return `plastic_${exportName}`;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
function toText(result: unknown): string {
|
|
376
|
-
if (typeof result === "string") return result;
|
|
377
|
-
return JSON.stringify(result, null, 2);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function normalizeArgs(args: unknown): Record<string, unknown> {
|
|
381
|
-
return args && typeof args === "object" ? { ...(args as Record<string, unknown>) } : {};
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function assignAlias(target: Record<string, unknown>, key: string, aliases: string[]): void {
|
|
385
|
-
if (target[key] !== undefined) return;
|
|
386
|
-
for (const alias of aliases) {
|
|
387
|
-
if (target[alias] !== undefined) {
|
|
388
|
-
target[key] = target[alias];
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
function normalizeWorkdirAliases(input: Record<string, unknown>): void {
|
|
395
|
-
assignAlias(input, "workdir", ["cwd", "workingDirectory", "working_directory"]);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function normalizeOutputFormatAlias(input: Record<string, unknown>): Record<string, unknown> {
|
|
399
|
-
if (typeof input.format === "string" && input.format.trim().toLowerCase() === "markdown") {
|
|
400
|
-
input.format = "text";
|
|
401
|
-
}
|
|
402
|
-
if (typeof input.output === "string" && input.output.trim().toLowerCase() === "markdown") {
|
|
403
|
-
input.output = "text";
|
|
404
|
-
}
|
|
405
|
-
return input;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
function promoteSinglePath(input: Record<string, unknown>): void {
|
|
409
|
-
if (input.paths !== undefined) return;
|
|
410
|
-
const singlePath = input.path ?? input.file;
|
|
411
|
-
if (typeof singlePath === "string" && singlePath.trim().length > 0) {
|
|
412
|
-
input.paths = [singlePath];
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
function getCoreTool(exportName: string): CoreTool {
|
|
417
|
-
const candidate = (core as Record<string, unknown>)[exportName] as CoreTool | undefined;
|
|
418
|
-
if (!candidate || typeof candidate.execute !== "function") {
|
|
419
|
-
throw new Error(`Missing Plastic core tool export '${exportName}'.`);
|
|
420
|
-
}
|
|
421
|
-
return candidate;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
function isCoreSchemaNode(value: unknown): value is CoreSchemaNode {
|
|
425
|
-
return Boolean(value) && typeof value === "object" && typeof (value as { kind?: unknown }).kind === "string";
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
function applySchemaMetadata(schema: TSchema, node: CoreSchemaNode): TSchema {
|
|
429
|
-
const metadata = node.metadata ?? {};
|
|
430
|
-
const options: { description?: string; minimum?: number; maximum?: number } = {};
|
|
431
|
-
|
|
432
|
-
if (metadata.description) options.description = metadata.description;
|
|
433
|
-
if (metadata.min !== undefined) options.minimum = metadata.min;
|
|
434
|
-
if (metadata.max !== undefined) options.maximum = metadata.max;
|
|
435
|
-
|
|
436
|
-
let nextSchema: TSchema = schema;
|
|
437
|
-
if (Object.keys(options).length > 0) {
|
|
438
|
-
if (Type.IsString(schema)) nextSchema = Type.String(options);
|
|
439
|
-
else if (Type.IsNumber(schema) || Type.IsInteger(schema)) nextSchema = metadata.int ? Type.Integer(options) : Type.Number(options);
|
|
440
|
-
else if (Type.IsBoolean(schema)) nextSchema = Type.Boolean(options);
|
|
441
|
-
else if (Type.IsArray(schema)) nextSchema = Type.Array(schema.items, options);
|
|
442
|
-
else nextSchema = Type.Unsafe({ ...schema, ...options });
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
if (metadata.int && Type.IsNumber(nextSchema)) {
|
|
446
|
-
nextSchema = Type.Integer(options);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
return metadata.optional ? Type.Optional(nextSchema) : nextSchema;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
function literalSchema(value: unknown): TSchema {
|
|
453
|
-
if (typeof value === "string") return Type.Literal(value);
|
|
454
|
-
if (typeof value === "number") return Number.isInteger(value) ? Type.Literal(value) : Type.Literal(value);
|
|
455
|
-
if (typeof value === "boolean") return Type.Literal(value);
|
|
456
|
-
return Type.Any();
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
function convertCoreSchema(node: unknown): TSchema {
|
|
460
|
-
if (!isCoreSchemaNode(node)) {
|
|
461
|
-
return literalSchema(node);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
let schema: TSchema;
|
|
465
|
-
switch (node.kind) {
|
|
466
|
-
case "string":
|
|
467
|
-
schema = Type.String();
|
|
468
|
-
break;
|
|
469
|
-
case "number":
|
|
470
|
-
schema = node.metadata?.int ? Type.Integer() : Type.Number();
|
|
471
|
-
break;
|
|
472
|
-
case "boolean":
|
|
473
|
-
schema = Type.Boolean();
|
|
474
|
-
break;
|
|
475
|
-
case "any":
|
|
476
|
-
schema = Type.Any();
|
|
477
|
-
break;
|
|
478
|
-
case "array":
|
|
479
|
-
schema = Type.Array(convertCoreSchema(node.inner));
|
|
480
|
-
break;
|
|
481
|
-
case "enum": {
|
|
482
|
-
const values = Array.isArray(node.values) ? node.values : [];
|
|
483
|
-
if (values.every((value) => typeof value === "string")) {
|
|
484
|
-
const valueSet = values;
|
|
485
|
-
if (arraysEqual(valueSet, ["text", "json"])) {
|
|
486
|
-
schema = OUTPUT_FORMAT_SCHEMA;
|
|
487
|
-
} else if (arraysEqual(valueSet, ["shelve", "bring", "cancel"])) {
|
|
488
|
-
schema = PENDING_CHANGES_SCHEMA;
|
|
489
|
-
} else if (arraysEqual(valueSet, ["auto", "source", "destination"])) {
|
|
490
|
-
schema = MERGE_STRATEGY_SCHEMA;
|
|
491
|
-
} else if (arraysEqual(valueSet, ["ignoreeol", "ignorewhitespaces", "ignoreeolandwhitespaces", "recognizeall"])) {
|
|
492
|
-
schema = COMPARISON_METHOD_SCHEMA;
|
|
493
|
-
} else if (arraysEqual(valueSet, ["branch", "changeset"])) {
|
|
494
|
-
schema = REVIEW_TARGET_TYPE_SCHEMA;
|
|
495
|
-
} else if (arraysEqual(valueSet, ["date", "branchname"])) {
|
|
496
|
-
schema = BRANCH_ORDER_BY_SCHEMA;
|
|
497
|
-
} else if (arraysEqual(valueSet, ["date", "modifieddate", "status"])) {
|
|
498
|
-
schema = REVIEW_ORDER_BY_SCHEMA;
|
|
499
|
-
} else {
|
|
500
|
-
schema = enumSchema(valueSet, metadataDescription(node));
|
|
501
|
-
}
|
|
502
|
-
} else {
|
|
503
|
-
schema = Type.Union(values.map((value) => literalSchema(value)));
|
|
504
|
-
}
|
|
505
|
-
break;
|
|
506
|
-
}
|
|
507
|
-
case "union": {
|
|
508
|
-
const values = Array.isArray(node.values) ? node.values : [];
|
|
509
|
-
const converted = values.map((value) => convertCoreSchema(value));
|
|
510
|
-
schema = converted.length > 1 ? Type.Union(converted) : (converted[0] ?? Type.Any());
|
|
511
|
-
break;
|
|
512
|
-
}
|
|
513
|
-
default:
|
|
514
|
-
schema = Type.Any();
|
|
515
|
-
break;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
return applySchemaMetadata(schema, node);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
function arraysEqual(left: readonly string[], right: readonly string[]): boolean {
|
|
522
|
-
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
function metadataDescription(node: CoreSchemaNode): string {
|
|
526
|
-
return node.metadata?.description ?? "Allowed values.";
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
type CapabilityDiagnosticContext = {
|
|
530
|
-
hasUI?: boolean;
|
|
531
|
-
ui?: { notify?: (message: string, level: "warning") => void };
|
|
532
|
-
};
|
|
533
|
-
|
|
534
|
-
type PatchCapabilityWarningGetter = () => Promise<string | undefined>;
|
|
535
|
-
|
|
536
|
-
export const __plasticCapabilityDiagnosticInternals = {
|
|
537
|
-
createPatchCapabilityWarningNotifier(getWarning: PatchCapabilityWarningGetter = () => core.getPatchBackendCapabilityWarning()) {
|
|
538
|
-
let emitted = false;
|
|
539
|
-
return async (ctx: CapabilityDiagnosticContext): Promise<void> => {
|
|
540
|
-
if (emitted || !ctx.hasUI || typeof ctx.ui?.notify !== "function") return;
|
|
541
|
-
const warning = await getWarning();
|
|
542
|
-
if (!warning) return;
|
|
543
|
-
emitted = true;
|
|
544
|
-
ctx.ui.notify(warning, "warning");
|
|
545
|
-
};
|
|
546
|
-
},
|
|
547
|
-
};
|
|
548
|
-
|
|
549
|
-
const notifyPatchCapabilityWarning = __plasticCapabilityDiagnosticInternals.createPatchCapabilityWarningNotifier();
|
|
550
|
-
|
|
551
|
-
function buildParameters(args: Record<string, unknown> | undefined): TSchema {
|
|
552
|
-
if (!args || Object.keys(args).length === 0) {
|
|
553
|
-
return EMPTY_PARAMETERS;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
const properties: Record<string, TSchema> = {};
|
|
557
|
-
for (const [key, value] of Object.entries(args)) {
|
|
558
|
-
properties[key] = convertCoreSchema(value);
|
|
559
|
-
}
|
|
560
|
-
return Type.Object(properties);
|
|
561
|
-
}
|
|
562
9
|
|
|
563
10
|
export default function plasticTools(pi: ExtensionAPI) {
|
|
564
|
-
|
|
565
|
-
for (const exportName of PLASTIC_EXPORTS) {
|
|
566
|
-
const coreTool = getCoreTool(exportName);
|
|
567
|
-
coreDescriptions.set(toToolName(exportName), coreTool.description ?? toToolName(exportName));
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
for (const exportName of PLASTIC_EXPORTS) {
|
|
571
|
-
const coreTool = getCoreTool(exportName);
|
|
572
|
-
const config = TOOL_CONFIG[exportName] ?? {};
|
|
573
|
-
pi.registerTool({
|
|
574
|
-
name: toToolName(exportName),
|
|
575
|
-
label: toToolName(exportName),
|
|
576
|
-
description: coreTool.description ?? toToolName(exportName),
|
|
577
|
-
parameters: buildParameters(coreTool.args),
|
|
578
|
-
prepareArguments: config.prepareArguments,
|
|
579
|
-
renderCall(args, theme, context) {
|
|
580
|
-
return renderPlasticCall(exportName, args ?? {}, theme, context);
|
|
581
|
-
},
|
|
582
|
-
renderResult(result, options, theme, context) {
|
|
583
|
-
return renderPlasticResult(exportName, result, options, theme, context);
|
|
584
|
-
},
|
|
585
|
-
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
586
|
-
const normalizedParams = normalizeArgs(params);
|
|
587
|
-
if (exportName !== "mergeBranches" && normalizedParams.workdir === undefined && ctx?.cwd) {
|
|
588
|
-
normalizedParams.workdir = ctx.cwd;
|
|
589
|
-
}
|
|
590
|
-
const result = await core.runWithAbortSignal(signal, async () => coreTool.execute(normalizedParams));
|
|
591
|
-
const text = toText(result);
|
|
592
|
-
return {
|
|
593
|
-
content: [{ type: "text", text }],
|
|
594
|
-
details: {
|
|
595
|
-
exportName,
|
|
596
|
-
rawResult: result,
|
|
597
|
-
...(typeof normalizedParams.workdir === "string" ? { workdir: normalizedParams.workdir } : {}),
|
|
598
|
-
},
|
|
599
|
-
};
|
|
600
|
-
},
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
pi.registerTool({
|
|
605
|
-
name: PLASTIC_TOOL_SEARCH_NAME,
|
|
606
|
-
label: "Plastic Tool Search",
|
|
607
|
-
description: "Search and enable Plastic SCM / Unity Version Control tools for workspace status and sync, changes and checkins, text-only diffs and patches, branches and merges, shelvesets, code reviews, and workspaces.",
|
|
608
|
-
promptSnippet: "Use plastic_tool_search to find and enable Plastic SCM capabilities that are not active.",
|
|
609
|
-
promptGuidelines: [
|
|
610
|
-
"Use plastic_tool_search before a Plastic SCM action when an appropriate plastic_* tool is not active. Inspect exact mutation targets. Do not preflight routinely: use preflight for ambiguous or broad scope, moved/deleted path rewriting, compound operations, or an explicit preview request.",
|
|
611
|
-
],
|
|
612
|
-
parameters: Type.Object({
|
|
613
|
-
query: Type.Optional(Type.String({ description: "Capability or workflow to search for." })),
|
|
614
|
-
toolNames: Type.Optional(Type.Array(Type.String({ description: "Exact public Plastic tool name." }), { maxItems: 4, description: "Optional exact tool names to enable." })),
|
|
615
|
-
limit: Type.Optional(Type.Integer({ minimum: 1, maximum: 4, description: "Maximum matching tools to enable. Defaults to the single best keyword match; exact toolNames requests may enable up to four." })),
|
|
616
|
-
}),
|
|
617
|
-
renderCall(args, theme, context) {
|
|
618
|
-
return renderPlasticCall("tool_search", args ?? {}, theme, context);
|
|
619
|
-
},
|
|
620
|
-
renderResult(result, options, theme, context) {
|
|
621
|
-
return renderPlasticSearchResult(result, options, theme, context);
|
|
622
|
-
},
|
|
623
|
-
async execute(_toolCallId, params) {
|
|
624
|
-
if (isPlasticToolBrowseRequest(params)) {
|
|
625
|
-
return {
|
|
626
|
-
content: [{ type: "text", text: PLASTIC_TOOL_BROWSE_TEXT }],
|
|
627
|
-
details: { browse: true, matches: [], added: [], alreadyActive: [], guidance: [] },
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
const ownership = getEffectivePlasticToolOwnership(pi.getAllTools(), EXTENSION_SOURCE_PATH);
|
|
632
|
-
const unknownToolNames = getUnknownExactPlasticToolNames(params.toolNames);
|
|
633
|
-
const active = pi.getActiveTools();
|
|
634
|
-
// Never infer ownership without canonical sourceInfo. In that
|
|
635
|
-
// compatibility mode we may describe known tools that are already active,
|
|
636
|
-
// but cannot safely activate an inactive same-named definition.
|
|
637
|
-
const matches = searchPlasticTools(params, coreDescriptions).filter((match) =>
|
|
638
|
-
ownership.usesSourceInfo ? ownership.ownedToolNames.has(match.name) : active.includes(match.name),
|
|
639
|
-
);
|
|
640
|
-
const requestedExactToolNames = Array.isArray(params.toolNames)
|
|
641
|
-
? [...new Set(params.toolNames.filter((name): name is string => typeof name === "string" && name.trim().length > 0).map((name) => name.trim()))]
|
|
642
|
-
: [];
|
|
643
|
-
const unavailableToolNames = requestedExactToolNames.filter((name) => !matches.some((match) => match.name.toLowerCase() === name.toLowerCase()));
|
|
644
|
-
if (matches.length === 0) {
|
|
645
|
-
const unavailable = unavailableToolNames.length > 0
|
|
646
|
-
? ` Unknown or unavailable exact tool names: ${unavailableToolNames.join(", ")}.`
|
|
647
|
-
: "";
|
|
648
|
-
return {
|
|
649
|
-
content: [{ type: "text", text: `No executable Plastic tools matched. Try a capability, workflow term, or exact public plastic_* tool name.${unavailable}` }],
|
|
650
|
-
details: { matches: [], added: [], alreadyActive: [], guidance: [], unknownToolNames, unavailableToolNames },
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
const matchNames = matches.map((match) => match.name);
|
|
655
|
-
const added = matchNames.filter((name) => !active.includes(name));
|
|
656
|
-
const alreadyActive = matchNames.filter((name) => active.includes(name));
|
|
657
|
-
if (added.length > 0) pi.setActiveTools([...new Set([...active, ...added])]);
|
|
658
|
-
|
|
659
|
-
const guidance = matches.flatMap((match) => match.guidance);
|
|
660
|
-
const unknownText = unavailableToolNames.length > 0 ? `\nUnknown or unavailable exact tool names: ${unavailableToolNames.join(", ")}.` : "";
|
|
661
|
-
const loadedText = added.length > 0 ? `Activated: ${added.join(", ")}.` : "All matching tools were already active.";
|
|
662
|
-
return {
|
|
663
|
-
content: [{
|
|
664
|
-
type: "text",
|
|
665
|
-
text: `${loadedText}\nMatches: ${matchNames.join(", ")}.\nGuidance: ${guidance.join(" ")}${unknownText}`,
|
|
666
|
-
}],
|
|
667
|
-
details: { matches: matchNames, added, alreadyActive, guidance, unknownToolNames, unavailableToolNames },
|
|
668
|
-
};
|
|
669
|
-
},
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
673
|
-
await notifyPatchCapabilityWarning(ctx as CapabilityDiagnosticContext);
|
|
674
|
-
const ownership = getEffectivePlasticToolOwnership(pi.getAllTools(), EXTENSION_SOURCE_PATH);
|
|
675
|
-
const active = pi.getActiveTools();
|
|
676
|
-
const mode = getPlasticToolLoadingMode();
|
|
677
|
-
// Fail safe when provenance is unavailable or the effective loader is a
|
|
678
|
-
// foreign first-registration-wins collision. Preserve the active set
|
|
679
|
-
// exactly; even adding the public loader name could activate foreign code.
|
|
680
|
-
if (!ownership.usesSourceInfo) return;
|
|
681
|
-
|
|
682
|
-
// The all-active eval mode keeps every currently exposed Plastic tool
|
|
683
|
-
// active while omitting the dynamic loader from the provider surface.
|
|
684
|
-
if (mode === "all-active") {
|
|
685
|
-
pi.setActiveTools(active.filter((name) => name !== PLASTIC_TOOL_SEARCH_NAME));
|
|
686
|
-
return;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
const initiallyInactive = getInitiallyInactivePlasticTools(mode);
|
|
690
|
-
const ownedInitiallyInactive = new Set([...initiallyInactive].filter((name) => ownership.ownedToolNames.has(name)));
|
|
691
|
-
const restored = getRestoredPlasticToolNames(ctx.sessionManager.getBranch(), ownership.ownedToolNames);
|
|
692
|
-
const preserved = active.filter((name) => !ownedInitiallyInactive.has(name));
|
|
693
|
-
pi.setActiveTools([...new Set([...preserved, PLASTIC_TOOL_SEARCH_NAME, ...restored])]);
|
|
694
|
-
});
|
|
11
|
+
registerPlasticTools(pi, EXTENSION_SOURCE_PATH);
|
|
695
12
|
}
|