@herbertgao/pi-extensions 2026.8.7 → 2026.8.9
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/README.md +8 -6
- package/node_modules/@czottmann/pi-automode/CHANGELOG.md +24 -0
- package/node_modules/@czottmann/pi-automode/README.md +78 -112
- package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +18 -14
- package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +44 -0
- package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +5 -0
- package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +198 -104
- package/node_modules/@czottmann/pi-automode/docs/configuration.md +155 -0
- package/node_modules/@czottmann/pi-automode/docs/defaults.md +55 -14
- package/node_modules/@czottmann/pi-automode/docs/diagnostics.md +90 -0
- package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +61 -26
- package/node_modules/@czottmann/pi-automode/examples/automode.local.json +5 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +172 -18
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +127 -30
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +3 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +273 -31
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/log.ts +60 -5
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +92 -8
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +203 -13
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/state.ts +1 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +11 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/utils.ts +9 -1
- package/node_modules/@czottmann/pi-automode/package.json +9 -2
- package/node_modules/@czottmann/pi-automode/skills/automode-diagnostics/SKILL.md +63 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +8 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +63 -15
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +56 -29
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +78 -16
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +13 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +30 -17
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-handoff/CHANGELOG.md +29 -0
- package/node_modules/@herbertgao/pi-handoff/README.md +15 -18
- package/node_modules/@herbertgao/pi-handoff/package.json +11 -4
- package/node_modules/@herbertgao/pi-handoff/src/complete-text.ts +33 -0
- package/node_modules/@herbertgao/pi-handoff/src/index.ts +127 -232
- package/node_modules/@herbertgao/pi-handoff/src/session-query.ts +15 -30
- package/node_modules/@herbertgao/pi-mermaid-open/CHANGELOG.md +14 -0
- package/node_modules/@herbertgao/pi-mermaid-open/README.md +21 -4
- package/node_modules/@herbertgao/pi-mermaid-open/herdr-plugin/herdr-plugin.toml +11 -0
- package/node_modules/@herbertgao/pi-mermaid-open/herdr-plugin/viewer.mjs +305 -0
- package/node_modules/@herbertgao/pi-mermaid-open/package.json +15 -4
- package/node_modules/@herbertgao/pi-mermaid-open/src/index.ts +351 -101
- package/node_modules/@herbertgao/pi-preferred-thinking/CHANGELOG.md +12 -0
- package/node_modules/@herbertgao/pi-preferred-thinking/README.md +30 -14
- package/node_modules/@herbertgao/pi-preferred-thinking/package.json +7 -4
- package/node_modules/@herbertgao/pi-preferred-thinking/src/index.ts +140 -85
- package/node_modules/@herbertgao/pi-recap/CHANGELOG.md +12 -0
- package/node_modules/@herbertgao/pi-recap/README.md +5 -3
- package/node_modules/@herbertgao/pi-recap/package.json +9 -3
- package/node_modules/@herbertgao/pi-recap/src/index.ts +3 -7
- package/node_modules/@herbertgao/pi-recap/src/model-picker.ts +6 -19
- package/node_modules/@herbertgao/pi-recap/src/models.ts +9 -21
- package/node_modules/@herbertgao/pi-recap/src/tui.ts +1 -1
- package/node_modules/@herbertgao/pi-rename/CHANGELOG.md +49 -0
- package/node_modules/@herbertgao/pi-rename/README.md +13 -11
- package/node_modules/@herbertgao/pi-rename/package.json +13 -3
- package/node_modules/@herbertgao/pi-rename/src/index.ts +135 -59
- package/node_modules/@herbertgao/pi-rename/src/models.ts +5 -13
- package/node_modules/@herbertgao/pi-rename/src/naming.ts +2 -6
- package/node_modules/@herbertgao/pi-stash/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +16 -3
- package/node_modules/@herbertgao/pi-subagents/package.json +1 -1
- package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +15 -4
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +16 -0
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +5 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +4 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +154 -96
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +3 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +7 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +3 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +137 -96
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +44 -32
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +56 -34
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +50 -4
- package/node_modules/@narumitw/pi-btw/package.json +2 -2
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
- package/node_modules/pi-lens/CHANGELOG.md +90 -0
- package/node_modules/pi-lens/README.md +106 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +97 -6
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +16 -6
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +14 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +22 -1
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
- package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +8 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +10 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +10 -15
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +19 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +35 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +8 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +110 -23
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +117 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +16 -14
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +8 -9
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +22 -0
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +5 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +7 -2
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +27 -2
- package/node_modules/pi-lens/dist/clients/lsp/client.js +144 -5
- package/node_modules/pi-lens/dist/clients/lsp/index.js +151 -6
- package/node_modules/pi-lens/dist/clients/module-report.js +14 -1
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +18 -9
- package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +7 -2
- package/node_modules/pi-lens/dist/clients/read-guard.js +88 -19
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
- package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +44 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +41 -0
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +47 -2
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
- package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
- package/node_modules/pi-lens/dist/index.js +1224 -393
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +10 -3
- package/node_modules/pi-lens/package.json +18 -5
- package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
- package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
- package/node_modules/pi-web-access/CHANGELOG.md +27 -0
- package/node_modules/pi-web-access/README.md +8 -7
- package/node_modules/pi-web-access/chrome-cookies.ts +96 -20
- package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
- package/node_modules/pi-web-access/extract.ts +12 -2
- package/node_modules/pi-web-access/firecrawl.ts +18 -2
- package/node_modules/pi-web-access/gemini-search.ts +28 -10
- package/node_modules/pi-web-access/github-extract.ts +65 -36
- package/node_modules/pi-web-access/index.ts +43 -14
- package/node_modules/pi-web-access/openai-search.ts +17 -6
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/pdf-extract.ts +18 -5
- package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
- package/package.json +19 -18
|
@@ -10,17 +10,13 @@ Generate session names for pi and Herdr.
|
|
|
10
10
|
pi install npm:@herbertgao/pi-rename
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
pi install /absolute/path/to/pi-extensions/packages/pi-rename
|
|
17
|
-
```
|
|
13
|
+
This package requires Pi 0.84.2 or newer.
|
|
18
14
|
|
|
19
15
|
## How it works
|
|
20
16
|
|
|
21
|
-
Run `/rename` to generate a fresh hyphen-separated session name. The extension applies the name to the pi session and, when pi is running inside Herdr, to the current
|
|
17
|
+
Run `/rename` to generate a fresh hyphen-separated session name. The extension applies the name to the pi session and, when pi is running inside Herdr, to the current pane and tab when it is the tab's only pane, or to the current pane in a split tab.
|
|
22
18
|
|
|
23
|
-
When a named session starts or resumes in Herdr, the extension
|
|
19
|
+
When a named session starts or resumes in Herdr, the extension applies the saved pi session name when the target still has its default label or the temporary `herdr-wrap` label.
|
|
24
20
|
|
|
25
21
|
`/rename` builds naming context from the first user message plus up to three latest user messages. It ignores assistant replies, tool output, and attachments. Before sending context to the rename model, it redacts common secrets.
|
|
26
22
|
|
|
@@ -43,7 +39,7 @@ Run `/rename config` to choose a different model.
|
|
|
43
39
|
|
|
44
40
|
After you choose a model, `pi-rename` uses only that model. Choose `Use default` in `/rename config` to return to the default.
|
|
45
41
|
|
|
46
|
-
You can also edit
|
|
42
|
+
You can also edit `$PI_CODING_AGENT_DIR/extensions/pi-rename.json` manually:
|
|
47
43
|
|
|
48
44
|
```json
|
|
49
45
|
{
|
|
@@ -53,14 +49,20 @@ You can also edit `~/.config/pi/extensions/pi-rename.json` manually:
|
|
|
53
49
|
|
|
54
50
|
## Herdr behavior
|
|
55
51
|
|
|
56
|
-
|
|
52
|
+
Herdr tab renaming requires the `herdr` CLI. If it is unavailable, the extension still renames the pi session.
|
|
57
53
|
|
|
58
|
-
|
|
54
|
+
The extension uses `HERDR_PANE_ID` to find the current Herdr pane. With one pane in the tab, it renames both the pane and tab. With sibling panes, it renames only the current pane.
|
|
59
55
|
|
|
60
|
-
On
|
|
56
|
+
On session startup or resume, it does not overwrite custom Herdr labels. It recognizes the temporary label from the Nushell `herdr-wrap` wrapper so saved session names still apply.
|
|
57
|
+
|
|
58
|
+
On quit, the target keeps the last session name.
|
|
61
59
|
|
|
62
60
|
If pi is not running inside Herdr, only the pi session name is updated.
|
|
63
61
|
|
|
62
|
+
## Release notes
|
|
63
|
+
|
|
64
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
|
65
|
+
|
|
64
66
|
## License
|
|
65
67
|
|
|
66
68
|
[MIT](LICENSE)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-rename",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Generate pi session names and rename the current Herdr tab.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"herdr",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"files": [
|
|
27
27
|
"src/**/*.ts",
|
|
28
28
|
"README.md",
|
|
29
|
+
"CHANGELOG.md",
|
|
29
30
|
"LICENSE"
|
|
30
31
|
],
|
|
31
32
|
"type": "module",
|
|
@@ -36,6 +37,15 @@
|
|
|
36
37
|
"access": "public",
|
|
37
38
|
"provenance": true
|
|
38
39
|
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"test": "node --experimental-strip-types --test tests/**/*.test.ts"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@earendil-works/pi-agent-core": ">=0.84.2",
|
|
45
|
+
"@earendil-works/pi-ai": ">=0.84.2",
|
|
46
|
+
"@earendil-works/pi-coding-agent": ">=0.84.2",
|
|
47
|
+
"@earendil-works/pi-tui": ">=0.84.2"
|
|
48
|
+
},
|
|
39
49
|
"engines": {
|
|
40
50
|
"node": ">=20"
|
|
41
51
|
},
|
|
@@ -46,8 +56,8 @@
|
|
|
46
56
|
},
|
|
47
57
|
"x-upstream": {
|
|
48
58
|
"package": "@tifan/pi-rename",
|
|
49
|
-
"version": "0.
|
|
59
|
+
"version": "0.5.0",
|
|
50
60
|
"repository": "https://github.com/tifandotme/pi-extensions",
|
|
51
|
-
"commit": "
|
|
61
|
+
"commit": "3f6b5e628e31817960a02cfae9bcb4a3f4bcd79b"
|
|
52
62
|
}
|
|
53
63
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { execFile } from "node:child_process"
|
|
2
|
+
import path from "node:path"
|
|
2
3
|
import { promisify } from "node:util"
|
|
3
4
|
import type { AgentMessage } from "@earendil-works/pi-agent-core"
|
|
4
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
CancellableLoader,
|
|
7
|
+
type AutocompleteItem,
|
|
8
|
+
} from "@earendil-works/pi-tui"
|
|
5
9
|
import type {
|
|
6
10
|
ExtensionAPI,
|
|
7
11
|
ExtensionContext,
|
|
@@ -61,10 +65,17 @@ function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
|
61
65
|
return value as Record<string, unknown>
|
|
62
66
|
}
|
|
63
67
|
|
|
68
|
+
interface HerdrPaneInfo {
|
|
69
|
+
readonly id: string
|
|
70
|
+
readonly label?: string
|
|
71
|
+
readonly tabId: string
|
|
72
|
+
}
|
|
73
|
+
|
|
64
74
|
interface HerdrTabInfo {
|
|
65
75
|
readonly id: string
|
|
66
76
|
readonly label?: string
|
|
67
77
|
readonly number?: number
|
|
78
|
+
readonly paneCount?: number
|
|
68
79
|
}
|
|
69
80
|
|
|
70
81
|
function parseRecord(value: string): Record<string, unknown> | undefined {
|
|
@@ -75,12 +86,33 @@ function parseRecord(value: string): Record<string, unknown> | undefined {
|
|
|
75
86
|
}
|
|
76
87
|
}
|
|
77
88
|
|
|
78
|
-
|
|
89
|
+
interface HerdrContext {
|
|
90
|
+
readonly pane: HerdrPaneInfo
|
|
91
|
+
readonly tab: HerdrTabInfo
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function extractPaneInfo(stdout: string): HerdrPaneInfo | undefined {
|
|
79
95
|
const parsed = parseRecord(stdout)
|
|
80
96
|
const result = asRecord(parsed?.["result"])
|
|
81
97
|
const pane = asRecord(result?.["pane"])
|
|
98
|
+
const paneId = pane?.["pane_id"]
|
|
82
99
|
const tabId = pane?.["tab_id"]
|
|
83
|
-
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
typeof paneId !== "string" ||
|
|
103
|
+
!paneId.trim() ||
|
|
104
|
+
typeof tabId !== "string" ||
|
|
105
|
+
!tabId.trim()
|
|
106
|
+
) {
|
|
107
|
+
return undefined
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const label = pane?.["label"]
|
|
111
|
+
return {
|
|
112
|
+
id: paneId,
|
|
113
|
+
tabId,
|
|
114
|
+
...(typeof label === "string" ? { label } : {}),
|
|
115
|
+
}
|
|
84
116
|
}
|
|
85
117
|
|
|
86
118
|
function extractTabInfo(stdout: string): HerdrTabInfo | undefined {
|
|
@@ -93,28 +125,35 @@ function extractTabInfo(stdout: string): HerdrTabInfo | undefined {
|
|
|
93
125
|
|
|
94
126
|
const label = tab?.["label"]
|
|
95
127
|
const number = tab?.["number"]
|
|
128
|
+
const paneCount = tab?.["pane_count"]
|
|
96
129
|
|
|
97
130
|
return {
|
|
98
131
|
id: tabId,
|
|
99
132
|
...(typeof label === "string" ? { label } : {}),
|
|
100
133
|
...(typeof number === "number" ? { number } : {}),
|
|
134
|
+
...(typeof paneCount === "number" ? { paneCount } : {}),
|
|
101
135
|
}
|
|
102
136
|
}
|
|
103
137
|
|
|
104
|
-
async function
|
|
138
|
+
async function getCurrentHerdrContext(): Promise<HerdrContext | undefined> {
|
|
105
139
|
const paneId = process.env["HERDR_PANE_ID"]?.trim()
|
|
106
140
|
if (!paneId) return undefined
|
|
107
141
|
|
|
108
|
-
const { stdout } = await execFileAsync("herdr", [
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
if (!
|
|
115
|
-
|
|
116
|
-
const { stdout } = await execFileAsync("herdr", [
|
|
117
|
-
|
|
142
|
+
const { stdout: paneStdout } = await execFileAsync("herdr", [
|
|
143
|
+
"pane",
|
|
144
|
+
"get",
|
|
145
|
+
paneId,
|
|
146
|
+
])
|
|
147
|
+
const pane = extractPaneInfo(paneStdout)
|
|
148
|
+
if (!pane) return undefined
|
|
149
|
+
|
|
150
|
+
const { stdout: tabStdout } = await execFileAsync("herdr", [
|
|
151
|
+
"tab",
|
|
152
|
+
"get",
|
|
153
|
+
pane.tabId,
|
|
154
|
+
])
|
|
155
|
+
const tab = extractTabInfo(tabStdout)
|
|
156
|
+
return tab ? { pane, tab } : undefined
|
|
118
157
|
}
|
|
119
158
|
|
|
120
159
|
function isDefaultHerdrTabLabel(tab: HerdrTabInfo): boolean {
|
|
@@ -124,22 +163,49 @@ function isDefaultHerdrTabLabel(tab: HerdrTabInfo): boolean {
|
|
|
124
163
|
return typeof tab.number === "number" && label === String(tab.number)
|
|
125
164
|
}
|
|
126
165
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
166
|
+
function isPiWrapperLabel(label: string | undefined): boolean {
|
|
167
|
+
return label?.trim() === `${path.basename(process.cwd())} (pi)`
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function canRenameSessionStart(context: HerdrContext): boolean {
|
|
171
|
+
const singlePane = context.tab.paneCount === 1
|
|
172
|
+
const label = singlePane ? context.tab.label : context.pane.label
|
|
173
|
+
return (
|
|
174
|
+
(singlePane ? isDefaultHerdrTabLabel(context.tab) : !label?.trim()) ||
|
|
175
|
+
isPiWrapperLabel(label)
|
|
176
|
+
)
|
|
177
|
+
}
|
|
130
178
|
|
|
131
|
-
|
|
179
|
+
async function renameHerdrTarget(
|
|
180
|
+
context: HerdrContext,
|
|
181
|
+
name: string,
|
|
182
|
+
): Promise<boolean> {
|
|
183
|
+
await execFileAsync("herdr", ["pane", "rename", context.pane.id, name])
|
|
184
|
+
if (context.tab.paneCount === 1) {
|
|
185
|
+
await execFileAsync("herdr", ["tab", "rename", context.tab.id, name])
|
|
186
|
+
}
|
|
132
187
|
return true
|
|
133
188
|
}
|
|
134
189
|
|
|
135
|
-
async function
|
|
136
|
-
const
|
|
137
|
-
|
|
190
|
+
async function renameCurrentHerdrTarget(name: string): Promise<boolean> {
|
|
191
|
+
const context = await getCurrentHerdrContext()
|
|
192
|
+
return context ? renameHerdrTarget(context, name) : false
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function renameCurrentHerdrTargetIfDefault(
|
|
196
|
+
name: string,
|
|
197
|
+
): Promise<boolean> {
|
|
198
|
+
const context = await getCurrentHerdrContext()
|
|
199
|
+
if (
|
|
200
|
+
!context ||
|
|
201
|
+
!canRenameSessionStart(context) ||
|
|
202
|
+
context.tab.label?.trim() === name ||
|
|
203
|
+
context.pane.label?.trim() === name
|
|
204
|
+
) {
|
|
138
205
|
return false
|
|
139
206
|
}
|
|
140
207
|
|
|
141
|
-
|
|
142
|
-
return true
|
|
208
|
+
return renameHerdrTarget(context, name)
|
|
143
209
|
}
|
|
144
210
|
|
|
145
211
|
function hasSessionContextReader(
|
|
@@ -166,7 +232,7 @@ function getCurrentSessionMessages(ctx: ExtensionContext): AgentMessage[] {
|
|
|
166
232
|
|
|
167
233
|
async function applyRename(pi: ExtensionAPI, name: string): Promise<boolean> {
|
|
168
234
|
pi.setSessionName(name)
|
|
169
|
-
return
|
|
235
|
+
return renameCurrentHerdrTarget(name)
|
|
170
236
|
}
|
|
171
237
|
|
|
172
238
|
async function runRenameCommand(
|
|
@@ -180,47 +246,57 @@ async function runRenameCommand(
|
|
|
180
246
|
return
|
|
181
247
|
}
|
|
182
248
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
249
|
+
if (ctx.mode === "tui") {
|
|
250
|
+
ctx.ui.setWidget("pi-rename", (tui, theme) => {
|
|
251
|
+
const color = (text: string) => theme.fg("dim", text)
|
|
252
|
+
return new CancellableLoader(tui, color, color, "renaming session...")
|
|
253
|
+
})
|
|
187
254
|
}
|
|
255
|
+
try {
|
|
256
|
+
const result = await generateRename(ctx, state.modelConfig, context)
|
|
257
|
+
if (!result) {
|
|
258
|
+
ctx.ui.notify("Could not generate a session name.", "error")
|
|
259
|
+
return
|
|
260
|
+
}
|
|
188
261
|
|
|
189
|
-
|
|
190
|
-
|
|
262
|
+
let renamedHerdr = false
|
|
263
|
+
let herdrError: string | undefined
|
|
191
264
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
265
|
+
try {
|
|
266
|
+
renamedHerdr = await applyRename(pi, result.name)
|
|
267
|
+
} catch (error) {
|
|
268
|
+
herdrError = error instanceof Error ? error.message : String(error)
|
|
269
|
+
}
|
|
197
270
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
271
|
+
if (result.source === "fallback") {
|
|
272
|
+
ctx.ui.notify(
|
|
273
|
+
[
|
|
274
|
+
`Session renamed with fallback: ${result.name}`,
|
|
275
|
+
`Could not use rename model: ${result.reason}`,
|
|
276
|
+
...(herdrError ? [`Herdr label rename failed: ${herdrError}`] : []),
|
|
277
|
+
].join("\n"),
|
|
278
|
+
"warning",
|
|
279
|
+
)
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (herdrError) {
|
|
284
|
+
ctx.ui.notify(
|
|
285
|
+
`Session renamed, but Herdr label rename failed: ${herdrError}`,
|
|
286
|
+
"warning",
|
|
287
|
+
)
|
|
288
|
+
return
|
|
289
|
+
}
|
|
209
290
|
|
|
210
|
-
if (herdrError) {
|
|
211
291
|
ctx.ui.notify(
|
|
212
|
-
|
|
213
|
-
|
|
292
|
+
renamedHerdr
|
|
293
|
+
? `Session and Herdr label renamed: ${result.name}`
|
|
294
|
+
: `Session renamed: ${result.name}`,
|
|
295
|
+
"info",
|
|
214
296
|
)
|
|
215
|
-
|
|
297
|
+
} finally {
|
|
298
|
+
if (ctx.mode === "tui") ctx.ui.setWidget("pi-rename", undefined)
|
|
216
299
|
}
|
|
217
|
-
|
|
218
|
-
ctx.ui.notify(
|
|
219
|
-
renamedHerdr
|
|
220
|
-
? `Session and Herdr tab renamed: ${result.name}`
|
|
221
|
-
: `Session renamed: ${result.name}`,
|
|
222
|
-
"info",
|
|
223
|
-
)
|
|
224
300
|
}
|
|
225
301
|
|
|
226
302
|
function getRenameArgumentCompletions(
|
|
@@ -293,7 +369,7 @@ async function notifyRenameStatus(
|
|
|
293
369
|
}
|
|
294
370
|
|
|
295
371
|
const context = getUserMessageContext(getCurrentSessionMessages(ctx))
|
|
296
|
-
const herdrLine = `herdr
|
|
372
|
+
const herdrLine = `herdr: ${process.env["HERDR_PANE_ID"]?.trim() ? "available" : "unavailable"}`
|
|
297
373
|
const contextLine = `context: ${context?.count ?? 0} user messages`
|
|
298
374
|
|
|
299
375
|
ctx.ui.notify(
|
|
@@ -361,7 +437,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
361
437
|
if (!sessionName) return
|
|
362
438
|
|
|
363
439
|
try {
|
|
364
|
-
await
|
|
440
|
+
await renameCurrentHerdrTargetIfDefault(sessionName)
|
|
365
441
|
} catch {
|
|
366
442
|
// Keep session startup quiet if Herdr is unavailable or rejects the rename.
|
|
367
443
|
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
writeFileSync,
|
|
7
7
|
} from "node:fs"
|
|
8
8
|
import path from "node:path"
|
|
9
|
-
import type { Api, Model
|
|
9
|
+
import type { Api, Model } from "@earendil-works/pi-ai"
|
|
10
10
|
import {
|
|
11
11
|
getAgentDir,
|
|
12
12
|
type ExtensionContext,
|
|
@@ -22,8 +22,6 @@ export interface RenameModelPreference {
|
|
|
22
22
|
|
|
23
23
|
export interface RenameModelAuth {
|
|
24
24
|
readonly model: Model<Api>
|
|
25
|
-
readonly apiKey: string
|
|
26
|
-
readonly headers: ProviderHeaders | undefined
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
export type RenameModelConfig =
|
|
@@ -134,14 +132,8 @@ async function getModelAuth(
|
|
|
134
132
|
)
|
|
135
133
|
if (!model) return undefined
|
|
136
134
|
|
|
137
|
-
const auth = await ctx.modelRegistry.
|
|
138
|
-
return auth.
|
|
139
|
-
? {
|
|
140
|
-
model,
|
|
141
|
-
apiKey: auth.apiKey,
|
|
142
|
-
headers: auth.headers,
|
|
143
|
-
}
|
|
144
|
-
: undefined
|
|
135
|
+
const auth = await ctx.modelRegistry.getProviderAuth(model.provider)
|
|
136
|
+
return auth?.auth.apiKey ? { model } : undefined
|
|
145
137
|
}
|
|
146
138
|
|
|
147
139
|
export async function getRenameModelAuth(
|
|
@@ -181,8 +173,8 @@ export async function getAuthenticatedTextModelPreferences(
|
|
|
181
173
|
.filter((model) => model.input.includes("text"))
|
|
182
174
|
const authenticatedModels = await Promise.all(
|
|
183
175
|
models.map(async (model) => {
|
|
184
|
-
const auth = await ctx.modelRegistry.
|
|
185
|
-
return auth
|
|
176
|
+
const auth = await ctx.modelRegistry.getProviderAuth(model.provider)
|
|
177
|
+
return auth?.auth.apiKey ? toModelPreference(model) : undefined
|
|
186
178
|
}),
|
|
187
179
|
)
|
|
188
180
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentMessage } from "@earendil-works/pi-agent-core"
|
|
2
|
-
import {
|
|
2
|
+
import type { Message } from "@earendil-works/pi-ai"
|
|
3
3
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent"
|
|
4
4
|
import {
|
|
5
5
|
formatRenameModelKey,
|
|
@@ -123,17 +123,13 @@ export async function generateRename(
|
|
|
123
123
|
const modelAuth = await getRenameModelAuth(ctx, modelConfig)
|
|
124
124
|
|
|
125
125
|
if (modelAuth.status === "ok") {
|
|
126
|
-
const response = await complete(
|
|
126
|
+
const response = await ctx.modelRegistry.complete(
|
|
127
127
|
modelAuth.auth.model,
|
|
128
128
|
{
|
|
129
129
|
systemPrompt: RENAME_SYSTEM_PROMPT,
|
|
130
130
|
messages: [buildRenamePrompt(context)],
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
|
-
apiKey: modelAuth.auth.apiKey,
|
|
134
|
-
...(modelAuth.auth.headers
|
|
135
|
-
? { headers: modelAuth.auth.headers }
|
|
136
|
-
: {}),
|
|
137
133
|
maxTokens: RENAME_MAX_TOKENS,
|
|
138
134
|
maxRetries: 0,
|
|
139
135
|
cacheRetention: "none",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-stash",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Stash one pi draft and restore it after the next message.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
},
|
|
45
45
|
"x-upstream": {
|
|
46
46
|
"package": "@tifan/pi-stash",
|
|
47
|
-
"version": "0.
|
|
47
|
+
"version": "0.2.0",
|
|
48
48
|
"repository": "https://github.com/tifandotme/pi-extensions",
|
|
49
|
-
"commit": "
|
|
49
|
+
"commit": "b39d1e6359c78718cbf8fe5c74c82b89065e9a0b"
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#116](https://github.com/HerbertGao/pi-extensions/pull/116) [`ecda398`](https://github.com/HerbertGao/pi-extensions/commit/ecda398b9a95212c512d53325c617e485e6ded8d) Thanks [@HerbertGao](https://github.com/HerbertGao)! - Port Ctrl+C conversation-viewer dismissal and cross-extension consumption of settled subagent results while preserving local spawn and ownership safeguards.
|
|
8
|
+
|
|
3
9
|
## 0.16.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
|
@@ -49,6 +55,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
49
55
|
|
|
50
56
|
### Fixed
|
|
51
57
|
|
|
58
|
+
- **Ctrl+C closes the conversation viewer** when it is not composing a steering message.
|
|
59
|
+
- **Cross-extension callers can consume settled RPC-spawned results** with `subagents:rpc:consume`, suppressing a duplicate completion notification after another extension has already shown the result.
|
|
52
60
|
- **One malformed agent file no longer aborts extension activation** ([#212](https://github.com/tintinweb/pi-subagents/issues/212) — thanks [@daromaj](https://github.com/daromaj)). Unreadable and unparseable files are skipped with a path-specific warning, including the earlier source that remains active when a broken file was an override.
|
|
53
61
|
|
|
54
62
|
## [0.15.1] - 2026-08-10
|
|
@@ -32,7 +32,7 @@ Spawn specialized agents that run in isolated sessions — each with its own too
|
|
|
32
32
|
- **Tool denylist** — block specific tools via `disallowed_tools` frontmatter
|
|
33
33
|
- **Styled completion notifications** — background agent results render as themed, compact notification boxes (icon, stats, result preview) instead of raw XML. Expandable to show full output. Group completions render each agent individually
|
|
34
34
|
- **Event bus** — lifecycle events (`subagents:created`, `started`, `completed`, `failed`, `steered`, `compacted`) emitted via `pi.events`, enabling other extensions to react to sub-agent activity
|
|
35
|
-
- **Cross-extension RPC** — other pi extensions can spawn and
|
|
35
|
+
- **Cross-extension RPC** — other pi extensions can spawn, stop, and consume subagent results via the `pi.events` event bus (`subagents:rpc:ping`, `subagents:rpc:spawn`, `subagents:rpc:stop`, `subagents:rpc:consume`). Standardized reply envelopes with protocol versioning. Emits `subagents:ready` on session start
|
|
36
36
|
- **Schedule subagents** — pass `schedule` to the `Agent` tool to fire on cron / interval / one-shot. Session-scoped jobs with PID-locked persistence; results land via the same `subagent-notification` followUp path as manual background completions; manage via `/agents → Scheduled jobs`
|
|
37
37
|
- **Model scope enforcement** — opt-in validation that subagent model choices stay within your pi `enabledModels` allowlist (sourced from `/scoped-models`, with both global and project-local pi settings honored). Caller-supplied out-of-scope → hard error to orchestrator; frontmatter-pinned out-of-scope → warning + runs anyway (frontmatter authoritative). Toggle via `/agents → Settings → Scope models`
|
|
38
38
|
|
|
@@ -520,7 +520,7 @@ Listen for `subagents:ready` to know when RPC handlers are available:
|
|
|
520
520
|
|
|
521
521
|
```typescript
|
|
522
522
|
pi.events.on("subagents:ready", () => {
|
|
523
|
-
// RPC handlers are registered — safe to call ping/spawn/stop
|
|
523
|
+
// RPC handlers are registered — safe to call ping/spawn/stop/consume
|
|
524
524
|
})
|
|
525
525
|
```
|
|
526
526
|
|
|
@@ -581,6 +581,19 @@ const unsub = pi.events.on(`subagents:rpc:stop:reply:${requestId}`, (reply) => {
|
|
|
581
581
|
pi.events.emit("subagents:rpc:stop", { requestId, agentId: "agent-id-here" })
|
|
582
582
|
```
|
|
583
583
|
|
|
584
|
+
### Consume
|
|
585
|
+
|
|
586
|
+
Mark a settled agent result as already shown so its completion notification is suppressed:
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
pi.events.emit("subagents:rpc:consume", {
|
|
590
|
+
requestId: crypto.randomUUID(),
|
|
591
|
+
agentId: "agent-id-here",
|
|
592
|
+
})
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
This is the event-bus equivalent of `get_subagent_result` consuming a result. Running, queued, unknown, and nested agents are refused; the channel is additive and remains outside the protocol-version handshake.
|
|
596
|
+
|
|
584
597
|
Reply channels are scoped per `requestId`, so concurrent requests don't interfere.
|
|
585
598
|
|
|
586
599
|
## Persistent Agent Memory
|
|
@@ -677,7 +690,7 @@ src/
|
|
|
677
690
|
agent-color.ts # Claude Code/Agency Agents name color parsing and badge rendering
|
|
678
691
|
agent-runner.ts # Session creation, execution, graceful max_turns, steer/resume
|
|
679
692
|
agent-manager.ts # Agent lifecycle, concurrency queue, completion notifications
|
|
680
|
-
cross-extension-rpc.ts # RPC handlers for cross-extension spawn/
|
|
693
|
+
cross-extension-rpc.ts # RPC handlers for cross-extension spawn/stop/consume via pi.events
|
|
681
694
|
group-join.ts # Group join manager: batched completion notifications with timeout
|
|
682
695
|
custom-agents.ts # Load user-defined agents from .pi/agents/, .agents/agents/, and global agents
|
|
683
696
|
memory.ts # Persistent agent memory (resolve, read, build prompt blocks)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cross-extension RPC handlers for the subagents extension.
|
|
3
3
|
*
|
|
4
|
-
* Exposes ping, spawn, and
|
|
4
|
+
* Exposes ping, spawn, stop, and consume RPCs over the pi.events event bus,
|
|
5
5
|
* using per-request scoped reply channels.
|
|
6
6
|
*
|
|
7
7
|
* Reply envelope follows pi-mono convention:
|
|
@@ -25,7 +25,7 @@ export type RpcReply<T = void> =
|
|
|
25
25
|
/** RPC protocol version — bumped when the envelope or method contracts change. */
|
|
26
26
|
export const PROTOCOL_VERSION = 2
|
|
27
27
|
|
|
28
|
-
/** Minimal AgentManager interface needed by the spawn/stop RPCs. */
|
|
28
|
+
/** Minimal AgentManager interface needed by the spawn/stop/consume RPCs. */
|
|
29
29
|
export interface SpawnCapable {
|
|
30
30
|
spawn(
|
|
31
31
|
pi: unknown,
|
|
@@ -35,6 +35,7 @@ export interface SpawnCapable {
|
|
|
35
35
|
options: any,
|
|
36
36
|
): string
|
|
37
37
|
abort(id: string): boolean
|
|
38
|
+
consumeResult(id: string): boolean
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export interface RpcDeps {
|
|
@@ -48,6 +49,7 @@ export interface RpcHandle {
|
|
|
48
49
|
unsubPing: () => void
|
|
49
50
|
unsubSpawn: () => void
|
|
50
51
|
unsubStop: () => void
|
|
52
|
+
unsubConsume: () => void
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
/**
|
|
@@ -76,7 +78,7 @@ function handleRpc<P extends { requestId: string }>(
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
/**
|
|
79
|
-
* Register ping, spawn, and
|
|
81
|
+
* Register ping, spawn, stop, and consume RPC handlers on the event bus.
|
|
80
82
|
* Returns unsub functions for cleanup.
|
|
81
83
|
*/
|
|
82
84
|
export function registerRpcHandlers(deps: RpcDeps): RpcHandle {
|
|
@@ -130,5 +132,14 @@ export function registerRpcHandlers(deps: RpcDeps): RpcHandle {
|
|
|
130
132
|
},
|
|
131
133
|
)
|
|
132
134
|
|
|
133
|
-
|
|
135
|
+
const unsubConsume = handleRpc<{
|
|
136
|
+
requestId: string
|
|
137
|
+
agentId: string
|
|
138
|
+
}>(events, "subagents:rpc:consume", ({ agentId }) => {
|
|
139
|
+
if (!manager.consumeResult(agentId)) {
|
|
140
|
+
throw new Error("Agent not found or still running")
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
return { unsubPing, unsubSpawn, unsubStop, unsubConsume }
|
|
134
145
|
}
|
|
@@ -890,6 +890,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
890
890
|
const record = manager.getRecord(id)
|
|
891
891
|
return !record?.parentAgentId && manager.abort(id)
|
|
892
892
|
},
|
|
893
|
+
consumeResult: (id) => {
|
|
894
|
+
const record = manager.getRecord(id)
|
|
895
|
+
if (
|
|
896
|
+
!record ||
|
|
897
|
+
record.parentAgentId ||
|
|
898
|
+
record.status === "running" ||
|
|
899
|
+
record.status === "queued"
|
|
900
|
+
) {
|
|
901
|
+
return false
|
|
902
|
+
}
|
|
903
|
+
record.resultConsumed = true
|
|
904
|
+
cancelNudge(record.id)
|
|
905
|
+
return true
|
|
906
|
+
},
|
|
893
907
|
},
|
|
894
908
|
})
|
|
895
909
|
// Broadcast readiness so extensions loaded alongside us can discover us.
|
|
@@ -911,6 +925,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
911
925
|
rpcHandle?.unsubSpawn()
|
|
912
926
|
rpcHandle?.unsubStop()
|
|
913
927
|
rpcHandle?.unsubPing()
|
|
928
|
+
rpcHandle?.unsubConsume()
|
|
914
929
|
rpcHandle = undefined
|
|
915
930
|
currentCtx = undefined
|
|
916
931
|
// Only release the global slot if this activation claimed it — a child
|
|
@@ -1068,6 +1083,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1068
1083
|
// Grab UI context from first tool execution + clear lingering widget on new turn
|
|
1069
1084
|
pi.on("tool_execution_start", async (_event, ctx) => {
|
|
1070
1085
|
widget.setUICtx(ctx.ui as UICtx)
|
|
1086
|
+
// SAFETY: both UI adapters receive the same Pi ExtensionContext UI surface.
|
|
1071
1087
|
fleet.setUICtx(ctx.ui as unknown as FleetUICtx)
|
|
1072
1088
|
widget.onTurnStart()
|
|
1073
1089
|
})
|
|
@@ -94,7 +94,11 @@ export class ConversationViewer implements Component {
|
|
|
94
94
|
return
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
if (
|
|
97
|
+
if (
|
|
98
|
+
matchesKey(data, "escape") ||
|
|
99
|
+
matchesKey(data, "ctrl+c") ||
|
|
100
|
+
matchesKey(data, "q")
|
|
101
|
+
) {
|
|
98
102
|
this.closed = true
|
|
99
103
|
this.done(undefined)
|
|
100
104
|
return
|