better-dsh 0.3.1-d → 0.3.1-f

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 CHANGED
@@ -90,17 +90,22 @@
90
90
  # dsh-web-app bundle declares (same id), restating its full shape per the
91
91
  # patch-layer contract, with `trustedHosts` merging the DSH_TRUSTED_HOSTS
92
92
  # environment (whitespace-separated, operator-declared serving authorities)
93
- # ahead of the upstream webRuntime-derived ones (LAN literals from an
94
- # all-interface bind plus --trusted-host extras). Unset/empty env ⇒ identical
95
- # behavior to the unpatched row. Malformed entries fail plugin load loudly
96
- # (upstream assertTrustedAuthority). The browser-side twin (page-authority
97
- # loopback verdict) is the plugin's webserver/index-inject boot script —
98
- # see src/web-trust.ts.
93
+ # ahead of the upstream invocation authorities. Since DSH 0.1.7 the parsed
94
+ # Web flags live on the `webStartup` service and every host in the declared
95
+ # peer range provides it, so the row injects webStartup and reads
96
+ # `ctx.webStartup.trustedHosts` (the --trusted-host values) — the 0.2.1+
97
+ # upstream row's own source; on pre-0.2.1 hosts this drops only the LAN
98
+ # literals an all-interface bind used to derive (wildcard binds are rejected
99
+ # there too, and this repo's lines always declare authorities explicitly).
100
+ # Unset/empty env ⇒ identical behavior to the unpatched row. Malformed entries
101
+ # fail plugin load loudly (upstream assertTrustedAuthority). The browser-side
102
+ # twin (page-authority loopback verdict) is the plugin's
103
+ # webserver/index-inject boot script — see src/web-trust.ts.
99
104
  - id: connection
100
105
  name: '@deepseek-ai/dsh-client-connection'
101
- inject: [webRuntime]
106
+ inject: [webStartup]
102
107
  config:
103
- trustedHosts: !!js (process.env.DSH_TRUSTED_HOSTS ?? '').split(/\s+/).filter(Boolean).concat(ctx.webRuntime.trustedHosts)
108
+ trustedHosts: !!js (process.env.DSH_TRUSTED_HOSTS ?? '').split(/\s+/).filter(Boolean).concat(ctx.webStartup.trustedHosts)
104
109
 
105
110
  - id: ui-settings-models
106
111
  name: '@deepseek-ai/dsh-client-ui-settings-models'
@@ -172,6 +172,20 @@ function FailoverRow({ catalog, loadConfig, save, t }) {
172
172
 
173
173
  //#endregion
174
174
  //#region src/mobile/gesture.ts
175
+ /**
176
+ * Whether the mobile adaptation mounts at all (2026-10-18 user ruling):
177
+ * touch-first means the device's PRIMARY input is a finger. A query
178
+ * answering FALSE — a hover-capable or fine primary pointer — decides
179
+ * desktop on its own (a touchscreen laptop keeps desktop behavior); the
180
+ * pair answering true is the standard idiom; and only when the queries
181
+ * are entirely unavailable does `maxTouchPoints` become the honest
182
+ * degrade (every such legacy device is a phone or tablet anyway).
183
+ */
184
+ function isTouchFirstDevice(input) {
185
+ if (input.hoverNone === false || input.pointerCoarse === false) return false;
186
+ if (input.hoverNone === true && input.pointerCoarse === true) return true;
187
+ return (input.maxTouchPoints ?? 0) > 0;
188
+ }
175
189
  /** Resolved defaults — the `1706b81` constants (120 / viewport÷4 / 40 / 1.3)
176
190
  * plus the one addition, the velocity gate. A slow text-selection drag runs
177
191
  * ~0.13 px/ms; 0.15 px/ms filters those while any comfortable sweep (0.4
@@ -260,6 +274,18 @@ function resolveMobileConfig(pageConfig) {
260
274
 
261
275
  //#endregion
262
276
  //#region src/mobile/client/index.ts
277
+ /**
278
+ * One media query, or `undefined` when the environment has none (old
279
+ * webviews throw or omit `matchMedia`) — the probe then rides the
280
+ * touch-points fallback in {@link isTouchFirstDevice}.
281
+ */
282
+ function safeMatchMedia(query) {
283
+ try {
284
+ return globalThis.matchMedia?.(query) ?? void 0;
285
+ } catch {
286
+ return;
287
+ }
288
+ }
263
289
  /** Left sidebar state, live off AppFrame's semantic attribute. */
264
290
  function readLeftCollapsed() {
265
291
  return document.querySelector("[data-sidebar-collapsed]") !== null;
@@ -340,17 +366,46 @@ function mobileCss() {
340
366
  }
341
367
  /**
342
368
  * Mount the mobile feature: style injection plus the swipe listeners.
343
- * Inert unless the host's boot script opted the page in.
369
+ * Inert unless the host's boot script opted the page in AND the device is
370
+ * touch-first (2026-10-18 user ruling). Capability flips (a tablet's
371
+ * primary pointer hardware changing) re-evaluate and mount/unmount the
372
+ * surface live; the media queries answer on every browser since ~2015 and
373
+ * a webview without `matchMedia` degrades to the touch-points probe.
344
374
  *
345
375
  * @param ctx - client root context.
346
- * @returns the effect disposer (style tag + listeners removed on unload).
347
376
  */
348
377
  function setupMobileLayout(ctx) {
349
378
  const pageConfig = globalThis.__DASHR_MOBILE__;
350
379
  const config = resolveMobileConfig(pageConfig);
351
380
  if (!config.enabled) return;
352
- const styleTagId = "better-dsh/mobile";
381
+ const coarseQuery = safeMatchMedia("(pointer: coarse)");
382
+ const hoverQuery = safeMatchMedia("(hover: none)");
353
383
  ctx.effect(() => {
384
+ let disposeSurface;
385
+ const apply$1 = () => {
386
+ const touchFirst = isTouchFirstDevice({
387
+ hoverNone: hoverQuery?.matches,
388
+ pointerCoarse: coarseQuery?.matches,
389
+ maxTouchPoints: navigator.maxTouchPoints
390
+ });
391
+ if (touchFirst && disposeSurface === void 0) disposeSurface = mountTouchSurface();
392
+ else if (!touchFirst && disposeSurface !== void 0) {
393
+ disposeSurface();
394
+ disposeSurface = void 0;
395
+ }
396
+ };
397
+ coarseQuery?.addEventListener("change", apply$1);
398
+ hoverQuery?.addEventListener("change", apply$1);
399
+ apply$1();
400
+ return () => {
401
+ coarseQuery?.removeEventListener("change", apply$1);
402
+ hoverQuery?.removeEventListener("change", apply$1);
403
+ disposeSurface?.();
404
+ };
405
+ }, "dashr: mobile layout");
406
+ /** The style tag + gesture listeners, mounted and disposed as one surface. */
407
+ function mountTouchSurface() {
408
+ const styleTagId = "better-dsh/mobile";
354
409
  const tag = document.createElement("style");
355
410
  tag.dataset.plugin = "better-dsh";
356
411
  tag.dataset.pluginCss = styleTagId;
@@ -363,9 +418,7 @@ function setupMobileLayout(ctx) {
363
418
  const onPointerDown = (event) => {
364
419
  start = void 0;
365
420
  const viewport = window.innerWidth;
366
- const coarsePointer = window.matchMedia?.("(pointer: coarse)").matches === true;
367
421
  const panels = readPanelState();
368
- if (!coarsePointer && !panels.leftCollapsed && !panels.rightOpen) return;
369
422
  if (!admitsSwipeStart(event.clientX, viewport, panels, config)) return;
370
423
  start = {
371
424
  x: event.clientX,
@@ -405,7 +458,7 @@ function setupMobileLayout(ctx) {
405
458
  tag.remove();
406
459
  Promise.resolve(offLayout.dispose());
407
460
  };
408
- }, "dashr: mobile layout");
461
+ }
409
462
  }
410
463
 
411
464
  //#endregion
package/lib/index.js CHANGED
@@ -1409,8 +1409,7 @@ const agentExecutor = async (rawArgs, exec, deps) => {
1409
1409
  if (!exec.agent) return { error: "agent() requires a calling agent (this run has no agent to delegate from)" };
1410
1410
  const subagents = deps.requireSubagents?.();
1411
1411
  if (!subagents) return { error: "agent() is unavailable: no ctx.subagents service is mounted in this composition" };
1412
- const delegation = {
1413
- label: description,
1412
+ const request = {
1414
1413
  prompt: [{
1415
1414
  type: "text",
1416
1415
  text: prompt
@@ -1419,30 +1418,60 @@ const agentExecutor = async (rawArgs, exec, deps) => {
1419
1418
  maxDepth: NATIVE_MAX_DEPTH
1420
1419
  };
1421
1420
  const runInBackground = a["run_in_background"] ?? true;
1421
+ const legacyRequest = {
1422
+ label: description,
1423
+ ...request,
1424
+ signal: exec.signal
1425
+ };
1426
+ if (subagents.startActivation === void 0) try {
1427
+ if (runInBackground) {
1428
+ if (subagents.startContinuable === void 0) return { error: "agent() is unavailable: this DSH host exposes neither managed activations nor the legacy continuable seam" };
1429
+ return {
1430
+ kind: "continuable",
1431
+ subagentId: (await subagents.startContinuable({
1432
+ provider,
1433
+ request: legacyRequest
1434
+ })).childId
1435
+ };
1436
+ }
1437
+ if (subagents.start === void 0) return { error: "agent() is unavailable: this DSH host exposes neither managed activations nor the legacy one-shot seam" };
1438
+ const run = await subagents.start(provider, legacyRequest);
1439
+ try {
1440
+ const result = await run.result;
1441
+ if (result.stopReason !== "completed") return { error: `agent() ${stopReasonError(result.stopReason)}` };
1442
+ return {
1443
+ kind: "foreground",
1444
+ subagentId: run.id,
1445
+ output: result.output
1446
+ };
1447
+ } finally {
1448
+ await run.dispose();
1449
+ }
1450
+ } catch (error) {
1451
+ return { error: `agent() failed: ${error instanceof Error ? error.message : String(error)}` };
1452
+ }
1422
1453
  try {
1454
+ const activation = await subagents.startActivation({
1455
+ provider,
1456
+ label: description,
1457
+ request,
1458
+ signal: exec.signal,
1459
+ delivery: runInBackground ? "parent" : "caller"
1460
+ });
1423
1461
  if (runInBackground) return {
1424
1462
  kind: "continuable",
1425
- subagentId: (await subagents.startContinuable({
1426
- provider,
1427
- label: description,
1428
- request: delegation,
1429
- signal: exec.signal
1430
- })).childId
1463
+ subagentId: activation.childId
1431
1464
  };
1432
- const run = await subagents.start(provider, {
1433
- ...delegation,
1434
- signal: exec.signal
1435
- });
1436
1465
  try {
1437
- const result = await run.result;
1466
+ const result = await activation.result;
1438
1467
  if (result.stopReason !== "completed") return { error: `agent() ${stopReasonError(result.stopReason)}` };
1439
1468
  return {
1440
1469
  kind: "foreground",
1441
- runId: run.id,
1470
+ subagentId: activation.childId,
1442
1471
  output: result.output
1443
1472
  };
1444
1473
  } finally {
1445
- await run.dispose();
1474
+ await activation.dispose();
1446
1475
  }
1447
1476
  } catch (error) {
1448
1477
  return { error: `agent() failed: ${error instanceof Error ? error.message : String(error)}` };
@@ -1650,7 +1679,7 @@ function createAgentBridgeTools(deps) {
1650
1679
  type: "string",
1651
1680
  enum: ["foreground"]
1652
1681
  },
1653
- runId: { type: "string" },
1682
+ subagentId: { type: "string" },
1654
1683
  output: { type: "json" }
1655
1684
  },
1656
1685
  additionalProperties: false
@@ -1,6 +1,6 @@
1
+ import { t as Schema } from "../index2.js";
1
2
  import { Context } from "@deepseek-ai/cordis";
2
3
  import { ToolDefinition } from "@deepseek-ai/dsh-tools";
3
- import * as _deepseek_ai_schemastery17 from "@deepseek-ai/schemastery";
4
4
 
5
5
  //#region src/url-schemes/tools/write.d.ts
6
6
 
@@ -50,12 +50,12 @@ declare const inject: string[];
50
50
  * real patch-line config. Schema-level defaults (both ON — the service is
51
51
  * opt-out) survive every overlay layer, per the v0.2.2a ruling.
52
52
  */
53
- declare const Config: _deepseek_ai_schemastery17.default<Schemastery.ObjectS<NoInfer<{
54
- urlSchemes: _deepseek_ai_schemastery17.default<boolean, boolean, "defined">;
55
- hashline: _deepseek_ai_schemastery17.default<boolean, boolean, "defined">;
53
+ declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
54
+ urlSchemes: Schema<boolean, boolean, "defined">;
55
+ hashline: Schema<boolean, boolean, "defined">;
56
56
  }>>, Schemastery.ObjectT<NoInfer<{
57
- urlSchemes: _deepseek_ai_schemastery17.default<boolean, boolean, "defined">;
58
- hashline: _deepseek_ai_schemastery17.default<boolean, boolean, "defined">;
57
+ urlSchemes: Schema<boolean, boolean, "defined">;
58
+ hashline: Schema<boolean, boolean, "defined">;
59
59
  }>>, "plain">;
60
60
  /** Register the four URL-aware tools on one agent's own scope layer. */
61
61
  /**
@@ -75,12 +75,12 @@ declare function apply(ctx: Context, config: UrlSchemesConfig | undefined): void
75
75
  declare const _default: {
76
76
  name: string;
77
77
  inject: string[];
78
- Config: _deepseek_ai_schemastery17.default<Schemastery.ObjectS<NoInfer<{
79
- urlSchemes: _deepseek_ai_schemastery17.default<boolean, boolean, "defined">;
80
- hashline: _deepseek_ai_schemastery17.default<boolean, boolean, "defined">;
78
+ Config: Schema<Schemastery.ObjectS<NoInfer<{
79
+ urlSchemes: Schema<boolean, boolean, "defined">;
80
+ hashline: Schema<boolean, boolean, "defined">;
81
81
  }>>, Schemastery.ObjectT<NoInfer<{
82
- urlSchemes: _deepseek_ai_schemastery17.default<boolean, boolean, "defined">;
83
- hashline: _deepseek_ai_schemastery17.default<boolean, boolean, "defined">;
82
+ urlSchemes: Schema<boolean, boolean, "defined">;
83
+ hashline: Schema<boolean, boolean, "defined">;
84
84
  }>>, "plain">;
85
85
  apply: typeof apply;
86
86
  };
@@ -1,7 +1,7 @@
1
+ import { t as Schema } from "./index2.js";
1
2
  import { Context } from "@deepseek-ai/cordis";
2
3
  import { IncomingMessage } from "node:http";
3
4
  import { CredentialRecord } from "@deepseek-ai/dsh-credentials";
4
- import * as _deepseek_ai_schemastery0 from "@deepseek-ai/schemastery";
5
5
 
6
6
  //#region src/web-password.d.ts
7
7
 
@@ -123,10 +123,10 @@ interface WebPasswordConfig {
123
123
  /** Absolute browser-session lifetime in days. Default: 30 (the native default). */
124
124
  cookieMaxAgeDays?: number;
125
125
  }
126
- declare const Config: _deepseek_ai_schemastery0.default<Schemastery.ObjectS<NoInfer<{
127
- cookieMaxAgeDays: _deepseek_ai_schemastery0.default<number, number, "defined">;
126
+ declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
127
+ cookieMaxAgeDays: Schema<number, number, "defined">;
128
128
  }>>, Schemastery.ObjectT<NoInfer<{
129
- cookieMaxAgeDays: _deepseek_ai_schemastery0.default<number, number, "defined">;
129
+ cookieMaxAgeDays: Schema<number, number, "defined">;
130
130
  }>>, "plain">;
131
131
  /** Cordis plugin name; also the scope of this row's credential record. */
132
132
  declare const name = "dashr-web-password";
@@ -145,10 +145,10 @@ declare function apply(ctx: Context, config?: WebPasswordConfig): void;
145
145
  declare const _default: {
146
146
  name: string;
147
147
  inject: string[];
148
- Config: _deepseek_ai_schemastery0.default<Schemastery.ObjectS<NoInfer<{
149
- cookieMaxAgeDays: _deepseek_ai_schemastery0.default<number, number, "defined">;
148
+ Config: Schema<Schemastery.ObjectS<NoInfer<{
149
+ cookieMaxAgeDays: Schema<number, number, "defined">;
150
150
  }>>, Schemastery.ObjectT<NoInfer<{
151
- cookieMaxAgeDays: _deepseek_ai_schemastery0.default<number, number, "defined">;
151
+ cookieMaxAgeDays: Schema<number, number, "defined">;
152
152
  }>>, "plain">;
153
153
  apply: typeof apply;
154
154
  };
@@ -1,2 +1,3 @@
1
+ import "./index2.js";
1
2
  import { a as _default, c as buildTrustScript, d as name, i as TrustConfig, l as deriveDefaultPageAuthorities, n as Config, o as apply, r as MobileConfig, s as buildMobileScript, t as BootScriptRow, u as inject } from "./web-trust2.js";
2
3
  export { BootScriptRow, Config, MobileConfig, TrustConfig, apply, buildMobileScript, buildTrustScript, _default as default, deriveDefaultPageAuthorities, inject, name };
@@ -1,5 +1,5 @@
1
+ import { t as Schema } from "./index2.js";
1
2
  import { Context } from "@deepseek-ai/cordis";
2
- import * as _deepseek_ai_schemastery7 from "@deepseek-ai/schemastery";
3
3
 
4
4
  //#region src/web-trust.d.ts
5
5
 
@@ -76,12 +76,12 @@ interface TrustConfig {
76
76
  trustedPageAuthorities?: readonly string[];
77
77
  }
78
78
  /** Row config schema (schema-level default derives from `DSH_TRUSTED_HOSTS`). */
79
- declare const Config: _deepseek_ai_schemastery7.default<Schemastery.ObjectS<NoInfer<{
80
- trustAllHosts: _deepseek_ai_schemastery7.default<boolean, boolean, "defined">;
81
- trustedPageAuthorities: _deepseek_ai_schemastery7.default<string[], string[], "defined">;
79
+ declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
80
+ trustAllHosts: Schema<boolean, boolean, "defined">;
81
+ trustedPageAuthorities: Schema<string[], string[], "defined">;
82
82
  }>>, Schemastery.ObjectT<NoInfer<{
83
- trustAllHosts: _deepseek_ai_schemastery7.default<boolean, boolean, "defined">;
84
- trustedPageAuthorities: _deepseek_ai_schemastery7.default<string[], string[], "defined">;
83
+ trustAllHosts: Schema<boolean, boolean, "defined">;
84
+ trustedPageAuthorities: Schema<string[], string[], "defined">;
85
85
  }>>, "plain">;
86
86
  /** Cordis plugin name. */
87
87
  declare const name = "dashr-web-trust";
@@ -100,12 +100,12 @@ declare function apply(ctx: Context, config: TrustConfig | undefined): void;
100
100
  declare const _default: {
101
101
  name: string;
102
102
  inject: string[];
103
- Config: _deepseek_ai_schemastery7.default<Schemastery.ObjectS<NoInfer<{
104
- trustAllHosts: _deepseek_ai_schemastery7.default<boolean, boolean, "defined">;
105
- trustedPageAuthorities: _deepseek_ai_schemastery7.default<string[], string[], "defined">;
103
+ Config: Schema<Schemastery.ObjectS<NoInfer<{
104
+ trustAllHosts: Schema<boolean, boolean, "defined">;
105
+ trustedPageAuthorities: Schema<string[], string[], "defined">;
106
106
  }>>, Schemastery.ObjectT<NoInfer<{
107
- trustAllHosts: _deepseek_ai_schemastery7.default<boolean, boolean, "defined">;
108
- trustedPageAuthorities: _deepseek_ai_schemastery7.default<string[], string[], "defined">;
107
+ trustAllHosts: Schema<boolean, boolean, "defined">;
108
+ trustedPageAuthorities: Schema<string[], string[], "defined">;
109
109
  }>>, "plain">;
110
110
  apply: typeof apply;
111
111
  };
package/lib/web-trust2.js CHANGED
@@ -252,20 +252,32 @@ function buildZoomGuardSection() {
252
252
  * A fixed, query-free index path prevents token exchange or redirects here;
253
253
  * original Host and Cookie headers preserve the native authority binding and
254
254
  * lifetime. No upstream private fields or cookie-format copies are needed.
255
+ *
256
+ * 0.2.1: the fence core is `admit()` — the HTTP bridge calls it directly and
257
+ * `requestRejection()` is a thin wrapper over it, so overriding the public
258
+ * `admit` is the one seam that still steers both paths. A fence rejection
259
+ * (403) is retried as cookie-only admission; every other verdict (a live
260
+ * peer, 401 from failed native authentication, disposed) passes through
261
+ * untouched. An accepted cookie admits as the shared browser peer — the same
262
+ * scope native browser authentication grants.
255
263
  */
256
264
  function installAuthenticationOnlyAdmission(connection) {
257
- const original = connection.requestRejection;
265
+ const original = connection.admit;
258
266
  const response = {
259
267
  writeHead() {},
260
268
  end() {}
261
269
  };
262
- connection.requestRejection = (request) => connection.authorizeIndex({
263
- headers: request.headers,
264
- method: "GET",
265
- url: "/index.html"
266
- }, response) ? void 0 : 401;
270
+ connection.admit = (request) => {
271
+ const admission = original.call(connection, request);
272
+ if (!("rejection" in admission) || admission.rejection !== 403) return admission;
273
+ return connection.authorizeIndex({
274
+ headers: request.headers,
275
+ method: "GET",
276
+ url: "/index.html"
277
+ }, response) ? { peer: connection.browserPeer } : { rejection: 401 };
278
+ };
267
279
  return () => {
268
- connection.requestRejection = original;
280
+ connection.admit = original;
269
281
  };
270
282
  }
271
283
 
@@ -1,15 +1,15 @@
1
+ import { t as Schema } from "./index2.js";
1
2
  import { Context } from "@deepseek-ai/cordis";
2
- import * as _deepseek_ai_schemastery5 from "@deepseek-ai/schemastery";
3
3
 
4
4
  //#region src/welcome-notice.d.ts
5
5
  declare const name = "dashr-welcome-notice";
6
6
  declare const inject: string[];
7
- declare const Config: _deepseek_ai_schemastery5.default<NoInfer<Schemastery.ObjectS<{}>>, NoInfer<Schemastery.ObjectT<{}>>, "volatile">;
7
+ declare const Config: Schema<NoInfer<Schemastery.ObjectS<{}>>, NoInfer<Schemastery.ObjectT<{}>>, "volatile">;
8
8
  declare function apply(ctx: Context): void;
9
9
  declare const _default: {
10
10
  name: string;
11
11
  inject: string[];
12
- Config: _deepseek_ai_schemastery5.default<NoInfer<Schemastery.ObjectS<{}>>, NoInfer<Schemastery.ObjectT<{}>>, "volatile">;
12
+ Config: Schema<NoInfer<Schemastery.ObjectS<{}>>, NoInfer<Schemastery.ObjectT<{}>>, "volatile">;
13
13
  apply: typeof apply;
14
14
  };
15
15
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-dsh",
3
- "version": "0.3.1-d",
3
+ "version": "0.3.1-f",
4
4
  "description": "Make your dsh ready for serious coding tasks. (Tools x Schemas)^REPL. `skill://`, `ctx://`, `agent://`, `dvc://`, `dsh://`, Python REPL, Context as Variables, cross compactions recallable, full context revive. `hash-edit`, `dvc://browser`, subagent as function, workflow as function.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",