@rol1n/pi-kit 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +87 -50
- package/README_zh.md +136 -0
- package/ask-u-questions/README.md +26 -0
- package/{extensions/ask-u-questions → ask-u-questions}/dialog-ui.ts +23 -0
- package/{extensions/ask-u-questions → ask-u-questions}/index.ts +9 -5
- package/{extensions/ask-u-questions → ask-u-questions}/multi-choice.ts +1 -3
- package/{extensions/ask-u-questions → ask-u-questions}/single-choice.ts +1 -3
- package/{extensions/ask-u-questions → ask-u-questions}/tool-renderers.ts +1 -3
- package/ask-u-questions/types.ts +192 -0
- package/continue-signal/README.md +20 -0
- package/{extensions/continue-signal → continue-signal}/index.ts +21 -3
- package/custom-providers/README.md +20 -0
- package/{extensions/custom-providers → custom-providers}/index.ts +16 -2
- package/image-generate/README.md +25 -0
- package/{extensions/image-generate → image-generate}/index.ts +22 -2
- package/{extensions/image-generate → image-generate}/model-selector.ts +1 -1
- package/memory-log/README.md +121 -0
- package/{extensions/memory-log → memory-log}/config.ts +1 -1
- package/{extensions/memory-log → memory-log}/hooks/compaction-hook.ts +58 -15
- package/memory-log/hooks/compaction-trigger.ts +87 -0
- package/{extensions/memory-log → memory-log}/hooks/observer-trigger.ts +2 -1
- package/{extensions/memory-log → memory-log}/index.ts +4 -0
- package/{extensions/memory-log → memory-log}/ledger/index.ts +1 -0
- package/memory-log/ledger/recall.ts +111 -0
- package/{extensions/memory-log → memory-log}/ledger/render.ts +3 -1
- package/{extensions/memory-log → memory-log}/ledger/serialize.ts +2 -4
- package/{extensions/memory-log → memory-log}/ledger/types.ts +4 -1
- package/{extensions/memory-log → memory-log}/runtime.ts +0 -5
- package/memory-log/tools/recall.ts +60 -0
- package/model-vision/README.md +22 -0
- package/{extensions/multi-harness → multi-harness}/README.md +3 -3
- package/oai-subquota/README.md +22 -0
- package/{extensions/oai-subquota → oai-subquota}/index.ts +16 -6
- package/{extensions/oai-subquota → oai-subquota}/snapshot.ts +127 -1
- package/{extensions/oai-subquota → oai-subquota}/ui.ts +1 -1
- package/package.json +46 -46
- package/prompt-snipaste/README.md +27 -0
- package/{extensions/prompt-snipaste → prompt-snipaste}/renderers.ts +0 -1
- package/{extensions/prompt-snipaste → prompt-snipaste}/snippets.ts +5 -2
- package/{extensions/prompt-snipaste → prompt-snipaste}/types.ts +0 -1
- package/screenshot/README.md +14 -0
- package/srp-theme/README.md +18 -0
- package/{extensions/srp-theme → srp-theme}/footer.ts +0 -1
- package/{extensions/srp-theme → srp-theme}/tps-meter.ts +0 -1
- package/{extensions/subagent → subagent}/README.md +1 -1
- package/tui-asr/README.md +21 -0
- package/{extensions/tui-asr → tui-asr}/dictation.ts +70 -3
- package/{extensions/tui-asr → tui-asr}/index.ts +2 -2
- package/{extensions/tui-asr → tui-asr}/input.ts +30 -1
- package/{extensions/tui-asr → tui-asr}/model-selector.ts +1 -1
- package/web-reach/README.md +19 -0
- package/windows-wheel-fix/README.md +12 -0
- package/extensions/ask-u-questions/README.md +0 -32
- package/extensions/ask-u-questions/answers.ts +0 -53
- package/extensions/ask-u-questions/results.ts +0 -83
- package/extensions/ask-u-questions/schema.ts +0 -17
- package/extensions/ask-u-questions/types.ts +0 -45
- package/extensions/ask-u-questions/ui-lock.ts +0 -24
- package/extensions/continue-signal/README.md +0 -28
- package/extensions/continue-signal/renderer.ts +0 -21
- package/extensions/custom-providers/README.md +0 -28
- package/extensions/image-generate/README.md +0 -29
- package/extensions/image-generate/models.ts +0 -19
- package/extensions/memory-log/README.md +0 -54
- package/extensions/memory-log/hooks/compaction-trigger.ts +0 -160
- package/extensions/model-vision/README.md +0 -28
- package/extensions/oai-subquota/README.md +0 -30
- package/extensions/oai-subquota/api.ts +0 -27
- package/extensions/oai-subquota/auth.ts +0 -34
- package/extensions/oai-subquota/cache.ts +0 -30
- package/extensions/oai-subquota/types.ts +0 -40
- package/extensions/prompt-snipaste/README.md +0 -33
- package/extensions/screenshot/README.md +0 -25
- package/extensions/srp-theme/README.md +0 -24
- package/extensions/subagent/skills/subagent/SKILL.md +0 -70
- package/extensions/tui-asr/README.md +0 -28
- package/extensions/tui-asr/audio.ts +0 -40
- package/extensions/tui-asr/clipboard.ts +0 -30
- package/extensions/tui-asr/providers.ts +0 -25
- package/extensions/web-reach/README.md +0 -37
- package/extensions/web-reach/html.ts +0 -83
- package/extensions/web-reach/index.ts +0 -82
- package/extensions/web-reach/page.ts +0 -132
- package/extensions/web-reach/pdf.ts +0 -42
- package/extensions/web-reach/reader.ts +0 -42
- package/extensions/web-reach/rsc.ts +0 -161
- package/extensions/web-reach/search.ts +0 -85
- package/extensions/web-reach/transport.ts +0 -35
- package/extensions/windows-wheel-fix/README.md +0 -21
- /package/{extensions/custom-providers → custom-providers}/asr/handlers/dashscope.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/asr/index.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/asr/models.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/asr/types.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/chat/index.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/chat/magpie.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/chat/models.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/classifier/index.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/classifier/models.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/image/handlers/dashscope.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/image/handlers/openrouter.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/image/index.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/image/models.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/image/types.ts +0 -0
- /package/{extensions/custom-providers → custom-providers}/types.ts +0 -0
- /package/{extensions/image-generate → image-generate}/files.ts +0 -0
- /package/{extensions/memory-log → memory-log}/agent/consolidator/prompt.ts +0 -0
- /package/{extensions/memory-log → memory-log}/agent/consolidator/tools.ts +0 -0
- /package/{extensions/memory-log → memory-log}/agent/cost.ts +0 -0
- /package/{extensions/memory-log → memory-log}/agent/index.ts +0 -0
- /package/{extensions/memory-log → memory-log}/agent/observer/prompt.ts +0 -0
- /package/{extensions/memory-log → memory-log}/agent/observer/tool.ts +0 -0
- /package/{extensions/memory-log → memory-log}/commands/compact.ts +0 -0
- /package/{extensions/memory-log → memory-log}/commands/consolidate.ts +0 -0
- /package/{extensions/memory-log → memory-log}/commands/status.ts +0 -0
- /package/{extensions/memory-log → memory-log}/debug-log.ts +0 -0
- /package/{extensions/memory-log → memory-log}/hooks/consolidator-trigger.ts +0 -0
- /package/{extensions/memory-log → memory-log}/ids.ts +0 -0
- /package/{extensions/memory-log → memory-log}/ledger/fold.ts +0 -0
- /package/{extensions/memory-log → memory-log}/ledger/pool.ts +0 -0
- /package/{extensions/memory-log → memory-log}/ledger/progress.ts +0 -0
- /package/{extensions/memory-log → memory-log}/ledger/projection.ts +0 -0
- /package/{extensions/memory-log → memory-log}/memory/index-render.ts +0 -0
- /package/{extensions/memory-log → memory-log}/memory/paths.ts +0 -0
- /package/{extensions/memory-log → memory-log}/memory/session.ts +0 -0
- /package/{extensions/memory-log → memory-log}/spawn/launch.ts +0 -0
- /package/{extensions/memory-log → memory-log}/spawn/runs.ts +0 -0
- /package/{extensions/memory-log → memory-log}/tokens.ts +0 -0
- /package/{extensions/memory-log → memory-log}/ui/status-controller.ts +0 -0
- /package/{extensions/memory-log → memory-log}/ui/timeline.ts +0 -0
- /package/{extensions/multi-harness → multi-harness}/adapters.mjs +0 -0
- /package/{extensions/multi-harness → multi-harness}/harness-done.mjs +0 -0
- /package/{extensions/multi-harness → multi-harness}/index.ts +0 -0
- /package/{extensions/multi-harness → multi-harness}/ipc.mjs +0 -0
- /package/{extensions/multi-harness → multi-harness}/opencode-plugin.mjs +0 -0
- /package/{extensions/multi-harness → multi-harness}/process-runner.mjs +0 -0
- /package/{extensions/multi-harness → multi-harness}/turn-hook.mjs +0 -0
- /package/{extensions/multi-harness → multi-harness}/worker-bridge.ts +0 -0
- /package/{extensions/prompt-snipaste → prompt-snipaste}/index.ts +0 -0
- /package/{extensions/prompt-snipaste → prompt-snipaste}/menu.ts +0 -0
- /package/{prompts → prompt-snipaste/prompts}/ask-questions.md +0 -0
- /package/{prompts → prompt-snipaste/prompts}/delegate-exploration.md +0 -0
- /package/{prompts → prompt-snipaste/prompts}/diagnose-report.md +0 -0
- /package/{prompts → prompt-snipaste/prompts}/frontend-tech-preset.md +0 -0
- /package/{prompts → prompt-snipaste/prompts}/orchestrator-mode.md +0 -0
- /package/{prompts → prompt-snipaste/prompts}/session-kickoff.md +0 -0
- /package/{prompts → prompt-snipaste/prompts}/verify-not-assume.md +0 -0
- /package/{extensions/srp-theme → srp-theme}/index.ts +0 -0
- /package/{extensions/subagent → subagent}/bridge.ts +0 -0
- /package/{extensions/subagent → subagent}/index.ts +0 -0
- /package/{extensions/subagent → subagent}/mux.ts +0 -0
- /package/{extensions/subagent → subagent}/session.ts +0 -0
- /package/{extensions/subagent → subagent}/ui.ts +0 -0
- /package/{extensions/tui-asr → tui-asr}/status.ts +0 -0
- /package/{extensions/windows-wheel-fix → windows-wheel-fix}/index.ts +0 -0
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# memory-log
|
|
2
|
-
|
|
3
|
-
Observational memory for long Pi sessions: background observers distill conversation chunks, a ledger records observations, and a consolidator writes durable project memory. Compaction rebuilds context from the recorded memory and recent conversation.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
pi install npm:@rol1n/memory-log
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Also included in `@rol1n/pi-kit`. The extension loads with new-session memory disabled by default.
|
|
12
|
-
|
|
13
|
-
## Commands
|
|
14
|
-
|
|
15
|
-
| Command | Action |
|
|
16
|
-
|---|---|
|
|
17
|
-
| `/mem-log on` / `/mem-log off` | Set the current session's memory gate |
|
|
18
|
-
| `/mem-log status` or `/mem-log:status` | Inspect observation progress, workers, memory, and costs |
|
|
19
|
-
| `/mem-log compact` or `/mem-log:compact` | Request compaction |
|
|
20
|
-
| `/mem-log consolidate` or `/mem-log:consolidate` | Consolidate the observation pool |
|
|
21
|
-
|
|
22
|
-
## Settings
|
|
23
|
-
|
|
24
|
-
Add `memoryLog` to personal or project Pi settings. Project values override personal values:
|
|
25
|
-
|
|
26
|
-
```json
|
|
27
|
-
{
|
|
28
|
-
"memoryLog": {
|
|
29
|
-
"defaultEnabled": false,
|
|
30
|
-
"chunkTokens": 10000,
|
|
31
|
-
"poolTargetTokens": 10000,
|
|
32
|
-
"consolidateAtPoolTokens": 15000,
|
|
33
|
-
"compactAtContextTokens": 150000,
|
|
34
|
-
"tailTokens": 20000,
|
|
35
|
-
"journeyTargetTokens": 1000,
|
|
36
|
-
"observerConcurrency": 4,
|
|
37
|
-
"resumeAfterMidRunCompaction": true,
|
|
38
|
-
"passive": false,
|
|
39
|
-
"debugLog": false,
|
|
40
|
-
"models": {
|
|
41
|
-
"observer": { "thinking": "low" },
|
|
42
|
-
"consolidator": { "thinking": "medium" }
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Observer and consolidator model objects accept `provider`, `id`, and `thinking`. An explicitly configured model takes priority over the session model, followed by Pi's configured default model. `chunkOverlapTokens` defaults to zero.
|
|
49
|
-
|
|
50
|
-
Environment overrides are `PI_OM_PASSIVE`, `PI_OM_OBSERVER_PROVIDER`, `PI_OM_OBSERVER_MODEL`, `PI_OM_OBSERVER_THINKING`, and the corresponding `PI_OM_CONSOLIDATOR_*` values. Passive mode disables automatic triggers separately from the session gate.
|
|
51
|
-
|
|
52
|
-
## Storage and requirements
|
|
53
|
-
|
|
54
|
-
Durable files live under `.memory/<session-id>/` in the working project, including topic files and `JOURNEY.md`. Gate changes and observation history are recorded in the Pi session ledger. Observer and consolidator workers require the `pi` executable and model credentials; they make additional model requests. Disabling memory aborts active background workers.
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
findLastCompactionIndex,
|
|
4
|
-
rawTokensAfterIndex,
|
|
5
|
-
rawTokensSinceLastCompaction,
|
|
6
|
-
type Entry,
|
|
7
|
-
} from "../ledger/index.ts";
|
|
8
|
-
import type { Runtime } from "../runtime.ts";
|
|
9
|
-
|
|
10
|
-
export const RESUME_PROMPT =
|
|
11
|
-
"[automatic] Your context was just compacted to free space; no user message was sent. " +
|
|
12
|
-
"Continue exactly where you left off, as if the compaction had not happened.";
|
|
13
|
-
|
|
14
|
-
export const RETRYABLE_ERROR_RE =
|
|
15
|
-
/overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i;
|
|
16
|
-
|
|
17
|
-
export function contextPressureTokens(
|
|
18
|
-
ctx: { getContextUsage?: () => { tokens: number | null } | undefined; sessionManager: { getBranch: () => Entry[] } },
|
|
19
|
-
threshold: number,
|
|
20
|
-
): { tokens: number; due: boolean } {
|
|
21
|
-
const branch = ctx.sessionManager.getBranch();
|
|
22
|
-
if (branch.length === 0) return { tokens: 0, due: false };
|
|
23
|
-
|
|
24
|
-
// If the last entry on the branch is already a compaction, context was just compacted on this branch.
|
|
25
|
-
const lastEntry = branch[branch.length - 1];
|
|
26
|
-
if (lastEntry.type === "compaction") {
|
|
27
|
-
return { tokens: 0, due: false };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const lastCompactionIdx = findLastCompactionIndex(branch);
|
|
31
|
-
if (lastCompactionIdx !== -1) {
|
|
32
|
-
// If no new source entries exist after compaction, context has not grown since compaction.
|
|
33
|
-
const tokensSinceCompaction = rawTokensAfterIndex(branch, lastCompactionIdx);
|
|
34
|
-
if (tokensSinceCompaction === 0) {
|
|
35
|
-
return { tokens: 0, due: false };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Check if any assistant message has responded after the compaction.
|
|
39
|
-
// In Pi, getContextUsage() returns tokens: null until an assistant message responds post-compaction.
|
|
40
|
-
let hasAssistantAfterCompaction = false;
|
|
41
|
-
for (let i = branch.length - 1; i > lastCompactionIdx; i--) {
|
|
42
|
-
const entry = branch[i];
|
|
43
|
-
if (entry.type === "message" && (entry.message as any)?.role === "assistant") {
|
|
44
|
-
hasAssistantAfterCompaction = true;
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if (!hasAssistantAfterCompaction) {
|
|
49
|
-
return { tokens: 0, due: false };
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const live = ctx.getContextUsage?.()?.tokens;
|
|
54
|
-
if (live != null) {
|
|
55
|
-
return { tokens: live, due: live >= threshold };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const raw = rawTokensSinceLastCompaction(branch);
|
|
59
|
-
return { tokens: raw, due: raw >= threshold };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function turnWillContinue(event: any): boolean {
|
|
63
|
-
const toolResults = event?.toolResults;
|
|
64
|
-
if (Array.isArray(toolResults) && toolResults.length > 0) return true;
|
|
65
|
-
const stop = event?.message?.stopReason;
|
|
66
|
-
return stop === "tool_use" || stop === "tool_calls";
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Register the automatic compaction trigger.
|
|
71
|
-
*
|
|
72
|
-
* NOTE on safe triggering vs mid-run aborts:
|
|
73
|
-
* In Pi, `AgentSession.compact()` immediately calls `await this.abort()`, which calls
|
|
74
|
-
* `this.agent.abort()`. Calling `ctx.compact()` during an active multi-turn tool chain
|
|
75
|
-
* (`turn_end` while tool calls are executing or turn will continue) violently aborts the agent run.
|
|
76
|
-
* This marks the active assistant message with `stopReason: "error"` and `errorMessage: "This operation was aborted"`,
|
|
77
|
-
* which renders as a red error in the TUI.
|
|
78
|
-
*
|
|
79
|
-
* To trigger compaction safely without aborting active turns, automatic compaction is evaluated on `agent_end`
|
|
80
|
-
* and deferred until the session is truly idle (`ctx.isIdle() === true`).
|
|
81
|
-
*/
|
|
82
|
-
export function registerCompactionTrigger(pi: ExtensionAPI, runtime: Runtime): void {
|
|
83
|
-
pi.on("agent_start", () => {
|
|
84
|
-
// A new turn is starting — abort any pending deferred auto-compaction wait
|
|
85
|
-
if (runtime.autoCompactionController) {
|
|
86
|
-
runtime.autoCompactionController.abort();
|
|
87
|
-
runtime.autoCompactionController = undefined;
|
|
88
|
-
runtime.compactInFlight = false;
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
pi.on("agent_end", (event: any, ctx: any) => {
|
|
93
|
-
if (!runtime.enabled || runtime.config.passive) return;
|
|
94
|
-
if (runtime.compactInFlight) return;
|
|
95
|
-
|
|
96
|
-
// Check if the run ended with a retryable error (Pi will auto-retry)
|
|
97
|
-
const lastAssistant = [...(event?.messages ?? [])]
|
|
98
|
-
.reverse()
|
|
99
|
-
.find((m): m is Extract<typeof m, { role: "assistant" }> => m?.role === "assistant");
|
|
100
|
-
if (
|
|
101
|
-
lastAssistant &&
|
|
102
|
-
lastAssistant.stopReason === "error" &&
|
|
103
|
-
lastAssistant.errorMessage &&
|
|
104
|
-
RETRYABLE_ERROR_RE.test(lastAssistant.errorMessage)
|
|
105
|
-
) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (!contextPressureTokens(ctx, runtime.config.compactAtContextTokens).due) return;
|
|
110
|
-
|
|
111
|
-
const hasUI = ctx.hasUI;
|
|
112
|
-
const ui = ctx.ui;
|
|
113
|
-
runtime.compactInFlight = true;
|
|
114
|
-
const controller = new AbortController();
|
|
115
|
-
runtime.autoCompactionController = controller;
|
|
116
|
-
const signal = controller.signal;
|
|
117
|
-
|
|
118
|
-
void (async () => {
|
|
119
|
-
try {
|
|
120
|
-
// Yield to the event loop first so agent_end handlers settle
|
|
121
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
122
|
-
|
|
123
|
-
// Poll isIdle() until the agent is truly idle so ctx.compact() does not abort an active run
|
|
124
|
-
while (typeof ctx.isIdle === "function" && !ctx.isIdle()) {
|
|
125
|
-
if (signal.aborted) return;
|
|
126
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (signal.aborted) return;
|
|
130
|
-
|
|
131
|
-
// Re-check pressure after settling
|
|
132
|
-
if (!contextPressureTokens(ctx, runtime.config.compactAtContextTokens).due) {
|
|
133
|
-
runtime.compactInFlight = false;
|
|
134
|
-
runtime.autoCompactionController = undefined;
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (hasUI) ui?.notify("memory-log: context threshold reached — compacting memory (waiting for pending observers)...", "info");
|
|
139
|
-
|
|
140
|
-
runtime.autoCompactionController = undefined;
|
|
141
|
-
ctx.compact({
|
|
142
|
-
onComplete: () => {
|
|
143
|
-
runtime.compactInFlight = false;
|
|
144
|
-
if (hasUI) ui?.notify("memory-log: memory compaction completed", "info");
|
|
145
|
-
},
|
|
146
|
-
onError: (error: { message: string }) => {
|
|
147
|
-
runtime.compactInFlight = false;
|
|
148
|
-
if (error.message === "Compaction cancelled") return;
|
|
149
|
-
if (hasUI) ui?.notify(`memory-log: ${error.message}`, "error");
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
} catch (error) {
|
|
153
|
-
runtime.compactInFlight = false;
|
|
154
|
-
runtime.autoCompactionController = undefined;
|
|
155
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
156
|
-
if (hasUI) ui?.notify(`memory-log: compaction trigger failed — ${msg}`, "error");
|
|
157
|
-
}
|
|
158
|
-
})();
|
|
159
|
-
});
|
|
160
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# model-vision
|
|
2
|
-
|
|
3
|
-
Analyze a local image or public image URL with a vision model. Registers the `model_vision` tool for OCR, UI inspection, and image questions.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
pi install npm:@rol1n/model-vision
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Available independently; it is not enabled in the aggregate package by default. The extension entrypoint is `extensions/model-vision/index.ts`; `analysis.ts` coordinates image loading (`image.ts`), network validation (`network.ts`), and model requests (`requests.ts`).
|
|
12
|
-
|
|
13
|
-
## Use
|
|
14
|
-
|
|
15
|
-
```json
|
|
16
|
-
{
|
|
17
|
-
"image": "./screenshots/error.png",
|
|
18
|
-
"prompt": "Read the error message and describe the relevant UI."
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Supported image formats are PNG, JPEG, WebP, GIF, and BMP. Local paths resolve from the working directory. Remote images must use public HTTP(S) addresses; private-network targets are rejected. Images are limited to 10 MiB and requests have a 90-second timeout.
|
|
23
|
-
|
|
24
|
-
## Model configuration
|
|
25
|
-
|
|
26
|
-
The current fallback chain is declared in `DEFAULT_VISION_MODELS` in `extensions/model-vision/models.ts`: Antigravity `gemini-3.8-flash` through Pi's native API, followed by SHUAI API `gpt-6-luna` through OpenAI completions. Change that source list to choose a different chain; there is currently no settings key or tool argument for choosing the vision model.
|
|
27
|
-
|
|
28
|
-
Install and authenticate the provider integrations you select. Antigravity is an external integration; SHUAI registration is available in [custom-providers](https://github.com/RolinShmily/pi-kit/tree/main/extensions/custom-providers). The tool returns extracted text and the provider/model used.
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# oai-subquota
|
|
2
|
-
|
|
3
|
-
Display OpenAI Codex subscription quota, reset windows, and a compact status line using the authenticated `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` | Show the Codex quota summary |
|
|
18
|
-
| `/oai-subquota refresh` | Force a new quota query |
|
|
19
|
-
| `/oai-subquota statusline` | Print compact quota text |
|
|
20
|
-
| `/oai-subquota chatgpt` | Report the parked ChatGPT OAuth integration's status |
|
|
21
|
-
|
|
22
|
-
## Authentication and cache
|
|
23
|
-
|
|
24
|
-
Authenticate through `/login openai-codex`. The extension uses Pi's provider authentication rather than a separate API-key setting. Cached snapshots are stored at `$XDG_CACHE_HOME/oai-subquota/usage.json`, falling back to `~/.cache/oai-subquota/usage.json`. The normal cache lifetime is 60 seconds.
|
|
25
|
-
|
|
26
|
-
The current implementation supports the Codex usage endpoint. General ChatGPT subscription quota lookup is explicitly parked and does not provide a working second quota source. Backend availability and subscription eligibility determine whether fresh quota data can be retrieved.
|
|
27
|
-
|
|
28
|
-
## Source layout
|
|
29
|
-
|
|
30
|
-
`index.ts` registers the command and lifecycle hooks and coordinates refreshes. `auth.ts` reads account claims from the provider token; `api.ts` handles usage requests; `cache.ts` handles snapshot persistence; `snapshot.ts` normalizes API responses and captured headers and merges snapshots. `types.ts` defines the shared data model, and `ui.ts` formats and renders quota output. The entrypoint re-exports the existing public types and formatting helpers.
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { isRecord } from "./snapshot.ts";
|
|
2
|
-
|
|
3
|
-
const USAGE_ENDPOINT = "https://chatgpt.com/backend-api/wham/usage";
|
|
4
|
-
const REQUEST_TIMEOUT_MS = 15_000;
|
|
5
|
-
|
|
6
|
-
export async function queryUsage(accessToken: string, accountId?: string): Promise<Record<string, unknown>> {
|
|
7
|
-
const headers: Record<string, string> = {
|
|
8
|
-
Authorization: `Bearer ${accessToken}`,
|
|
9
|
-
"User-Agent": "codex-cli",
|
|
10
|
-
Accept: "application/json",
|
|
11
|
-
};
|
|
12
|
-
if (accountId) headers["ChatGPT-Account-Id"] = accountId;
|
|
13
|
-
|
|
14
|
-
const res = await fetch(USAGE_ENDPOINT, {
|
|
15
|
-
method: "GET",
|
|
16
|
-
headers,
|
|
17
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
if (res.status === 401 || res.status === 403) throw new Error(`Authentication rejected (HTTP ${res.status}). Please run /login openai-codex.`);
|
|
21
|
-
if (res.status === 429) throw new Error("Rate limit exceeded for usage endpoint (HTTP 429). Please try again later.");
|
|
22
|
-
if (!res.ok) throw new Error(`Usage request failed (HTTP ${res.status}).`);
|
|
23
|
-
|
|
24
|
-
const body = await res.json();
|
|
25
|
-
if (!isRecord(body)) throw new Error("Invalid JSON received from usage endpoint.");
|
|
26
|
-
return body;
|
|
27
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Buffer } from "node:buffer";
|
|
2
|
-
import { isRecord } from "./snapshot.ts";
|
|
3
|
-
import type { AccountSnapshot } from "./types.ts";
|
|
4
|
-
|
|
5
|
-
const JWT_AUTH_CLAIM = "https://api.openai.com/auth";
|
|
6
|
-
const JWT_PROFILE_CLAIM = "https://api.openai.com/profile";
|
|
7
|
-
|
|
8
|
-
function decodeJwtPayload(token: string): Record<string, unknown> | undefined {
|
|
9
|
-
const part = token.split(".")[1];
|
|
10
|
-
if (!part) return undefined;
|
|
11
|
-
try {
|
|
12
|
-
const json = JSON.parse(Buffer.from(part, "base64url").toString("utf8"));
|
|
13
|
-
return isRecord(json) ? json : undefined;
|
|
14
|
-
} catch {
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function extractAccountFromToken(token: string): AccountSnapshot {
|
|
20
|
-
const payload = decodeJwtPayload(token);
|
|
21
|
-
if (!payload) return {};
|
|
22
|
-
|
|
23
|
-
const auth = isRecord(payload[JWT_AUTH_CLAIM]) ? payload[JWT_AUTH_CLAIM] : undefined;
|
|
24
|
-
const profile = isRecord(payload[JWT_PROFILE_CLAIM]) ? payload[JWT_PROFILE_CLAIM] : undefined;
|
|
25
|
-
|
|
26
|
-
const accountId = typeof auth?.chatgpt_account_id === "string" ? auth.chatgpt_account_id : undefined;
|
|
27
|
-
const plan = typeof auth?.chatgpt_plan_type === "string" ? auth.chatgpt_plan_type : undefined;
|
|
28
|
-
const email =
|
|
29
|
-
(typeof profile?.email === "string" && profile.email) ||
|
|
30
|
-
(typeof payload.email === "string" && payload.email) ||
|
|
31
|
-
undefined;
|
|
32
|
-
|
|
33
|
-
return { accountId, plan, email };
|
|
34
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
import { isRecord } from "./snapshot.ts";
|
|
5
|
-
import type { CodexUsageSnapshot } from "./types.ts";
|
|
6
|
-
|
|
7
|
-
function getCachePath(): string {
|
|
8
|
-
const base = process.env.XDG_CACHE_HOME || join(homedir() || ".", ".cache");
|
|
9
|
-
return join(base, "oai-subquota", "usage.json");
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export async function readCachedSnapshot(): Promise<CodexUsageSnapshot | undefined> {
|
|
13
|
-
try {
|
|
14
|
-
const raw = await readFile(getCachePath(), "utf8");
|
|
15
|
-
const parsed = JSON.parse(raw);
|
|
16
|
-
return isRecord(parsed) ? (parsed as unknown as CodexUsageSnapshot) : undefined;
|
|
17
|
-
} catch {
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function writeCachedSnapshot(snapshot: CodexUsageSnapshot): Promise<void> {
|
|
23
|
-
try {
|
|
24
|
-
const file = getCachePath();
|
|
25
|
-
await mkdir(dirname(file), { recursive: true });
|
|
26
|
-
await writeFile(file, `${JSON.stringify(snapshot, null, 2)}\n`, { mode: 0o600 });
|
|
27
|
-
} catch {
|
|
28
|
-
// Non-fatal if filesystem is read-only
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
export interface LimitWindow {
|
|
2
|
-
usedPercent: number;
|
|
3
|
-
leftPercent: number;
|
|
4
|
-
windowSeconds?: number;
|
|
5
|
-
resetAt?: number;
|
|
6
|
-
resetAfterSeconds?: number;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface RateLimit {
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
primary?: LimitWindow;
|
|
13
|
-
secondary?: LimitWindow;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface CreditsSnapshot {
|
|
17
|
-
hasCredits?: boolean;
|
|
18
|
-
unlimited?: boolean;
|
|
19
|
-
balance?: number | string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ResetsSnapshot {
|
|
23
|
-
availableCount?: number;
|
|
24
|
-
applicableCount?: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface AccountSnapshot {
|
|
28
|
-
email?: string;
|
|
29
|
-
plan?: string;
|
|
30
|
-
accountId?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface CodexUsageSnapshot {
|
|
34
|
-
source: "api" | "headers" | "cache";
|
|
35
|
-
fetchedAt: string;
|
|
36
|
-
account: AccountSnapshot;
|
|
37
|
-
defaultLimit?: RateLimit;
|
|
38
|
-
credits?: CreditsSnapshot;
|
|
39
|
-
resets?: ResetsSnapshot;
|
|
40
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# prompt-snipaste
|
|
2
|
-
|
|
3
|
-
Choose prompt snippets to prepend or append to the next user message, with a terminal preview and a session transcript card.
|
|
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 `/snipaste` or press Alt+S. Use the arrow keys to navigate, Space to toggle snippets, Tab to preview, Enter to confirm, and Escape to cancel. Selected snippets apply once to the next user input; they are then cleared.
|
|
16
|
-
|
|
17
|
-
## Prompt configuration
|
|
18
|
-
|
|
19
|
-
The picker uses Pi's resolved prompt commands, including prompts installed through packages. Package resource filters and disabled prompts are respected; a top-level `prompts: []` does not hide enabled package prompts. Personal and project prompt directories or explicit prompt paths can still be configured through Pi normally.
|
|
20
|
-
|
|
21
|
-
Markdown frontmatter controls each snippet:
|
|
22
|
-
|
|
23
|
-
```markdown
|
|
24
|
-
---
|
|
25
|
-
name: Review checklist
|
|
26
|
-
description: Add the review criteria to the next message
|
|
27
|
-
placement: append
|
|
28
|
-
order: 100
|
|
29
|
-
---
|
|
30
|
-
Check correctness, error handling, and missing validation.
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
`placement` accepts `prepend` or `append`; append is the default. Lower `order` values come first within a placement. Without frontmatter, the file name becomes the snippet name and the body is used directly. The extension's fallback loader, when used without a Pi runtime, reads conventional prompt directories and explicit prompt paths.
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# screenshot
|
|
2
|
-
|
|
3
|
-
Insert the path of the newest Windows system screenshot into Pi's editor. It references an existing image rather than taking a new screenshot.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
pi install npm:@rol1n/screenshot
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Available independently; it is not enabled in the aggregate package by default.
|
|
12
|
-
|
|
13
|
-
## Use
|
|
14
|
-
|
|
15
|
-
Take a screenshot with the system screenshot tool, then run `/screenshot` in Pi. The extension finds the newest supported image by modification time and pastes its path into the editor.
|
|
16
|
-
|
|
17
|
-
## Platform support
|
|
18
|
-
|
|
19
|
-
Native Windows checks standard and localized `Pictures/Screenshots` folders, including supported OneDrive locations, under `USERPROFILE`. WSL searches Windows profiles under the standard `/mnt/c/Users` mount. PNG, JPEG, GIF, BMP, and WebP files are supported.
|
|
20
|
-
|
|
21
|
-
On other platforms the command reports that Windows screenshots are unavailable. There is no screenshot-folder setting; a nonstandard Windows drive mount or screenshot location requires a source change. No model credentials are needed.
|
|
22
|
-
|
|
23
|
-
## Source layout
|
|
24
|
-
|
|
25
|
-
`index.ts` registers the editor command. `discovery.ts` contains platform detection, screenshot-folder discovery, and newest-image selection.
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# srp-theme
|
|
2
|
-
|
|
3
|
-
A Pi terminal presentation extension with a custom footer, prompt preview, agent-loop timing, and a tokens-per-second meter. It is an extension rather than a JSON theme package.
|
|
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
|
-
```
|
|
19
|
-
|
|
20
|
-
These commands enable or disable the extension's footer/prompt presentation and TPS meter for the running session. The extension observes agent and turn events to update timing and throughput information.
|
|
21
|
-
|
|
22
|
-
## Requirements and customization
|
|
23
|
-
|
|
24
|
-
Use Pi's interactive terminal mode for the custom widgets. The extension uses the active Pi theme's colors and does not replace your selected JSON theme. Appearance and layout constants live in `extensions/srp-theme/footer.ts` and `extensions/srp-theme/tps-meter.ts`; lifecycle hooks and the command are wired in `extensions/srp-theme/index.ts`. There is currently no package-specific settings section. No credentials or system binaries are required by the presentation layer itself.
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: subagent
|
|
3
|
-
description: Dispatch, message, and collaborate with parallel, full-powered Pi subagent workers running in split terminal panes or silent background processes.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Subagent
|
|
7
|
-
|
|
8
|
-
Use the native `subagent` tool to delegate tasks to independent, full-powered Pi instances ("workers"). Workers run in dedicated split terminal panes (inside tmux or Zellij) or run silently as background processes (in standard terminals, VSCode, CI/CD, or headless environments). Every worker inherits all standard tools, skills, and extensions, and operates completely asynchronously.
|
|
9
|
-
|
|
10
|
-
## Spawning Workers
|
|
11
|
-
|
|
12
|
-
Call the `subagent` tool directly. The tool returns **immediately** with an acknowledgement. You do **not** need to wait or poll:
|
|
13
|
-
|
|
14
|
-
```json
|
|
15
|
-
subagent({
|
|
16
|
-
"task": "Investigate the authentication middleware in src/auth.ts and propose fixes.",
|
|
17
|
-
"name": "auth-audit"
|
|
18
|
-
})
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
- `task`: Clear, comprehensive instructions for the worker.
|
|
22
|
-
- `name`: Short, descriptive identifier (e.g. `frontend`, `db-migration`, `tester`).
|
|
23
|
-
- `model`: (Optional) Model override (e.g. a faster model for simple exploration).
|
|
24
|
-
- `cwd`: (Optional) Working directory for the worker.
|
|
25
|
-
|
|
26
|
-
### Parallel Workers
|
|
27
|
-
|
|
28
|
-
You can dispatch **multiple workers in parallel in a single turn**:
|
|
29
|
-
|
|
30
|
-
```json
|
|
31
|
-
[
|
|
32
|
-
{ "name": "subagent", "arguments": { "task": "Audit frontend router in src/routes/", "name": "frontend" } },
|
|
33
|
-
{ "name": "subagent", "arguments": { "task": "Audit database models in src/db/", "name": "backend" } }
|
|
34
|
-
]
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
All workers run concurrently in separate split panes. As each worker finishes, the system automatically injects its final result into your conversation as a **steer message**, waking you up to review the findings.
|
|
38
|
-
|
|
39
|
-
## Non-Blocking Principle
|
|
40
|
-
|
|
41
|
-
- **DO NOT** write bash scripts, `sleep` commands, `tail` logs, or polling loops to check on a worker.
|
|
42
|
-
- **DO NOT** fabricate or assume worker results before receiving the steer message.
|
|
43
|
-
- After calling `subagent`, either end your turn immediately or work on other independent tasks. The harness will wake you with the result as soon as it is ready.
|
|
44
|
-
|
|
45
|
-
## Answering Worker Questions
|
|
46
|
-
|
|
47
|
-
Workers have an `ask_question` tool. When a worker encounters ambiguity or needs a decision:
|
|
48
|
-
1. The worker pauses its work and marks itself as `waiting: ask`.
|
|
49
|
-
2. You receive a steer notification: `[Subagent "<name>" question] ...`.
|
|
50
|
-
3. Answer the worker by targeting its name:
|
|
51
|
-
|
|
52
|
-
```json
|
|
53
|
-
subagent({
|
|
54
|
-
"target": "auth-audit",
|
|
55
|
-
"task": "Use the JWT verification method rather than session cookies."
|
|
56
|
-
})
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
The worker absorbs your guidance, resumes execution, and reports back when done.
|
|
60
|
-
|
|
61
|
-
## Stopping a Worker
|
|
62
|
-
|
|
63
|
-
If a worker is no longer needed or is off-track, terminate it:
|
|
64
|
-
|
|
65
|
-
```json
|
|
66
|
-
subagent({
|
|
67
|
-
"target": "auth-audit",
|
|
68
|
-
"action": "stop"
|
|
69
|
-
})
|
|
70
|
-
```
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# tui-asr
|
|
2
|
-
|
|
3
|
-
Streaming voice dictation for Pi's terminal editor using Aliyun DashScope Paraformer. Includes a live audio-level meter and a searchable ASR model selector.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
pi install npm:@rol1n/tui-asr
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Also included in `@rol1n/pi-kit`. The extension entrypoint is `extensions/tui-asr/index.ts`; `dictation.ts` owns the recording lifecycle, with separate audio, provider/auth, clipboard, input insertion, status animation, and model-selector helpers.
|
|
12
|
-
|
|
13
|
-
## Commands and shortcuts
|
|
14
|
-
|
|
15
|
-
| Action | Command or shortcut |
|
|
16
|
-
|---|---|
|
|
17
|
-
| Start or stop dictation | `/asr` or Alt+M |
|
|
18
|
-
| Cancel dictation | Alt+N |
|
|
19
|
-
| Choose a model | `/asr model` |
|
|
20
|
-
| Select by model ID | `/asr model paraformer-realtime-v2` |
|
|
21
|
-
|
|
22
|
-
The startup model is `paraformer-realtime-v2`. Final transcripts are inserted into the focused editor/input target, with a system clipboard fallback when direct insertion is unavailable.
|
|
23
|
-
|
|
24
|
-
## Requirements and authentication
|
|
25
|
-
|
|
26
|
-
Install SoX and ensure the recorder is on PATH: Windows uses `sox` with the `waveaudio` input, while POSIX uses `rec` / `sox` with the default audio device. A usable microphone and OS recording permission are required. Clipboard fallback uses the platform's clipboard utility, such as `clip`, `pbcopy`, or Wayland/X11 tools.
|
|
27
|
-
|
|
28
|
-
Supply `DASHSCOPE_API_KEY` or `ALIYUN_API_KEY`, or authenticate through `/login dashscope` when [custom-providers](https://github.com/RolinShmily/pi-kit/tree/main/extensions/custom-providers) is loaded. Shared ASR helpers ship in this package; provider registration remains a separate extension entrypoint. Model selection is session-local.
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { spawn, type ChildProcessByStdio } from "node:child_process";
|
|
2
|
-
import type { Readable } from "node:stream";
|
|
3
|
-
|
|
4
|
-
export function rmsFromPcm16(buf: Buffer): number {
|
|
5
|
-
if (buf.length < 2) return 0;
|
|
6
|
-
const sampleCount = Math.floor(buf.length / 2);
|
|
7
|
-
let sumSquares = 0;
|
|
8
|
-
for (let i = 0; i < sampleCount; i++) {
|
|
9
|
-
const sample = buf.readInt16LE(i * 2);
|
|
10
|
-
sumSquares += sample * sample;
|
|
11
|
-
}
|
|
12
|
-
const meanSquare = sumSquares / sampleCount;
|
|
13
|
-
return Math.sqrt(meanSquare);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Spawn the existing 16 kHz mono PCM recorder for the current platform. */
|
|
17
|
-
export function spawnRecorder(): ChildProcessByStdio<null, Readable, Readable> {
|
|
18
|
-
const commonAudioArgs = [
|
|
19
|
-
"-q",
|
|
20
|
-
"--buffer", "512",
|
|
21
|
-
"-r", "16000",
|
|
22
|
-
"-c", "1",
|
|
23
|
-
"-b", "16",
|
|
24
|
-
"-e", "signed-integer",
|
|
25
|
-
"-t", "raw",
|
|
26
|
-
"-",
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
let proc: ChildProcessByStdio<null, Readable, Readable>;
|
|
30
|
-
if (process.platform === "win32") {
|
|
31
|
-
proc = spawn("sox", ["-t", "waveaudio", "default", ...commonAudioArgs], { stdio: ["ignore", "pipe", "pipe"] });
|
|
32
|
-
} else {
|
|
33
|
-
try {
|
|
34
|
-
proc = spawn("rec", commonAudioArgs, { stdio: ["ignore", "pipe", "pipe"] });
|
|
35
|
-
} catch {
|
|
36
|
-
proc = spawn("sox", ["-d", ...commonAudioArgs], { stdio: ["ignore", "pipe", "pipe"] });
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return proc;
|
|
40
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { spawn, type ChildProcessByStdio } from "node:child_process";
|
|
2
|
-
|
|
3
|
-
export function copyToClipboard(text: string): boolean {
|
|
4
|
-
try {
|
|
5
|
-
const isWsl =
|
|
6
|
-
process.platform === "linux" &&
|
|
7
|
-
typeof process.env.WSL_DISTRO_NAME === "string";
|
|
8
|
-
|
|
9
|
-
let proc: ChildProcessByStdio<any, any, any>;
|
|
10
|
-
if (isWsl) {
|
|
11
|
-
proc = spawn("clip.exe", [], { stdio: ["pipe", "ignore", "ignore"] });
|
|
12
|
-
} else if (process.platform === "win32") {
|
|
13
|
-
proc = spawn("clip", [], { stdio: ["pipe", "ignore", "ignore"] });
|
|
14
|
-
} else if (process.platform === "darwin") {
|
|
15
|
-
proc = spawn("pbcopy", [], { stdio: ["pipe", "ignore", "ignore"] });
|
|
16
|
-
} else {
|
|
17
|
-
try {
|
|
18
|
-
proc = spawn("wl-copy", [], { stdio: ["pipe", "ignore", "ignore"] });
|
|
19
|
-
} catch {
|
|
20
|
-
proc = spawn("xclip", ["-selection", "clipboard"], { stdio: ["pipe", "ignore", "ignore"] });
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
proc.stdin.write(text);
|
|
25
|
-
proc.stdin.end();
|
|
26
|
-
return true;
|
|
27
|
-
} catch {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
}
|