@sqdr2/dsh-fusion 0.3.2 → 0.3.4

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/src/identity.ts CHANGED
@@ -33,12 +33,30 @@ export const PLUGIN_NAME = 'dsh-fusion'
33
33
  /** The plugin id and package name this project used before the rename. */
34
34
  export const LEGACY_PLUGIN_NAME = 'dsh-model-fusion'
35
35
 
36
- /** Registered provider route for the Fusion model entry. */
36
+ /** Registered provider route for the Fusion model entries. */
37
37
  export const FUSION_PROVIDER = 'dsh-fusion'
38
38
 
39
- /** The single model id the Fusion entry advertises. */
39
+ /**
40
+ * The model id of the combo every installation starts with.
41
+ *
42
+ * It is a pair id like any other; keeping this exact spelling for the first
43
+ * combo means a durable `model/selection` written before combos existed still
44
+ * names a combo that exists.
45
+ */
40
46
  export const FUSION_MODEL = 'auto'
41
47
 
48
+ /**
49
+ * The model ids this provider advertises: `auto` plus one generated
50
+ * `pair-xxxxxxxx` per additional combo. The browser bundle inlines this module,
51
+ * so the namespace shape is fixed here rather than read from a settings
52
+ * document at import time.
53
+ */
54
+ const FUSION_MODEL_PATTERN = /^(?:auto|pair-[a-z0-9]{6,12})$/
55
+
56
+ /** Whether a model id names a Fusion combo on this provider. */
57
+ export const isFusionModel = (model: string | undefined): boolean =>
58
+ typeof model === 'string' && FUSION_MODEL_PATTERN.test(model)
59
+
42
60
  /**
43
61
  * The provider route this plugin registered before it was renamed from
44
62
  * `dsh-model-fusion`. Sessions created then still name it in their durable
@@ -51,26 +69,31 @@ export const LEGACY_FUSION_PROVIDER = 'dsh-model-fusion'
51
69
  export const isFusionProvider = (provider: string | undefined): boolean =>
52
70
  provider === FUSION_PROVIDER || provider === LEGACY_FUSION_PROVIDER
53
71
 
54
- /** Whether a route names the Fusion entry, under either name. */
72
+ /** Whether a route names a Fusion combo, under either provider spelling. */
55
73
  export const isFusionSelection = (route: { provider?: string; model?: string } | undefined): boolean =>
56
- isFusionProvider(route?.provider) && route?.model === FUSION_MODEL
74
+ isFusionProvider(route?.provider) && isFusionModel(route?.model)
57
75
 
58
76
  /**
59
- * How a native model-switch notice names this entry (`provider/model`).
77
+ * How a native model-switch notice names a combo: `provider/model`, or the bare
78
+ * model when both sides share this provider (switching from one combo to
79
+ * another).
60
80
  *
61
- * Both spellings are listed: a session that switched to Fusion before the
62
- * rename carries the old one in its durable log, and the notice is the same
63
- * non-change on every Fusion step either way.
81
+ * The notice is a pseudo-change: it compares the virtual menu route with the
82
+ * physical Lead route that actually dispatches, so it would otherwise repeat on
83
+ * every Fusion step. Both provider spellings are accepted because a session
84
+ * that switched to Fusion before the rename carries the old one in its durable
85
+ * log; any combo id matches, since combos are not physical models.
64
86
  */
65
- export const FUSION_SELECTION_LABELS = [
66
- `${FUSION_PROVIDER}/${FUSION_MODEL}`,
67
- `${LEGACY_FUSION_PROVIDER}/${FUSION_MODEL}`,
68
- ] as const
87
+ const FUSION_SELECTION_LABEL_PATTERN = /(?:(?:dsh-fusion|dsh-model-fusion)\/|→ )(?:auto|pair-[a-z0-9]{6,12})$/
88
+
89
+ /** Whether a switch-notice summary describes a Fusion combo as either side. */
90
+ export const isFusionSelectionLabel = (summary: string | undefined): boolean =>
91
+ typeof summary === 'string' && FUSION_SELECTION_LABEL_PATTERN.test(summary)
69
92
 
70
93
  /**
71
- * Whether a route already names the entry under its current name. A durable
72
- * intent that fails this is rewritten before the next request is assembled;
73
- * the legacy spelling is a read-side alias, not a route that still dispatches.
94
+ * Whether a route already names a combo under its current provider spelling. A
95
+ * durable intent that fails this is rewritten before the next request is
96
+ * assembled; the legacy spelling is a read-side alias, not a dispatching route.
74
97
  */
75
98
  export const isCurrentFusionSelection = (route: { provider?: string; model?: string } | undefined): boolean =>
76
- route?.provider === FUSION_PROVIDER && route.model === FUSION_MODEL
99
+ route?.provider === FUSION_PROVIDER && isFusionModel(route.model)
package/src/status.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ControlView } from './host/native-model-control.js'
2
- import type { PhysicalRoute, Role, TokenMeasurement, VerificationLevel } from './contracts.js'
2
+ import type { PhysicalRoute, Role, SandboxMode, TokenMeasurement, VerificationLevel } from './contracts.js'
3
3
 
4
4
  /** Bounded, read-only UI projection. No prompts, tool arguments or credentials. */
5
5
  export interface FusionStatus {
@@ -20,6 +20,22 @@ export interface FusionStatus {
20
20
  workerId: string | null
21
21
  modelControl?: ControlView
22
22
  models: { lead: PhysicalRoute; worker: PhysicalRoute; compactor: PhysicalRoute | null }
23
+ /**
24
+ * Role-separated sandbox modes, present while Fusion confines the Lead. The
25
+ * composer's own permission control follows the conversation (Lead) session,
26
+ * so the UI shows these instead of the derived preset name.
27
+ */
28
+ permissions?: {
29
+ /**
30
+ * What the Lead's own work is confined to. The session is widened only for the
31
+ * checks Fusion runs itself and for the Lead during a Host-unlocked takeover.
32
+ */
33
+ lead: SandboxMode
34
+ /** What the Sidekick runs under: the mode the user chose for this conversation. */
35
+ worker: SandboxMode
36
+ /** The role working right now; null while the task waits. */
37
+ active: Role | null
38
+ }
23
39
  usage: {
24
40
  calls: number
25
41
  finalCalls: number