@sagmans/dsh-tui 0.3.0 → 0.5.0
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/LICENSE +1 -1
- package/README.md +407 -53
- package/cordis.patch.yml +14 -0
- package/lib/agent/present.js +1 -1
- package/lib/agent/present.js.map +1 -1
- package/lib/agent/projections.d.ts +22 -6
- package/lib/agent/projections.d.ts.map +1 -1
- package/lib/agent/projections.js +21 -10
- package/lib/agent/projections.js.map +1 -1
- package/lib/agent/prompt-history.d.ts +89 -0
- package/lib/agent/prompt-history.d.ts.map +1 -0
- package/lib/agent/prompt-history.js +382 -0
- package/lib/agent/prompt-history.js.map +1 -0
- package/lib/agent/status.d.ts +6 -0
- package/lib/agent/status.d.ts.map +1 -1
- package/lib/agent/status.js +1 -0
- package/lib/agent/status.js.map +1 -1
- package/lib/cards.d.ts +83 -13
- package/lib/cards.d.ts.map +1 -1
- package/lib/cards.js +96 -28
- package/lib/cards.js.map +1 -1
- package/lib/export.d.ts +3 -3
- package/lib/export.d.ts.map +1 -1
- package/lib/export.js +23 -13
- package/lib/export.js.map +1 -1
- package/lib/fold-cursor.d.ts +12 -5
- package/lib/fold-cursor.d.ts.map +1 -1
- package/lib/fold-cursor.js +16 -5
- package/lib/fold-cursor.js.map +1 -1
- package/lib/gates.d.ts.map +1 -1
- package/lib/gates.js +42 -9
- package/lib/gates.js.map +1 -1
- package/lib/herdr/client.d.ts +57 -0
- package/lib/herdr/client.d.ts.map +1 -0
- package/lib/herdr/client.js +218 -0
- package/lib/herdr/client.js.map +1 -0
- package/lib/herdr/constants.d.ts +93 -0
- package/lib/herdr/constants.d.ts.map +1 -0
- package/lib/herdr/constants.js +79 -0
- package/lib/herdr/constants.js.map +1 -0
- package/lib/herdr/reporter.d.ts +60 -0
- package/lib/herdr/reporter.d.ts.map +1 -0
- package/lib/herdr/reporter.js +217 -0
- package/lib/herdr/reporter.js.map +1 -0
- package/lib/herdr/state.d.ts +57 -0
- package/lib/herdr/state.d.ts.map +1 -0
- package/lib/herdr/state.js +62 -0
- package/lib/herdr/state.js.map +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +700 -81
- package/lib/index.js.map +1 -1
- package/lib/injection.d.ts +9 -0
- package/lib/injection.d.ts.map +1 -0
- package/lib/injection.js +128 -0
- package/lib/injection.js.map +1 -0
- package/lib/input/actions.d.ts +19 -2
- package/lib/input/actions.d.ts.map +1 -1
- package/lib/input/actions.js +60 -11
- package/lib/input/actions.js.map +1 -1
- package/lib/input/cancel.d.ts +55 -0
- package/lib/input/cancel.d.ts.map +1 -0
- package/lib/input/cancel.js +47 -0
- package/lib/input/cancel.js.map +1 -0
- package/lib/input/completion.d.ts +5 -2
- package/lib/input/completion.d.ts.map +1 -1
- package/lib/input/completion.js +79 -4
- package/lib/input/completion.js.map +1 -1
- package/lib/input/file-search.d.ts +105 -0
- package/lib/input/file-search.d.ts.map +1 -0
- package/lib/input/file-search.js +665 -0
- package/lib/input/file-search.js.map +1 -0
- package/lib/input/fuzzy.d.ts +42 -0
- package/lib/input/fuzzy.d.ts.map +1 -0
- package/lib/input/fuzzy.js +289 -0
- package/lib/input/fuzzy.js.map +1 -0
- package/lib/input/ghost.d.ts +46 -0
- package/lib/input/ghost.d.ts.map +1 -0
- package/lib/input/ghost.js +58 -0
- package/lib/input/ghost.js.map +1 -0
- package/lib/input/keymap.d.ts +3 -1
- package/lib/input/keymap.d.ts.map +1 -1
- package/lib/input/keymap.js +16 -3
- package/lib/input/keymap.js.map +1 -1
- package/lib/input/match.d.ts +12 -4
- package/lib/input/match.d.ts.map +1 -1
- package/lib/input/match.js +50 -51
- package/lib/input/match.js.map +1 -1
- package/lib/input/submission.d.ts +34 -1
- package/lib/input/submission.d.ts.map +1 -1
- package/lib/input/submission.js +33 -5
- package/lib/input/submission.js.map +1 -1
- package/lib/keys-command.d.ts +19 -3
- package/lib/keys-command.d.ts.map +1 -1
- package/lib/keys-command.js +34 -31
- package/lib/keys-command.js.map +1 -1
- package/lib/settings-notice.d.ts +5 -0
- package/lib/settings-notice.d.ts.map +1 -1
- package/lib/settings-notice.js +9 -7
- package/lib/settings-notice.js.map +1 -1
- package/lib/stash/lock.d.ts +72 -0
- package/lib/stash/lock.d.ts.map +1 -0
- package/lib/stash/lock.js +374 -0
- package/lib/stash/lock.js.map +1 -0
- package/lib/stash/paths.d.ts +22 -0
- package/lib/stash/paths.d.ts.map +1 -0
- package/lib/stash/paths.js +84 -0
- package/lib/stash/paths.js.map +1 -0
- package/lib/stash/private-fs.d.ts +61 -0
- package/lib/stash/private-fs.d.ts.map +1 -0
- package/lib/stash/private-fs.js +379 -0
- package/lib/stash/private-fs.js.map +1 -0
- package/lib/stash/schema.d.ts +56 -0
- package/lib/stash/schema.d.ts.map +1 -0
- package/lib/stash/schema.js +108 -0
- package/lib/stash/schema.js.map +1 -0
- package/lib/stash/store.d.ts +92 -0
- package/lib/stash/store.d.ts.map +1 -0
- package/lib/stash/store.js +262 -0
- package/lib/stash/store.js.map +1 -0
- package/lib/stash.d.ts +122 -0
- package/lib/stash.d.ts.map +1 -0
- package/lib/stash.js +353 -0
- package/lib/stash.js.map +1 -0
- package/lib/terminal/external-editor.d.ts +93 -0
- package/lib/terminal/external-editor.d.ts.map +1 -0
- package/lib/terminal/external-editor.js +263 -0
- package/lib/terminal/external-editor.js.map +1 -0
- package/lib/terminal/host-writes.d.ts +39 -0
- package/lib/terminal/host-writes.d.ts.map +1 -0
- package/lib/terminal/host-writes.js +136 -0
- package/lib/terminal/host-writes.js.map +1 -0
- package/lib/terminal/signals.d.ts +25 -0
- package/lib/terminal/signals.d.ts.map +1 -0
- package/lib/terminal/signals.js +39 -0
- package/lib/terminal/signals.js.map +1 -0
- package/lib/terminal/warning-screen.d.ts +19 -1
- package/lib/terminal/warning-screen.d.ts.map +1 -1
- package/lib/terminal/warning-screen.js +37 -1
- package/lib/terminal/warning-screen.js.map +1 -1
- package/lib/terminal-text.d.ts +72 -0
- package/lib/terminal-text.d.ts.map +1 -0
- package/lib/terminal-text.js +603 -0
- package/lib/terminal-text.js.map +1 -0
- package/lib/text.d.ts +45 -6
- package/lib/text.d.ts.map +1 -1
- package/lib/text.js +106 -46
- package/lib/text.js.map +1 -1
- package/lib/theme-command.d.ts +7 -4
- package/lib/theme-command.d.ts.map +1 -1
- package/lib/theme-command.js +32 -12
- package/lib/theme-command.js.map +1 -1
- package/lib/theme-files.d.ts +110 -0
- package/lib/theme-files.d.ts.map +1 -0
- package/lib/theme-files.js +352 -0
- package/lib/theme-files.js.map +1 -0
- package/lib/theme-schema.d.ts +121 -0
- package/lib/theme-schema.d.ts.map +1 -0
- package/lib/theme-schema.js +87 -0
- package/lib/theme-schema.js.map +1 -0
- package/lib/theme-settings.d.ts +72 -10
- package/lib/theme-settings.d.ts.map +1 -1
- package/lib/theme-settings.js +162 -45
- package/lib/theme-settings.js.map +1 -1
- package/lib/theme-tokens.d.ts +39 -7
- package/lib/theme-tokens.d.ts.map +1 -1
- package/lib/theme-tokens.js +104 -13
- package/lib/theme-tokens.js.map +1 -1
- package/lib/theme.d.ts +24 -2
- package/lib/theme.d.ts.map +1 -1
- package/lib/theme.js +49 -6
- package/lib/theme.js.map +1 -1
- package/lib/todo-guard.d.ts +116 -0
- package/lib/todo-guard.d.ts.map +1 -0
- package/lib/todo-guard.js +259 -0
- package/lib/todo-guard.js.map +1 -0
- package/lib/tool-display.d.ts +57 -0
- package/lib/tool-display.d.ts.map +1 -0
- package/lib/tool-display.js +51 -0
- package/lib/tool-display.js.map +1 -0
- package/lib/transcript.d.ts +28 -0
- package/lib/transcript.d.ts.map +1 -1
- package/lib/transcript.js +126 -37
- package/lib/transcript.js.map +1 -1
- package/lib/ui/diff.d.ts +49 -0
- package/lib/ui/diff.d.ts.map +1 -0
- package/lib/ui/diff.js +208 -0
- package/lib/ui/diff.js.map +1 -0
- package/lib/ui/dock.d.ts.map +1 -1
- package/lib/ui/dock.js +9 -6
- package/lib/ui/dock.js.map +1 -1
- package/lib/ui/editor.d.ts +41 -1
- package/lib/ui/editor.d.ts.map +1 -1
- package/lib/ui/editor.js +100 -4
- package/lib/ui/editor.js.map +1 -1
- package/lib/ui/frame.d.ts +16 -5
- package/lib/ui/frame.d.ts.map +1 -1
- package/lib/ui/frame.js +32 -13
- package/lib/ui/frame.js.map +1 -1
- package/lib/ui/history-picker.d.ts +15 -0
- package/lib/ui/history-picker.d.ts.map +1 -0
- package/lib/ui/history-picker.js +26 -0
- package/lib/ui/history-picker.js.map +1 -0
- package/lib/ui/keymap-picker.d.ts +16 -0
- package/lib/ui/keymap-picker.d.ts.map +1 -0
- package/lib/ui/keymap-picker.js +41 -0
- package/lib/ui/keymap-picker.js.map +1 -0
- package/lib/ui/layout.d.ts +33 -0
- package/lib/ui/layout.d.ts.map +1 -0
- package/lib/ui/layout.js +33 -0
- package/lib/ui/layout.js.map +1 -0
- package/lib/ui/markdown.d.ts +25 -3
- package/lib/ui/markdown.d.ts.map +1 -1
- package/lib/ui/markdown.js +12 -8
- package/lib/ui/markdown.js.map +1 -1
- package/lib/ui/picker-card.d.ts +42 -0
- package/lib/ui/picker-card.d.ts.map +1 -0
- package/lib/ui/picker-card.js +148 -0
- package/lib/ui/picker-card.js.map +1 -0
- package/lib/ui/picker.d.ts +50 -2
- package/lib/ui/picker.d.ts.map +1 -1
- package/lib/ui/picker.js +66 -7
- package/lib/ui/picker.js.map +1 -1
- package/lib/ui/prompt.d.ts +12 -2
- package/lib/ui/prompt.d.ts.map +1 -1
- package/lib/ui/prompt.js +25 -2
- package/lib/ui/prompt.js.map +1 -1
- package/lib/ui/rows.d.ts +8 -6
- package/lib/ui/rows.d.ts.map +1 -1
- package/lib/ui/rows.js +10 -18
- package/lib/ui/rows.js.map +1 -1
- package/lib/ui/stash-picker.d.ts +43 -0
- package/lib/ui/stash-picker.d.ts.map +1 -0
- package/lib/ui/stash-picker.js +78 -0
- package/lib/ui/stash-picker.js.map +1 -0
- package/lib/ui/status.d.ts +2 -0
- package/lib/ui/status.d.ts.map +1 -1
- package/lib/ui/status.js +25 -16
- package/lib/ui/status.js.map +1 -1
- package/lib/ui/theme-picker.d.ts +18 -0
- package/lib/ui/theme-picker.d.ts.map +1 -0
- package/lib/ui/theme-picker.js +68 -0
- package/lib/ui/theme-picker.js.map +1 -0
- package/lib/ui/view.d.ts +146 -22
- package/lib/ui/view.d.ts.map +1 -1
- package/lib/ui/view.js +461 -154
- package/lib/ui/view.js.map +1 -1
- package/lib/work.d.ts +3 -1
- package/lib/work.d.ts.map +1 -1
- package/lib/work.js +9 -1
- package/lib/work.js.map +1 -1
- package/package.json +7 -1
- package/themes/deepseek-blue.yaml +183 -0
- package/themes/violet-orbit.yaml +178 -0
package/cordis.patch.yml
CHANGED
|
@@ -97,6 +97,20 @@
|
|
|
97
97
|
color: !!js ctx.tuiStartup.color
|
|
98
98
|
bell: !!js ctx.tuiStartup.bell
|
|
99
99
|
|
|
100
|
+
# Advisory todo discipline for every agent this profile runs. The tool and
|
|
101
|
+
# its list already exist per session; this row only notices when a plan has
|
|
102
|
+
# aged and rides the next tool result with a reminder. It is host-plane on
|
|
103
|
+
# purpose: it registers no tool, provides no service, and never gates a
|
|
104
|
+
# call, so it needs no preset and no realm. `staleSteps` and the rest are
|
|
105
|
+
# documented in the README and overridable from a profile patch.
|
|
106
|
+
- id: tui-todo-guard
|
|
107
|
+
name: '@sagmans/dsh-tui/todo-guard'
|
|
108
|
+
config:
|
|
109
|
+
staleSteps: 6
|
|
110
|
+
missingListSteps: 12
|
|
111
|
+
maxRemindersPerTurn: 3
|
|
112
|
+
previewItems: 5
|
|
113
|
+
|
|
100
114
|
# The roster of agent compositions, and the mode a session starts in when
|
|
101
115
|
# nobody names one. PTC leads because a flagless run should reach every tool
|
|
102
116
|
# through one program rather than one shell call at a time. A profile patch
|
package/lib/agent/present.js
CHANGED
|
@@ -67,7 +67,7 @@ export function createToolPresenter(ctx, scope) {
|
|
|
67
67
|
try {
|
|
68
68
|
const view = definition(name)?.presentResult?.(parseArguments(input.argumentsJson), { content: toolResultContent(input.content), isError: input.isError, meta: input.meta });
|
|
69
69
|
return cardOfResult(view, {
|
|
70
|
-
|
|
70
|
+
name,
|
|
71
71
|
failed: input.isError,
|
|
72
72
|
contentLines: contentLines(input.content),
|
|
73
73
|
});
|
package/lib/agent/present.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"present.js","sourceRoot":"","sources":["../../src/agent/present.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,YAAY,GAGb,MAAM,aAAa,CAAA;AAEpB,SAAS,cAAc,CAAC,aAAqB;IAC3C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAY,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,iBAAiB,CAAC,OAAgB;IACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAA;IAC3C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,SAAQ;QACzD,MAAM,MAAM,GAAG,KAAgC,CAAA;QAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,OAAO,MAAM,CAAC,OAAO,CAAA;IAC3F,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY,EAAE,KAA+B;IAC/E,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QAClC,IAAI,CAAC;YACH,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC,CAAA;IACD,OAAO;QACL,IAAI,CAAC,IAAI,EAAE,aAAa;YACtB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC,cAAc,CAAC,aAAa,CAAU,CAAC,CAAA;gBACpF,wEAAwE;gBACxE,wEAAwE;gBACxE,sEAAsE;gBACtE,yCAAyC;gBACzC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YAChE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,EAAE,KAAsB;YACjC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,CAC5C,cAAc,CAAC,KAAK,CAAC,aAAa,CAAU,EAC5C,EAAE,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAW,CACjG,CAAA;gBACD,OAAO,YAAY,CAAC,IAAI,EAAE;oBACxB,
|
|
1
|
+
{"version":3,"file":"present.js","sourceRoot":"","sources":["../../src/agent/present.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,YAAY,GAGb,MAAM,aAAa,CAAA;AAEpB,SAAS,cAAc,CAAC,aAAqB;IAC3C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAY,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,iBAAiB,CAAC,OAAgB;IACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAA;IAC3C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,SAAQ;QACzD,MAAM,MAAM,GAAG,KAAgC,CAAA;QAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,OAAO,MAAM,CAAC,OAAO,CAAA;IAC3F,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY,EAAE,KAA+B;IAC/E,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QAClC,IAAI,CAAC;YACH,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC,CAAA;IACD,OAAO;QACL,IAAI,CAAC,IAAI,EAAE,aAAa;YACtB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC,cAAc,CAAC,aAAa,CAAU,CAAC,CAAA;gBACpF,wEAAwE;gBACxE,wEAAwE;gBACxE,sEAAsE;gBACtE,yCAAyC;gBACzC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YAChE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,EAAE,KAAsB;YACjC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,CAC5C,cAAc,CAAC,KAAK,CAAC,aAAa,CAAU,EAC5C,EAAE,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAW,CACjG,CAAA;gBACD,OAAO,YAAY,CAAC,IAAI,EAAE;oBACxB,IAAI;oBACJ,MAAM,EAAE,KAAK,CAAC,OAAO;oBACrB,YAAY,EAAE,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC;iBAC1C,CAAC,CAAA;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
/** One projection read that keeps "not registered" apart from "cannot answer". */
|
|
3
|
+
export type ProjectionRead = {
|
|
4
|
+
readonly kind: 'state';
|
|
5
|
+
readonly state: unknown;
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: 'unregistered';
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: 'unavailable';
|
|
10
|
+
};
|
|
2
11
|
/**
|
|
3
|
-
* One session projection's state.
|
|
12
|
+
* One session projection's state, with the reason a missing answer is kept.
|
|
4
13
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
14
|
+
* `stateOf` answers `undefined` only for a key that is not registered; a
|
|
15
|
+
* composition without a registry, and a registered unit that throws, are the
|
|
16
|
+
* two cases that leave nothing to read at all. A caller that merely decorates a
|
|
17
|
+
* screen may collapse them, but one deciding whether it knows enough to speak
|
|
18
|
+
* must be able to tell them apart.
|
|
19
|
+
*/
|
|
20
|
+
export declare function projectionRead(ctx: Context, session: unknown, key: string): ProjectionRead;
|
|
21
|
+
/**
|
|
22
|
+
* One session projection's state, or `undefined` whenever there is none to read.
|
|
23
|
+
*
|
|
24
|
+
* The surface reads projections while rendering, where a missing fact may cost a
|
|
25
|
+
* segment but never the session, so every unreadable case collapses here.
|
|
10
26
|
*/
|
|
11
27
|
export declare function projectionState(ctx: Context, session: unknown, key: string): unknown;
|
|
12
28
|
/** One projection's state when it is a record. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projections.d.ts","sourceRoot":"","sources":["../../src/agent/projections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAOlD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"projections.d.ts","sourceRoot":"","sources":["../../src/agent/projections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAOlD,kFAAkF;AAClF,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GACjC;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;CAAE,CAAA;AAEpC;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,CAS1F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAGpF;AAED,kDAAkD;AAClD,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,GACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAGrC;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGhG"}
|
package/lib/agent/projections.js
CHANGED
|
@@ -1,23 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* One session projection's state.
|
|
2
|
+
* One session projection's state, with the reason a missing answer is kept.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* `stateOf` answers `undefined` only for a key that is not registered; a
|
|
5
|
+
* composition without a registry, and a registered unit that throws, are the
|
|
6
|
+
* two cases that leave nothing to read at all. A caller that merely decorates a
|
|
7
|
+
* screen may collapse them, but one deciding whether it knows enough to speak
|
|
8
|
+
* must be able to tell them apart.
|
|
9
9
|
*/
|
|
10
|
-
export function
|
|
10
|
+
export function projectionRead(ctx, session, key) {
|
|
11
11
|
const projections = ctx.get('sessionProjections');
|
|
12
12
|
if (projections?.stateOf === undefined)
|
|
13
|
-
return
|
|
13
|
+
return { kind: 'unavailable' };
|
|
14
14
|
try {
|
|
15
|
-
|
|
15
|
+
const state = projections.stateOf(session, key);
|
|
16
|
+
return state === undefined ? { kind: 'unregistered' } : { kind: 'state', state };
|
|
16
17
|
}
|
|
17
18
|
catch {
|
|
18
|
-
return
|
|
19
|
+
return { kind: 'unavailable' };
|
|
19
20
|
}
|
|
20
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* One session projection's state, or `undefined` whenever there is none to read.
|
|
24
|
+
*
|
|
25
|
+
* The surface reads projections while rendering, where a missing fact may cost a
|
|
26
|
+
* segment but never the session, so every unreadable case collapses here.
|
|
27
|
+
*/
|
|
28
|
+
export function projectionState(ctx, session, key) {
|
|
29
|
+
const read = projectionRead(ctx, session, key);
|
|
30
|
+
return read.kind === 'state' ? read.state : undefined;
|
|
31
|
+
}
|
|
21
32
|
/** One projection's state when it is a record. */
|
|
22
33
|
export function projectionRecord(ctx, session, key) {
|
|
23
34
|
const state = projectionState(ctx, session, key);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projections.js","sourceRoot":"","sources":["../../src/agent/projections.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"projections.js","sourceRoot":"","sources":["../../src/agent/projections.ts"],"names":[],"mappings":"AAaA;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,GAAY,EAAE,OAAgB,EAAE,GAAW;IACxE,MAAM,WAAW,GAAG,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAA4B,CAAA;IAC5E,IAAI,WAAW,EAAE,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;IACtE,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;QAC/C,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;IAChC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,OAAgB,EAAE,GAAW;IACzE,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IAC9C,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AACvD,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,gBAAgB,CAC9B,GAAY,EACZ,OAAgB,EAChB,GAAW;IAEX,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAgC,CAAC,CAAC,CAAC,SAAS,CAAA;AACnG,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,gBAAgB,CAAC,GAAY,EAAE,OAAgB,EAAE,GAAW;IAC1E,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AACtE,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global prompt history for the terminal surface.
|
|
3
|
+
*
|
|
4
|
+
* The file is deliberately project-agnostic: a reader who types the same prompt
|
|
5
|
+
* in two checkouts wants it offered in both, so nothing here records a working
|
|
6
|
+
* directory. It lives beside the reader's other harness preferences rather than
|
|
7
|
+
* inside the profile, because a profile is replaced on install and history is
|
|
8
|
+
* theirs to keep.
|
|
9
|
+
*/
|
|
10
|
+
/** Environment variable that overrides the harness home, matching the launcher. */
|
|
11
|
+
export declare const DSH_HOME_ENV = "DSH_HOME";
|
|
12
|
+
/** Directory name of the default harness home under the OS home. */
|
|
13
|
+
export declare const DSH_HOME_DIR_NAME = ".dsh";
|
|
14
|
+
/** File name the history is stored under, inside the harness home. */
|
|
15
|
+
export declare const HISTORY_FILE_NAME = "prompt-history.json";
|
|
16
|
+
/** Schema this build writes; a file that names another positive version is left alone. */
|
|
17
|
+
export declare const HISTORY_SCHEMA_VERSION = 1;
|
|
18
|
+
/** Entries kept when the reader configures nothing. */
|
|
19
|
+
export declare const DEFAULT_MAX_ENTRIES = 2000;
|
|
20
|
+
/** Largest cap a reader may ask for, so a typo cannot grow the file without bound. */
|
|
21
|
+
export declare const MAX_ENTRIES_LIMIT = 20000;
|
|
22
|
+
/** Why the store refuses to write, which is a reason the reader can act on. */
|
|
23
|
+
export type HistoryBlockReason = 'corrupt_history' | 'unsupported_schema' | 'unreadable_history';
|
|
24
|
+
/** One recorded prompt, newest first in the file. */
|
|
25
|
+
export interface PromptEntry {
|
|
26
|
+
readonly text: string;
|
|
27
|
+
readonly updatedAt: string;
|
|
28
|
+
readonly useCount: number;
|
|
29
|
+
}
|
|
30
|
+
/** The persisted document, versioned so a future shape can be recognized. */
|
|
31
|
+
export interface PromptHistoryFile {
|
|
32
|
+
readonly version: number;
|
|
33
|
+
readonly updatedAt: string;
|
|
34
|
+
readonly entries: readonly PromptEntry[];
|
|
35
|
+
}
|
|
36
|
+
/** A file read reduced to what a caller can act on. */
|
|
37
|
+
export type ParsedHistoryFile = {
|
|
38
|
+
readonly kind: 'ready';
|
|
39
|
+
readonly file: PromptHistoryFile;
|
|
40
|
+
} | {
|
|
41
|
+
readonly kind: 'blocked';
|
|
42
|
+
readonly reason: HistoryBlockReason;
|
|
43
|
+
};
|
|
44
|
+
/** The store the surface holds; mutations are fire-and-forget and serialized. */
|
|
45
|
+
export interface PromptHistory {
|
|
46
|
+
/** Current entries, newest first; the array identity is stable per snapshot. */
|
|
47
|
+
entries(): readonly PromptEntry[];
|
|
48
|
+
/** Persist one submitted prompt; blank input is ignored. */
|
|
49
|
+
record(text: string): void;
|
|
50
|
+
/** Remove every entry and report how many went. */
|
|
51
|
+
clear(): Promise<number>;
|
|
52
|
+
/** Resolve once every queued mutation has settled; errors are reported, not thrown. */
|
|
53
|
+
flush(): Promise<void>;
|
|
54
|
+
/** Absolute path of the file, for a status line and diagnostics. */
|
|
55
|
+
path(): string;
|
|
56
|
+
/** Why writes are refused, or undefined while the store is healthy. */
|
|
57
|
+
blockedReason(): HistoryBlockReason | undefined;
|
|
58
|
+
}
|
|
59
|
+
/** Inputs the surface supplies; every one is a seam a test drives. */
|
|
60
|
+
export interface PromptHistoryOptions {
|
|
61
|
+
/** Resolved harness home; defaults to $DSH_HOME or ~/.dsh. */
|
|
62
|
+
readonly home?: string;
|
|
63
|
+
/** Read per mutation so a settings edit takes effect without a restart. */
|
|
64
|
+
readonly cap: () => number;
|
|
65
|
+
readonly now?: () => Date;
|
|
66
|
+
readonly warn?: (message: string) => void;
|
|
67
|
+
/** Lock wait a test can shorten; defaults to LOCK_WAIT_MS. */
|
|
68
|
+
readonly lockWaitMs?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolve the harness home.
|
|
72
|
+
*
|
|
73
|
+
* Precedence is the launcher's own: $DSH_HOME, then ~/.dsh. A blank override is
|
|
74
|
+
* treated as unset, because resolving to the working directory would scatter
|
|
75
|
+
* private history into whatever tree the reader happened to start from.
|
|
76
|
+
*/
|
|
77
|
+
export declare function resolveDshHome(env?: NodeJS.ProcessEnv): string;
|
|
78
|
+
/** Read one persisted document, refusing anything this build cannot safely rewrite. */
|
|
79
|
+
export declare function parseHistoryFile(text: string): ParsedHistoryFile;
|
|
80
|
+
/**
|
|
81
|
+
* Put one prompt at the front, replacing an exact duplicate.
|
|
82
|
+
*
|
|
83
|
+
* A duplicate is moved rather than copied so a repeated prompt resurfaces as the
|
|
84
|
+
* newest suggestion without ever appearing twice in the list.
|
|
85
|
+
*/
|
|
86
|
+
export declare function upsertEntry(entries: readonly PromptEntry[], text: string, now: string, maxEntries: number): PromptEntry[];
|
|
87
|
+
/** Build the store the surface records into and completes from. */
|
|
88
|
+
export declare function createPromptHistory(options: PromptHistoryOptions): PromptHistory;
|
|
89
|
+
//# sourceMappingURL=prompt-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-history.d.ts","sourceRoot":"","sources":["../../src/agent/prompt-history.ts"],"names":[],"mappings":"AAMA;;;;;;;;GAQG;AAEH,mFAAmF;AACnF,eAAO,MAAM,YAAY,aAAa,CAAA;AACtC,oEAAoE;AACpE,eAAO,MAAM,iBAAiB,SAAS,CAAA;AACvC,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,wBAAwB,CAAA;AACtD,0FAA0F;AAC1F,eAAO,MAAM,sBAAsB,IAAI,CAAA;AACvC,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,OAAO,CAAA;AACvC,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,QAAS,CAAA;AAmBvC,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,GAAG,oBAAoB,GAAG,oBAAoB,CAAA;AAShG,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAA;CACzC;AAED,uDAAuD;AACvD,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAA;AAErE,iFAAiF;AACjF,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,OAAO,IAAI,SAAS,WAAW,EAAE,CAAA;IACjC,4DAA4D;IAC5D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,mDAAmD;IACnD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IACxB,uFAAuF;IACvF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,oEAAoE;IACpE,IAAI,IAAI,MAAM,CAAA;IACd,uEAAuE;IACvE,aAAa,IAAI,kBAAkB,GAAG,SAAS,CAAA;CAChD;AAED,sEAAsE;AACtE,MAAM,WAAW,oBAAoB;IACnC,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAA;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B;AAuJD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAM3E;AAED,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAiBhE;AAyBD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,WAAW,EAAE,CAMf;AAMD,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAsGhF"}
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { chmod, link, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { dirname, join, resolve as resolvePath } from 'node:path';
|
|
5
|
+
import { displayText } from "../text.js";
|
|
6
|
+
/**
|
|
7
|
+
* Global prompt history for the terminal surface.
|
|
8
|
+
*
|
|
9
|
+
* The file is deliberately project-agnostic: a reader who types the same prompt
|
|
10
|
+
* in two checkouts wants it offered in both, so nothing here records a working
|
|
11
|
+
* directory. It lives beside the reader's other harness preferences rather than
|
|
12
|
+
* inside the profile, because a profile is replaced on install and history is
|
|
13
|
+
* theirs to keep.
|
|
14
|
+
*/
|
|
15
|
+
/** Environment variable that overrides the harness home, matching the launcher. */
|
|
16
|
+
export const DSH_HOME_ENV = 'DSH_HOME';
|
|
17
|
+
/** Directory name of the default harness home under the OS home. */
|
|
18
|
+
export const DSH_HOME_DIR_NAME = '.dsh';
|
|
19
|
+
/** File name the history is stored under, inside the harness home. */
|
|
20
|
+
export const HISTORY_FILE_NAME = 'prompt-history.json';
|
|
21
|
+
/** Schema this build writes; a file that names another positive version is left alone. */
|
|
22
|
+
export const HISTORY_SCHEMA_VERSION = 1;
|
|
23
|
+
/** Entries kept when the reader configures nothing. */
|
|
24
|
+
export const DEFAULT_MAX_ENTRIES = 2000;
|
|
25
|
+
/** Largest cap a reader may ask for, so a typo cannot grow the file without bound. */
|
|
26
|
+
export const MAX_ENTRIES_LIMIT = 20_000;
|
|
27
|
+
/** Only the reader can read or write the file. */
|
|
28
|
+
const PRIVATE_FILE_MODE = 0o600;
|
|
29
|
+
/** A created home directory stays private; an existing one is never re-moded. */
|
|
30
|
+
const PRIVATE_DIR_MODE = 0o700;
|
|
31
|
+
/** Suffix of the file that serializes mutations across sessions. */
|
|
32
|
+
const LOCK_SUFFIX = '.lock';
|
|
33
|
+
/** Suffix of the lock that guards replacing a lock whose holder stopped. */
|
|
34
|
+
const LOCK_RECLAIM_SUFFIX = '.reclaim';
|
|
35
|
+
/** Suffix of the file a lock is staged in before it is published. */
|
|
36
|
+
const LOCK_TEMP_SUFFIX = '.tmp';
|
|
37
|
+
/** How long a mutation waits for another session's lock before giving up. */
|
|
38
|
+
const LOCK_WAIT_MS = 2_000;
|
|
39
|
+
/** Delay between lock attempts, so a short hold is not a spin. */
|
|
40
|
+
const LOCK_RETRY_MS = 20;
|
|
41
|
+
/** Separates the fields a lock file names its holder with. */
|
|
42
|
+
const LOCK_FIELD_SEPARATOR = ' ';
|
|
43
|
+
/** One phrase per refusal, so a notice reads the same wherever it is raised. */
|
|
44
|
+
const BLOCK_DESCRIPTIONS = {
|
|
45
|
+
corrupt_history: 'corrupt',
|
|
46
|
+
unsupported_schema: 'a newer format',
|
|
47
|
+
unreadable_history: 'unreadable',
|
|
48
|
+
};
|
|
49
|
+
function isRecord(value) {
|
|
50
|
+
return typeof value === 'object' && value !== null;
|
|
51
|
+
}
|
|
52
|
+
function isAlreadyExists(error) {
|
|
53
|
+
return isRecord(error) && error.code === 'EEXIST';
|
|
54
|
+
}
|
|
55
|
+
function delay(ms) {
|
|
56
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
57
|
+
}
|
|
58
|
+
function serializeOwner(owner) {
|
|
59
|
+
return owner.pid + LOCK_FIELD_SEPARATOR + owner.token + '\n';
|
|
60
|
+
}
|
|
61
|
+
function parseOwner(text) {
|
|
62
|
+
const [pid, token] = text.trim().split(LOCK_FIELD_SEPARATOR);
|
|
63
|
+
const value = Number(pid);
|
|
64
|
+
if (!isPositiveInteger(value) || token === undefined || token === '')
|
|
65
|
+
return undefined;
|
|
66
|
+
return { pid: value, token };
|
|
67
|
+
}
|
|
68
|
+
/** Whether the recorded holder can still run; only ESRCH proves that it cannot. */
|
|
69
|
+
function isOwnerAlive(pid) {
|
|
70
|
+
try {
|
|
71
|
+
process.kill(pid, 0);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return !isRecord(error) || error.code !== 'ESRCH';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Take the lock that serializes mutations across sessions.
|
|
80
|
+
*
|
|
81
|
+
* A second session that read the same entries before this one wrote would
|
|
82
|
+
* otherwise replace the file with its own view and lose the first session's
|
|
83
|
+
* prompts. The lock names its holder, so a dead session can be displaced while
|
|
84
|
+
* a running one is waited for, and a holder that never lets go costs one
|
|
85
|
+
* mutation rather than the whole file.
|
|
86
|
+
*/
|
|
87
|
+
async function acquireLock(lockPath, waitMs) {
|
|
88
|
+
const deadline = Date.now() + waitMs;
|
|
89
|
+
const owner = { pid: process.pid, token: randomUUID() };
|
|
90
|
+
for (;;) {
|
|
91
|
+
const contents = await readFile(lockPath, 'utf8').catch(() => undefined);
|
|
92
|
+
if (contents !== undefined) {
|
|
93
|
+
const holder = parseOwner(contents);
|
|
94
|
+
if (holder !== undefined && isOwnerAlive(holder.pid)) {
|
|
95
|
+
if (Date.now() >= deadline)
|
|
96
|
+
throw new Error('another session is writing the prompt history');
|
|
97
|
+
await delay(LOCK_RETRY_MS);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
await reclaimLock(lockPath, contents, Math.max(1, deadline - Date.now()));
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (await publishLock(lockPath, owner))
|
|
104
|
+
return owner;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Publish a lock naming `owner`; false when another holder got there first. */
|
|
108
|
+
async function publishLock(lockPath, owner) {
|
|
109
|
+
// The holder is written before the lock path exists, so a contender can never
|
|
110
|
+
// read a half-published lock and displace a live session.
|
|
111
|
+
const staged = lockPath + '.' + owner.token + LOCK_TEMP_SUFFIX;
|
|
112
|
+
await writeFile(staged, serializeOwner(owner), { encoding: 'utf8', mode: PRIVATE_FILE_MODE });
|
|
113
|
+
try {
|
|
114
|
+
await link(staged, lockPath);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (!isAlreadyExists(error))
|
|
119
|
+
throw error;
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
await rm(staged, { force: true }).catch(() => { });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Replace a lock whose holder cannot run, under a lock of its own.
|
|
128
|
+
*
|
|
129
|
+
* Two sessions that both judge the same lock dead would otherwise each remove
|
|
130
|
+
* it, and one could remove the lock the other had just published, admitting two
|
|
131
|
+
* writers. Displacing a stopped reclaimer would need a third lock, so that case
|
|
132
|
+
* refuses instead: a wrong guess here means concurrent writers.
|
|
133
|
+
*/
|
|
134
|
+
async function reclaimLock(lockPath, deadContents, waitMs) {
|
|
135
|
+
const reclaimPath = lockPath + LOCK_RECLAIM_SUFFIX;
|
|
136
|
+
const owner = { pid: process.pid, token: randomUUID() };
|
|
137
|
+
const deadline = Date.now() + waitMs;
|
|
138
|
+
for (;;) {
|
|
139
|
+
const contents = await readFile(reclaimPath, 'utf8').catch(() => undefined);
|
|
140
|
+
if (contents === undefined) {
|
|
141
|
+
if (await publishLock(reclaimPath, owner))
|
|
142
|
+
break;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const holder = parseOwner(contents);
|
|
146
|
+
if (holder !== undefined && isOwnerAlive(holder.pid)) {
|
|
147
|
+
if (Date.now() >= deadline)
|
|
148
|
+
throw new Error('another session is reclaiming the prompt history lock');
|
|
149
|
+
await delay(LOCK_RETRY_MS);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
throw new Error('prompt history lock at ' + reclaimPath + ' names a session that stopped; remove it to continue');
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
// No other reclaimer runs now, and a path cannot be published over, so the
|
|
156
|
+
// dead lock is still the one this session judged.
|
|
157
|
+
const current = await readFile(lockPath, 'utf8').catch(() => undefined);
|
|
158
|
+
if (current === deadContents)
|
|
159
|
+
await rm(lockPath, { force: true });
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
await releaseLock(reclaimPath, owner);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/** Give the lock back only while it still names this holder, never a successor. */
|
|
166
|
+
async function releaseLock(lockPath, owner) {
|
|
167
|
+
const contents = await readFile(lockPath, 'utf8').catch(() => undefined);
|
|
168
|
+
if (contents !== serializeOwner(owner))
|
|
169
|
+
return;
|
|
170
|
+
await rm(lockPath, { force: true }).catch(() => { });
|
|
171
|
+
}
|
|
172
|
+
/** Run one read-modify-replace under the lock, so nothing lands between them. */
|
|
173
|
+
async function withLock(lockPath, waitMs, operation) {
|
|
174
|
+
await mkdir(dirname(lockPath), { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
175
|
+
const owner = await acquireLock(lockPath, waitMs);
|
|
176
|
+
try {
|
|
177
|
+
return await operation();
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
await releaseLock(lockPath, owner);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function isPositiveInteger(value) {
|
|
184
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
|
|
185
|
+
}
|
|
186
|
+
/** Expand a tilde the way the launcher does, so both spell the home the same. */
|
|
187
|
+
function expandHome(path) {
|
|
188
|
+
if (path === '~')
|
|
189
|
+
return homedir();
|
|
190
|
+
if (path.startsWith('~/') || path.startsWith('~\\'))
|
|
191
|
+
return join(homedir(), path.slice(2));
|
|
192
|
+
return path;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Resolve the harness home.
|
|
196
|
+
*
|
|
197
|
+
* Precedence is the launcher's own: $DSH_HOME, then ~/.dsh. A blank override is
|
|
198
|
+
* treated as unset, because resolving to the working directory would scatter
|
|
199
|
+
* private history into whatever tree the reader happened to start from.
|
|
200
|
+
*/
|
|
201
|
+
export function resolveDshHome(env = process.env) {
|
|
202
|
+
const configured = env[DSH_HOME_ENV];
|
|
203
|
+
const chosen = configured !== undefined && configured.trim() !== ''
|
|
204
|
+
? expandHome(configured)
|
|
205
|
+
: join(homedir(), DSH_HOME_DIR_NAME);
|
|
206
|
+
return resolvePath(chosen);
|
|
207
|
+
}
|
|
208
|
+
/** Read one persisted document, refusing anything this build cannot safely rewrite. */
|
|
209
|
+
export function parseHistoryFile(text) {
|
|
210
|
+
let raw;
|
|
211
|
+
try {
|
|
212
|
+
raw = JSON.parse(text);
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
return { kind: 'blocked', reason: 'corrupt_history' };
|
|
216
|
+
}
|
|
217
|
+
if (!isRecord(raw) || !isPositiveInteger(raw.version))
|
|
218
|
+
return { kind: 'blocked', reason: 'corrupt_history' };
|
|
219
|
+
// Any other positive version may be valid to newer code, so preserve it rather
|
|
220
|
+
// than normalize it away and lose entries this build does not understand.
|
|
221
|
+
if (raw.version !== HISTORY_SCHEMA_VERSION)
|
|
222
|
+
return { kind: 'blocked', reason: 'unsupported_schema' };
|
|
223
|
+
if (typeof raw.updatedAt !== 'string' || !Array.isArray(raw.entries)) {
|
|
224
|
+
return { kind: 'blocked', reason: 'corrupt_history' };
|
|
225
|
+
}
|
|
226
|
+
const entries = normalizeEntries(raw.entries);
|
|
227
|
+
if (entries === undefined)
|
|
228
|
+
return { kind: 'blocked', reason: 'corrupt_history' };
|
|
229
|
+
return { kind: 'ready', file: { version: HISTORY_SCHEMA_VERSION, updatedAt: raw.updatedAt, entries } };
|
|
230
|
+
}
|
|
231
|
+
function normalizeEntries(rawEntries) {
|
|
232
|
+
const entries = [];
|
|
233
|
+
for (const raw of rawEntries) {
|
|
234
|
+
const normalized = normalizeEntry(raw);
|
|
235
|
+
if (normalized === undefined)
|
|
236
|
+
return undefined;
|
|
237
|
+
entries.push(normalized);
|
|
238
|
+
}
|
|
239
|
+
return entries;
|
|
240
|
+
}
|
|
241
|
+
function normalizeEntry(raw) {
|
|
242
|
+
if (!isRecord(raw))
|
|
243
|
+
return undefined;
|
|
244
|
+
if (typeof raw.text !== 'string' || raw.text.trim() === '')
|
|
245
|
+
return undefined;
|
|
246
|
+
if (typeof raw.updatedAt !== 'string')
|
|
247
|
+
return undefined;
|
|
248
|
+
if (!isPositiveInteger(raw.useCount))
|
|
249
|
+
return undefined;
|
|
250
|
+
// A prompt reaches the ghost, the picker, and the bar again, and the terminal
|
|
251
|
+
// executes what it is given: the stored text is the one boundary every later
|
|
252
|
+
// consumer crosses, so a control sequence is spelled out before it is kept. A
|
|
253
|
+
// tab is kept as a tab, because the bar it is restored into has stops of its
|
|
254
|
+
// own and expanding it here would change what the reader typed.
|
|
255
|
+
return { text: displayText(raw.text, { tab: 'keep' }), updatedAt: raw.updatedAt, useCount: raw.useCount };
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Put one prompt at the front, replacing an exact duplicate.
|
|
259
|
+
*
|
|
260
|
+
* A duplicate is moved rather than copied so a repeated prompt resurfaces as the
|
|
261
|
+
* newest suggestion without ever appearing twice in the list.
|
|
262
|
+
*/
|
|
263
|
+
export function upsertEntry(entries, text, now, maxEntries) {
|
|
264
|
+
const existing = entries.find(entry => entry.text === text);
|
|
265
|
+
const next = existing === undefined
|
|
266
|
+
? { text, updatedAt: now, useCount: 1 }
|
|
267
|
+
: { text, updatedAt: laterTimestamp(existing.updatedAt, now), useCount: existing.useCount + 1 };
|
|
268
|
+
return [next, ...entries.filter(entry => entry.text !== text)].slice(0, Math.max(0, maxEntries));
|
|
269
|
+
}
|
|
270
|
+
function laterTimestamp(left, right) {
|
|
271
|
+
return left >= right ? left : right;
|
|
272
|
+
}
|
|
273
|
+
/** Build the store the surface records into and completes from. */
|
|
274
|
+
export function createPromptHistory(options) {
|
|
275
|
+
const now = options.now ?? (() => new Date());
|
|
276
|
+
const warn = options.warn ?? (() => { });
|
|
277
|
+
const filePath = join(options.home ?? resolveDshHome(), HISTORY_FILE_NAME);
|
|
278
|
+
const lockPath = filePath + LOCK_SUFFIX;
|
|
279
|
+
let entries = [];
|
|
280
|
+
let blocked;
|
|
281
|
+
const warned = new Set();
|
|
282
|
+
const warnOnce = (key, message) => {
|
|
283
|
+
if (warned.has(key))
|
|
284
|
+
return;
|
|
285
|
+
warned.add(key);
|
|
286
|
+
warn(message);
|
|
287
|
+
};
|
|
288
|
+
// Every mutation rides one chain so a clear can never be overtaken by a record
|
|
289
|
+
// that started earlier; without it a slow initial read could resurrect an
|
|
290
|
+
// entry the reader just removed. Each mutation also re-reads the file, because
|
|
291
|
+
// a second session may have written since this one loaded and its prompts must
|
|
292
|
+
// be folded in rather than overwritten.
|
|
293
|
+
let chain = load();
|
|
294
|
+
async function load() {
|
|
295
|
+
let text;
|
|
296
|
+
try {
|
|
297
|
+
text = await readFile(filePath, 'utf8');
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
if (isMissingFile(error))
|
|
301
|
+
return;
|
|
302
|
+
blocked = 'unreadable_history';
|
|
303
|
+
warnOnce('load:unreadable', 'prompt history is unreadable; writes are disabled until it can be read');
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const parsed = parseHistoryFile(text);
|
|
307
|
+
if (parsed.kind === 'blocked') {
|
|
308
|
+
blocked = parsed.reason;
|
|
309
|
+
warnOnce('load:' + parsed.reason, 'prompt history is ' + BLOCK_DESCRIPTIONS[parsed.reason] + '; writes are disabled and the file is left untouched');
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
entries = parsed.file.entries;
|
|
313
|
+
}
|
|
314
|
+
function enqueue(operation) {
|
|
315
|
+
const run = chain.then(operation);
|
|
316
|
+
chain = run.then(() => { }, () => { });
|
|
317
|
+
return run;
|
|
318
|
+
}
|
|
319
|
+
async function write() {
|
|
320
|
+
const file = { version: HISTORY_SCHEMA_VERSION, updatedAt: now().toISOString(), entries };
|
|
321
|
+
const tempPath = filePath + '.' + process.pid + '.' + Date.now() + '.tmp';
|
|
322
|
+
await mkdir(dirname(filePath), { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
323
|
+
try {
|
|
324
|
+
await writeFile(tempPath, JSON.stringify(file, null, 2) + '\n', { encoding: 'utf8', mode: PRIVATE_FILE_MODE });
|
|
325
|
+
await chmod(tempPath, PRIVATE_FILE_MODE);
|
|
326
|
+
await rename(tempPath, filePath);
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
await rm(tempPath, { force: true });
|
|
330
|
+
throw error;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
entries: () => entries,
|
|
335
|
+
path: () => filePath,
|
|
336
|
+
blockedReason: () => blocked,
|
|
337
|
+
record(text) {
|
|
338
|
+
if (text.trim() === '')
|
|
339
|
+
return;
|
|
340
|
+
const prompt = displayText(text, { tab: 'keep' });
|
|
341
|
+
void enqueue(() => withLock(lockPath, options.lockWaitMs ?? LOCK_WAIT_MS, async () => {
|
|
342
|
+
await load();
|
|
343
|
+
if (blocked !== undefined)
|
|
344
|
+
return;
|
|
345
|
+
entries = upsertEntry(entries, prompt, now().toISOString(), options.cap());
|
|
346
|
+
await write();
|
|
347
|
+
})).catch((error) => {
|
|
348
|
+
// The reason can name the lock file that must be removed by hand, so it
|
|
349
|
+
// belongs in the notice rather than behind a single opaque sentence.
|
|
350
|
+
const reason = error instanceof Error && error.message !== '' ? ': ' + error.message : '';
|
|
351
|
+
warnOnce('write' + reason, 'prompt history could not be written; this session keeps it in memory only' + reason);
|
|
352
|
+
});
|
|
353
|
+
},
|
|
354
|
+
clear() {
|
|
355
|
+
return enqueue(() => withLock(lockPath, options.lockWaitMs ?? LOCK_WAIT_MS, async () => {
|
|
356
|
+
await load();
|
|
357
|
+
// A file that changed under the reader cannot be cleared safely, and
|
|
358
|
+
// reporting a successful clear of nothing would be worse than refusing.
|
|
359
|
+
if (blocked !== undefined)
|
|
360
|
+
throw new Error('the file is ' + BLOCK_DESCRIPTIONS[blocked]);
|
|
361
|
+
const removed = entries.length;
|
|
362
|
+
const previous = entries;
|
|
363
|
+
entries = [];
|
|
364
|
+
try {
|
|
365
|
+
await write();
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
// The file still holds the prompts, so memory follows it back rather
|
|
369
|
+
// than reporting a clear the reader would meet again on next start.
|
|
370
|
+
entries = previous;
|
|
371
|
+
throw error;
|
|
372
|
+
}
|
|
373
|
+
return removed;
|
|
374
|
+
}));
|
|
375
|
+
},
|
|
376
|
+
flush: () => chain,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function isMissingFile(error) {
|
|
380
|
+
return isRecord(error) && error.code === 'ENOENT';
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=prompt-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-history.js","sourceRoot":"","sources":["../../src/agent/prompt-history.ts"],"names":[],"mappings":"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"}
|