weir-harness 1.1.4 → 1.1.6
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/cordis.patch.yml +48 -87
- package/icon.svg +1 -0
- package/lib/client.capability-badge.js +16 -16
- package/lib/client.capability-manager.js +87 -36
- package/lib/client.capability-model.js +151 -31
- package/lib/client.capability-presets.js +187 -39
- package/lib/client.edit-lock-maintenance.js +27 -12
- package/lib/client.edit-lock-panel.js +52 -19
- package/lib/client.js +270 -12
- package/lib/client.settings-page.js +13 -8
- package/lib/client.worktree-model.js +20 -1
- package/lib/client.worktree-view.js +32 -9
- package/package.json +4 -2
- package/skills/deep-work/SKILL.md +7 -3
- package/src/blackboard/durable.js +199 -0
- package/src/blackboard/index.js +62 -42
- package/src/blackboard/kernel.js +20 -1
- package/src/blackboard/remote.js +36 -28
- package/src/blackboard/storage.js +238 -0
- package/src/capabilities/capability-remote.js +122 -69
- package/src/capabilities/preset-library.js +113 -87
- package/src/capabilities/read-payloads.js +21 -4
- package/src/capabilities/skill-selection-plugin.js +188 -168
- package/src/capabilities/skill-selection-provider.js +13 -0
- package/src/capabilities/store/enumerate.js +46 -0
- package/src/capabilities/store/store.js +86 -1
- package/src/context-guard/index.js +222 -117
- package/src/context-guard/pressure.js +12 -3
- package/src/context-guard/recovery.js +25 -0
- package/src/core/doctrine.js +3 -3
- package/src/delegate/group-coordinator.js +2 -1
- package/src/delegate/supervision-mount.js +41 -2
- package/src/delegate/tool.js +11 -3
- package/src/edit-lock/admin-ledger.js +42 -6
- package/src/edit-lock/admin-recovery.js +4 -2
- package/src/edit-lock/binding-attestation.js +29 -0
- package/src/edit-lock/binding-guidance.js +43 -0
- package/src/edit-lock/domain.js +20 -5
- package/src/edit-lock/host.js +3 -3
- package/src/edit-lock/index.js +268 -57
- package/src/edit-lock/lifecycle.js +106 -47
- package/src/edit-lock/maintenance.js +12 -3
- package/src/edit-lock/manager.js +8 -3
- package/src/edit-lock/peer.js +2 -0
- package/src/edit-lock/publisher.js +57 -1
- package/src/edit-lock/remote.js +120 -52
- package/src/edit-lock/runtime.js +8 -0
- package/src/edit-lock/view.js +27 -12
- package/src/settings/sections.js +30 -6
- package/src/shared/audit.js +6 -0
- package/src/shared/delegate-edit-lifecycle.js +36 -0
- package/src/todo-driver/index.js +16 -1
- package/src/worktree/cards.js +47 -3
- package/src/worktree/command.js +29 -5
- package/src/worktree/git.js +39 -5
- package/src/worktree/lanes.js +83 -25
- package/src/worktree/prompts.js +2 -1
|
@@ -11,20 +11,37 @@ window.__ModuleLoader__.load({
|
|
|
11
11
|
// is a function over plain data so the DOM layer stays thin and the
|
|
12
12
|
// node:test suite covers the semantics.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// Like the SEGMENT-regex mirror below, same-package sync require is
|
|
15
|
+
// impossible in the ModuleLoader. Mirror src/capabilities/skill-identity.js.
|
|
16
|
+
function skillIdentityKeyOf(identity) {
|
|
17
|
+
if (!identity || typeof identity !== "object" || Array.isArray(identity)) return null;
|
|
18
|
+
const { scope, root, name, provenance, opaqueId } = identity;
|
|
19
|
+
if (typeof scope !== "string" || typeof root !== "string" || typeof name !== "string") return null;
|
|
20
|
+
const sorted = provenance == null ? null : Object.fromEntries(Object.keys(provenance).sort().map(key => [key, provenance[key]]));
|
|
21
|
+
return JSON.stringify([scope, root, name, sorted, sorted === null ? (opaqueId ?? null) : null]);
|
|
22
|
+
}
|
|
23
|
+
function skillEntryKeyOf(entry) {
|
|
24
|
+
if (typeof entry === "string") return "name:" + entry;
|
|
25
|
+
const key = skillIdentityKeyOf(entry);
|
|
26
|
+
return key === null ? null : "id:" + key;
|
|
27
|
+
}
|
|
28
|
+
const sortSkills = (entries) => [...entries].sort((a, b) => {
|
|
29
|
+
const left = skillEntryKeyOf(a), right = skillEntryKeyOf(b);
|
|
30
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/** Only a complete, warning-free effective receipt proves applied counts. */
|
|
15
34
|
function badgeStateOf(receipt, draft) {
|
|
16
|
-
const applied = receipt && receipt.status === "applied"
|
|
17
|
-
? { skills: Array.isArray(receipt.effective?.skills) ? receipt.effective.skills.length : 0, mcpServers: Array.isArray(receipt.effective?.mcpServers) ? receipt.effective.mcpServers.length : 0 }
|
|
18
|
-
: { skills: 0, mcpServers: 0 };
|
|
19
35
|
const warnings = Array.isArray(receipt?.warnings) ? [...receipt.warnings] : [];
|
|
20
|
-
const
|
|
36
|
+
const known = receipt?.status === "applied" && warnings.length === 0
|
|
37
|
+
&& Array.isArray(receipt?.effective?.skills) && Array.isArray(receipt?.effective?.mcpServers);
|
|
21
38
|
return {
|
|
22
|
-
applied,
|
|
39
|
+
applied: known ? { skills: receipt.effective.skills.length, mcpServers: receipt.effective.mcpServers.length } : null,
|
|
23
40
|
warnings,
|
|
24
41
|
unavailable: warnings.filter((warning) => typeof warning === "string" && warning.includes("unavailable")),
|
|
25
|
-
draftDirty,
|
|
26
|
-
|
|
27
|
-
|
|
42
|
+
draftDirty: Boolean(draft && draft.dirty),
|
|
43
|
+
known,
|
|
44
|
+
degraded: receipt?.status === "applied" && !known,
|
|
28
45
|
};
|
|
29
46
|
}
|
|
30
47
|
|
|
@@ -46,6 +63,7 @@ window.__ModuleLoader__.load({
|
|
|
46
63
|
missing: status !== "parsed" && status !== "unknown",
|
|
47
64
|
selected: Boolean(candidate?.selected),
|
|
48
65
|
conflict: candidate?.conflict === true,
|
|
66
|
+
identity: candidate?.identity ?? null,
|
|
49
67
|
};
|
|
50
68
|
}
|
|
51
69
|
function partitionManagerListing(listing) {
|
|
@@ -110,32 +128,110 @@ window.__ModuleLoader__.load({
|
|
|
110
128
|
// ---- Draft editing (12.3 manager Apply surface) ----
|
|
111
129
|
/** The edit draft seeded from the server receipt (CAS revision included). */
|
|
112
130
|
function draftFromReceipt(receipt) {
|
|
113
|
-
const skills = Array.isArray(receipt?.effective?.
|
|
131
|
+
const skills = Array.isArray(receipt?.effective?.skillIdentities) ? [...receipt.effective.skillIdentities]
|
|
132
|
+
: Array.isArray(receipt?.effective?.skills) ? [...receipt.effective.skills] : [];
|
|
114
133
|
const mcpServers = Array.isArray(receipt?.effective?.mcpServers) ? [...receipt.effective.mcpServers] : [];
|
|
134
|
+
const warnings = Array.isArray(receipt?.warnings) ? receipt.warnings.filter(Boolean).map(String) : [];
|
|
135
|
+
const digest = receipt?.effective?.digest;
|
|
136
|
+
const provable = receipt?.status === "applied" && warnings.length === 0 && Number.isSafeInteger(receipt.revision) && receipt.revision >= 0
|
|
137
|
+
&& Array.isArray(receipt?.effective?.skillIdentities) && Array.isArray(receipt?.effective?.mcpServers)
|
|
138
|
+
&& typeof digest === "string" && /^[a-f0-9]{64}$/.test(digest);
|
|
115
139
|
return {
|
|
116
|
-
skills:
|
|
140
|
+
skills: sortSkills(skills),
|
|
117
141
|
mcpServers: [...mcpServers].sort(),
|
|
118
|
-
applied: { skills:
|
|
142
|
+
applied: { skills: sortSkills(skills), mcpServers: [...mcpServers].sort(), unresolvedRefs: Array.isArray(receipt?.effective?.unresolvedRefs) ? [...receipt.effective.unresolvedRefs] : [] },
|
|
143
|
+
unresolvedRefs: Array.isArray(receipt?.effective?.unresolvedRefs) ? [...receipt.effective.unresolvedRefs] : [],
|
|
144
|
+
...(provable ? { appliedDigest: digest } : {}),
|
|
145
|
+
appliedSourceIssue: warnings.length ? "unavailable" : provable ? null : "receipt",
|
|
119
146
|
revision: Number.isSafeInteger(receipt?.revision) ? receipt.revision : 0,
|
|
120
147
|
dirty: false,
|
|
121
148
|
};
|
|
122
149
|
}
|
|
150
|
+
/** A degraded read is not permission to overwrite a user's staged selection.
|
|
151
|
+
* Keep the last CAS base (the server will reject a stale revision) and
|
|
152
|
+
* revoke applied-source proof until a complete refresh arrives. */
|
|
153
|
+
function draftAfterRefresh(current, receipt) {
|
|
154
|
+
if (!badgeStateOf(receipt, null).known) {
|
|
155
|
+
if (current) return { ...current, unknownBaseline: true, overwriteConfirmed: false, appliedSourceIssue: "unavailable", appliedDigest: undefined };
|
|
156
|
+
return receipt?.status === "applied" && Number.isSafeInteger(receipt.revision) && receipt.revision >= 0
|
|
157
|
+
? { ...draftFromReceipt(receipt), unknownBaseline: true, overwriteConfirmed: false } : null;
|
|
158
|
+
}
|
|
159
|
+
const fresh = draftFromReceipt(receipt);
|
|
160
|
+
if (!current?.dirty) return fresh;
|
|
161
|
+
const sameBase = current.revision === fresh.revision
|
|
162
|
+
&& JSON.stringify(current.applied.skills.map(skillEntryKeyOf)) === JSON.stringify(fresh.applied.skills.map(skillEntryKeyOf))
|
|
163
|
+
&& JSON.stringify(current.applied.mcpServers) === JSON.stringify(fresh.applied.mcpServers);
|
|
164
|
+
return { ...current, unknownBaseline: current.unknownBaseline === true && !sameBase, overwriteConfirmed: false, appliedSourceIssue: sameBase ? fresh.appliedSourceIssue : "receipt", appliedDigest: sameBase ? fresh.appliedDigest : undefined };
|
|
165
|
+
}
|
|
123
166
|
|
|
124
|
-
/** Toggle one
|
|
167
|
+
/** Toggle one entry in the draft; skills compare by identity, MCP by name. */
|
|
125
168
|
function draftToggle(draft, kind, name) {
|
|
169
|
+
if (kind === "skills") {
|
|
170
|
+
const key = skillEntryKeyOf(name);
|
|
171
|
+
const list = new Map(draft.skills.map(entry => [skillEntryKeyOf(entry), entry]));
|
|
172
|
+
if (list.has(key)) list.delete(key); else list.set(key, name);
|
|
173
|
+
const next = { ...draft, overwriteConfirmed: false, skills: sortSkills([...list.values()]) };
|
|
174
|
+
next.dirty = draftDiffOf(next).any;
|
|
175
|
+
return next;
|
|
176
|
+
}
|
|
126
177
|
const list = new Set(draft[kind]);
|
|
127
178
|
if (list.has(name)) list.delete(name); else list.add(name);
|
|
128
|
-
const next = { ...draft, [kind]: [...list].sort() };
|
|
179
|
+
const next = { ...draft, overwriteConfirmed: false, [kind]: [...list].sort() };
|
|
129
180
|
const same = (a, b) => a.length === b.length && a.every((value, index) => value === b[index]);
|
|
130
|
-
next.dirty = !same(next.skills, draft.applied.skills) || !same(next.mcpServers, draft.applied.mcpServers);
|
|
181
|
+
next.dirty = !same(next.skills.map(skillEntryKeyOf), draft.applied.skills.map(skillEntryKeyOf)) || !same(next.mcpServers, draft.applied.mcpServers);
|
|
182
|
+
return next;
|
|
183
|
+
}
|
|
184
|
+
/** Preflight the complete draft against the unfiltered inventory. Strings are not identities. */
|
|
185
|
+
function skillDraftConflicts(draft, listing) {
|
|
186
|
+
const byName = new Map(), names = new Set();
|
|
187
|
+
for (const entry of Array.isArray(draft?.skills) ? draft.skills : []) {
|
|
188
|
+
if (typeof entry === "string") { if (entry) names.add(entry); continue; }
|
|
189
|
+
const key = skillIdentityKeyOf(entry);
|
|
190
|
+
if (key === null) continue;
|
|
191
|
+
if (!byName.has(entry.name)) byName.set(entry.name, new Map());
|
|
192
|
+
byName.get(entry.name).set(key, entry);
|
|
193
|
+
}
|
|
194
|
+
const selected = [...byName].filter(([, group]) => group.size > 1).map(([name, group]) => ({ name, identities: [...group.values()] }));
|
|
195
|
+
const rows = Array.isArray(listing?.skills) ? listing.skills : null;
|
|
196
|
+
const unresolved = [...names].map(name => {
|
|
197
|
+
if (!rows) return { name, state: "unavailable", candidates: [] };
|
|
198
|
+
const candidates = [...new Map(rows.filter(row => row?.status === "parsed" && row.name === name && skillIdentityKeyOf(row.identity) !== null)
|
|
199
|
+
.map(row => [skillIdentityKeyOf(row.identity), row.identity])).values()];
|
|
200
|
+
return { name, state: candidates.length > 1 ? "ambiguous" : candidates.length === 1 ? "unique" : "unknown", candidates };
|
|
201
|
+
});
|
|
202
|
+
return { selected, unresolved };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Explicit legacy-name recovery never consumes any other entry or CAS metadata. */
|
|
206
|
+
function resolveSkillName(draft, name, identity) {
|
|
207
|
+
if (!draft || typeof name !== "string" || !name || !draft.skills?.includes(name) || (identity !== null && (skillIdentityKeyOf(identity) === null || identity.name !== name))) return draft;
|
|
208
|
+
const entries = draft.skills.filter(entry => entry !== name);
|
|
209
|
+
if (identity && !entries.some(entry => skillEntryKeyOf(entry) === skillEntryKeyOf(identity))) entries.push(identity);
|
|
210
|
+
const next = { ...draft, overwriteConfirmed: false, skills: sortSkills(entries) };
|
|
211
|
+
next.dirty = draftDiffOf(next).any;
|
|
131
212
|
return next;
|
|
132
213
|
}
|
|
133
214
|
|
|
215
|
+
/** Scoped ordinal distinguishes same-scope roots without displaying paths or IDs. */
|
|
216
|
+
function skillSourceLabels(rows) {
|
|
217
|
+
const labels = new Map(), totals = new Map();
|
|
218
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
219
|
+
const key = skillIdentityKeyOf(row.identity);
|
|
220
|
+
if (key === null || labels.has(key)) continue;
|
|
221
|
+
const scope = SOURCE_LABELS[row.scopeKey ?? row.scope] ?? row.scopeKey ?? row.scope ?? "unknown";
|
|
222
|
+
const group = `${row.name}:${scope}`;
|
|
223
|
+
const number = (totals.get(group) ?? 0) + 1;
|
|
224
|
+
totals.set(group, number);
|
|
225
|
+
labels.set(key, { scope, group, number });
|
|
226
|
+
}
|
|
227
|
+
for (const [key, item] of labels) labels.set(key, totals.get(item.group) > 1 ? `${item.scope} · source ${item.number}` : item.scope);
|
|
228
|
+
return Object.fromEntries(labels);
|
|
229
|
+
}
|
|
134
230
|
/**
|
|
135
231
|
* Map the engine response onto the commit state machine (12.3): applied
|
|
136
232
|
* refreshes; revision-conflict shows the current state for re-pick;
|
|
137
|
-
* indeterminate stays queryable;
|
|
138
|
-
*
|
|
233
|
+
* indeterminate stays queryable; structured rejections preserve names;
|
|
234
|
+
* anything else keeps the draft.
|
|
139
235
|
*/
|
|
140
236
|
function commitOutcomeOf(response) {
|
|
141
237
|
if (!response || typeof response !== "object") return { phase: "failed", error: "no response", draftKept: true };
|
|
@@ -148,7 +244,8 @@ window.__ModuleLoader__.load({
|
|
|
148
244
|
if (response.status === "applied") return { phase: "applied", revision: response.revision ?? null, skipped };
|
|
149
245
|
if (response.status === "revision-conflict") return { phase: "revision-conflict", current: response.current ?? null, draftKept: true };
|
|
150
246
|
if (response.status === "indeterminate") return { phase: "indeterminate", requestId: response.receipt?.requestId ?? null, queryable: true };
|
|
151
|
-
if (response.status === "missing") return { phase: "
|
|
247
|
+
if (response.status === "missing") return { phase: "missing", names: Array.isArray(response.missing) ? response.missing.filter(name => typeof name === "string") : [], draftKept: true };
|
|
248
|
+
if (response.status === "rejected" && response.reason === "same-name-conflict") return { phase: "same-name-conflict", names: Array.isArray(response.conflicts) ? response.conflicts.map(item => item?.name).filter(name => typeof name === "string") : [], draftKept: true };
|
|
152
249
|
return { phase: "failed", error: String(response.reason ?? response.status ?? "unknown"), draftKept: true };
|
|
153
250
|
}
|
|
154
251
|
|
|
@@ -189,7 +286,7 @@ window.__ModuleLoader__.load({
|
|
|
189
286
|
for (const name of baseSet) if (!currentSet.has(name)) removed += 1;
|
|
190
287
|
return { added, removed };
|
|
191
288
|
};
|
|
192
|
-
const skills = count(draft.skills, draft.applied.skills);
|
|
289
|
+
const skills = count(draft.skills.map(skillEntryKeyOf), (draft.applied.skills ?? []).map(skillEntryKeyOf));
|
|
193
290
|
const mcp = count(draft.mcpServers, draft.applied.mcpServers);
|
|
194
291
|
return {
|
|
195
292
|
skillsAdded: skills.added,
|
|
@@ -222,10 +319,11 @@ window.__ModuleLoader__.load({
|
|
|
222
319
|
* carried for reporting; the CAS base (revision/applied) is kept; preset
|
|
223
320
|
* metadata never produces an Apply by itself — dirty is recomputed
|
|
224
321
|
* against the applied sets. */
|
|
225
|
-
function draftFromPreset(document, current) {
|
|
322
|
+
function draftFromPreset(document, current, resolveName) {
|
|
226
323
|
const selection = document?.selection ?? {};
|
|
227
324
|
const clean = (value) => (Array.isArray(value) ? value.map(String) : []).sort();
|
|
228
|
-
const skills =
|
|
325
|
+
const skills = sortSkills((Array.isArray(selection.skills) ? selection.skills : []).map(entry =>
|
|
326
|
+
typeof entry === "string" ? (resolveName?.(entry) ?? entry) : entry));
|
|
229
327
|
const mcpServers = clean(selection.mcpServers);
|
|
230
328
|
const unresolvedRefs = Array.isArray(selection.unresolvedRefs) ? [...selection.unresolvedRefs] : [];
|
|
231
329
|
const applied = current?.applied && Array.isArray(current.applied.skills) && Array.isArray(current.applied.mcpServers)
|
|
@@ -237,8 +335,12 @@ window.__ModuleLoader__.load({
|
|
|
237
335
|
mcpServers,
|
|
238
336
|
applied,
|
|
239
337
|
revision: Number.isSafeInteger(current?.revision) ? current.revision : 0,
|
|
338
|
+
unknownBaseline: current?.unknownBaseline === true,
|
|
339
|
+
overwriteConfirmed: false,
|
|
340
|
+
...(typeof current?.appliedDigest === "string" ? { appliedDigest: current.appliedDigest } : {}),
|
|
341
|
+
appliedSourceIssue: current?.appliedSourceIssue === null ? null : current?.appliedSourceIssue ?? "receipt",
|
|
240
342
|
unresolvedRefs,
|
|
241
|
-
dirty: !same(skills,
|
|
343
|
+
dirty: !same(skills.map(skillEntryKeyOf), sortSkills(applied.skills).map(skillEntryKeyOf)) || !same(mcpServers, [...applied.mcpServers].sort()),
|
|
242
344
|
};
|
|
243
345
|
}
|
|
244
346
|
|
|
@@ -260,6 +362,12 @@ window.__ModuleLoader__.load({
|
|
|
260
362
|
};
|
|
261
363
|
}
|
|
262
364
|
|
|
365
|
+
/** A tombstone or incomplete document cannot be staged as an empty draft. */
|
|
366
|
+
function loadablePresetOf(response) {
|
|
367
|
+
const document = response?.document;
|
|
368
|
+
return response?.status === "ok" && document && document.deleted !== true && document.tombstone !== true
|
|
369
|
+
&& Array.isArray(document.selection?.skills) && Array.isArray(document.selection?.mcpServers) && Array.isArray(document.selection?.unresolvedRefs);
|
|
370
|
+
}
|
|
263
371
|
/** Preset listing grouped by namespace, sorted by display name. */
|
|
264
372
|
function groupPresets(payload) {
|
|
265
373
|
const rows = (Array.isArray(payload?.presets) ? payload.presets : []).map(presetRowOf);
|
|
@@ -277,7 +385,9 @@ window.__ModuleLoader__.load({
|
|
|
277
385
|
if (!response || typeof response !== "object" || response.error === true) return { kind: "error" };
|
|
278
386
|
if (response.status === "created" || response.status === "edited") return { kind: response.status, presetId: response.presetId ?? null, revision: response.revision ?? null };
|
|
279
387
|
if (response.status === "deleted") return { kind: "deleted", revision: response.revision ?? null };
|
|
280
|
-
if (response.status === "name-conflict" || response.status === "rename-required") return { kind: "name-conflict", with: response.with ?? null };
|
|
388
|
+
if (response.status === "name-conflict" || response.status === "rename-required") return { kind: "name-conflict", with: response.with ?? null, ...(Number.isSafeInteger(response.withRevision) && response.withRevision > 0 ? { withRevision: response.withRevision } : {}) };
|
|
389
|
+
if (response.status === "source-unavailable") return { kind: "source-unavailable", missing: Array.isArray(response.missing) ? response.missing.filter(name => typeof name === "string") : [] };
|
|
390
|
+
if (["locked", "unreadable", "unsupported", "source-changed", "absent", "deleted", "confirmation-required", "indeterminate"].includes(response.status)) return { kind: response.status };
|
|
281
391
|
if (response.status === "revision-conflict") return { kind: "revision-conflict" };
|
|
282
392
|
if (response.status === "exists") return { kind: "exists", presetId: response.presetId ?? null };
|
|
283
393
|
if (response.status === "no-workspace") return { kind: "no-workspace" };
|
|
@@ -289,15 +399,16 @@ window.__ModuleLoader__.load({
|
|
|
289
399
|
* failure. */
|
|
290
400
|
function importFeedbackOf(response) {
|
|
291
401
|
if (!response || typeof response !== "object" || response.error === true) return { kind: "error" };
|
|
292
|
-
if (response.status === "created") {
|
|
402
|
+
if (response.status === "created" || response.status === "edited") {
|
|
293
403
|
return {
|
|
294
|
-
kind:
|
|
404
|
+
kind: response.status,
|
|
295
405
|
presetId: response.presetId ?? null,
|
|
296
406
|
bound: Number.isSafeInteger(response.bound?.mcpServers) ? response.bound.mcpServers : 0,
|
|
297
407
|
unresolved: Number.isSafeInteger(response.bound?.unresolvedRefs) ? response.bound.unresolvedRefs : 0,
|
|
298
408
|
};
|
|
299
409
|
}
|
|
300
|
-
if (response.status === "name-conflict" || response.status === "rename-required") return { kind: "name-conflict", with: response.with ?? null };
|
|
410
|
+
if (response.status === "name-conflict" || response.status === "rename-required") return { kind: "name-conflict", with: response.with ?? null, ...(Number.isSafeInteger(response.withRevision) && response.withRevision > 0 ? { withRevision: response.withRevision } : {}) };
|
|
411
|
+
if (["locked", "unreadable", "unsupported", "revision-conflict", "confirmation-required", "indeterminate"].includes(response.status)) return { kind: response.status };
|
|
301
412
|
if (response.status === "rejected") return { kind: "rejected", reason: String(response.reason ?? "rejected") };
|
|
302
413
|
if (response.status === "no-workspace") return { kind: "no-workspace" };
|
|
303
414
|
return { kind: "error", status: response.status ?? "unknown" };
|
|
@@ -420,11 +531,12 @@ window.__ModuleLoader__.load({
|
|
|
420
531
|
* rollback count (no preset record was created), or a missing target
|
|
421
532
|
* root. */
|
|
422
533
|
function importConfirmOutcomeOf(response) {
|
|
423
|
-
if (!response || typeof response !== "object"
|
|
424
|
-
if (response.
|
|
534
|
+
if (!response || typeof response !== "object") return { kind: "error" };
|
|
535
|
+
if (response.error === true) return { kind: "error", ...(Array.isArray(response.installed) ? { installed: response.installed } : {}), ...(response.presetStatus === "unconfirmed" ? { presetStatus: "unconfirmed" } : {}) };
|
|
536
|
+
if (response.status === "created" || response.status === "edited") {
|
|
425
537
|
const scopeOf = (value) => (typeof value === "string" && value !== "" ? value : "project");
|
|
426
538
|
return {
|
|
427
|
-
kind:
|
|
539
|
+
kind: response.status,
|
|
428
540
|
presetId: response.presetId ?? null,
|
|
429
541
|
bound: Number.isSafeInteger(response.bound?.mcpServers) ? response.bound.mcpServers : 0,
|
|
430
542
|
unresolved: Number.isSafeInteger(response.bound?.unresolvedRefs)
|
|
@@ -449,10 +561,11 @@ window.__ModuleLoader__.load({
|
|
|
449
561
|
return { kind: "install-failed", reason: String(response.reason ?? "install-failed"), rolledBack: Number.isSafeInteger(response.rolledBack) && response.rolledBack >= 0 ? response.rolledBack : 0 };
|
|
450
562
|
}
|
|
451
563
|
if (response.status === "no-target-root") return { kind: "no-target-root", targetScope: String(response.targetScope ?? "unknown") };
|
|
452
|
-
if (response.status === "name-conflict" || response.status === "rename-required") return { kind: "name-conflict", with: response.with ?? null };
|
|
564
|
+
if (response.status === "name-conflict" || response.status === "rename-required") return { kind: "name-conflict", with: response.with ?? null, ...(Number.isSafeInteger(response.withRevision) && response.withRevision > 0 ? { withRevision: response.withRevision } : {}) };
|
|
565
|
+
if (["locked", "unreadable", "unsupported", "revision-conflict", "confirmation-required", "indeterminate", "commit-failed", "write-failed", "preset-unconfirmed"].includes(response.status)) return { kind: response.status, installed: Array.isArray(response.installed) ? response.installed : [], ...(response.presetStatus === "unconfirmed" ? { presetStatus: "unconfirmed" } : {}) };
|
|
453
566
|
if (response.status === "no-workspace") return { kind: "no-workspace" };
|
|
454
567
|
if (response.status === "rejected") return { kind: "rejected", reason: String(response.reason ?? "rejected") };
|
|
455
|
-
return { kind: "error", status: response.status ?? "unknown" };
|
|
568
|
+
return { kind: "error", status: response.status ?? "unknown", ...(Array.isArray(response.installed) ? { installed: response.installed } : {}), ...(response.presetStatus === "unconfirmed" ? { presetStatus: "unconfirmed" } : {}) };
|
|
456
569
|
}
|
|
457
570
|
|
|
458
571
|
/** Download filename for the exported package JSON: derived from the
|
|
@@ -468,6 +581,8 @@ window.__ModuleLoader__.load({
|
|
|
468
581
|
return `${base}.json`;
|
|
469
582
|
}
|
|
470
583
|
|
|
584
|
+
exports.skillIdentityKeyOf = skillIdentityKeyOf;
|
|
585
|
+
exports.skillEntryKeyOf = skillEntryKeyOf;
|
|
471
586
|
exports.badgeStateOf = badgeStateOf;
|
|
472
587
|
exports.skillRowOf = skillRowOf;
|
|
473
588
|
exports.partitionManagerListing = partitionManagerListing;
|
|
@@ -476,8 +591,12 @@ window.__ModuleLoader__.load({
|
|
|
476
591
|
exports.closeDirtyDraft = closeDirtyDraft;
|
|
477
592
|
exports.frameRefreshesSession = frameRefreshesSession;
|
|
478
593
|
exports.draftFromReceipt = draftFromReceipt;
|
|
594
|
+
exports.draftAfterRefresh = draftAfterRefresh;
|
|
479
595
|
exports.draftToggle = draftToggle;
|
|
480
596
|
exports.commitOutcomeOf = commitOutcomeOf;
|
|
597
|
+
exports.skillDraftConflicts = skillDraftConflicts;
|
|
598
|
+
exports.resolveSkillName = resolveSkillName;
|
|
599
|
+
exports.skillSourceLabels = skillSourceLabels;
|
|
481
600
|
exports.convergenceHintOf = convergenceHintOf;
|
|
482
601
|
exports.groupSkillRows = groupSkillRows;
|
|
483
602
|
exports.filterSkillRows = filterSkillRows;
|
|
@@ -486,6 +605,7 @@ window.__ModuleLoader__.load({
|
|
|
486
605
|
exports.draftFromPreset = draftFromPreset;
|
|
487
606
|
exports.presetRowOf = presetRowOf;
|
|
488
607
|
exports.groupPresets = groupPresets;
|
|
608
|
+
exports.loadablePresetOf = loadablePresetOf;
|
|
489
609
|
exports.presetWriteOutcomeOf = presetWriteOutcomeOf;
|
|
490
610
|
exports.importFeedbackOf = importFeedbackOf;
|
|
491
611
|
exports.presetExportTextOf = presetExportTextOf;
|