@psnext/slingcli 2.5.20260722-2 → 2.5.20260722-3
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/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +9 -7
- package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +25 -23
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +32 -19
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +6 -7
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +75 -26
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/utils.js +6 -17
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.js +56 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/memory-storage.js +56 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo-utils.js +2 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +30 -14
- package/node_modules/@earendil-works/pi-agent-core/dist/index.js +4 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/stream-fn.js +17 -0
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +2 -7
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +14 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js +2 -4
- package/node_modules/@earendil-works/pi-ai/dist/auth/helpers.js +3 -2
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js +249 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +60 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +4 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/all.js +8 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +3 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cerebras.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/groq.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/kimi-coding.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai-cn.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai-codex.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan-cn.json +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan.json +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/xai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.js +10 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.js +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan-cn.js +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan-cn.models.js +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan.js +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/qwen-token-plan.models.js +5 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/radius-config.js +18 -14
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +3 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +79 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/text.js +10 -0
- package/node_modules/@earendil-works/{pi-agent-core/dist/harness/session → pi-ai/dist/utils}/uuid.js +4 -8
- package/node_modules/@earendil-works/pi-ai/package.json +8 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +72 -57
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/branch-summarization.js +8 -11
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +63 -26
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/utils.js +6 -17
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +5 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-runtime.js +18 -15
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/remote-catalog-provider.js +26 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +6 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +100 -24
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/usage-totals.js +52 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/client.js +3 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/index.js +3 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +5 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js +20 -21
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +69 -25
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.js +7 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +4 -0
- package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +16 -31
- package/node_modules/@earendil-works/pi-coding-agent/package.json +4 -4
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/cli.js +5 -5
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/config.js +9 -9
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/ipc/client.js +1 -1
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/ipc/server.js +1 -1
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/radius.js +8 -8
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/rpc-process.js +1 -1
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/serve.js +3 -3
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/storage.js +7 -7
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/supervisor.js +2 -2
- package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/package.json +9 -6
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +16 -10
- package/node_modules/@earendil-works/pi-tui/dist/tui.js +4 -2
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
- package/slingshot/index.js +253 -250
- /package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/handler.js +0 -0
- /package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/index.js +0 -0
- /package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/ipc/protocol.js +0 -0
- /package/node_modules/@earendil-works/{pi-orchestrator → pi-server}/dist/types.js +0 -0
package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js
CHANGED
|
@@ -24,6 +24,7 @@ import { SessionManager, sessionEntryToContextMessages } from "../../core/sessio
|
|
|
24
24
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
25
25
|
import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
26
26
|
import { hasTrustRequiringProjectResources, ProjectTrustStore } from "../../core/trust-manager.js";
|
|
27
|
+
import { getUsageCostBreakdown } from "../../core/usage-totals.js";
|
|
27
28
|
import { getChangelogPath, getNewEntries, normalizeChangelogLinks, parseChangelog } from "../../utils/changelog.js";
|
|
28
29
|
import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
|
|
29
30
|
import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
|
|
@@ -191,8 +192,9 @@ export class InteractiveMode {
|
|
|
191
192
|
hiddenThinkingLabel = this.defaultHiddenThinkingLabel;
|
|
192
193
|
lastSigintTime = 0;
|
|
193
194
|
lastEscapeTime = 0;
|
|
195
|
+
changelogMarkdown = undefined;
|
|
194
196
|
startupNoticesShown = false;
|
|
195
|
-
|
|
197
|
+
anthropicSubscriptionWarningShown = false;
|
|
196
198
|
// Status line tracking (for mutating immediately-sequential status updates)
|
|
197
199
|
lastStatusSpacer = undefined;
|
|
198
200
|
lastStatusText = undefined;
|
|
@@ -427,6 +429,32 @@ export class InteractiveMode {
|
|
|
427
429
|
this.editor.setAutocompleteProvider?.(provider);
|
|
428
430
|
}
|
|
429
431
|
}
|
|
432
|
+
showStartupNoticesIfNeeded() {
|
|
433
|
+
if (this.startupNoticesShown) {
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
this.startupNoticesShown = true;
|
|
437
|
+
if (!this.changelogMarkdown) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
if (this.chatContainer.children.length > 0) {
|
|
441
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
442
|
+
}
|
|
443
|
+
this.chatContainer.addChild(new DynamicBorder());
|
|
444
|
+
if (this.settingsManager.getCollapseChangelog()) {
|
|
445
|
+
const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
|
|
446
|
+
const latestVersion = versionMatch ? versionMatch[1] : this.version;
|
|
447
|
+
const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
|
|
448
|
+
this.chatContainer.addChild(new Text(condensedText, 1, 0));
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
|
|
452
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
453
|
+
this.chatContainer.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, this.getMarkdownThemeWithSettings()));
|
|
454
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
455
|
+
}
|
|
456
|
+
this.chatContainer.addChild(new DynamicBorder());
|
|
457
|
+
}
|
|
430
458
|
async init() {
|
|
431
459
|
if (this.isInitialized)
|
|
432
460
|
return;
|
|
@@ -553,6 +581,12 @@ export class InteractiveMode {
|
|
|
553
581
|
*/
|
|
554
582
|
async run() {
|
|
555
583
|
await this.init();
|
|
584
|
+
if (!process.env.PI_OFFLINE) {
|
|
585
|
+
void this.session.modelRuntime
|
|
586
|
+
.refresh()
|
|
587
|
+
.then(() => this.updateAvailableProviderCount())
|
|
588
|
+
.catch(() => { });
|
|
589
|
+
}
|
|
556
590
|
// Start version check asynchronously
|
|
557
591
|
checkForNewPiVersion(this.version).then((newRelease) => {
|
|
558
592
|
if (newRelease) {
|
|
@@ -679,7 +713,7 @@ export class InteractiveMode {
|
|
|
679
713
|
return "tmux extended-keys is off. Modified Enter keys may not work. Add `set -g extended-keys on` to ~/.tmux.conf and restart tmux.";
|
|
680
714
|
}
|
|
681
715
|
if (extendedKeysFormat === "xterm") {
|
|
682
|
-
return "tmux extended-keys-format is xterm.
|
|
716
|
+
return "tmux extended-keys-format is xterm. Pi works best with csi-u. Add `set -g extended-keys-format csi-u` to ~/.tmux.conf and restart tmux.";
|
|
683
717
|
}
|
|
684
718
|
return undefined;
|
|
685
719
|
}
|
|
@@ -2488,6 +2522,28 @@ export class InteractiveMode {
|
|
|
2488
2522
|
this.ui.requestRender();
|
|
2489
2523
|
break;
|
|
2490
2524
|
}
|
|
2525
|
+
case "summarization_retry_scheduled": {
|
|
2526
|
+
this.showError(event.errorMessage);
|
|
2527
|
+
this.showStatusIndicator(new RetryStatusIndicator(this.ui, event.attempt, event.maxAttempts, event.delayMs));
|
|
2528
|
+
this.ui.requestRender();
|
|
2529
|
+
break;
|
|
2530
|
+
}
|
|
2531
|
+
case "summarization_retry_attempt_start": {
|
|
2532
|
+
this.clearStatusIndicator("retry");
|
|
2533
|
+
if (event.source === "branchSummary") {
|
|
2534
|
+
this.showStatusIndicator(new BranchSummaryStatusIndicator(this.ui));
|
|
2535
|
+
}
|
|
2536
|
+
else {
|
|
2537
|
+
this.showStatusIndicator(new CompactionStatusIndicator(this.ui, event.reason));
|
|
2538
|
+
}
|
|
2539
|
+
this.ui.requestRender();
|
|
2540
|
+
break;
|
|
2541
|
+
}
|
|
2542
|
+
case "summarization_retry_finished": {
|
|
2543
|
+
this.clearStatusIndicator("retry");
|
|
2544
|
+
this.ui.requestRender();
|
|
2545
|
+
break;
|
|
2546
|
+
}
|
|
2491
2547
|
}
|
|
2492
2548
|
}
|
|
2493
2549
|
/** Extract text content from a user message */
|
|
@@ -3566,10 +3622,12 @@ export class InteractiveMode {
|
|
|
3566
3622
|
return [];
|
|
3567
3623
|
}
|
|
3568
3624
|
}
|
|
3569
|
-
/** Update the footer's available provider count from current
|
|
3570
|
-
|
|
3571
|
-
const models =
|
|
3572
|
-
|
|
3625
|
+
/** Update the footer's available provider count from the current snapshot without refreshing catalogs. */
|
|
3626
|
+
updateAvailableProviderCount() {
|
|
3627
|
+
const models = this.session.scopedModels.length > 0
|
|
3628
|
+
? this.session.scopedModels.map((scoped) => scoped.model)
|
|
3629
|
+
: this.session.modelRuntime.getAvailableSnapshot();
|
|
3630
|
+
const uniqueProviders = new Set(models.map((model) => model.provider));
|
|
3573
3631
|
this.footerDataProvider.setAvailableProviderCount(uniqueProviders.size);
|
|
3574
3632
|
}
|
|
3575
3633
|
async maybeWarnAboutAnthropicSubscriptionAuth(model = this.session.model) {
|
|
@@ -4657,23 +4715,9 @@ export class InteractiveMode {
|
|
|
4657
4715
|
const entries = this.sessionManager.getEntries();
|
|
4658
4716
|
const cacheWaste = computeCacheWaste(entries, this.session.modelRuntime);
|
|
4659
4717
|
// Cost/token totals per provider/model actually used (e.g. OpenRouter `auto`
|
|
4660
|
-
// resolves to a concrete responseModel)
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
if (entry.type !== "message" || entry.message.role !== "assistant")
|
|
4664
|
-
continue;
|
|
4665
|
-
const message = entry.message;
|
|
4666
|
-
const usage = message.usage;
|
|
4667
|
-
const key = `${message.provider}/${message.responseModel ?? message.model}`;
|
|
4668
|
-
let bucket = perModelMap.get(key);
|
|
4669
|
-
if (!bucket) {
|
|
4670
|
-
bucket = { key, cost: 0, tokens: 0 };
|
|
4671
|
-
perModelMap.set(key, bucket);
|
|
4672
|
-
}
|
|
4673
|
-
bucket.cost += usage.cost.total;
|
|
4674
|
-
bucket.tokens += usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
4675
|
-
}
|
|
4676
|
-
const perModel = Array.from(perModelMap.values()).sort((a, b) => b.cost - a.cost);
|
|
4718
|
+
// resolves to a concrete responseModel). Usage without model attribution is
|
|
4719
|
+
// grouped separately so the breakdown reconciles with the session total.
|
|
4720
|
+
const usageBreakdown = getUsageCostBreakdown(entries);
|
|
4677
4721
|
let info = `${theme.bold("Session Info")}\n\n`;
|
|
4678
4722
|
if (sessionName) {
|
|
4679
4723
|
info += `${theme.fg("dim", "Name:")} ${sessionName}\n`;
|
|
@@ -4704,8 +4748,8 @@ export class InteractiveMode {
|
|
|
4704
4748
|
if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
|
|
4705
4749
|
info += `\n${theme.bold("Cost")}\n`;
|
|
4706
4750
|
info += `${theme.fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
|
|
4707
|
-
if (
|
|
4708
|
-
for (const entry of
|
|
4751
|
+
if (usageBreakdown.length > 1) {
|
|
4752
|
+
for (const entry of usageBreakdown) {
|
|
4709
4753
|
info += `\n ${theme.fg("dim", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${theme.fg("dim", `(${formatTokens(entry.tokens)} tokens)`)}`;
|
|
4710
4754
|
}
|
|
4711
4755
|
}
|
|
@@ -203,6 +203,13 @@ export class RpcClient {
|
|
|
203
203
|
const response = await this.send({ type: "cycle_thinking_level" });
|
|
204
204
|
return this.getData(response);
|
|
205
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* Get list of available thinking levels for the current model.
|
|
208
|
+
*/
|
|
209
|
+
async getAvailableThinkingLevels() {
|
|
210
|
+
const response = await this.send({ type: "get_available_thinking_levels" });
|
|
211
|
+
return this.getData(response).levels;
|
|
212
|
+
}
|
|
206
213
|
/**
|
|
207
214
|
* Set steering mode.
|
|
208
215
|
*/
|
|
@@ -394,6 +394,10 @@ export async function runRpcMode(runtimeHost) {
|
|
|
394
394
|
}
|
|
395
395
|
return success(id, "cycle_thinking_level", { level });
|
|
396
396
|
}
|
|
397
|
+
case "get_available_thinking_levels": {
|
|
398
|
+
const levels = session.getAvailableThinkingLevels();
|
|
399
|
+
return success(id, "get_available_thinking_levels", { levels });
|
|
400
|
+
}
|
|
397
401
|
// =================================================================
|
|
398
402
|
// Queue Modes
|
|
399
403
|
// =================================================================
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-coding-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.81.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@earendil-works/pi-coding-agent",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.81.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
13
|
-
"@earendil-works/pi-ai": "^0.
|
|
14
|
-
"@earendil-works/pi-tui": "^0.
|
|
12
|
+
"@earendil-works/pi-agent-core": "^0.81.1",
|
|
13
|
+
"@earendil-works/pi-ai": "^0.81.1",
|
|
14
|
+
"@earendil-works/pi-tui": "^0.81.1",
|
|
15
15
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
16
16
|
"chalk": "5.6.2",
|
|
17
17
|
"cross-spawn": "7.0.6",
|
|
@@ -474,11 +474,11 @@
|
|
|
474
474
|
}
|
|
475
475
|
},
|
|
476
476
|
"node_modules/@earendil-works/pi-agent-core": {
|
|
477
|
-
"version": "0.
|
|
478
|
-
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.
|
|
477
|
+
"version": "0.81.1",
|
|
478
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.81.1.tgz",
|
|
479
479
|
"license": "MIT",
|
|
480
480
|
"dependencies": {
|
|
481
|
-
"@earendil-works/pi-ai": "^0.
|
|
481
|
+
"@earendil-works/pi-ai": "^0.81.1",
|
|
482
482
|
"ignore": "7.0.5",
|
|
483
483
|
"typebox": "1.1.38",
|
|
484
484
|
"yaml": "2.9.0"
|
|
@@ -488,8 +488,8 @@
|
|
|
488
488
|
}
|
|
489
489
|
},
|
|
490
490
|
"node_modules/@earendil-works/pi-ai": {
|
|
491
|
-
"version": "0.
|
|
492
|
-
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.
|
|
491
|
+
"version": "0.81.1",
|
|
492
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.81.1.tgz",
|
|
493
493
|
"license": "MIT",
|
|
494
494
|
"dependencies": {
|
|
495
495
|
"@anthropic-ai/sdk": "0.91.1",
|
|
@@ -505,15 +505,15 @@
|
|
|
505
505
|
"typebox": "1.1.38"
|
|
506
506
|
},
|
|
507
507
|
"bin": {
|
|
508
|
-
"pi-ai": "
|
|
508
|
+
"pi-ai": "dist/cli.js"
|
|
509
509
|
},
|
|
510
510
|
"engines": {
|
|
511
511
|
"node": ">=22.19.0"
|
|
512
512
|
}
|
|
513
513
|
},
|
|
514
514
|
"node_modules/@earendil-works/pi-tui": {
|
|
515
|
-
"version": "0.
|
|
516
|
-
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.
|
|
515
|
+
"version": "0.81.1",
|
|
516
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.81.1.tgz",
|
|
517
517
|
"license": "MIT",
|
|
518
518
|
"dependencies": {
|
|
519
519
|
"get-east-asian-width": "1.6.0",
|
|
@@ -628,9 +628,6 @@
|
|
|
628
628
|
"cpu": [
|
|
629
629
|
"arm64"
|
|
630
630
|
],
|
|
631
|
-
"libc": [
|
|
632
|
-
"glibc"
|
|
633
|
-
],
|
|
634
631
|
"optional": true
|
|
635
632
|
},
|
|
636
633
|
"node_modules/@mariozechner/clipboard-linux-arm64-musl": {
|
|
@@ -647,9 +644,6 @@
|
|
|
647
644
|
"cpu": [
|
|
648
645
|
"arm64"
|
|
649
646
|
],
|
|
650
|
-
"libc": [
|
|
651
|
-
"musl"
|
|
652
|
-
],
|
|
653
647
|
"optional": true
|
|
654
648
|
},
|
|
655
649
|
"node_modules/@mariozechner/clipboard-linux-riscv64-gnu": {
|
|
@@ -666,9 +660,6 @@
|
|
|
666
660
|
"cpu": [
|
|
667
661
|
"riscv64"
|
|
668
662
|
],
|
|
669
|
-
"libc": [
|
|
670
|
-
"glibc"
|
|
671
|
-
],
|
|
672
663
|
"optional": true
|
|
673
664
|
},
|
|
674
665
|
"node_modules/@mariozechner/clipboard-linux-x64-gnu": {
|
|
@@ -685,9 +676,6 @@
|
|
|
685
676
|
"cpu": [
|
|
686
677
|
"x64"
|
|
687
678
|
],
|
|
688
|
-
"libc": [
|
|
689
|
-
"glibc"
|
|
690
|
-
],
|
|
691
679
|
"optional": true
|
|
692
680
|
},
|
|
693
681
|
"node_modules/@mariozechner/clipboard-linux-x64-musl": {
|
|
@@ -704,9 +692,6 @@
|
|
|
704
692
|
"cpu": [
|
|
705
693
|
"x64"
|
|
706
694
|
],
|
|
707
|
-
"libc": [
|
|
708
|
-
"musl"
|
|
709
|
-
],
|
|
710
695
|
"optional": true
|
|
711
696
|
},
|
|
712
697
|
"node_modules/@mariozechner/clipboard-win32-arm64-msvc": {
|
|
@@ -1037,9 +1022,9 @@
|
|
|
1037
1022
|
"license": "MIT"
|
|
1038
1023
|
},
|
|
1039
1024
|
"node_modules/brace-expansion": {
|
|
1040
|
-
"version": "5.0.
|
|
1041
|
-
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.
|
|
1042
|
-
"integrity": "sha512-
|
|
1025
|
+
"version": "5.0.7",
|
|
1026
|
+
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
|
|
1027
|
+
"integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
|
|
1043
1028
|
"license": "MIT",
|
|
1044
1029
|
"dependencies": {
|
|
1045
1030
|
"balanced-match": "^4.0.2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-coding-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.81.1",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"piConfig": {
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"prepublishOnly": "npm run clean && npm run build && npm run shrinkwrap"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
44
|
-
"@earendil-works/pi-ai": "^0.
|
|
45
|
-
"@earendil-works/pi-tui": "^0.
|
|
43
|
+
"@earendil-works/pi-agent-core": "^0.81.1",
|
|
44
|
+
"@earendil-works/pi-ai": "^0.81.1",
|
|
45
|
+
"@earendil-works/pi-tui": "^0.81.1",
|
|
46
46
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
47
47
|
"chalk": "5.6.2",
|
|
48
48
|
"cross-spawn": "7.0.6",
|
|
@@ -12,7 +12,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
12
12
|
const __dirname = dirname(__filename);
|
|
13
13
|
const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
|
|
14
14
|
function printHelp() {
|
|
15
|
-
console.log(`
|
|
15
|
+
console.log(`server v${packageJson.version}\n\nUsage:\n server serve\n server list\n server spawn [--cwd <path>] [--label <label>]\n server status <instance-id>\n server stop <instance-id>\n server rpc <instance-id> <json-command>\n server rpc-stream <instance-id>\n server --help\n server --version\n\nRPC stream stdin expects JSONL RpcCommand or extension_ui_response messages.`);
|
|
16
16
|
}
|
|
17
17
|
function printResponse(response) {
|
|
18
18
|
console.log(JSON.stringify(response, null, 2));
|
|
@@ -90,7 +90,7 @@ async function main() {
|
|
|
90
90
|
if (args[0] === "status") {
|
|
91
91
|
const instanceId = args[1];
|
|
92
92
|
if (!instanceId) {
|
|
93
|
-
console.error("Usage:
|
|
93
|
+
console.error("Usage: server status <instance-id>");
|
|
94
94
|
process.exit(1);
|
|
95
95
|
}
|
|
96
96
|
printResponse(await sendIpcRequest({ type: "status", instanceId }));
|
|
@@ -99,7 +99,7 @@ async function main() {
|
|
|
99
99
|
if (args[0] === "stop") {
|
|
100
100
|
const instanceId = args[1];
|
|
101
101
|
if (!instanceId) {
|
|
102
|
-
console.error("Usage:
|
|
102
|
+
console.error("Usage: server stop <instance-id>");
|
|
103
103
|
process.exit(1);
|
|
104
104
|
}
|
|
105
105
|
printResponse(await sendIpcRequest({ type: "stop", instanceId }));
|
|
@@ -109,7 +109,7 @@ async function main() {
|
|
|
109
109
|
const instanceId = args[1];
|
|
110
110
|
const commandJson = args[2];
|
|
111
111
|
if (!instanceId || !commandJson) {
|
|
112
|
-
console.error("Usage:
|
|
112
|
+
console.error("Usage: server rpc <instance-id> <json-command>");
|
|
113
113
|
process.exit(1);
|
|
114
114
|
}
|
|
115
115
|
printResponse(await sendIpcRequest({
|
|
@@ -122,7 +122,7 @@ async function main() {
|
|
|
122
122
|
if (args[0] === "rpc-stream") {
|
|
123
123
|
const instanceId = args[1];
|
|
124
124
|
if (!instanceId) {
|
|
125
|
-
console.error("Usage:
|
|
125
|
+
console.error("Usage: server rpc-stream <instance-id>");
|
|
126
126
|
process.exit(1);
|
|
127
127
|
}
|
|
128
128
|
await rpcStream(instanceId);
|
|
@@ -2,8 +2,8 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
const CONFIG_DIR_NAME = ".
|
|
6
|
-
const
|
|
5
|
+
const CONFIG_DIR_NAME = ".pi";
|
|
6
|
+
const ENV_SERVER_DIR = "PI_SERVER_DIR";
|
|
7
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
8
|
const __dirname = dirname(__filename);
|
|
9
9
|
/**
|
|
@@ -32,24 +32,24 @@ catch (e) {
|
|
|
32
32
|
throw e;
|
|
33
33
|
}
|
|
34
34
|
export const VERSION = pkg.version || "0.0.0";
|
|
35
|
-
export function
|
|
36
|
-
const envDir = process.env[
|
|
35
|
+
export function getServerDir() {
|
|
36
|
+
const envDir = process.env[ENV_SERVER_DIR];
|
|
37
37
|
if (envDir) {
|
|
38
38
|
return envDir;
|
|
39
39
|
}
|
|
40
40
|
const piDir = process.env.PI_CONFIG_DIR || join(homedir(), CONFIG_DIR_NAME);
|
|
41
|
-
return join(piDir, "
|
|
41
|
+
return join(piDir, "server");
|
|
42
42
|
}
|
|
43
43
|
export function getAuthPath() {
|
|
44
|
-
return join(
|
|
44
|
+
return join(getServerDir(), "auth.json");
|
|
45
45
|
}
|
|
46
46
|
export function getMachinePath() {
|
|
47
|
-
return join(
|
|
47
|
+
return join(getServerDir(), "machine.json");
|
|
48
48
|
}
|
|
49
49
|
export function getInstancesPath() {
|
|
50
|
-
return join(
|
|
50
|
+
return join(getServerDir(), "instances.json");
|
|
51
51
|
}
|
|
52
52
|
export function getSocketPath() {
|
|
53
|
-
return join(
|
|
53
|
+
return join(getServerDir(), "server.sock");
|
|
54
54
|
}
|
|
55
55
|
//# sourceMappingURL=config.js.map
|
|
@@ -48,7 +48,7 @@ export async function sendIpcRequest(request) {
|
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
settled = true;
|
|
51
|
-
reject(new Error(`
|
|
51
|
+
reject(new Error(`Server socket closed before a response was received: ${socketPath}`));
|
|
52
52
|
cleanup();
|
|
53
53
|
});
|
|
54
54
|
});
|
|
@@ -105,7 +105,7 @@ async function removeStaleSocketIfNeeded(socketPath) {
|
|
|
105
105
|
}
|
|
106
106
|
const isLive = await isSocketLive(socketPath);
|
|
107
107
|
if (isLive) {
|
|
108
|
-
throw new Error(`
|
|
108
|
+
throw new Error(`server is already running: ${socketPath}`);
|
|
109
109
|
}
|
|
110
110
|
unlinkSync(socketPath);
|
|
111
111
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { hostname, platform } from "node:os";
|
|
2
2
|
import { readStoredCredential } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import {
|
|
3
|
+
import { getServerDir, getSocketPath, VERSION } from "./config.js";
|
|
4
4
|
import { loadMachine, saveMachine } from "./storage.js";
|
|
5
5
|
const DEFAULT_RADIUS_URL = "https://radius.pi.dev/";
|
|
6
|
-
const
|
|
6
|
+
const DEFAULT_SERVER_BASE_PATH = "/v1/";
|
|
7
7
|
const NOT_FOUND_RETRY_THRESHOLD = 3;
|
|
8
8
|
const HEARTBEAT_BACKOFF_BASE_MS = 1_000;
|
|
9
9
|
const HEARTBEAT_BACKOFF_MAX_MS = 30_000;
|
|
@@ -17,7 +17,7 @@ class RadiusHttpError extends Error {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
async function post(path, body) {
|
|
20
|
-
const response = await fetch(new URL(path,
|
|
20
|
+
const response = await fetch(new URL(path, getRadiusServerBaseUrl()), {
|
|
21
21
|
method: "POST",
|
|
22
22
|
headers: {
|
|
23
23
|
Authorization: `Bearer ${getRadiusAccessToken()}`,
|
|
@@ -31,7 +31,7 @@ async function post(path, body) {
|
|
|
31
31
|
return (await response.json());
|
|
32
32
|
}
|
|
33
33
|
async function maybePost(path, body) {
|
|
34
|
-
const response = await fetch(new URL(path,
|
|
34
|
+
const response = await fetch(new URL(path, getRadiusServerBaseUrl()), {
|
|
35
35
|
method: "POST",
|
|
36
36
|
headers: {
|
|
37
37
|
Authorization: `Bearer ${getRadiusAccessToken()}`,
|
|
@@ -66,12 +66,12 @@ function logRadiusRetry(scope, action, delayMs, failureCount, error) {
|
|
|
66
66
|
export function getRadiusUrl() {
|
|
67
67
|
return process.env.PI_RADIUS_URL || DEFAULT_RADIUS_URL;
|
|
68
68
|
}
|
|
69
|
-
export function
|
|
70
|
-
const explicitUrl = process.env.
|
|
69
|
+
export function getRadiusServerBaseUrl() {
|
|
70
|
+
const explicitUrl = process.env.PI_RADIUS_SERVER_URL;
|
|
71
71
|
if (explicitUrl) {
|
|
72
72
|
return explicitUrl;
|
|
73
73
|
}
|
|
74
|
-
return new URL(
|
|
74
|
+
return new URL(DEFAULT_SERVER_BASE_PATH, getRadiusUrl()).toString();
|
|
75
75
|
}
|
|
76
76
|
function getStoredRadiusCredential() {
|
|
77
77
|
const credential = readStoredCredential(RADIUS_PROVIDER);
|
|
@@ -246,7 +246,7 @@ export class RadiusPresence {
|
|
|
246
246
|
}
|
|
247
247
|
try {
|
|
248
248
|
await maybePost(`machines/${this.machine.id}/heartbeat`, {
|
|
249
|
-
cwd:
|
|
249
|
+
cwd: getServerDir(),
|
|
250
250
|
socketPath: getSocketPath(),
|
|
251
251
|
});
|
|
252
252
|
this.machineConsecutiveNotFoundCount = 0;
|
|
@@ -116,7 +116,7 @@ export class RpcProcessInstance {
|
|
|
116
116
|
if (this.exited) {
|
|
117
117
|
throw new Error(`RPC process is not running. Stderr: ${this.stderrBuffer}`);
|
|
118
118
|
}
|
|
119
|
-
const id = command.id ?? `
|
|
119
|
+
const id = command.id ?? `server_${++this.nextRequestId}_${randomUUID()}`;
|
|
120
120
|
const fullCommand = { ...command, id };
|
|
121
121
|
return new Promise((resolve, reject) => {
|
|
122
122
|
this.pendingRequests.set(id, { resolve, reject });
|
|
@@ -3,7 +3,7 @@ import { dirname } from "node:path";
|
|
|
3
3
|
import { getSocketPath } from "./config.js";
|
|
4
4
|
import { handleIpcRequest, openRpcStream } from "./handler.js";
|
|
5
5
|
import { startIpcServer } from "./ipc/server.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getRadiusServerBaseUrl, isRadiusEnabled, radiusPresence } from "./radius.js";
|
|
7
7
|
import { supervisor } from "./supervisor.js";
|
|
8
8
|
export async function serve() {
|
|
9
9
|
const socketPath = getSocketPath();
|
|
@@ -15,7 +15,7 @@ export async function serve() {
|
|
|
15
15
|
await supervisor.recoverAfterRestart();
|
|
16
16
|
if (isRadiusEnabled()) {
|
|
17
17
|
const machine = await radiusPresence.start();
|
|
18
|
-
console.log(`radius integration enabled: ${socketPath} -> ${
|
|
18
|
+
console.log(`radius integration enabled: ${socketPath} -> ${getRadiusServerBaseUrl()}`);
|
|
19
19
|
if (machine) {
|
|
20
20
|
console.log(`radius machine id: ${machine.id}`);
|
|
21
21
|
}
|
|
@@ -31,7 +31,7 @@ export async function serve() {
|
|
|
31
31
|
}
|
|
32
32
|
throw error;
|
|
33
33
|
}
|
|
34
|
-
console.log(`
|
|
34
|
+
console.log(`server listening on ${socketPath}`);
|
|
35
35
|
let shutdownPromise;
|
|
36
36
|
const shutdown = async (exitCode) => {
|
|
37
37
|
if (shutdownPromise) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { getInstancesPath, getMachinePath,
|
|
3
|
-
function
|
|
4
|
-
const
|
|
5
|
-
if (!existsSync(
|
|
6
|
-
mkdirSync(
|
|
2
|
+
import { getInstancesPath, getMachinePath, getServerDir } from "./config.js";
|
|
3
|
+
function ensureServerDir() {
|
|
4
|
+
const serverDir = getServerDir();
|
|
5
|
+
if (!existsSync(serverDir)) {
|
|
6
|
+
mkdirSync(serverDir, { recursive: true });
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
export function loadMachine() {
|
|
@@ -15,7 +15,7 @@ export function loadMachine() {
|
|
|
15
15
|
return JSON.parse(data);
|
|
16
16
|
}
|
|
17
17
|
export function saveMachine(machine) {
|
|
18
|
-
|
|
18
|
+
ensureServerDir();
|
|
19
19
|
writeFileSync(getMachinePath(), JSON.stringify(machine, null, 2));
|
|
20
20
|
}
|
|
21
21
|
export function deleteMachine() {
|
|
@@ -34,7 +34,7 @@ export function loadInstances() {
|
|
|
34
34
|
return JSON.parse(data);
|
|
35
35
|
}
|
|
36
36
|
export function saveInstances(instances) {
|
|
37
|
-
|
|
37
|
+
ensureServerDir();
|
|
38
38
|
writeFileSync(getInstancesPath(), JSON.stringify(instances, null, 2));
|
|
39
39
|
}
|
|
40
40
|
export function getInstance(instanceId) {
|
|
@@ -26,7 +26,7 @@ function shouldRefreshSessionMetadata(command) {
|
|
|
26
26
|
function isGetStateSuccess(response) {
|
|
27
27
|
return response.success === true && response.command === "get_state" && "data" in response;
|
|
28
28
|
}
|
|
29
|
-
export class
|
|
29
|
+
export class ServerSupervisor {
|
|
30
30
|
liveInstances = new Map();
|
|
31
31
|
setStatus(live, status) {
|
|
32
32
|
live.record = {
|
|
@@ -275,7 +275,7 @@ export class OrchestratorSupervisor {
|
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
|
-
export const supervisor = new
|
|
278
|
+
export const supervisor = new ServerSupervisor();
|
|
279
279
|
radiusPresence.setCoordinator({
|
|
280
280
|
getLiveInstance(instanceId) {
|
|
281
281
|
return supervisor.getLiveInstance(instanceId);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@earendil-works/pi-
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "experimental
|
|
2
|
+
"name": "@earendil-works/pi-server",
|
|
3
|
+
"version": "0.81.1",
|
|
4
|
+
"description": "experimental server package for pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"server": "./dist/cli.js"
|
|
16
|
+
},
|
|
14
17
|
"files": [
|
|
15
18
|
"dist",
|
|
16
19
|
"README.md",
|
|
@@ -24,20 +27,20 @@
|
|
|
24
27
|
},
|
|
25
28
|
"keywords": [
|
|
26
29
|
"pi",
|
|
27
|
-
"
|
|
30
|
+
"server"
|
|
28
31
|
],
|
|
29
32
|
"author": "Earendil Works",
|
|
30
33
|
"license": "MIT",
|
|
31
34
|
"repository": {
|
|
32
35
|
"type": "git",
|
|
33
36
|
"url": "git+https://github.com/earendil-works/pi.git",
|
|
34
|
-
"directory": "packages/
|
|
37
|
+
"directory": "packages/server"
|
|
35
38
|
},
|
|
36
39
|
"engines": {
|
|
37
40
|
"node": ">=22.19.0"
|
|
38
41
|
},
|
|
39
42
|
"dependencies": {
|
|
40
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
43
|
+
"@earendil-works/pi-coding-agent": "^0.81.1"
|
|
41
44
|
},
|
|
42
45
|
"devDependencies": {
|
|
43
46
|
"shx": "0.4.0"
|