@rol1n/pi-kit 0.1.0 → 0.1.1

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.
Files changed (149) hide show
  1. package/README.md +33 -58
  2. package/ask-u-questions/README.md +26 -0
  3. package/{extensions/ask-u-questions → ask-u-questions}/dialog-ui.ts +23 -0
  4. package/{extensions/ask-u-questions → ask-u-questions}/index.ts +9 -5
  5. package/{extensions/ask-u-questions → ask-u-questions}/multi-choice.ts +1 -3
  6. package/{extensions/ask-u-questions → ask-u-questions}/single-choice.ts +1 -3
  7. package/{extensions/ask-u-questions → ask-u-questions}/tool-renderers.ts +1 -3
  8. package/ask-u-questions/types.ts +192 -0
  9. package/continue-signal/README.md +20 -0
  10. package/{extensions/continue-signal → continue-signal}/index.ts +21 -3
  11. package/custom-providers/README.md +20 -0
  12. package/{extensions/custom-providers → custom-providers}/index.ts +16 -2
  13. package/image-generate/README.md +25 -0
  14. package/{extensions/image-generate → image-generate}/index.ts +22 -2
  15. package/{extensions/image-generate → image-generate}/model-selector.ts +1 -1
  16. package/model-vision/README.md +22 -0
  17. package/{extensions/multi-harness → multi-harness}/README.md +3 -3
  18. package/oai-subquota/README.md +22 -0
  19. package/{extensions/oai-subquota → oai-subquota}/index.ts +16 -6
  20. package/{extensions/oai-subquota → oai-subquota}/snapshot.ts +127 -1
  21. package/{extensions/oai-subquota → oai-subquota}/ui.ts +1 -1
  22. package/package.json +45 -46
  23. package/prompt-snipaste/README.md +27 -0
  24. package/{extensions/prompt-snipaste → prompt-snipaste}/renderers.ts +0 -1
  25. package/{extensions/prompt-snipaste → prompt-snipaste}/snippets.ts +5 -2
  26. package/{extensions/prompt-snipaste → prompt-snipaste}/types.ts +0 -1
  27. package/screenshot/README.md +14 -0
  28. package/srp-theme/README.md +18 -0
  29. package/{extensions/srp-theme → srp-theme}/footer.ts +0 -1
  30. package/{extensions/srp-theme → srp-theme}/tps-meter.ts +0 -1
  31. package/{extensions/subagent → subagent}/README.md +1 -1
  32. package/tui-asr/README.md +21 -0
  33. package/{extensions/tui-asr → tui-asr}/dictation.ts +70 -3
  34. package/{extensions/tui-asr → tui-asr}/index.ts +2 -2
  35. package/{extensions/tui-asr → tui-asr}/input.ts +30 -1
  36. package/{extensions/tui-asr → tui-asr}/model-selector.ts +1 -1
  37. package/web-reach/README.md +19 -0
  38. package/{extensions/web-reach → web-reach}/page.ts +84 -2
  39. package/windows-wheel-fix/README.md +12 -0
  40. package/extensions/ask-u-questions/README.md +0 -32
  41. package/extensions/ask-u-questions/answers.ts +0 -53
  42. package/extensions/ask-u-questions/results.ts +0 -83
  43. package/extensions/ask-u-questions/schema.ts +0 -17
  44. package/extensions/ask-u-questions/types.ts +0 -45
  45. package/extensions/ask-u-questions/ui-lock.ts +0 -24
  46. package/extensions/continue-signal/README.md +0 -28
  47. package/extensions/continue-signal/renderer.ts +0 -21
  48. package/extensions/custom-providers/README.md +0 -28
  49. package/extensions/image-generate/README.md +0 -29
  50. package/extensions/image-generate/models.ts +0 -19
  51. package/extensions/model-vision/README.md +0 -28
  52. package/extensions/oai-subquota/README.md +0 -30
  53. package/extensions/oai-subquota/api.ts +0 -27
  54. package/extensions/oai-subquota/auth.ts +0 -34
  55. package/extensions/oai-subquota/cache.ts +0 -30
  56. package/extensions/oai-subquota/types.ts +0 -40
  57. package/extensions/prompt-snipaste/README.md +0 -33
  58. package/extensions/screenshot/README.md +0 -25
  59. package/extensions/srp-theme/README.md +0 -24
  60. package/extensions/subagent/skills/subagent/SKILL.md +0 -70
  61. package/extensions/tui-asr/README.md +0 -28
  62. package/extensions/tui-asr/audio.ts +0 -40
  63. package/extensions/tui-asr/clipboard.ts +0 -30
  64. package/extensions/tui-asr/providers.ts +0 -25
  65. package/extensions/web-reach/README.md +0 -37
  66. package/extensions/web-reach/pdf.ts +0 -42
  67. package/extensions/web-reach/reader.ts +0 -42
  68. package/extensions/windows-wheel-fix/README.md +0 -21
  69. /package/{extensions/custom-providers → custom-providers}/asr/handlers/dashscope.ts +0 -0
  70. /package/{extensions/custom-providers → custom-providers}/asr/index.ts +0 -0
  71. /package/{extensions/custom-providers → custom-providers}/asr/models.ts +0 -0
  72. /package/{extensions/custom-providers → custom-providers}/asr/types.ts +0 -0
  73. /package/{extensions/custom-providers → custom-providers}/chat/index.ts +0 -0
  74. /package/{extensions/custom-providers → custom-providers}/chat/magpie.ts +0 -0
  75. /package/{extensions/custom-providers → custom-providers}/chat/models.ts +0 -0
  76. /package/{extensions/custom-providers → custom-providers}/classifier/index.ts +0 -0
  77. /package/{extensions/custom-providers → custom-providers}/classifier/models.ts +0 -0
  78. /package/{extensions/custom-providers → custom-providers}/image/handlers/dashscope.ts +0 -0
  79. /package/{extensions/custom-providers → custom-providers}/image/handlers/openrouter.ts +0 -0
  80. /package/{extensions/custom-providers → custom-providers}/image/index.ts +0 -0
  81. /package/{extensions/custom-providers → custom-providers}/image/models.ts +0 -0
  82. /package/{extensions/custom-providers → custom-providers}/image/types.ts +0 -0
  83. /package/{extensions/custom-providers → custom-providers}/types.ts +0 -0
  84. /package/{extensions/image-generate → image-generate}/files.ts +0 -0
  85. /package/{extensions/memory-log → memory-log}/README.md +0 -0
  86. /package/{extensions/memory-log → memory-log}/agent/consolidator/prompt.ts +0 -0
  87. /package/{extensions/memory-log → memory-log}/agent/consolidator/tools.ts +0 -0
  88. /package/{extensions/memory-log → memory-log}/agent/cost.ts +0 -0
  89. /package/{extensions/memory-log → memory-log}/agent/index.ts +0 -0
  90. /package/{extensions/memory-log → memory-log}/agent/observer/prompt.ts +0 -0
  91. /package/{extensions/memory-log → memory-log}/agent/observer/tool.ts +0 -0
  92. /package/{extensions/memory-log → memory-log}/commands/compact.ts +0 -0
  93. /package/{extensions/memory-log → memory-log}/commands/consolidate.ts +0 -0
  94. /package/{extensions/memory-log → memory-log}/commands/status.ts +0 -0
  95. /package/{extensions/memory-log → memory-log}/config.ts +0 -0
  96. /package/{extensions/memory-log → memory-log}/debug-log.ts +0 -0
  97. /package/{extensions/memory-log → memory-log}/hooks/compaction-hook.ts +0 -0
  98. /package/{extensions/memory-log → memory-log}/hooks/compaction-trigger.ts +0 -0
  99. /package/{extensions/memory-log → memory-log}/hooks/consolidator-trigger.ts +0 -0
  100. /package/{extensions/memory-log → memory-log}/hooks/observer-trigger.ts +0 -0
  101. /package/{extensions/memory-log → memory-log}/ids.ts +0 -0
  102. /package/{extensions/memory-log → memory-log}/index.ts +0 -0
  103. /package/{extensions/memory-log → memory-log}/ledger/fold.ts +0 -0
  104. /package/{extensions/memory-log → memory-log}/ledger/index.ts +0 -0
  105. /package/{extensions/memory-log → memory-log}/ledger/pool.ts +0 -0
  106. /package/{extensions/memory-log → memory-log}/ledger/progress.ts +0 -0
  107. /package/{extensions/memory-log → memory-log}/ledger/projection.ts +0 -0
  108. /package/{extensions/memory-log → memory-log}/ledger/render.ts +0 -0
  109. /package/{extensions/memory-log → memory-log}/ledger/serialize.ts +0 -0
  110. /package/{extensions/memory-log → memory-log}/ledger/types.ts +0 -0
  111. /package/{extensions/memory-log → memory-log}/memory/index-render.ts +0 -0
  112. /package/{extensions/memory-log → memory-log}/memory/paths.ts +0 -0
  113. /package/{extensions/memory-log → memory-log}/memory/session.ts +0 -0
  114. /package/{extensions/memory-log → memory-log}/runtime.ts +0 -0
  115. /package/{extensions/memory-log → memory-log}/spawn/launch.ts +0 -0
  116. /package/{extensions/memory-log → memory-log}/spawn/runs.ts +0 -0
  117. /package/{extensions/memory-log → memory-log}/tokens.ts +0 -0
  118. /package/{extensions/memory-log → memory-log}/ui/status-controller.ts +0 -0
  119. /package/{extensions/memory-log → memory-log}/ui/timeline.ts +0 -0
  120. /package/{extensions/multi-harness → multi-harness}/adapters.mjs +0 -0
  121. /package/{extensions/multi-harness → multi-harness}/harness-done.mjs +0 -0
  122. /package/{extensions/multi-harness → multi-harness}/index.ts +0 -0
  123. /package/{extensions/multi-harness → multi-harness}/ipc.mjs +0 -0
  124. /package/{extensions/multi-harness → multi-harness}/opencode-plugin.mjs +0 -0
  125. /package/{extensions/multi-harness → multi-harness}/process-runner.mjs +0 -0
  126. /package/{extensions/multi-harness → multi-harness}/turn-hook.mjs +0 -0
  127. /package/{extensions/multi-harness → multi-harness}/worker-bridge.ts +0 -0
  128. /package/{extensions/prompt-snipaste → prompt-snipaste}/index.ts +0 -0
  129. /package/{extensions/prompt-snipaste → prompt-snipaste}/menu.ts +0 -0
  130. /package/{prompts → prompt-snipaste/prompts}/ask-questions.md +0 -0
  131. /package/{prompts → prompt-snipaste/prompts}/delegate-exploration.md +0 -0
  132. /package/{prompts → prompt-snipaste/prompts}/diagnose-report.md +0 -0
  133. /package/{prompts → prompt-snipaste/prompts}/frontend-tech-preset.md +0 -0
  134. /package/{prompts → prompt-snipaste/prompts}/orchestrator-mode.md +0 -0
  135. /package/{prompts → prompt-snipaste/prompts}/session-kickoff.md +0 -0
  136. /package/{prompts → prompt-snipaste/prompts}/verify-not-assume.md +0 -0
  137. /package/{extensions/srp-theme → srp-theme}/index.ts +0 -0
  138. /package/{extensions/subagent → subagent}/bridge.ts +0 -0
  139. /package/{extensions/subagent → subagent}/index.ts +0 -0
  140. /package/{extensions/subagent → subagent}/mux.ts +0 -0
  141. /package/{extensions/subagent → subagent}/session.ts +0 -0
  142. /package/{extensions/subagent → subagent}/ui.ts +0 -0
  143. /package/{extensions/tui-asr → tui-asr}/status.ts +0 -0
  144. /package/{extensions/web-reach → web-reach}/html.ts +0 -0
  145. /package/{extensions/web-reach → web-reach}/index.ts +0 -0
  146. /package/{extensions/web-reach → web-reach}/rsc.ts +0 -0
  147. /package/{extensions/web-reach → web-reach}/search.ts +0 -0
  148. /package/{extensions/web-reach → web-reach}/transport.ts +0 -0
  149. /package/{extensions/windows-wheel-fix → windows-wheel-fix}/index.ts +0 -0
@@ -14,10 +14,10 @@ Also included in `@rol1n/pi-kit`. Enable one copy of the extension.
14
14
 
15
15
  ## Use
16
16
 
17
- Load `extensions/multi-harness` through the aggregate package, or run from this repository:
17
+ Load `multi-harness` through the aggregate package, or run from this repository:
18
18
 
19
19
  ```sh
20
- pi --no-extensions -e ./extensions/multi-harness/index.ts
20
+ pi --no-extensions -e ./multi-harness/index.ts
21
21
  ```
22
22
 
23
23
  Example tool calls:
@@ -60,4 +60,4 @@ Session entries record only worker artifact locations. On session restore/reload
60
60
  - Windows requires PowerShell 7 (`pwsh`) for external CLI invocation. Encoded PowerShell commands preserve Unicode, multiline tasks, JSON, and quoted paths. CLI hooks and `harness-done.cmd`/`.ps1` wrappers use the same native Windows Node installation. A mux must be available for visible TUIs; otherwise process fallback applies.
61
61
  - Existing worktrees, reports, and sessions created by the removed `worktree-studio` extension are left untouched. Its old `the_road_not_taken` tool and two-route manifests are not imported into this runtime. Synchronize platform resources/reload before using the new tool; old running workers should be finished before upgrading.
62
62
 
63
- Validation scripts are kept outside the repository. Check extension loading from this repository with `pi --no-extensions -e ./extensions/multi-harness/index.ts --list-models '<filter>'`.
63
+ Validation scripts are kept outside the repository. Check extension loading from this repository with `pi --no-extensions -e ./multi-harness/index.ts --list-models '<filter>'`.
@@ -0,0 +1,22 @@
1
+ # oai-subquota
2
+
3
+ Monitor OpenAI Codex subscription quota (5-hour and 7-day windows, resets, and credits) when using the `openai-codex` provider.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ pi install npm:@rol1n/oai-subquota
9
+ ```
10
+
11
+ Also included in `@rol1n/pi-kit`.
12
+
13
+ ## Commands
14
+
15
+ | Command | Action |
16
+ |---|---|
17
+ | `/oai-subquota codex` | Render boxed quota summary and refresh footer |
18
+ | `/oai-subquota refresh` | Force a fresh backend query |
19
+ | `/oai-subquota statusline` | Print compact single-line quota text |
20
+ | `/oai-subquota chatgpt` | Inspect parked ChatGPT OAuth quota status |
21
+
22
+ Authenticate with `/login openai-codex`. Snapshots are cached under `$XDG_CACHE_HOME/oai-subquota/usage.json` (or `~/.cache/oai-subquota/usage.json`) for 60 seconds.
@@ -15,14 +15,24 @@
15
15
  */
16
16
 
17
17
  import type { AutocompleteItem, ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
18
- import { extractAccountFromToken } from "./auth.ts";
19
- import { queryUsage } from "./api.ts";
20
- import { readCachedSnapshot, writeCachedSnapshot } from "./cache.ts";
21
- import { mergeSnapshots, parseCodexRateLimitHeaders, parseUsageApiResponse } from "./snapshot.ts";
18
+ import {
19
+ extractAccountFromToken,
20
+ mergeSnapshots,
21
+ parseCodexRateLimitHeaders,
22
+ parseUsageApiResponse,
23
+ queryUsage,
24
+ readCachedSnapshot,
25
+ writeCachedSnapshot,
26
+ type AccountSnapshot,
27
+ type CodexUsageSnapshot,
28
+ type CreditsSnapshot,
29
+ type LimitWindow,
30
+ type RateLimit,
31
+ type ResetsSnapshot,
32
+ } from "./snapshot.ts";
22
33
  import { dimText, formatBoxedStatus, formatRightAlignedStatusline, formatStatusline, renderStatusMessage } from "./ui.ts";
23
- import type { CodexUsageSnapshot } from "./types.ts";
24
34
 
25
- export type { LimitWindow, RateLimit, CreditsSnapshot, ResetsSnapshot, AccountSnapshot, CodexUsageSnapshot } from "./types.ts";
35
+ export type { LimitWindow, RateLimit, CreditsSnapshot, ResetsSnapshot, AccountSnapshot, CodexUsageSnapshot };
26
36
  export { bar, formatDuration, formatStatusline, formatBoxedStatus, formatRightAlignedStatusline } from "./ui.ts";
27
37
 
28
38
  const CODEX_PROVIDER = "openai-codex";
@@ -1,4 +1,48 @@
1
- import type { AccountSnapshot, CodexUsageSnapshot, CreditsSnapshot, LimitWindow, ResetsSnapshot } from "./types.ts";
1
+ import { Buffer } from "node:buffer";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+
6
+ export interface LimitWindow {
7
+ usedPercent: number;
8
+ leftPercent: number;
9
+ windowSeconds?: number;
10
+ resetAt?: number;
11
+ resetAfterSeconds?: number;
12
+ }
13
+
14
+ export interface RateLimit {
15
+ id: string;
16
+ name: string;
17
+ primary?: LimitWindow;
18
+ secondary?: LimitWindow;
19
+ }
20
+
21
+ export interface CreditsSnapshot {
22
+ hasCredits?: boolean;
23
+ unlimited?: boolean;
24
+ balance?: number | string;
25
+ }
26
+
27
+ export interface ResetsSnapshot {
28
+ availableCount?: number;
29
+ applicableCount?: number;
30
+ }
31
+
32
+ export interface AccountSnapshot {
33
+ email?: string;
34
+ plan?: string;
35
+ accountId?: string;
36
+ }
37
+
38
+ export interface CodexUsageSnapshot {
39
+ source: "api" | "headers" | "cache";
40
+ fetchedAt: string;
41
+ account: AccountSnapshot;
42
+ defaultLimit?: RateLimit;
43
+ credits?: CreditsSnapshot;
44
+ resets?: ResetsSnapshot;
45
+ }
2
46
 
3
47
  export function isRecord(val: unknown): val is Record<string, unknown> {
4
48
  return typeof val === "object" && val !== null && !Array.isArray(val);
@@ -165,3 +209,85 @@ export function mergeSnapshots(existing: CodexUsageSnapshot | undefined, update:
165
209
  resets: update.resets ?? existing.resets,
166
210
  };
167
211
  }
212
+
213
+ const JWT_AUTH_CLAIM = "https://api.openai.com/auth";
214
+ const JWT_PROFILE_CLAIM = "https://api.openai.com/profile";
215
+
216
+ function decodeJwtPayload(token: string): Record<string, unknown> | undefined {
217
+ const part = token.split(".")[1];
218
+ if (!part) return undefined;
219
+ try {
220
+ const json = JSON.parse(Buffer.from(part, "base64url").toString("utf8"));
221
+ return isRecord(json) ? json : undefined;
222
+ } catch {
223
+ return undefined;
224
+ }
225
+ }
226
+
227
+ export function extractAccountFromToken(token: string): AccountSnapshot {
228
+ const payload = decodeJwtPayload(token);
229
+ if (!payload) return {};
230
+
231
+ const auth = isRecord(payload[JWT_AUTH_CLAIM]) ? payload[JWT_AUTH_CLAIM] : undefined;
232
+ const profile = isRecord(payload[JWT_PROFILE_CLAIM]) ? payload[JWT_PROFILE_CLAIM] : undefined;
233
+
234
+ const accountId = typeof auth?.chatgpt_account_id === "string" ? auth.chatgpt_account_id : undefined;
235
+ const plan = typeof auth?.chatgpt_plan_type === "string" ? auth.chatgpt_plan_type : undefined;
236
+ const email =
237
+ (typeof profile?.email === "string" && profile.email) ||
238
+ (typeof payload.email === "string" && payload.email) ||
239
+ undefined;
240
+
241
+ return { accountId, plan, email };
242
+ }
243
+
244
+ const USAGE_ENDPOINT = "https://chatgpt.com/backend-api/wham/usage";
245
+ const REQUEST_TIMEOUT_MS = 15_000;
246
+
247
+ export async function queryUsage(accessToken: string, accountId?: string): Promise<Record<string, unknown>> {
248
+ const headers: Record<string, string> = {
249
+ Authorization: `Bearer ${accessToken}`,
250
+ "User-Agent": "codex-cli",
251
+ Accept: "application/json",
252
+ };
253
+ if (accountId) headers["ChatGPT-Account-Id"] = accountId;
254
+
255
+ const res = await fetch(USAGE_ENDPOINT, {
256
+ method: "GET",
257
+ headers,
258
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
259
+ });
260
+
261
+ if (res.status === 401 || res.status === 403) throw new Error(`Authentication rejected (HTTP ${res.status}). Please run /login openai-codex.`);
262
+ if (res.status === 429) throw new Error("Rate limit exceeded for usage endpoint (HTTP 429). Please try again later.");
263
+ if (!res.ok) throw new Error(`Usage request failed (HTTP ${res.status}).`);
264
+
265
+ const body = await res.json();
266
+ if (!isRecord(body)) throw new Error("Invalid JSON received from usage endpoint.");
267
+ return body;
268
+ }
269
+
270
+ function getCachePath(): string {
271
+ const base = process.env.XDG_CACHE_HOME || join(homedir() || ".", ".cache");
272
+ return join(base, "oai-subquota", "usage.json");
273
+ }
274
+
275
+ export async function readCachedSnapshot(): Promise<CodexUsageSnapshot | undefined> {
276
+ try {
277
+ const raw = await readFile(getCachePath(), "utf8");
278
+ const parsed = JSON.parse(raw);
279
+ return isRecord(parsed) ? (parsed as unknown as CodexUsageSnapshot) : undefined;
280
+ } catch {
281
+ return undefined;
282
+ }
283
+ }
284
+
285
+ export async function writeCachedSnapshot(snapshot: CodexUsageSnapshot): Promise<void> {
286
+ try {
287
+ const file = getCachePath();
288
+ await mkdir(dirname(file), { recursive: true });
289
+ await writeFile(file, `${JSON.stringify(snapshot, null, 2)}\n`, { mode: 0o600 });
290
+ } catch {
291
+ // Non-fatal if filesystem is read-only
292
+ }
293
+ }
@@ -1,6 +1,6 @@
1
1
  import type { ExtensionCommandContext, ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
2
2
  import { Text, visibleWidth } from "@earendil-works/pi-tui";
3
- import type { CodexUsageSnapshot, LimitWindow } from "./types.ts";
3
+ import type { CodexUsageSnapshot, LimitWindow } from "./snapshot.ts";
4
4
 
5
5
  const USAGE_SETTINGS_URL = "https://chatgpt.com/codex/settings/usage";
6
6
  const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@rol1n/pi-kit",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A selectable collection of Pi extensions and prompt templates.",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "git+ssh://git@github.com/RolinShmily/pi-kit.git"
7
+ "url": "git+https://github.com/RolinShmily/pi-kit.git"
8
8
  },
9
9
  "homepage": "https://github.com/RolinShmily/pi-kit#readme",
10
10
  "bugs": {
@@ -21,42 +21,41 @@
21
21
  "manifest": "node scripts/package.mjs sync",
22
22
  "check": "node scripts/package.mjs check",
23
23
  "prepare:extension": "node scripts/package.mjs extension",
24
+ "publish:ci": "node scripts/package.mjs publish",
24
25
  "prepack": "node scripts/package.mjs check"
25
26
  },
26
27
  "publishConfig": {
27
28
  "access": "public"
28
29
  },
29
30
  "files": [
30
- "prompts",
31
- "extensions/ask-u-questions/README.md",
32
- "extensions/continue-signal/README.md",
33
- "extensions/custom-providers/README.md",
34
- "extensions/image-generate/README.md",
35
- "extensions/memory-log/README.md",
36
- "extensions/model-vision/README.md",
37
- "extensions/multi-harness/README.md",
38
- "extensions/oai-subquota/README.md",
39
- "extensions/prompt-snipaste/README.md",
40
- "extensions/screenshot/README.md",
41
- "extensions/srp-theme/README.md",
42
- "extensions/subagent/README.md",
43
- "extensions/tui-asr/README.md",
44
- "extensions/web-reach/README.md",
45
- "extensions/windows-wheel-fix/README.md",
46
- "extensions/ask-u-questions",
47
- "extensions/continue-signal",
48
- "extensions/custom-providers",
49
- "extensions/image-generate",
50
- "extensions/memory-log",
51
- "extensions/multi-harness",
52
- "extensions/subagent/mux.ts",
53
- "extensions/oai-subquota",
54
- "extensions/prompt-snipaste",
55
- "extensions/srp-theme",
56
- "extensions/subagent",
57
- "extensions/tui-asr",
58
- "extensions/web-reach",
59
- "extensions/windows-wheel-fix",
31
+ "ask-u-questions/README.md",
32
+ "continue-signal/README.md",
33
+ "custom-providers/README.md",
34
+ "image-generate/README.md",
35
+ "memory-log/README.md",
36
+ "model-vision/README.md",
37
+ "multi-harness/README.md",
38
+ "oai-subquota/README.md",
39
+ "prompt-snipaste/README.md",
40
+ "screenshot/README.md",
41
+ "srp-theme/README.md",
42
+ "subagent/README.md",
43
+ "tui-asr/README.md",
44
+ "web-reach/README.md",
45
+ "windows-wheel-fix/README.md",
46
+ "ask-u-questions",
47
+ "continue-signal",
48
+ "custom-providers",
49
+ "image-generate",
50
+ "memory-log",
51
+ "multi-harness",
52
+ "subagent",
53
+ "oai-subquota",
54
+ "prompt-snipaste",
55
+ "srp-theme",
56
+ "tui-asr",
57
+ "web-reach",
58
+ "windows-wheel-fix",
60
59
  "!**/test/**",
61
60
  "!**/tests/**",
62
61
  "!**/*.{test,spec}.{ts,js,mjs,cjs}",
@@ -72,23 +71,23 @@
72
71
  },
73
72
  "pi": {
74
73
  "extensions": [
75
- "./extensions/ask-u-questions/index.ts",
76
- "./extensions/continue-signal/index.ts",
77
- "./extensions/custom-providers/index.ts",
78
- "./extensions/image-generate/index.ts",
79
- "./extensions/memory-log/index.ts",
80
- "./extensions/multi-harness/index.ts",
81
- "./extensions/oai-subquota/index.ts",
82
- "./extensions/prompt-snipaste/index.ts",
83
- "./extensions/srp-theme/index.ts",
84
- "./extensions/subagent/index.ts",
85
- "./extensions/tui-asr/index.ts",
86
- "./extensions/web-reach/index.ts",
87
- "./extensions/windows-wheel-fix/index.ts"
74
+ "./ask-u-questions/index.ts",
75
+ "./continue-signal/index.ts",
76
+ "./custom-providers/index.ts",
77
+ "./image-generate/index.ts",
78
+ "./memory-log/index.ts",
79
+ "./multi-harness/index.ts",
80
+ "./oai-subquota/index.ts",
81
+ "./prompt-snipaste/index.ts",
82
+ "./srp-theme/index.ts",
83
+ "./subagent/index.ts",
84
+ "./tui-asr/index.ts",
85
+ "./web-reach/index.ts",
86
+ "./windows-wheel-fix/index.ts"
88
87
  ],
89
88
  "skills": [],
90
89
  "prompts": [
91
- "./prompts"
90
+ "./prompt-snipaste/prompts"
92
91
  ],
93
92
  "themes": []
94
93
  }
@@ -0,0 +1,27 @@
1
+ # prompt-snipaste
2
+
3
+ Select prompt snippets to prepend or append to the next user message, with live preview and a session transcript card. Bundles 7 built-in prompt snippets under `prompts/`.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ pi install npm:@rol1n/prompt-snipaste
9
+ ```
10
+
11
+ Also included in `@rol1n/pi-kit`.
12
+
13
+ ## Use
14
+
15
+ Open with `/snipaste` or `Alt+S`. Navigate with arrow keys, toggle with `Space`, preview with `Tab`, confirm with `Enter`, and cancel with `Escape`.
16
+
17
+ ## Frontmatter
18
+
19
+ ```markdown
20
+ ---
21
+ name: Review checklist
22
+ description: Add review criteria to the next message
23
+ placement: append
24
+ order: 100
25
+ ---
26
+ Check correctness, error handling, and missing validation.
27
+ ```
@@ -85,4 +85,3 @@ export function updateSnippetWidget(
85
85
  invalidate() {},
86
86
  }));
87
87
  }
88
-
@@ -1,6 +1,9 @@
1
1
  import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
- import { basename, isAbsolute, join, resolve } from "node:path";
3
+ import { basename, dirname, isAbsolute, join, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const BUNDLED_PROMPTS_DIR = join(dirname(fileURLToPath(import.meta.url)), "prompts");
4
7
  import { CONFIG_DIR_NAME, getAgentDir, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
5
8
  import type { Snippet } from "./types.ts";
6
9
 
@@ -108,6 +111,7 @@ export function loadSnippets(cwd: string, pi?: ExtensionAPI): Snippet[] {
108
111
  .filter((command) => command.source === "prompt")
109
112
  .map((command) => command.sourceInfo.path);
110
113
  const defaultDirs = loadedPromptPaths ? [] : [
114
+ BUNDLED_PROMPTS_DIR,
111
115
  join(getAgentDir(), "prompts"),
112
116
  join(cwd, CONFIG_DIR_NAME, "prompts"),
113
117
  ];
@@ -200,4 +204,3 @@ export function loadSnippets(cwd: string, pi?: ExtensionAPI): Snippet[] {
200
204
  return a.name.localeCompare(b.name);
201
205
  });
202
206
  }
203
-
@@ -16,4 +16,3 @@ export interface PromptCardData {
16
16
  body: string;
17
17
  }[];
18
18
  }
19
-
@@ -0,0 +1,14 @@
1
+ # screenshot
2
+
3
+ Insert the file path of the most recently modified Windows/WSL system screenshot into Pi's editor via `/screenshot`.
4
+
5
+ Searches standard and localized `Pictures/Screenshots` and OneDrive screenshot directories under `USERPROFILE` on Windows or `/mnt/c/Users` on WSL.
6
+
7
+
8
+ ## Install
9
+
10
+ ```sh
11
+ pi install npm:@rol1n/screenshot
12
+ ```
13
+
14
+ Available as a standalone package (not enabled in `@rol1n/pi-kit` by default).
@@ -0,0 +1,18 @@
1
+ # srp-theme
2
+
3
+ Incremental Pi terminal presentation enhancement: adds a `belowEditor` last-prompt preview widget and a real-time streaming TPS (tokens per second) status meter while keeping Pi's native header and footer intact.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ pi install npm:@rol1n/srp-theme
9
+ ```
10
+
11
+ Also included in `@rol1n/pi-kit`.
12
+
13
+ ## Commands
14
+
15
+ ```text
16
+ /srp-theme on
17
+ /srp-theme off
18
+ ```
@@ -191,4 +191,3 @@ export function renderTimeAndFinishedLine(
191
191
  const line = truncateToWidth(content, width, "…");
192
192
  return [theme.fg("dim", line)];
193
193
  }
194
-
@@ -439,4 +439,3 @@ export const safeFallbackTheme: Theme = {
439
439
  bg: (_color: string, text: string) => text,
440
440
  bold: (text: string) => text,
441
441
  } as unknown as Theme;
442
-
@@ -32,4 +32,4 @@ Without a usable multiplexer, the worker backend falls back to a background proc
32
32
 
33
33
  ## Other delegation packages
34
34
 
35
- Use [multi-harness](https://github.com/RolinShmily/pi-kit/tree/main/extensions/multi-harness) for Codex, Claude, or OpenCode peers. That package shares multiplexer helpers but provides a separate tool and does not automatically enable this extension's entrypoint. The bundled subagent skill file is reference material and is not registered by the package manifest.
35
+ Use [multi-harness](https://github.com/RolinShmily/pi-kit/tree/main/multi-harness) for Codex, Claude, or OpenCode peers. That package shares multiplexer helpers (`mux.ts`) while exposing a separate tool.
@@ -0,0 +1,21 @@
1
+ # tui-asr
2
+
3
+ Streaming voice dictation for Pi's terminal editor using Aliyun DashScope Paraformer.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ pi install npm:@rol1n/tui-asr
9
+ ```
10
+
11
+ Also included in `@rol1n/pi-kit`. Installing this package automatically installs `@rol1n/custom-providers`.
12
+
13
+ ## Commands and shortcuts
14
+
15
+ | Action | Trigger |
16
+ |---|---|
17
+ | Start / stop dictation | `/asr` or `Alt+M` |
18
+ | Cancel dictation | `Alt+N` |
19
+ | Switch ASR model | `/asr model [name]` |
20
+
21
+ Requires `sox` (`rec` on POSIX, `sox -t waveaudio` on Windows) on `PATH` and DashScope credentials via `/login dashscope`, `DASHSCOPE_API_KEY`, or `ALIYUN_API_KEY`.
@@ -1,11 +1,78 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
- import type { ChildProcessByStdio } from "node:child_process";
2
+ import { spawn, type ChildProcessByStdio } from "node:child_process";
3
3
  import type { Readable } from "node:stream";
4
- import { rmsFromPcm16, spawnRecorder } from "./audio.ts";
4
+ import {
5
+ ALL_ASR_MODELS,
6
+ createAsrProvider,
7
+ ensureCustomProviders,
8
+ type AsrModelDefinition,
9
+ type StreamingAsrProvider,
10
+ } from "../custom-providers/index.ts";
5
11
  import { insertTranscript } from "./input.ts";
6
- import { ALL_ASR_MODELS, createAsrProvider, resolveProviderApiKey, type StreamingAsrProvider } from "./providers.ts";
7
12
  import { createStatusDisplay } from "./status.ts";
8
13
 
14
+ export { ALL_ASR_MODELS, createAsrProvider, ensureCustomProviders, type AsrModelDefinition, type StreamingAsrProvider };
15
+
16
+ export async function resolveProviderApiKey(provider: string, ctx?: ExtensionContext | null): Promise<string> {
17
+ if (ctx?.modelRegistry) {
18
+ const candidates = provider === "dashscope" ? ["dashscope", "aliyun"] : [provider];
19
+ for (const id of candidates) {
20
+ try {
21
+ const key = await ctx.modelRegistry.getApiKeyForProvider(id);
22
+ if (key?.trim()) return key.trim();
23
+ } catch {}
24
+ try {
25
+ const auth = await ctx.modelRegistry.getProviderAuth(id);
26
+ if (auth?.auth?.apiKey?.trim()) return auth.auth.apiKey.trim();
27
+ } catch {}
28
+ }
29
+ }
30
+ const envKey = process.env[`${provider.toUpperCase()}_API_KEY`];
31
+ if (envKey?.trim()) return envKey.trim();
32
+ if (provider === "dashscope") {
33
+ return process.env.ALIYUN_API_KEY?.trim() || "";
34
+ }
35
+ return "";
36
+ }
37
+
38
+ export function rmsFromPcm16(buf: Buffer): number {
39
+ if (buf.length < 2) return 0;
40
+ const sampleCount = Math.floor(buf.length / 2);
41
+ let sumSquares = 0;
42
+ for (let i = 0; i < sampleCount; i++) {
43
+ const sample = buf.readInt16LE(i * 2);
44
+ sumSquares += sample * sample;
45
+ }
46
+ const meanSquare = sumSquares / sampleCount;
47
+ return Math.sqrt(meanSquare);
48
+ }
49
+
50
+ /** Spawn the existing 16 kHz mono PCM recorder for the current platform. */
51
+ export function spawnRecorder(): ChildProcessByStdio<null, Readable, Readable> {
52
+ const commonAudioArgs = [
53
+ "-q",
54
+ "--buffer", "512",
55
+ "-r", "16000",
56
+ "-c", "1",
57
+ "-b", "16",
58
+ "-e", "signed-integer",
59
+ "-t", "raw",
60
+ "-",
61
+ ];
62
+
63
+ let proc: ChildProcessByStdio<null, Readable, Readable>;
64
+ if (process.platform === "win32") {
65
+ proc = spawn("sox", ["-t", "waveaudio", "default", ...commonAudioArgs], { stdio: ["ignore", "pipe", "pipe"] });
66
+ } else {
67
+ try {
68
+ proc = spawn("rec", commonAudioArgs, { stdio: ["ignore", "pipe", "pipe"] });
69
+ } catch {
70
+ proc = spawn("sox", ["-d", ...commonAudioArgs], { stdio: ["ignore", "pipe", "pipe"] });
71
+ }
72
+ }
73
+ return proc;
74
+ }
75
+
9
76
  type State = "idle" | "recording" | "stopping";
10
77
 
11
78
  /** Keep recording state, cancellation guards, and cleanup in one session-local controller. */
@@ -19,8 +19,7 @@
19
19
 
20
20
  import { type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
21
21
  import type { AutocompleteItem } from "@earendil-works/pi-tui";
22
- import { ALL_ASR_MODELS, resolveProviderApiKey, type AsrModelDefinition } from "./providers.ts";
23
- import { createDictationController } from "./dictation.ts";
22
+ import { ALL_ASR_MODELS, createDictationController, ensureCustomProviders, resolveProviderApiKey, type AsrModelDefinition } from "./dictation.ts";
24
23
  import { SearchableAsrModelSelectorComponent } from "./model-selector.ts";
25
24
 
26
25
  /** Default startup ASR model ID */
@@ -31,6 +30,7 @@ const TOGGLE_SHORTCUTS = ["alt+m"];
31
30
  const CANCEL_SHORTCUTS = ["alt+n"];
32
31
 
33
32
  export default function (pi: ExtensionAPI) {
33
+ ensureCustomProviders(pi);
34
34
  let activeModel = DEFAULT_ASR_MODEL;
35
35
 
36
36
  // TUI state
@@ -1,5 +1,34 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
- import { copyToClipboard } from "./clipboard.ts";
2
+ import { spawn, type ChildProcessByStdio } from "node:child_process";
3
+
4
+ export function copyToClipboard(text: string): boolean {
5
+ try {
6
+ const isWsl =
7
+ process.platform === "linux" &&
8
+ typeof process.env.WSL_DISTRO_NAME === "string";
9
+
10
+ let proc: ChildProcessByStdio<any, any, any>;
11
+ if (isWsl) {
12
+ proc = spawn("clip.exe", [], { stdio: ["pipe", "ignore", "ignore"] });
13
+ } else if (process.platform === "win32") {
14
+ proc = spawn("clip", [], { stdio: ["pipe", "ignore", "ignore"] });
15
+ } else if (process.platform === "darwin") {
16
+ proc = spawn("pbcopy", [], { stdio: ["pipe", "ignore", "ignore"] });
17
+ } else {
18
+ try {
19
+ proc = spawn("wl-copy", [], { stdio: ["pipe", "ignore", "ignore"] });
20
+ } catch {
21
+ proc = spawn("xclip", ["-selection", "clipboard"], { stdio: ["pipe", "ignore", "ignore"] });
22
+ }
23
+ }
24
+
25
+ proc.stdin.write(text);
26
+ proc.stdin.end();
27
+ return true;
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
3
32
 
4
33
  interface EditorLike {
5
34
  getText(): string;
@@ -1,5 +1,5 @@
1
1
  import { Input, fuzzyFilter, getKeybindings } from "@earendil-works/pi-tui";
2
- import type { AsrModelDefinition } from "./providers.ts";
2
+ import type { AsrModelDefinition } from "./dictation.ts";
3
3
 
4
4
  export class SearchableAsrModelSelectorComponent {
5
5
  private searchInput = new Input();
@@ -0,0 +1,19 @@
1
+ # web-reach
2
+
3
+ Keyless web search (`web_search` via Exa MCP) and multi-tier page extraction (`web_fetch` supporting Next.js RSC, semantic HTML-to-Markdown, optional `unpdf` PDF extraction, and Jina Reader fallback).
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ pi install npm:@rol1n/web-reach
9
+ ```
10
+
11
+ Also included in `@rol1n/pi-kit`.
12
+
13
+ ## Configuration
14
+
15
+ | Environment variable | Default |
16
+ |---|---|
17
+ | `SRP_WEB_SEARCH_TIMEOUT_MS` | `60000` |
18
+ | `SRP_WEB_FETCH_TIMEOUT_MS` | `20000` |
19
+ | `SRP_WEB_FETCH_MAX_BYTES` | `4194304` (4 MiB) |