@treeseed/dsh-chapters 0.2.3 → 0.2.5
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/docs/contract.md +11 -1
- package/lib/client.js +44 -8
- package/lib/client.js.map +1 -1
- package/lib/commands.js +23 -5
- package/lib/commands.js.map +1 -1
- package/lib/enrich.js +13 -3
- package/lib/enrich.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +92 -6
- package/lib/index.js.map +1 -1
- package/lib/prompt-loop.js +7 -1
- package/lib/prompt-loop.js.map +1 -1
- package/lib/prompt.d.ts +119 -18
- package/lib/prompt.js +203 -72
- package/lib/prompt.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/docs/contract.md
CHANGED
|
@@ -604,7 +604,17 @@ and does not let a plugin do, with anchors:
|
|
|
604
604
|
`{value.result.kind/text}`). New **wire events are NOT available to plugins**: the forwarded
|
|
605
605
|
allowlist is app-owned ("the one home of this application's forwarded-Host-event allowlist",
|
|
606
606
|
`packages/api/remotes/src/remote-events.ts:24`).
|
|
607
|
-
|
|
607
|
+
**Every execution is recorded** (measured, `packages/interaction/commands/src/index.ts:365-385`):
|
|
608
|
+
`command/run` + `command/done` lifecycle events, log-only (never model surface) but rendered as
|
|
609
|
+
history nodes by the web UI; `recordInput: false` (definition flag, `index.ts:71-75`) suppresses
|
|
610
|
+
only the `args` payload, NOT the node pair. There is no quiet-invocation mode — a polling client
|
|
611
|
+
on this wire writes visible history every pull, which is why the bar's cadence is a tested
|
|
612
|
+
decision (#193) and the push swap (#194) is the structural fix.
|
|
613
|
+
- **Push transport is 0.2.1+ (measured 2026-10-30, #193 — this line said "0.2.x-only" and was
|
|
614
|
+
wrong):** `appendPluginRecord` has **zero occurrences** at tag `dsh-v0.2.0-rc.2`
|
|
615
|
+
(`packages/core/session/src/index.ts`) and is present at `dsh-v0.2.1-rc.2` (`:492`). The pinned
|
|
616
|
+
rig host (0.2.0-rc.2) therefore CANNOT serve the push swap; #194 gates on a host-pin bump plus
|
|
617
|
+
feature detection with pull fallback. `appendPluginRecord(session, 'plugin:<name>', data)`
|
|
608
618
|
(`packages/core/session/src/index.ts:492`, grammar/types at `types.ts:525-543`, reader
|
|
609
619
|
`pluginRecordOf` at `index.ts:508`): durable, append-only, "never enters the model-visible
|
|
610
620
|
surface", retained by fork/resume, skipped by unknown readers. The `verify-plugin-record-callers`
|
package/lib/client.js
CHANGED
|
@@ -94,7 +94,7 @@ window.__ModuleLoader__.load({
|
|
|
94
94
|
case "goal": return {
|
|
95
95
|
...state,
|
|
96
96
|
goalPhase: ev.phase,
|
|
97
|
-
autorun: ev.phase === "complete" ? "disarmed" : state.autorun
|
|
97
|
+
autorun: ev.phase === "complete" || ev.phase === "blocked" ? "disarmed" : state.autorun
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
100
|
return state;
|
|
@@ -105,6 +105,23 @@ window.__ModuleLoader__.load({
|
|
|
105
105
|
if (s.status === "ready" || s.status === "failed") return "Recommended Next Step";
|
|
106
106
|
return null;
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* #193: the pull cadence, as a decision instead of an interval constant. Every pull is two recorded
|
|
110
|
+
* host lifecycle events (`command/run` + `command/done`) the UI renders as history nodes — cadence
|
|
111
|
+
* IS the litter, so it belongs in this module with a row for every arm. Active = the state can
|
|
112
|
+
* plausibly change on a short clock (generation in flight, an armed loop to fire, a turn running
|
|
113
|
+
* that will end into an offer). Quiet = stable; one pull a minute is plenty for a state that only
|
|
114
|
+
* changes at turn boundaries. Hidden-and-quiet = pull NOTHING (a background tab should write zero
|
|
115
|
+
* history); hidden-and-active still pulls, because walking away from a running loop is the point of
|
|
116
|
+
* autorun and pausing it silently would be the loop dying with nobody told.
|
|
117
|
+
*/
|
|
118
|
+
const ACTIVE_POLL_MS = 1e4;
|
|
119
|
+
const QUIET_POLL_MS = 6e4;
|
|
120
|
+
function pollSpacingFor(s) {
|
|
121
|
+
const active = s.status === "analyzing" || s.autorun === "armed" || s.running;
|
|
122
|
+
if (!active && s.hidden) return null;
|
|
123
|
+
return active ? ACTIVE_POLL_MS : QUIET_POLL_MS;
|
|
124
|
+
}
|
|
108
125
|
function barVisible(s) {
|
|
109
126
|
if (s.status === "off") return false;
|
|
110
127
|
if (s.status === "ready" && (s.text === null || s.text === "")) return false;
|
|
@@ -119,7 +136,7 @@ window.__ModuleLoader__.load({
|
|
|
119
136
|
if (s.goal !== null && s.goal.phase === "active" && s.goal.activation === "armed") return false;
|
|
120
137
|
if (s.autorun !== "armed") return false;
|
|
121
138
|
if (s.running) return false;
|
|
122
|
-
if (s.goalPhase === "complete") return false;
|
|
139
|
+
if (s.goalPhase === "complete" || s.goalPhase === "blocked") return false;
|
|
123
140
|
if (s.hiddenTurnSeq !== null && s.hiddenTurnSeq === s.turnSeq) return false;
|
|
124
141
|
return true;
|
|
125
142
|
}
|
|
@@ -310,9 +327,6 @@ window.__ModuleLoader__.load({
|
|
|
310
327
|
const PULL_TIMEOUT_MS = 15e3;
|
|
311
328
|
/** Retry ceiling for the FIRST pull only, in attempts and spacing. A mount-time race must not be able to
|
|
312
329
|
* starve the bar forever, and a real `off` answer stops the loop on the first reply either way. */
|
|
313
|
-
/** Cadence of the keep-poll. A local RPC that answers in milliseconds; the cost is one command per
|
|
314
|
-
* interval, and it ends the moment the state is `off`. */
|
|
315
|
-
const POLL_SPACING_MS = 1e4;
|
|
316
330
|
function execWithTimeout(exec, line, ms) {
|
|
317
331
|
return new Promise((resolve, reject) => {
|
|
318
332
|
const timer = setTimeout(() => {
|
|
@@ -341,6 +355,7 @@ window.__ModuleLoader__.load({
|
|
|
341
355
|
alive.current = false;
|
|
342
356
|
}, []);
|
|
343
357
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
358
|
+
const kick = (0, react.useRef)(void 0);
|
|
344
359
|
const answered = (0, react.useRef)(false);
|
|
345
360
|
const replyStatus = (0, react.useRef)("unknown");
|
|
346
361
|
const stateRef = (0, react.useRef)(initialBarState());
|
|
@@ -380,22 +395,43 @@ window.__ModuleLoader__.load({
|
|
|
380
395
|
pulled.current = true;
|
|
381
396
|
let timer;
|
|
382
397
|
const tick = async () => {
|
|
383
|
-
|
|
398
|
+
const spacing = pollSpacingFor({
|
|
399
|
+
status: replyStatus.current,
|
|
400
|
+
autorun: stateRef.current.autorun,
|
|
401
|
+
running: stateRef.current.running,
|
|
402
|
+
hidden: typeof document !== "undefined" && document.hidden === true
|
|
403
|
+
});
|
|
404
|
+
if (spacing !== null) await refresh();
|
|
384
405
|
if (replyStatus.current === "off") return;
|
|
385
406
|
timer = setTimeout(() => {
|
|
386
407
|
tick();
|
|
387
|
-
},
|
|
408
|
+
}, spacing ?? 6e4);
|
|
409
|
+
};
|
|
410
|
+
kick.current = () => {
|
|
411
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
412
|
+
tick();
|
|
413
|
+
};
|
|
414
|
+
const onVisible = () => {
|
|
415
|
+
if (typeof document !== "undefined" && !document.hidden) kick.current?.();
|
|
388
416
|
};
|
|
417
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", onVisible);
|
|
389
418
|
tick();
|
|
390
419
|
return () => {
|
|
391
420
|
if (timer !== void 0) clearTimeout(timer);
|
|
421
|
+
kick.current = void 0;
|
|
422
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", onVisible);
|
|
392
423
|
};
|
|
393
424
|
}, [refresh]);
|
|
425
|
+
const prevRunning = (0, react.useRef)(props.running ?? true);
|
|
394
426
|
(0, react.useEffect)(() => {
|
|
427
|
+
const next = props.running ?? true;
|
|
428
|
+
const prev = prevRunning.current;
|
|
429
|
+
prevRunning.current = next;
|
|
395
430
|
dispatch({
|
|
396
431
|
t: "running",
|
|
397
|
-
running:
|
|
432
|
+
running: next
|
|
398
433
|
});
|
|
434
|
+
if (prev && !next) kick.current?.();
|
|
399
435
|
}, [props.running]);
|
|
400
436
|
const run = (0, react.useCallback)(() => {
|
|
401
437
|
if (state.text === null || state.text === "" || exec === void 0) return;
|