@herbertgao/pi-extensions 2026.8.12 → 2026.8.14
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 +15 -8
- package/THIRD_PARTY_NOTICES.md +4 -0
- package/node_modules/@czottmann/pi-automode/CHANGELOG.md +12 -0
- package/node_modules/@czottmann/pi-automode/README.md +1 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +55 -4
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +7 -3
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +2 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +134 -23
- package/node_modules/@czottmann/pi-automode/package.json +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +2 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +8 -1
- package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +376 -0
- package/node_modules/@luxusai/pi-hindsight/README.md +92 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +56 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +169 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +107 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +89 -0
- package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +189 -0
- package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
- package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
- package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +54 -0
- package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +75 -0
- package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +300 -0
- package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +158 -0
- package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +164 -0
- package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +139 -0
- package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +74 -0
- package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +261 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +151 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +18 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +46 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +383 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +240 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +176 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +178 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +41 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +386 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +39 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +34 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +140 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +61 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +925 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +247 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +547 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +480 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +182 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +86 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +1010 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +175 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +425 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +210 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +817 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +25 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +319 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +196 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +189 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +65 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +260 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +244 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +59 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +82 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +45 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +331 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +354 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +66 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +132 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +228 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +74 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +16 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +648 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +105 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +68 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +71 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +13 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +162 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +131 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +104 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +37 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +893 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +35 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +177 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +7 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +21 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +112 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +111 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +214 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +70 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +392 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +45 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +9 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +860 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +105 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +189 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +299 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +201 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +47 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +239 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +50 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +259 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +77 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +534 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +319 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +325 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +42 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +244 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +56 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +50 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +167 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +207 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +120 -0
- package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +8 -0
- package/node_modules/@luxusai/pi-hindsight/package.json +118 -0
- package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +75 -0
- package/node_modules/@narumitw/pi-btw/package.json +2 -2
- package/node_modules/@tifan/pi-preferred-thinking/README.md +1 -1
- package/node_modules/@tifan/pi-preferred-thinking/package.json +1 -1
- package/node_modules/@tifan/pi-preferred-thinking/src/index.ts +15 -2
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +33 -0
- package/node_modules/pi-mcp-adapter/README.md +3 -0
- package/node_modules/pi-mcp-adapter/cli.js +4 -4
- package/node_modules/pi-mcp-adapter/config.ts +11 -0
- package/node_modules/pi-mcp-adapter/dist/config.js +11 -0
- package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.d.ts +24 -0
- package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js +336 -0
- package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/types.d.ts +2 -0
- package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -1
- package/node_modules/pi-mcp-adapter/index.ts +90 -6
- package/node_modules/pi-mcp-adapter/init.ts +5 -1
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +19 -0
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +0 -2
- package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +89 -0
- package/node_modules/pi-mcp-adapter/mcp-references.ts +9 -1
- package/node_modules/pi-mcp-adapter/package.json +1 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +40 -10
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +1 -1
- package/node_modules/pi-mcp-adapter/types.ts +2 -0
- package/node_modules/pi-web-access/CHANGELOG.md +22 -0
- package/node_modules/pi-web-access/README.md +11 -8
- package/node_modules/pi-web-access/curator-page.ts +12 -3
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/extract.ts +31 -1
- package/node_modules/pi-web-access/gemini-search.ts +10 -5
- package/node_modules/pi-web-access/index.ts +39 -39
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/xcrawl.ts +264 -0
- package/package.json +15 -12
- package/node_modules/@herbertgao/pi-stash/LICENSE +0 -22
- package/node_modules/@herbertgao/pi-stash/README.md +0 -34
- package/node_modules/@herbertgao/pi-stash/package.json +0 -51
- package/node_modules/@herbertgao/pi-stash/src/index.ts +0 -118
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bankConfigOverrideSummaryLines,
|
|
3
|
+
bankSettingsTargetDisplay,
|
|
4
|
+
} from "../banks/bank-settings-presenter.js";
|
|
5
|
+
import type { HindsightLikeClient, ResolvedConfig } from "../types.js";
|
|
6
|
+
import { redactError } from "./sanitize.js";
|
|
7
|
+
|
|
8
|
+
export type StatusHealthFacts = Array<[string, string]>;
|
|
9
|
+
|
|
10
|
+
type BankRoute = {
|
|
11
|
+
label: "Project bank" | "User bank";
|
|
12
|
+
location: "Project" | "User";
|
|
13
|
+
bankId: string;
|
|
14
|
+
};
|
|
15
|
+
const STATUS_HEALTH_TIMEOUT_MS = 1_500;
|
|
16
|
+
|
|
17
|
+
async function withStatusTimeout<T>(promise: Promise<T>, label: string): Promise<T> {
|
|
18
|
+
let timer: NodeJS.Timeout | undefined;
|
|
19
|
+
try {
|
|
20
|
+
return await Promise.race([
|
|
21
|
+
promise,
|
|
22
|
+
new Promise<never>((_resolve, reject) => {
|
|
23
|
+
timer = setTimeout(
|
|
24
|
+
() => reject(new Error(`${label} timed out after ${STATUS_HEALTH_TIMEOUT_MS}ms`)),
|
|
25
|
+
STATUS_HEALTH_TIMEOUT_MS,
|
|
26
|
+
);
|
|
27
|
+
}),
|
|
28
|
+
]);
|
|
29
|
+
} finally {
|
|
30
|
+
if (timer) clearTimeout(timer);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
35
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function numberField(value: unknown, key: string): number | undefined {
|
|
39
|
+
return isRecord(value) && typeof value[key] === "number" ? value[key] : undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function dateField(value: unknown, key: string): string | undefined {
|
|
43
|
+
return isRecord(value) && typeof value[key] === "string" ? value[key] : undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function bankRoutes(config: ResolvedConfig, projectBankId: string): BankRoute[] {
|
|
47
|
+
return [
|
|
48
|
+
...(config.banks.project.enabled
|
|
49
|
+
? [{ label: "Project bank" as const, location: "Project" as const, bankId: projectBankId }]
|
|
50
|
+
: []),
|
|
51
|
+
...(config.banks.user.enabled && config.banks.user.bankId
|
|
52
|
+
? [
|
|
53
|
+
{
|
|
54
|
+
label: "User bank" as const,
|
|
55
|
+
location: "User" as const,
|
|
56
|
+
bankId: config.banks.user.bankId,
|
|
57
|
+
},
|
|
58
|
+
]
|
|
59
|
+
: []),
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function textField(value: unknown, key: string): string | undefined {
|
|
64
|
+
return isRecord(value) && typeof value[key] === "string" ? value[key] : undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function nestedRecord(value: unknown, key: string): Record<string, unknown> | undefined {
|
|
68
|
+
return isRecord(value) && isRecord(value[key]) ? value[key] : undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function missionSummary(value: string | undefined): string | undefined {
|
|
72
|
+
if (!value) return undefined;
|
|
73
|
+
return value.length > 90 ? `${value.slice(0, 87)}...` : value;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function formatMissionConfig(configResponse: unknown): string | undefined {
|
|
77
|
+
const config = nestedRecord(configResponse, "config");
|
|
78
|
+
const overrides = nestedRecord(configResponse, "overrides");
|
|
79
|
+
const retain =
|
|
80
|
+
textField(overrides, "retain_custom_instructions") ??
|
|
81
|
+
textField(overrides, "retain_mission") ??
|
|
82
|
+
textField(config, "retain_custom_instructions") ??
|
|
83
|
+
textField(config, "retain_mission");
|
|
84
|
+
const reflect = textField(overrides, "reflect_mission") ?? textField(config, "reflect_mission");
|
|
85
|
+
const observations =
|
|
86
|
+
textField(overrides, "observations_mission") ?? textField(config, "observations_mission");
|
|
87
|
+
const parts = [
|
|
88
|
+
retain ? `retain ${missionSummary(retain)}` : undefined,
|
|
89
|
+
reflect ? `reflect ${missionSummary(reflect)}` : undefined,
|
|
90
|
+
observations ? `observations ${missionSummary(observations)}` : undefined,
|
|
91
|
+
].filter(Boolean);
|
|
92
|
+
return parts.length ? parts.join(" · ") : undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function formatStats(stats: unknown): string | undefined {
|
|
96
|
+
const memories = numberField(stats, "total_nodes");
|
|
97
|
+
const documents = numberField(stats, "total_documents");
|
|
98
|
+
const observations = numberField(stats, "total_observations");
|
|
99
|
+
const facts = numberField(stats, "fact_count");
|
|
100
|
+
const pending = numberField(stats, "pending_consolidation");
|
|
101
|
+
const failed = numberField(stats, "failed_consolidation");
|
|
102
|
+
const last = dateField(stats, "last_consolidated_at");
|
|
103
|
+
const lastDocument = dateField(stats, "last_document_at");
|
|
104
|
+
const parts = [
|
|
105
|
+
memories !== undefined ? `memories ${memories}` : undefined,
|
|
106
|
+
documents !== undefined ? `docs ${documents}` : undefined,
|
|
107
|
+
observations !== undefined ? `observations ${observations}` : undefined,
|
|
108
|
+
facts !== undefined ? `facts ${facts}` : undefined,
|
|
109
|
+
pending !== undefined ? `pending ${pending}` : undefined,
|
|
110
|
+
failed !== undefined ? `failed ${failed}` : undefined,
|
|
111
|
+
last ? `last consolidated ${last}` : undefined,
|
|
112
|
+
lastDocument ? `last document ${lastDocument}` : undefined,
|
|
113
|
+
].filter(Boolean);
|
|
114
|
+
return parts.length ? parts.join(" · ") : undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function bankFact(client: HindsightLikeClient, route: BankRoute): Promise<StatusHealthFacts> {
|
|
118
|
+
try {
|
|
119
|
+
const profile = client.getBankProfile
|
|
120
|
+
? await withStatusTimeout(client.getBankProfile(route.bankId), `${route.label} profile`)
|
|
121
|
+
: undefined;
|
|
122
|
+
const name =
|
|
123
|
+
isRecord(profile) && typeof profile.name === "string" ? profile.name : route.bankId;
|
|
124
|
+
const target = bankSettingsTargetDisplay({ location: route.location, bankId: route.bankId });
|
|
125
|
+
const facts: StatusHealthFacts = [[route.label, `reachable · ${name} · ${target.reviewLine}`]];
|
|
126
|
+
if (client.getBankConfig) {
|
|
127
|
+
try {
|
|
128
|
+
const config = await withStatusTimeout(
|
|
129
|
+
client.getBankConfig(route.bankId),
|
|
130
|
+
`${route.label} config`,
|
|
131
|
+
);
|
|
132
|
+
const summary = formatMissionConfig(config);
|
|
133
|
+
const overrideSummary = bankConfigOverrideSummaryLines(config).join(" · ");
|
|
134
|
+
facts.push([`${route.label} config`, overrideSummary]);
|
|
135
|
+
if (summary) facts.push([`${route.label} missions`, `db · ${summary}`]);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
facts.push([`${route.label} missions`, `unavailable · ${redactError(error)}`]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (client.getBankStats) {
|
|
141
|
+
try {
|
|
142
|
+
const stats = await withStatusTimeout(
|
|
143
|
+
client.getBankStats(route.bankId),
|
|
144
|
+
`${route.label} stats`,
|
|
145
|
+
);
|
|
146
|
+
const summary = formatStats(stats);
|
|
147
|
+
if (summary) facts.push([`${route.label} stats`, summary]);
|
|
148
|
+
const failed = numberField(stats, "failed_consolidation");
|
|
149
|
+
if (failed !== undefined && failed > 0)
|
|
150
|
+
facts.push([
|
|
151
|
+
`${route.label} consolidation`,
|
|
152
|
+
`failed ${failed} · run hindsight_recover_consolidation`,
|
|
153
|
+
]);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
facts.push([`${route.label} stats`, `unavailable · ${redactError(error)}`]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return facts;
|
|
159
|
+
} catch (error) {
|
|
160
|
+
return [[route.label, `unreachable · ${redactError(error)}`]];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function serverVersionFact(
|
|
165
|
+
client: HindsightLikeClient,
|
|
166
|
+
): Promise<[string, string] | undefined> {
|
|
167
|
+
if (!client.getVersion) return undefined;
|
|
168
|
+
try {
|
|
169
|
+
const version = await withStatusTimeout(client.getVersion(), "Hindsight version");
|
|
170
|
+
const apiVersion = textField(version, "api_version");
|
|
171
|
+
if (!apiVersion) return undefined;
|
|
172
|
+
const features = nestedRecord(version, "features");
|
|
173
|
+
const enabled = features
|
|
174
|
+
? Object.keys(features)
|
|
175
|
+
.filter((key) => features[key] === true)
|
|
176
|
+
.sort()
|
|
177
|
+
: [];
|
|
178
|
+
return [
|
|
179
|
+
"Server version",
|
|
180
|
+
enabled.length ? `${apiVersion} · features: ${enabled.join(", ")}` : apiVersion,
|
|
181
|
+
];
|
|
182
|
+
} catch {
|
|
183
|
+
// Version endpoint is optional enrichment; older servers lack /version.
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export async function collectStatusHealthFacts(args: {
|
|
189
|
+
client: HindsightLikeClient;
|
|
190
|
+
config: ResolvedConfig;
|
|
191
|
+
projectBankId: string;
|
|
192
|
+
}): Promise<StatusHealthFacts> {
|
|
193
|
+
const facts: StatusHealthFacts = [];
|
|
194
|
+
try {
|
|
195
|
+
if (args.client.health) await withStatusTimeout(args.client.health(), "Hindsight health");
|
|
196
|
+
facts.push(["Server", "reachable"]);
|
|
197
|
+
const versionFact = await serverVersionFact(args.client);
|
|
198
|
+
if (versionFact) facts.push(versionFact);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
facts.push(["Server", `unreachable · ${redactError(error)}`]);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const routes = bankRoutes(args.config, args.projectBankId);
|
|
204
|
+
if (!routes.length) return [...facts, ["Banks", "none configured"]];
|
|
205
|
+
for (const route of routes) facts.push(...(await bankFact(args.client, route)));
|
|
206
|
+
return facts;
|
|
207
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import type { ResolvedConfig, StatusStyle } from "../types.js";
|
|
3
|
+
|
|
4
|
+
export type HindsightActivity =
|
|
5
|
+
| "idle"
|
|
6
|
+
| "connected"
|
|
7
|
+
| "offline"
|
|
8
|
+
| "recalling"
|
|
9
|
+
| "recalled"
|
|
10
|
+
| "recall-empty"
|
|
11
|
+
| "recall-failed"
|
|
12
|
+
| "retaining"
|
|
13
|
+
| "retained"
|
|
14
|
+
| "retain-queued"
|
|
15
|
+
| "retain-failed"
|
|
16
|
+
| "importing"
|
|
17
|
+
| "imported"
|
|
18
|
+
| "import-queued"
|
|
19
|
+
| "import-failed";
|
|
20
|
+
|
|
21
|
+
export interface HindsightStatusState {
|
|
22
|
+
projectBankId: string;
|
|
23
|
+
cwd: string;
|
|
24
|
+
activity: HindsightActivity;
|
|
25
|
+
memoryCount?: number;
|
|
26
|
+
queueRemaining?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function truncate(value: string, max: number): string {
|
|
30
|
+
if (max <= 0) return "";
|
|
31
|
+
if (value.length <= max) return value;
|
|
32
|
+
return `${value.slice(0, Math.max(1, max - 1))}…`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function shortProject(cwd: string, max: number): string {
|
|
36
|
+
return truncate(basename(cwd) || "project", max);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function shortBank(bankId: string, max: number): string {
|
|
40
|
+
return truncate(bankId.replace(/^pi-project-/, ""), max);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function formatHindsightActivity(
|
|
44
|
+
activity: HindsightActivity,
|
|
45
|
+
memoryCount?: number,
|
|
46
|
+
queueRemaining?: number,
|
|
47
|
+
): string {
|
|
48
|
+
switch (activity) {
|
|
49
|
+
case "connected":
|
|
50
|
+
return "connected";
|
|
51
|
+
case "offline":
|
|
52
|
+
return "offline";
|
|
53
|
+
case "recalling":
|
|
54
|
+
return "recalling";
|
|
55
|
+
case "recalled":
|
|
56
|
+
return memoryCount !== undefined ? `recalled:${memoryCount}` : "recalled";
|
|
57
|
+
case "recall-empty":
|
|
58
|
+
return "no-memory";
|
|
59
|
+
case "recall-failed":
|
|
60
|
+
return "recall-failed";
|
|
61
|
+
case "retaining":
|
|
62
|
+
return "retaining";
|
|
63
|
+
case "retained":
|
|
64
|
+
return queueRemaining ? `queued:${queueRemaining}` : "retained";
|
|
65
|
+
case "retain-queued":
|
|
66
|
+
return queueRemaining !== undefined ? `queued:${queueRemaining}` : "queued";
|
|
67
|
+
case "retain-failed":
|
|
68
|
+
return "retain-failed";
|
|
69
|
+
case "importing":
|
|
70
|
+
return "importing";
|
|
71
|
+
case "imported":
|
|
72
|
+
return queueRemaining ? `imported+queued:${queueRemaining}` : "imported";
|
|
73
|
+
case "import-queued":
|
|
74
|
+
return queueRemaining !== undefined ? `import-queued:${queueRemaining}` : "import-queued";
|
|
75
|
+
case "import-failed":
|
|
76
|
+
return "import-failed";
|
|
77
|
+
default:
|
|
78
|
+
return "idle";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function prefix(style: StatusStyle, activity: HindsightActivity): string {
|
|
83
|
+
if (style === "emoji") {
|
|
84
|
+
if (activity.includes("failed") || activity === "offline") return "🤯";
|
|
85
|
+
return "🧠";
|
|
86
|
+
}
|
|
87
|
+
if (style === "nerdfont") {
|
|
88
|
+
if (activity.includes("failed") || activity === "offline") return "";
|
|
89
|
+
if (activity === "recalling" || activity === "recalled") return "";
|
|
90
|
+
if (activity === "retaining" || activity === "retained") return "";
|
|
91
|
+
if (activity === "importing" || activity === "imported" || activity === "import-queued")
|
|
92
|
+
return "";
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
return "mem";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function formatHindsightStatus(
|
|
99
|
+
config: ResolvedConfig,
|
|
100
|
+
state: HindsightStatusState,
|
|
101
|
+
): string | undefined {
|
|
102
|
+
if (!config.enabled) return undefined;
|
|
103
|
+
const { style, detail, maxLength, showActivity } = config.status;
|
|
104
|
+
if (style === "off") return undefined;
|
|
105
|
+
const p = prefix(style, state.activity);
|
|
106
|
+
const project = shortProject(state.cwd, Math.max(4, maxLength));
|
|
107
|
+
const bank = shortBank(state.projectBankId, Math.max(8, maxLength));
|
|
108
|
+
const activity = showActivity
|
|
109
|
+
? formatHindsightActivity(state.activity, state.memoryCount, state.queueRemaining)
|
|
110
|
+
: "idle";
|
|
111
|
+
|
|
112
|
+
let body: string;
|
|
113
|
+
if (detail === "minimal") body = "";
|
|
114
|
+
else if (detail === "project") body = bank;
|
|
115
|
+
else if (detail === "activity") body = activity;
|
|
116
|
+
else body = `${project}:${bank}:${activity}`;
|
|
117
|
+
|
|
118
|
+
const separator = style === "text" ? ":" : " ";
|
|
119
|
+
return truncate(body ? `${p}${separator}${body}` : p, maxLength);
|
|
120
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const PI_HINDSIGHT_VERSION = "0.12.0"; // x-release-please-version
|
|
2
|
+
export const PI_HINDSIGHT_USER_AGENT = `pi-hindsight/${PI_HINDSIGHT_VERSION}`;
|
|
3
|
+
|
|
4
|
+
export const PI_HINDSIGHT_SUPPORTED_NODE = ">=20";
|
|
5
|
+
export const PI_HINDSIGHT_SUPPORTED_NPM = ">=10";
|
|
6
|
+
export const PI_HINDSIGHT_CLIENT_PACKAGE = "@vectorize-io/hindsight-client";
|
|
7
|
+
export const PI_HINDSIGHT_CLIENT_RANGE = "^0.9.0";
|
|
8
|
+
export const PI_HINDSIGHT_SUPPORTED_TYPEBOX = ">=1.1.24 <2";
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@luxusai/pi-hindsight",
|
|
3
|
+
"version": "0.12.0",
|
|
4
|
+
"description": "Pi extension for durable Hindsight-backed long-term memory.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"hindsight",
|
|
7
|
+
"memory",
|
|
8
|
+
"pi",
|
|
9
|
+
"pi-package"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://luxus.github.io/pi-hindsight/",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/luxus/pi-hindsight/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/luxus/pi-hindsight.git"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"extensions",
|
|
22
|
+
"README.md",
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"docs/adr",
|
|
25
|
+
"docs/assets",
|
|
26
|
+
"docs/compatibility.md",
|
|
27
|
+
"docs/hindsight-core-functions.md",
|
|
28
|
+
"docs/risky-memory-modes.md",
|
|
29
|
+
"docs/next-opt-out-design.md",
|
|
30
|
+
"docs/surface-reference.md",
|
|
31
|
+
"docs/starter-mental-model-suggestions.md",
|
|
32
|
+
"docs/coding-memory-evaluation.md",
|
|
33
|
+
"docs/mission-and-mental-model-quality.md",
|
|
34
|
+
"skills"
|
|
35
|
+
],
|
|
36
|
+
"type": "module",
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"typecheck": "tsgo -p tsconfig.json --noEmit",
|
|
42
|
+
"typecheck:tsc": "tsc --noEmit",
|
|
43
|
+
"lint": "oxlint --type-aware --type-check extensions tests",
|
|
44
|
+
"lint:fix": "oxlint --type-aware --type-check --fix extensions tests",
|
|
45
|
+
"format": "oxfmt --check --no-error-on-unmatched-pattern \"extensions/**/*.ts\" \"tests/**/*.ts\" \"tests/**/*.mjs\" \"scripts/**/*.mjs\" \"scripts/**/*.ts\" \"docs/**/*.md\" \"README.md\" \"CONTEXT.md\" \"CONTRIBUTING.md\" \"SECURITY.md\" \"package.json\" \"package-lock.json\" \"tsconfig.json\" \"vitest.config.ts\" \".oxfmtrc.json\" \".commitlintrc.json\" \"*.yml\" \".github/**/*.yml\" \".github/**/*.md\" \"docs-site/src/content/docs/**/*.md\" \"docs-site/src/content/docs/**/*.mdx\" \"astro.config.mjs\" \"docs-site/src/content.config.ts\"",
|
|
46
|
+
"format:fix": "oxfmt --write --no-error-on-unmatched-pattern \"extensions/**/*.ts\" \"tests/**/*.ts\" \"tests/**/*.mjs\" \"scripts/**/*.mjs\" \"scripts/**/*.ts\" \"docs/**/*.md\" \"README.md\" \"CONTEXT.md\" \"CONTRIBUTING.md\" \"SECURITY.md\" \"package.json\" \"package-lock.json\" \"tsconfig.json\" \"vitest.config.ts\" \".oxfmtrc.json\" \".commitlintrc.json\" \"*.yml\" \".github/**/*.yml\" \".github/**/*.md\" \"docs-site/src/content/docs/**/*.md\" \"docs-site/src/content/docs/**/*.mdx\" \"astro.config.mjs\" \"docs-site/src/content.config.ts\"",
|
|
47
|
+
"surface-reference": "tsx scripts/generate-surface-reference.ts",
|
|
48
|
+
"surface-reference:check": "tsx scripts/generate-surface-reference.ts --check",
|
|
49
|
+
"check": "npm run docs:check && npm run format && npm run lint && npm run typecheck && npm test",
|
|
50
|
+
"check:ci": "npm run check && npm run check:coverage",
|
|
51
|
+
"check:release": "npm run check && npm run check:coverage && npm run typecheck:tsc && npm run audit:signatures && npm run pack:verify && npm run smoke:hindsight",
|
|
52
|
+
"install-hooks": "node scripts/install-hooks.mjs",
|
|
53
|
+
"prepare": "npm run install-hooks",
|
|
54
|
+
"precommit": "npm run check",
|
|
55
|
+
"test": "vitest run",
|
|
56
|
+
"smoke:hindsight": "tsx scripts/smoke-hindsight.ts",
|
|
57
|
+
"bench:memory": "tsx scripts/bench-memory.ts",
|
|
58
|
+
"changelog": "node scripts/generate-changelog.mjs",
|
|
59
|
+
"version": "npm run changelog && npm run format:fix && git add CHANGELOG.md",
|
|
60
|
+
"test:coverage": "vitest run --coverage",
|
|
61
|
+
"check:coverage": "npm run test:coverage",
|
|
62
|
+
"pack:verify": "npm run release:verify && npm pack --dry-run && node scripts/install-smoke.mjs",
|
|
63
|
+
"audit:signatures": "npm audit signatures",
|
|
64
|
+
"release:verify": "node scripts/verify-release.mjs",
|
|
65
|
+
"pr:check": "node scripts/check-pr-body.mjs",
|
|
66
|
+
"docs:dev": "astro dev",
|
|
67
|
+
"docs:build": "astro build",
|
|
68
|
+
"docs:links": "node scripts/check-docs.mjs",
|
|
69
|
+
"docs:check": "npm run surface-reference:check && npm run code-map:check && npm run docs:links && npm run docs:build",
|
|
70
|
+
"code-map": "node scripts/generate-code-map.mjs",
|
|
71
|
+
"code-map:check": "node scripts/generate-code-map.mjs --check"
|
|
72
|
+
},
|
|
73
|
+
"dependencies": {
|
|
74
|
+
"@vectorize-io/hindsight-client": "^0.9.0",
|
|
75
|
+
"jsonc-parser": "^3.3.1"
|
|
76
|
+
},
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"@astrojs/starlight": "^0.41.3",
|
|
79
|
+
"@commitlint/cli": "^21.0.0",
|
|
80
|
+
"@commitlint/config-conventional": "^21.0.1",
|
|
81
|
+
"@earendil-works/pi-agent-core": "0.84.1",
|
|
82
|
+
"@earendil-works/pi-coding-agent": "0.84.1",
|
|
83
|
+
"@earendil-works/pi-tui": "0.84.1",
|
|
84
|
+
"@mermaid-js/layout-elk": "^0.2.1",
|
|
85
|
+
"@types/node": "^25.9.1",
|
|
86
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
87
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
88
|
+
"astro": "^7.0.6",
|
|
89
|
+
"astro-mermaid": "^2.0.1",
|
|
90
|
+
"mermaid": "^11.14.0",
|
|
91
|
+
"oxfmt": "^0.56.0",
|
|
92
|
+
"oxlint": "^1.61.0",
|
|
93
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
94
|
+
"starlight-llm-button": "^0.0.8",
|
|
95
|
+
"tsx": "4.23.0",
|
|
96
|
+
"typebox": "1.3.9",
|
|
97
|
+
"typescript": "^7.0.2",
|
|
98
|
+
"vitest": "^4.1.5"
|
|
99
|
+
},
|
|
100
|
+
"peerDependencies": {
|
|
101
|
+
"@earendil-works/pi-agent-core": "*",
|
|
102
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
103
|
+
"@earendil-works/pi-tui": "*",
|
|
104
|
+
"typebox": ">=1.1.24 <2"
|
|
105
|
+
},
|
|
106
|
+
"engines": {
|
|
107
|
+
"node": ">=20",
|
|
108
|
+
"npm": ">=10"
|
|
109
|
+
},
|
|
110
|
+
"pi": {
|
|
111
|
+
"extensions": [
|
|
112
|
+
"./extensions"
|
|
113
|
+
],
|
|
114
|
+
"skills": [
|
|
115
|
+
"./skills"
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hindsight-memory-doctor
|
|
3
|
+
description: >
|
|
4
|
+
Self-check Pi Hindsight memory when the user is frustrated, confused, or
|
|
5
|
+
complains about memory quality (wrong prefs, missing context, "it forgot",
|
|
6
|
+
"never ask questions" vs wants questions, empty inject, wrong project).
|
|
7
|
+
Inspect status/scope/mental models/bank missions, compare to quality docs,
|
|
8
|
+
propose dry-run fixes. Trigger on memory complaints, "memory is wrong",
|
|
9
|
+
"forgot", "why did it inject", /hindsight-memory-doctor, or conflict with
|
|
10
|
+
recalled/MM content. Do NOT run every turn.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Hindsight memory doctor
|
|
14
|
+
|
|
15
|
+
When the user is **upset or skeptical about memory**, behave like a careful human under conflict: **stop, inspect, question the memory stack**, then propose a small fix. Do not argue from broken inject. Do not mutate banks silently.
|
|
16
|
+
|
|
17
|
+
Authoritative criteria: `docs/mission-and-mental-model-quality.md` (packaged; also docs-site _Mission and mental-model quality_).
|
|
18
|
+
|
|
19
|
+
## Trigger (yes)
|
|
20
|
+
|
|
21
|
+
- User complains about memory / Hindsight / inject / prefs / “forgot” / wrong project context
|
|
22
|
+
- Injected MM or recall **contradicts** the user (e.g. “do not ask questions” vs wants high-signal questions)
|
|
23
|
+
- User asks why memory looks wrong or empty
|
|
24
|
+
- Explicit `/skill:hindsight-memory-doctor`
|
|
25
|
+
|
|
26
|
+
## Do not trigger
|
|
27
|
+
|
|
28
|
+
- Normal coding with healthy inject
|
|
29
|
+
- Single imperfect recall hit
|
|
30
|
+
- Every turn “maybe refresh?”
|
|
31
|
+
|
|
32
|
+
## Workflow (always)
|
|
33
|
+
|
|
34
|
+
1. **Acknowledge** the complaint in one line. Treat it as a possible **system** issue, not only user error.
|
|
35
|
+
2. **Inspect** (tools; no dry-run needed for reads):
|
|
36
|
+
- `hindsight_status`
|
|
37
|
+
- `hindsight_scope`
|
|
38
|
+
- `hindsight_mental_model` action=list (coding bank; life/user if enabled)
|
|
39
|
+
- `hindsight_mental_model` action=get for broken/suspicious ids
|
|
40
|
+
- `hindsight_bank` action=get for coding (and life if enabled) — missions
|
|
41
|
+
3. **Score against the quality guide** (priority order):
|
|
42
|
+
1. Broken/empty MM content (`#`, empty, Generating…) — prefs MMs may need `fact_types` world+experience+observation, not observation-only
|
|
43
|
+
2. Prefs contradict the user
|
|
44
|
+
3. Missing starters for **this** `project:<id>`
|
|
45
|
+
4. Fat inject / truncation
|
|
46
|
+
5. Mission noise (only if multi-session pattern)
|
|
47
|
+
6. Polish-only → skip
|
|
48
|
+
4. **Propose** a short plan (max 3 actions). Prefer:
|
|
49
|
+
- explicit retain of the **correct** durable fact
|
|
50
|
+
- refresh (or clear+refresh if delta-drift)
|
|
51
|
+
- create missing starters for this project
|
|
52
|
+
- mission patch only if extraction is systematically wrong
|
|
53
|
+
5. **Dry-run first** for any mutation (`hindsight_mental_model` / `hindsight_bank` dryRun true). Apply only after user ok (`dryRun: false` or hub).
|
|
54
|
+
6. **Verify** list/get again. Note inject cache may lag (`mentalModels.cacheTtlMs`, often ~5 min) — new session or wait.
|
|
55
|
+
|
|
56
|
+
## Output shape
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
Memory doctor
|
|
60
|
+
- What I checked: …
|
|
61
|
+
- What’s wrong (priority): …
|
|
62
|
+
- Proposed fixes (dry-run): …
|
|
63
|
+
- Not doing: … (noise / other projects / silent rewrite)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Hard rules
|
|
67
|
+
|
|
68
|
+
- Never silent create/update/delete of mental models or missions.
|
|
69
|
+
- Never edit another project’s `project:<other>` models to “fix” this session.
|
|
70
|
+
- Same-turn retain + rely-on-recall is invalid; refresh after retain has landed.
|
|
71
|
+
- If tools unavailable / setup incomplete: say so and point to `/hindsight` setup.
|
|
72
|
+
|
|
73
|
+
## Optional user invoke
|
|
74
|
+
|
|
75
|
+
`/skill:hindsight-memory-doctor` — run full workflow once.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narumitw/pi-btw",
|
|
3
|
-
"version": "0.55.
|
|
3
|
+
"version": "0.55.4",
|
|
4
4
|
"description": "Pi extension that adds a /btw side-question command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"directory": "packages/pi-btw"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@narumitw/pi-tui-kit": "^0.
|
|
50
|
+
"@narumitw/pi-tui-kit": "^0.59.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"@earendil-works/pi-ai": "*",
|
|
@@ -41,7 +41,7 @@ The extension requires `enabledModels` to exist before it can save a pin. If
|
|
|
41
41
|
the selected model is not listed, it adds an exact entry without removing other
|
|
42
42
|
models or patterns.
|
|
43
43
|
|
|
44
|
-
The old
|
|
44
|
+
The old `$PI_CODING_AGENT_DIR/extensions/pi-preferred-thinking.json` file is no longer
|
|
45
45
|
read. Existing users must move preferences to `enabledModels` or set them with
|
|
46
46
|
`/preferred-thinking`.
|
|
47
47
|
|
|
@@ -138,6 +138,15 @@ function showHint(ctx: ExtensionContext, modelKey: string): void {
|
|
|
138
138
|
}, HINT_DURATION_MS)
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
function hasExplicitSubagentThinking(): boolean {
|
|
142
|
+
return (
|
|
143
|
+
Boolean(process.env["PI_SUBAGENT_ID"]) &&
|
|
144
|
+
process.argv.some(
|
|
145
|
+
(arg) => arg === "--thinking" || arg.startsWith("--thinking="),
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
141
150
|
function applyPreferredThinking(
|
|
142
151
|
pi: ExtensionAPI,
|
|
143
152
|
ctx: ExtensionContext,
|
|
@@ -210,11 +219,15 @@ export default function (pi: ExtensionAPI): void {
|
|
|
210
219
|
|
|
211
220
|
pi.on("session_start", async (_event, ctx) => {
|
|
212
221
|
nudgedModels.clear()
|
|
213
|
-
if (ctx.model
|
|
222
|
+
if (ctx.model && !hasExplicitSubagentThinking()) {
|
|
223
|
+
applyPreferredThinking(pi, ctx, ctx.model)
|
|
224
|
+
}
|
|
214
225
|
})
|
|
215
226
|
|
|
216
227
|
pi.on("model_select", async (event, ctx) => {
|
|
217
|
-
|
|
228
|
+
if (!hasExplicitSubagentThinking()) {
|
|
229
|
+
applyPreferredThinking(pi, ctx, event.model)
|
|
230
|
+
}
|
|
218
231
|
})
|
|
219
232
|
|
|
220
233
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.30.0] - 2026-08-28
|
|
11
|
+
|
|
12
|
+
### Highlights
|
|
13
|
+
- Other extensions can safely inspect one runtime MCP server without seeing the whole MCP config.
|
|
14
|
+
- OAuth setup works better with providers that publish authorization metadata at a custom URL.
|
|
15
|
+
- MCP tool names are safer for providers, including servers with non-ASCII names.
|
|
16
|
+
- Token CLI commands and Windows request-header cleanup are less fragile in installed packages and long-running sessions.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Added a fail-closed API for child extensions to inspect one selected runtime MCP server without exporting configured servers or persisting the registration. (#453)
|
|
21
|
+
- Added `oauth.authServerMetadataUrl` for servers whose authorization-server metadata cannot be discovered through MCP protected-resource metadata. Thanks to [@fmoda3](https://github.com/fmoda3) for #458.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Namespace proxy tool names now use provider-safe characters without making encoded-looking server names collide with non-ASCII server names. Thanks to [@nyankosama](https://github.com/nyankosama) for PR #463.
|
|
26
|
+
- npm-installed token CLI commands now load their credential, config, and utility helpers from the published JavaScript build instead of package-local TypeScript files. Thanks to [@Qhilm](https://github.com/Qhilm) for #456.
|
|
27
|
+
- Server-scoped MCP calls now resolve raw upstream tool names before normalized fallbacks without weakening ambiguity checks. Thanks to [@MikeLP](https://github.com/MikeLP) for #452.
|
|
28
|
+
- Windows request-header command cleanup now treats an already-exited process (`taskkill` exit code 128) as successful cleanup. Thanks to [@peterxcx](https://github.com/peterxcx) for #457.
|
|
29
|
+
|
|
30
|
+
## [2.29.0] - 2026-08-26
|
|
31
|
+
|
|
32
|
+
### Highlights
|
|
33
|
+
- `/mcp setup` can now add Parallel Search as an opt-in preset.
|
|
34
|
+
- Users can try web search and page fetching without first creating an API key.
|
|
35
|
+
- MCP status updates work better in non-TUI hosts that provide plain theme values.
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- Added an opt-in Parallel Search preset to `/mcp setup` for web search and page fetching without an API key. Thanks to [@georgeatparallel](https://github.com/georgeatparallel) for PR #448.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
- MCP status updates now use plain text when a non-TUI host provides a theme without styling methods. Thanks to [@jinnnyang](https://github.com/jinnnyang) for #449.
|
|
42
|
+
|
|
10
43
|
## [2.28.0] - 2026-08-26
|
|
11
44
|
|
|
12
45
|
### Highlights
|
|
@@ -276,6 +276,7 @@ In the configuration examples below, `30000` is illustrative only. If `requestTi
|
|
|
276
276
|
| `oauth.clientName` | Client display name advertised during Dynamic Client Registration fallback |
|
|
277
277
|
| `oauth.clientUri` | Client homepage URI advertised during Dynamic Client Registration fallback. Defaults to `piConfig.clientUri` from the host's manifest when set, and is omitted rather than guessed under a rebranded host |
|
|
278
278
|
| `oauth.logoUri` | Client logo URL advertised during Dynamic Client Registration fallback (RFC 7591 `logo_uri`). Must be an absolute `http(s)` URL — consent screens fetch it server-side, so local paths render nothing. Omitted from the registration request when unset |
|
|
279
|
+
| `oauth.authServerMetadataUrl` | HTTPS URL of an OAuth/OIDC authorization-server metadata document. When set, this document is authoritative instead of MCP protected-resource discovery; its issuer remains validated by default |
|
|
279
280
|
| `oauth.skipIssuerMetadataValidation` | `true` disables the OAuth authorization-server metadata issuer check for this server. This weakens OAuth mix-up protection and should only be used for known-misconfigured internal servers while their metadata is being fixed. |
|
|
280
281
|
| `bearerToken` / `bearerTokenEnv` | Token or env var name; `bearerToken` supports `${VAR}` and `$env:VAR` interpolation. A leading `!` in `bearerToken` runs a command when the HTTP server connects; use `!!` for a literal leading `!`. |
|
|
281
282
|
| `bearerTokenStore` | Set to `true` to read a static bearer token from the adapter-owned OS credential store when `auth` is `"bearer"` and no `bearerToken` or `bearerTokenEnv` is configured. Stored records are keyed only by the server name, bind to the resolved server URL, and are never named by config. Store a token with `pi-mcp-adapter token set <server>`, which reads it from a masked prompt or stdin pipe and never from an argument. `/mcp token status <server>` and `/mcp token remove <server>` manage non-secret state inside Pi; `/mcp token set` stays disabled until Pi exposes masked secret input. |
|
|
@@ -307,6 +308,8 @@ For pre-registered browser OAuth clients, set `oauth.redirectUri` to the exact c
|
|
|
307
308
|
|
|
308
309
|
If an internal authorization server publishes mismatched OAuth metadata and cannot be fixed immediately, set `oauth.skipIssuerMetadataValidation: true` on that server only. This is security-weakening. It disables the RFC 8414 issuer echo check and should not be used for public or untrusted servers.
|
|
309
310
|
|
|
311
|
+
If an MCP server does not publish usable protected-resource metadata, set `oauth.authServerMetadataUrl` to its HTTPS OAuth/OIDC authorization-server metadata document. The configured document is used authoritatively, while issuer validation remains enabled by default. This is trusted configuration; use it only for a metadata endpoint you control or explicitly trust.
|
|
312
|
+
|
|
310
313
|
Secret values in `headers`, `bearerToken`, `oauth.clientSecret`, and stdio `env` may use a leading `!command` to obtain their value at connection or authentication time. The command runs with stdin and stderr suppressed, stdout is limited to 1 MiB and trimmed, and it must finish within 10 seconds with non-empty output; failures stop the connection or authentication flow. Commands are not run during OAuth discovery or while reading, merging, previewing, hashing, or rendering configuration. Use `!!` to escape a literal leading `!`; ordinary and escaped values retain environment interpolation.
|
|
311
314
|
|
|
312
315
|
For local desktop bearer tokens, `bearerTokenStore: true` can opt in to the adapter-owned credential-store namespace. It never falls back to plaintext if the store is unavailable, if the stored record is malformed, or if the stored URL differs from the effective server URL. Literal tokens, command tokens, and environment tokens keep precedence so existing configs do not change. Create or rotate a stored token with `pi-mcp-adapter token set <server>` (masked prompt on a terminal, or piped stdin such as `security find-generic-password -s my-token -w | pi-mcp-adapter token set <server>`); the record binds to the effective configured URL at write time. Token commands need Node 22.18+.
|