dsh-capability-panel 1.1.0 → 1.1.1

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/lib/index.d.ts CHANGED
@@ -98,6 +98,8 @@ interface HostServices {
98
98
  * part of a listener still has to contain its own failures.
99
99
  */
100
100
  listener: (payload: AgentCreatedPayload) => void | Promise<void>): void;
101
+ /** Fired when a blank session's preset switch commits (never at creation). */
102
+ on(event: 'agent-preset/selected', listener: (sessionId: unknown, presetId: unknown) => void | Promise<void>): void;
101
103
  on(event: 'tools/result', listener: (exec: {
102
104
  name?: unknown;
103
105
  arguments?: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/loopback.ts","../src/host/types.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;AACiB,UAAA,YAAA,CAAY;;;oBAGT;ECeH;AAIjB;AASA;;EACU,SAAA,MAAA,CAAA,EAAA;IACqB,SAAA,aAAA,CAAA,EAAA,MAAA;EAAO,CAAA;AA8BtC;;;;AAwBmD,UArElC,aAAA,CAqEkC;EACqB,GAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EArE9C,SAqE8C,GAAA,SAAA;;AAAD,UAlEtD,eAAA,CAkEsD;EAGtD,SAAA,EAAA,EAAA,MAAY;EAMZ,SAAA,KAAA,EAAA,QAAmB,GAAA,MAAA;EAOnB,SAAA,IAAA,CAAA,EAAY,MAAA;EAKR,SAAA,IAAA,CAAA,EAAA,MAAA;EAAmB,SAAA,WAAA,CAAA,EAAA,MAAA;EAAuB,SAAA,MAAA,CAAA,EAAA,MAAA;;AAIlC,UAlFZ,mBAAA,CAkFY;EACJ,IAAA,EAAA,EAlFf,OAkFe,CAlFP,eAkFO,EAAA,CAAA;EACF,cAAA,CAAA,EAAA,CAAA,EAAA,MAAA,CAAA,EAlFQ,OAkFR,CAAA,OAAA,CAAA;EACD,cAAA,CAAA,QAAA,EAAA,OAAA,CAAA,EAAA,MAAA,GAAA,SAAA;;UArDL;SACR;;;;;;4BAMmB;;UAGX,eAAA;;;;MAE8E,kBAAkB;;UAWhG,aAAA;;;;MACkC,iBAAiB;;;;MACJ,QAAQ;;UAGvD,YAAA;4BACW;;;;;;;;;;;;UAKX,mBAAA;kBACC;;;0BAEsB;;;;UAIvB,YAAA;;;;;qBAKI,qBAAmB,uBAAuB;;;uBAGxC;6BACM;yBACJ;uBACF;sBACD;;;;;;;;sBASE,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;iBAcrC;;;;SACT;;;;;;;UAqBQ,mBAAA;;;;;UAIA,SAAA;;;;;;;;;;;;;;;;;;;;UAeA,YAAA;;;;;;;;;;UASA,mBAAA;;;;;;;;UASA,cAAA,SAAqB;;;;;UAMrB,kBAAA;qCACoB;;;;;AD7MrC;iBESgB,KAAA,MAAW;cA0Bd"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/loopback.ts","../src/host/types.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;AACiB,UAAA,YAAA,CAAY;;;oBAGT;ECeH;AAIjB;AASA;;EACU,SAAA,MAAA,CAAA,EAAA;IACqB,SAAA,aAAA,CAAA,EAAA,MAAA;EAAO,CAAA;AA8BtC;;;;AAwBmD,UArElC,aAAA,CAqEkC;EACqB,GAAA,CAAA,SAAA,EAAA,MAAA,CAAA,EArE9C,SAqE8C,GAAA,SAAA;;AAAD,UAlEtD,eAAA,CAkEsD;EAGtD,SAAA,EAAA,EAAA,MAAY;EAMZ,SAAA,KAAA,EAAA,QAAmB,GAAA,MAAA;EAOnB,SAAA,IAAA,CAAA,EAAY,MAAA;EAKR,SAAA,IAAA,CAAA,EAAA,MAAA;EAAmB,SAAA,WAAA,CAAA,EAAA,MAAA;EAAuB,SAAA,MAAA,CAAA,EAAA,MAAA;;AAIlC,UAlFZ,mBAAA,CAkFY;EACJ,IAAA,EAAA,EAlFf,OAkFe,CAlFP,eAkFO,EAAA,CAAA;EACF,cAAA,CAAA,EAAA,CAAA,EAAA,MAAA,CAAA,EAlFQ,OAkFR,CAAA,OAAA,CAAA;EACD,cAAA,CAAA,QAAA,EAAA,OAAA,CAAA,EAAA,MAAA,GAAA,SAAA;;UArDL;SACR;;;;;;4BAMmB;;UAGX,eAAA;;;;MAE8E,kBAAkB;;UAWhG,aAAA;;;;MACkC,iBAAiB;;;;MACJ,QAAQ;;UAGvD,YAAA;4BACW;;;;;;;;;;;;UAKX,mBAAA;kBACC;;;0BAEsB;;;;UAIvB,YAAA;;;;;qBAKI,qBAAmB,uBAAuB;;;uBAGxC;6BACM;yBACJ;uBACF;sBACD;;;;;;;;sBASE,+BAA+B;;iGAKS;;;;;;;;;;;;;;;;;;;;;;;;iBAc9C;;;;SACT;;;;;;;UAqBQ,mBAAA;;;;;UAIA,SAAA;;;;;;;;;;;;;;;;;;;;UAeA,YAAA;;;;;;;;;;UASA,mBAAA;;;;;;;;UASA,cAAA,SAAqB;;;;;UAMrB,kBAAA;qCACoB;;;;;ADlNrC;iBESgB,KAAA,MAAW;cA0Bd"}
package/lib/index.js CHANGED
@@ -360,33 +360,60 @@ function createCapabilityController(ctx, appendStats, blockedCounts) {
360
360
  }
361
361
  if (maskedAny) ensurePromptNote(agent, ensureState());
362
362
  };
363
+ const mutationQueues = /* @__PURE__ */ new Map();
364
+ const enqueue = (sessionId, op) => {
365
+ const next = (mutationQueues.get(sessionId) ?? Promise.resolve()).then(op, op);
366
+ mutationQueues.set(sessionId, next.then(() => void 0, () => void 0));
367
+ return next;
368
+ };
369
+ const restoreImpl = async (sessionId, overrides) => {
370
+ const groups = [
371
+ ["skill", overrides.skills],
372
+ ["mcp-server", overrides.mcpServers],
373
+ ["mcp-tool", overrides.mcpTools],
374
+ ["system-tool", overrides.systemTools]
375
+ ];
376
+ for (const [kind, positions] of groups) for (const [name, enabled] of Object.entries(positions)) {
377
+ if (states.get(sessionId)?.userToggled.has(`${kind}:${name}`) === true) continue;
378
+ try {
379
+ if (kind === "skill") await setSkill(sessionId, name, enabled);
380
+ else if (kind === "mcp-server") setServer(sessionId, name, enabled);
381
+ else setTool(sessionId, name, enabled, kind === "system-tool");
382
+ } catch {}
383
+ }
384
+ const st = states.get(sessionId);
385
+ if (st !== void 0 && st.userToggled.size === 0 && st.skills.size === 0 && st.mcpServers.size === 0 && st.mcpTools.size === 0 && st.systemTools.size === 0) {
386
+ st.noteDispose?.();
387
+ delete st.noteDispose;
388
+ states.delete(sessionId);
389
+ }
390
+ };
363
391
  return {
364
392
  states,
365
393
  state: (sessionId) => states.get(sessionId),
366
- seed,
367
- async restore(sessionId, overrides) {
368
- const groups = [
369
- ["skill", overrides.skills],
370
- ["mcp-server", overrides.mcpServers],
371
- ["mcp-tool", overrides.mcpTools],
372
- ["system-tool", overrides.systemTools]
373
- ];
374
- for (const [kind, positions] of groups) for (const [name, enabled] of Object.entries(positions)) {
375
- if (states.get(sessionId)?.userToggled.has(`${kind}:${name}`) === true) continue;
376
- try {
377
- if (kind === "skill") await setSkill(sessionId, name, enabled);
378
- else if (kind === "mcp-server") setServer(sessionId, name, enabled);
379
- else setTool(sessionId, name, enabled, kind === "system-tool");
380
- } catch {}
381
- }
394
+ seed: (sessionId, defaults) => enqueue(sessionId, () => seed(sessionId, defaults)),
395
+ restore: (sessionId, overrides) => enqueue(sessionId, () => restoreImpl(sessionId, overrides)),
396
+ reseed: (sessionId, defaults, overrides) => enqueue(sessionId, async () => {
382
397
  const st = states.get(sessionId);
383
- if (st !== void 0 && st.userToggled.size === 0 && st.skills.size === 0 && st.mcpServers.size === 0 && st.mcpTools.size === 0 && st.systemTools.size === 0) {
398
+ if (st !== void 0) {
399
+ for (const map of [
400
+ st.systemTools,
401
+ st.mcpServers,
402
+ st.mcpTools,
403
+ st.skills
404
+ ]) {
405
+ for (const dispose of map.values()) dispose();
406
+ map.clear();
407
+ }
384
408
  st.noteDispose?.();
385
409
  delete st.noteDispose;
410
+ st.userToggled.clear();
386
411
  states.delete(sessionId);
387
412
  }
388
- },
389
- async set(sessionId, kind, name, enabled) {
413
+ if (defaults.tools.length > 0 || defaults.skills.length > 0) await seed(sessionId, defaults);
414
+ if (overrides !== void 0) await restoreImpl(sessionId, overrides);
415
+ }),
416
+ set: (sessionId, kind, name, enabled) => enqueue(sessionId, async () => {
390
417
  stateFor(sessionId).userToggled.add(`${kind}:${name}`);
391
418
  if (kind === "skill") await setSkill(sessionId, name, enabled);
392
419
  else if (kind === "mcp-server") setServer(sessionId, name, enabled);
@@ -397,7 +424,7 @@ function createCapabilityController(ctx, appendStats, blockedCounts) {
397
424
  kind: enabled ? "enable" : "disable",
398
425
  name: `${kind}:${name}`
399
426
  });
400
- }
427
+ })
401
428
  };
402
429
  }
403
430
 
@@ -450,6 +477,27 @@ function registerPresetEnforcement(ctx, capabilities, presetTools, sessionOverri
450
477
  return;
451
478
  }
452
479
  });
480
+ /**
481
+ * A preset switch lands AFTER creation (the session header records the
482
+ * composing preset at creation, and the picker's select() recomposes the
483
+ * blank session later): the first agent/created seeded the ORIGINAL
484
+ * preset's defaults, so the new preset's defaults must re-seed on top of a
485
+ * clean slate. Session overrides replay last — the user's own switches in
486
+ * this session outrank either preset's defaults.
487
+ */
488
+ ctx.on("agent-preset/selected", (sessionId, presetId) => {
489
+ try {
490
+ if (typeof sessionId !== "string" || typeof presetId !== "string") return void 0;
491
+ const defaults = presetTools.defaultsFor(presetId) ?? {
492
+ tools: [],
493
+ skills: []
494
+ };
495
+ const overrides = sessionOverrides.overridesFor(sessionId);
496
+ return capabilities.reseed(sessionId, defaults, overrides);
497
+ } catch {
498
+ return;
499
+ }
500
+ });
453
501
  }
454
502
 
455
503
  //#endregion
@@ -1035,21 +1083,18 @@ function createPresetToolController(ctx, access) {
1035
1083
  presets: await Promise.all(presets.map(async (preset) => {
1036
1084
  let entries = [];
1037
1085
  let skillRows = [];
1086
+ let mountError;
1038
1087
  if (preset.broken === void 0) {
1039
1088
  let scope;
1040
1089
  try {
1041
1090
  scope = await agentPresets.standingKeyFor(preset.id);
1042
1091
  entries = toolSummaries(tools, scope);
1043
- } catch (error) {
1044
- throw new HttpError(503, `preset "${preset.id}" tools are unavailable: ${errorMessage(error)}`);
1045
- }
1046
- if (skills !== void 0) {
1047
- const disabledSkills = new Set(stored.presetSkills[preset.id] ?? []);
1048
- try {
1092
+ if (skills !== void 0) {
1093
+ const disabledSkills = new Set(stored.presetSkills[preset.id] ?? []);
1049
1094
  skillRows = await presetSkillRows(skills, scope, disabledSkills, cwd, presetDirs);
1050
- } catch (error) {
1051
- throw new HttpError(503, `preset "${preset.id}" skills are unavailable: ${errorMessage(error)}`);
1052
1095
  }
1096
+ } catch (error) {
1097
+ mountError = errorMessage(error);
1053
1098
  }
1054
1099
  }
1055
1100
  const disabled = new Set(configured[preset.id] ?? []);
@@ -1083,7 +1128,7 @@ function createPresetToolController(ctx, access) {
1083
1128
  name: preset.name ?? preset.id,
1084
1129
  trust: preset.trust,
1085
1130
  ...preset.description === void 0 ? {} : { description: preset.description },
1086
- ...preset.broken === void 0 ? {} : { broken: preset.broken },
1131
+ ...preset.broken !== void 0 ? { broken: preset.broken } : mountError === void 0 ? {} : { broken: `failed to mount: ${mountError}` },
1087
1132
  skills: skillRows,
1088
1133
  mcp,
1089
1134
  systemTools