@hyperdrive.bot/paseo-server 0.3.23 → 0.3.26
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/dist/server/server/agent/provider-registry.d.ts +30 -0
- package/dist/server/server/agent/provider-registry.js +36 -0
- package/dist/server/server/agent/providers/claude/agent.d.ts +18 -0
- package/dist/server/server/agent/providers/claude/agent.js +104 -2
- package/dist/server/server/agent/providers/claude/pty-session-launcher.d.ts +3 -0
- package/dist/server/server/agent/providers/claude/pty-session-launcher.js +1 -0
- package/dist/server/server/agent/providers/claude/transport/pty-query.d.ts +32 -0
- package/dist/server/server/agent/providers/claude/transport/pty-query.js +47 -4
- package/dist/server/web-ui/_expo/static/js/web/{index-47b07b144bbc651587bf14a2bf8bc9e4.js → index-045767cf5362f85583f2649254d4471a.js} +4 -4
- package/dist/server/web-ui/_expo/static/js/web/index-045767cf5362f85583f2649254d4471a.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-045767cf5362f85583f2649254d4471a.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-47b07b144bbc651587bf14a2bf8bc9e4.js.map.br → index-045767cf5362f85583f2649254d4471a.js.map.br} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-47b07b144bbc651587bf14a2bf8bc9e4.js.map.gz → index-045767cf5362f85583f2649254d4471a.js.map.gz} +0 -0
- package/dist/server/web-ui/index.html +1 -1
- package/dist/server/web-ui/index.html.br +0 -0
- package/dist/server/web-ui/index.html.gz +0 -0
- package/package.json +6 -6
- package/dist/server/web-ui/_expo/static/js/web/index-47b07b144bbc651587bf14a2bf8bc9e4.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-47b07b144bbc651587bf14a2bf8bc9e4.js.gz +0 -0
|
@@ -8,6 +8,36 @@ export declare function resolveClaudeTransport(setting: "sdk" | "pty" | "auto" |
|
|
|
8
8
|
requireNodePty?: () => unknown;
|
|
9
9
|
probeClaudeBinary?: () => void;
|
|
10
10
|
}): "sdk" | "pty";
|
|
11
|
+
/**
|
|
12
|
+
* Internal agents (session-digest and auto-title generation) are headless,
|
|
13
|
+
* one-shot, `persistSession: false` runs. They have no TUI to drive: they are
|
|
14
|
+
* handed a prompt and asked for one structured answer.
|
|
15
|
+
*
|
|
16
|
+
* `resolveClaudeTransport` returns "pty" whenever node-pty and the `claude`
|
|
17
|
+
* binary are both present, which on a developer box is always, so these runs
|
|
18
|
+
* were being given a full interactive terminal and their prompt written through
|
|
19
|
+
* the PTY's bracketed-paste path. That path can refuse the write when the TUI
|
|
20
|
+
* is not in an input-accepting state, and the caller sees:
|
|
21
|
+
*
|
|
22
|
+
* "Your message did not reach the agent: the terminal would not accept it."
|
|
23
|
+
*
|
|
24
|
+
* Measured on 2026-08-04: 187 of 191 structured-generation failures (98%) were
|
|
25
|
+
* exactly that error, across claude/pool/pool-tu and across haiku, opus-5 and
|
|
26
|
+
* opus-4-8, so it is neither provider- nor model-specific. Each failure burned
|
|
27
|
+
* a provider attempt until the digest's 120s budget expired, losing ~46% of all
|
|
28
|
+
* digests (116 DigestGenerationTimeoutError against 113 successful digests that
|
|
29
|
+
* day). Every lost digest also silently costs a Jarvis judgement, because the
|
|
30
|
+
* judge only wakes on the `onSettled` hook that a completed digest fires.
|
|
31
|
+
*
|
|
32
|
+
* Two cheaper explanations were tested and rejected before this one: prompt
|
|
33
|
+
* size (2 KB / 8 KB / 32 KB pastes all delivered fine) and a spawn/readiness
|
|
34
|
+
* race (three spawn-then-immediately-send probes all delivered fine).
|
|
35
|
+
*
|
|
36
|
+
* So internal agents default to the SDK transport, which needs no terminal. An
|
|
37
|
+
* EXPLICIT `transport` setting still wins: this only redirects the "auto" case,
|
|
38
|
+
* so anyone deliberately pinning "pty" keeps it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveInternalAgentTransportSetting(internal: boolean | undefined, setting: "sdk" | "pty" | "auto" | undefined): "sdk" | "pty" | "auto" | undefined;
|
|
11
41
|
export declare const NODE_PTY_UNAVAILABLE_REASON = "node-pty native module not built. Run 'npm rebuild node-pty' in packages/server.";
|
|
12
42
|
export declare function isNodePtyAvailable(deps?: {
|
|
13
43
|
requireNodePty?: () => unknown;
|
|
@@ -38,6 +38,42 @@ export function resolveClaudeTransport(setting, deps) {
|
|
|
38
38
|
return "sdk";
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Internal agents (session-digest and auto-title generation) are headless,
|
|
43
|
+
* one-shot, `persistSession: false` runs. They have no TUI to drive: they are
|
|
44
|
+
* handed a prompt and asked for one structured answer.
|
|
45
|
+
*
|
|
46
|
+
* `resolveClaudeTransport` returns "pty" whenever node-pty and the `claude`
|
|
47
|
+
* binary are both present, which on a developer box is always, so these runs
|
|
48
|
+
* were being given a full interactive terminal and their prompt written through
|
|
49
|
+
* the PTY's bracketed-paste path. That path can refuse the write when the TUI
|
|
50
|
+
* is not in an input-accepting state, and the caller sees:
|
|
51
|
+
*
|
|
52
|
+
* "Your message did not reach the agent: the terminal would not accept it."
|
|
53
|
+
*
|
|
54
|
+
* Measured on 2026-08-04: 187 of 191 structured-generation failures (98%) were
|
|
55
|
+
* exactly that error, across claude/pool/pool-tu and across haiku, opus-5 and
|
|
56
|
+
* opus-4-8, so it is neither provider- nor model-specific. Each failure burned
|
|
57
|
+
* a provider attempt until the digest's 120s budget expired, losing ~46% of all
|
|
58
|
+
* digests (116 DigestGenerationTimeoutError against 113 successful digests that
|
|
59
|
+
* day). Every lost digest also silently costs a Jarvis judgement, because the
|
|
60
|
+
* judge only wakes on the `onSettled` hook that a completed digest fires.
|
|
61
|
+
*
|
|
62
|
+
* Two cheaper explanations were tested and rejected before this one: prompt
|
|
63
|
+
* size (2 KB / 8 KB / 32 KB pastes all delivered fine) and a spawn/readiness
|
|
64
|
+
* race (three spawn-then-immediately-send probes all delivered fine).
|
|
65
|
+
*
|
|
66
|
+
* So internal agents default to the SDK transport, which needs no terminal. An
|
|
67
|
+
* EXPLICIT `transport` setting still wins: this only redirects the "auto" case,
|
|
68
|
+
* so anyone deliberately pinning "pty" keeps it.
|
|
69
|
+
*/
|
|
70
|
+
export function resolveInternalAgentTransportSetting(internal, setting) {
|
|
71
|
+
if (!internal)
|
|
72
|
+
return setting;
|
|
73
|
+
if (setting === "sdk" || setting === "pty")
|
|
74
|
+
return setting;
|
|
75
|
+
return "sdk";
|
|
76
|
+
}
|
|
41
77
|
export const NODE_PTY_UNAVAILABLE_REASON = "node-pty native module not built. Run 'npm rebuild node-pty' in packages/server.";
|
|
42
78
|
export function isNodePtyAvailable(deps) {
|
|
43
79
|
const tryRequire = deps?.requireNodePty ?? (() => requireFromHere("node-pty"));
|
|
@@ -101,6 +101,8 @@ export declare class ClaudeAgentSession implements AgentSession {
|
|
|
101
101
|
private toolUseIndexToId;
|
|
102
102
|
private toolUseInputBuffers;
|
|
103
103
|
private pendingPermissions;
|
|
104
|
+
/** Permission id currently standing in for a PTY TUI dialog, if any. */
|
|
105
|
+
private ptyDialogRequestId;
|
|
104
106
|
private activeForegroundTurnId;
|
|
105
107
|
private autonomousTurn;
|
|
106
108
|
private readonly subscribers;
|
|
@@ -280,6 +282,22 @@ export declare class ClaudeAgentSession implements AgentSession {
|
|
|
280
282
|
private handleSystemMessage;
|
|
281
283
|
private readMissingResumedConversationError;
|
|
282
284
|
private convertUsage;
|
|
285
|
+
/**
|
|
286
|
+
* Raise (and retract) a permission request for a dialog the PTY's TUI is showing.
|
|
287
|
+
*
|
|
288
|
+
* The SDK path gets these through `canUseTool`, which is how the app renders a real
|
|
289
|
+
* question card with its options. The PTY path has no such hook - the TUI owns the
|
|
290
|
+
* dialog - so before this the app only saw an inert `AskUserQuestion` tool chip and the
|
|
291
|
+
* session sat waiting with nothing to tap (observed live: 11h51m). Surfacing the same
|
|
292
|
+
* request shape reuses the app's existing question UI, and the answer is played back
|
|
293
|
+
* into the terminal as the dialog's own keystrokes.
|
|
294
|
+
*
|
|
295
|
+
* Scoped to questions on purpose: a plan dialog's options are the CLI's and version-
|
|
296
|
+
* dependent, so guessing an index there could approve an implementation nobody chose.
|
|
297
|
+
*/
|
|
298
|
+
private handlePtyDialogChange;
|
|
299
|
+
/** Map the app's chosen answer back to the dialog's option index and press the keys. */
|
|
300
|
+
private answerPtyDialogFromPermission;
|
|
283
301
|
private handlePermissionRequest;
|
|
284
302
|
private enqueueTimeline;
|
|
285
303
|
private flushPendingToolCalls;
|
|
@@ -30,7 +30,7 @@ import { getAgentStreamEventTurnId, } from "../../agent-sdk-types.js";
|
|
|
30
30
|
import { importSessionFromPersistence } from "../../provider-session-import.js";
|
|
31
31
|
import { SETTING_APPLIES_NEXT_TURN_NOTICE } from "../../provider-notices.js";
|
|
32
32
|
import { checkProviderLaunchAvailable, createProviderEnv, createProviderEnvSpec, resolveProviderLaunch, } from "../../provider-launch-config.js";
|
|
33
|
-
import { isNodePtyAvailable, NODE_PTY_UNAVAILABLE_REASON, resolveClaudeTransport, } from "../../provider-registry.js";
|
|
33
|
+
import { isNodePtyAvailable, NODE_PTY_UNAVAILABLE_REASON, resolveClaudeTransport, resolveInternalAgentTransportSetting, } from "../../provider-registry.js";
|
|
34
34
|
import { isCommandAvailable } from "../../../../executable-resolution/executable-resolution.js";
|
|
35
35
|
import { withTimeout } from "../../../../utils/promise-timeout.js";
|
|
36
36
|
import { terminateWithTreeKill } from "../../../../utils/tree-kill.js";
|
|
@@ -714,6 +714,33 @@ function isPermissionUpdate(value) {
|
|
|
714
714
|
const destination = value.destination;
|
|
715
715
|
return Array.isArray(rules) && typeof behavior === "string" && typeof destination === "string";
|
|
716
716
|
}
|
|
717
|
+
/**
|
|
718
|
+
* The app answers a question by echoing the tool input back with the chosen label(s). The
|
|
719
|
+
* exact key varies by question text, so collect every string leaf rather than guessing one
|
|
720
|
+
* path; the caller matches these against the dialog's on-screen options.
|
|
721
|
+
*/
|
|
722
|
+
function collectAnswerLabels(input) {
|
|
723
|
+
const labels = [];
|
|
724
|
+
const visit = (value, depth) => {
|
|
725
|
+
if (depth > 4)
|
|
726
|
+
return;
|
|
727
|
+
if (typeof value === "string") {
|
|
728
|
+
labels.push(value);
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
if (Array.isArray(value)) {
|
|
732
|
+
for (const item of value)
|
|
733
|
+
visit(item, depth + 1);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if (isMetadata(value)) {
|
|
737
|
+
for (const item of Object.values(value))
|
|
738
|
+
visit(item, depth + 1);
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
visit(input, 0);
|
|
742
|
+
return labels;
|
|
743
|
+
}
|
|
717
744
|
function resolvePermissionKind(toolName, input) {
|
|
718
745
|
if (toolName === "ExitPlanMode")
|
|
719
746
|
return "plan";
|
|
@@ -1469,6 +1496,8 @@ export class ClaudeAgentSession {
|
|
|
1469
1496
|
this.toolUseIndexToId = new Map();
|
|
1470
1497
|
this.toolUseInputBuffers = new Map();
|
|
1471
1498
|
this.pendingPermissions = new Map();
|
|
1499
|
+
/** Permission id currently standing in for a PTY TUI dialog, if any. */
|
|
1500
|
+
this.ptyDialogRequestId = null;
|
|
1472
1501
|
this.activeForegroundTurnId = null;
|
|
1473
1502
|
this.autonomousTurn = null;
|
|
1474
1503
|
this.subscribers = new Set();
|
|
@@ -2314,7 +2343,7 @@ export class ClaudeAgentSession {
|
|
|
2314
2343
|
ensureTransport() {
|
|
2315
2344
|
if (this.resolvedTransport)
|
|
2316
2345
|
return this.resolvedTransport;
|
|
2317
|
-
this.resolvedTransport = resolveClaudeTransport(this.runtimeSettings?.transport);
|
|
2346
|
+
this.resolvedTransport = resolveClaudeTransport(resolveInternalAgentTransportSetting(this.config.internal, this.runtimeSettings?.transport));
|
|
2318
2347
|
this.fireTransportSpawnedTelemetry(this.resolvedTransport);
|
|
2319
2348
|
return this.resolvedTransport;
|
|
2320
2349
|
}
|
|
@@ -2501,6 +2530,7 @@ export class ClaudeAgentSession {
|
|
|
2501
2530
|
? this.normalizeMcpServers(this.config.mcpServers)
|
|
2502
2531
|
: undefined,
|
|
2503
2532
|
logger: this.logger,
|
|
2533
|
+
onDialogChange: (dialog) => this.handlePtyDialogChange(dialog),
|
|
2504
2534
|
});
|
|
2505
2535
|
this.activeTransport = ptySession.transport;
|
|
2506
2536
|
this.query = ptySession.query;
|
|
@@ -3580,6 +3610,78 @@ export class ClaudeAgentSession {
|
|
|
3580
3610
|
convertUsage(message, modelUsage) {
|
|
3581
3611
|
return this.contextUsage.buildResultUsage(message, modelUsage);
|
|
3582
3612
|
}
|
|
3613
|
+
/**
|
|
3614
|
+
* Raise (and retract) a permission request for a dialog the PTY's TUI is showing.
|
|
3615
|
+
*
|
|
3616
|
+
* The SDK path gets these through `canUseTool`, which is how the app renders a real
|
|
3617
|
+
* question card with its options. The PTY path has no such hook - the TUI owns the
|
|
3618
|
+
* dialog - so before this the app only saw an inert `AskUserQuestion` tool chip and the
|
|
3619
|
+
* session sat waiting with nothing to tap (observed live: 11h51m). Surfacing the same
|
|
3620
|
+
* request shape reuses the app's existing question UI, and the answer is played back
|
|
3621
|
+
* into the terminal as the dialog's own keystrokes.
|
|
3622
|
+
*
|
|
3623
|
+
* Scoped to questions on purpose: a plan dialog's options are the CLI's and version-
|
|
3624
|
+
* dependent, so guessing an index there could approve an implementation nobody chose.
|
|
3625
|
+
*/
|
|
3626
|
+
handlePtyDialogChange(dialog) {
|
|
3627
|
+
if (!dialog) {
|
|
3628
|
+
const pendingId = this.ptyDialogRequestId;
|
|
3629
|
+
this.ptyDialogRequestId = null;
|
|
3630
|
+
if (!pendingId)
|
|
3631
|
+
return;
|
|
3632
|
+
const pending = this.pendingPermissions.get(pendingId);
|
|
3633
|
+
if (!pending)
|
|
3634
|
+
return;
|
|
3635
|
+
// Answered in the terminal (or by keystrokes): retract the card, don't leave it up.
|
|
3636
|
+
this.pendingPermissions.delete(pendingId);
|
|
3637
|
+
pending.cleanup?.();
|
|
3638
|
+
this.pushEvent({
|
|
3639
|
+
type: "permission_resolved",
|
|
3640
|
+
provider: "claude",
|
|
3641
|
+
requestId: pendingId,
|
|
3642
|
+
resolution: { behavior: "allow" },
|
|
3643
|
+
});
|
|
3644
|
+
return;
|
|
3645
|
+
}
|
|
3646
|
+
if (dialog.name !== "AskUserQuestion" || this.ptyDialogRequestId)
|
|
3647
|
+
return;
|
|
3648
|
+
const requestId = `permission-${randomUUID()}`;
|
|
3649
|
+
this.ptyDialogRequestId = requestId;
|
|
3650
|
+
const request = {
|
|
3651
|
+
id: requestId,
|
|
3652
|
+
provider: "claude",
|
|
3653
|
+
name: dialog.name,
|
|
3654
|
+
kind: "question",
|
|
3655
|
+
input: normalizeClaudeAskUserQuestionRequestInput(dialog.name, dialog.input),
|
|
3656
|
+
metadata: { toolUseId: dialog.toolUseId },
|
|
3657
|
+
};
|
|
3658
|
+
const options = dialog.options;
|
|
3659
|
+
this.pendingPermissions.set(requestId, {
|
|
3660
|
+
request,
|
|
3661
|
+
// There is no SDK promise to settle here: "resolving" means playing the answer into
|
|
3662
|
+
// the terminal. An answer that names no known option is left to the user to type.
|
|
3663
|
+
resolve: (result) => {
|
|
3664
|
+
void this.answerPtyDialogFromPermission(result, options);
|
|
3665
|
+
},
|
|
3666
|
+
reject: () => { },
|
|
3667
|
+
});
|
|
3668
|
+
this.pushEvent({ type: "permission_requested", provider: "claude", request });
|
|
3669
|
+
}
|
|
3670
|
+
/** Map the app's chosen answer back to the dialog's option index and press the keys. */
|
|
3671
|
+
async answerPtyDialogFromPermission(result, options) {
|
|
3672
|
+
if (result.behavior !== "allow")
|
|
3673
|
+
return;
|
|
3674
|
+
const query = this.query;
|
|
3675
|
+
if (typeof query?.answerDialogByIndex !== "function")
|
|
3676
|
+
return;
|
|
3677
|
+
const chosen = collectAnswerLabels(result.updatedInput);
|
|
3678
|
+
const index = options.findIndex((option) => chosen.some((label) => label.trim().toLowerCase() === option.trim().toLowerCase()));
|
|
3679
|
+
if (index < 0) {
|
|
3680
|
+
this.logger.warn({ chosen, options }, "PTY dialog answer matched no on-screen option; leaving the dialog up");
|
|
3681
|
+
return;
|
|
3682
|
+
}
|
|
3683
|
+
await query.answerDialogByIndex(index);
|
|
3684
|
+
}
|
|
3583
3685
|
enqueueTimeline(item) {
|
|
3584
3686
|
this.pushEvent({ type: "timeline", item, provider: "claude" });
|
|
3585
3687
|
}
|
|
@@ -2,6 +2,7 @@ import type { Logger } from "pino";
|
|
|
2
2
|
import type { Query, SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
3
3
|
import { type ProviderRuntimeSettings } from "../../provider-launch-config.js";
|
|
4
4
|
import { PtyTransport } from "./transport/pty.js";
|
|
5
|
+
import { type PtyInteractiveDialog } from "./transport/pty-query.js";
|
|
5
6
|
export interface CreatePtySessionOptions {
|
|
6
7
|
binary: string;
|
|
7
8
|
cwd: string;
|
|
@@ -22,6 +23,8 @@ export interface CreatePtySessionOptions {
|
|
|
22
23
|
cols: number;
|
|
23
24
|
rows: number;
|
|
24
25
|
};
|
|
26
|
+
/** Surfaces TUI question/plan dialogs so the provider can raise a permission request. */
|
|
27
|
+
onDialogChange?: (dialog: PtyInteractiveDialog | null) => void;
|
|
25
28
|
}
|
|
26
29
|
export interface PtySession {
|
|
27
30
|
transport: PtyTransport;
|
|
@@ -55,6 +55,7 @@ export async function createPtySession(opts) {
|
|
|
55
55
|
transcriptPath,
|
|
56
56
|
sessionId: opts.sessionId,
|
|
57
57
|
logger: opts.logger,
|
|
58
|
+
...(opts.onDialogChange ? { onDialogChange: opts.onDialogChange } : {}),
|
|
58
59
|
});
|
|
59
60
|
opts.logger.debug({ pid: transport.context().pid, sessionId: opts.sessionId, transcriptPath }, "PTY claude session spawned");
|
|
60
61
|
return { transport, query, transcriptPath, systemPromptFilePath };
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { Logger } from "pino";
|
|
2
2
|
import type { ModelInfo, SDKMessage, SDKSystemMessage, SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
3
3
|
import type { PtyTransport } from "./pty.js";
|
|
4
|
+
/** An interactive TUI dialog the user has to answer for the turn to continue. */
|
|
5
|
+
export interface PtyInteractiveDialog {
|
|
6
|
+
toolUseId: string;
|
|
7
|
+
/** "AskUserQuestion" | "ExitPlanMode" */
|
|
8
|
+
name: string;
|
|
9
|
+
/** The tool_use input verbatim, so the app renders the real questions and options. */
|
|
10
|
+
input: Record<string, unknown>;
|
|
11
|
+
/** Option labels of the FIRST question, in on-screen order; empty when unknown. */
|
|
12
|
+
options: string[];
|
|
13
|
+
}
|
|
4
14
|
export interface PtyQueryOptions {
|
|
5
15
|
transport: PtyTransport;
|
|
6
16
|
/** The shared input channel (createAsyncMessageInput().iterable) fed by startTurn(). */
|
|
@@ -15,6 +25,12 @@ export interface PtyQueryOptions {
|
|
|
15
25
|
* {@link TURN_STALL_TIMEOUT_MS}. Pass `0` to disable the liveness backstop.
|
|
16
26
|
*/
|
|
17
27
|
stallTimeoutMs?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Called when the TUI starts (dialog) or finishes (null) waiting on an interactive
|
|
30
|
+
* question. The provider turns this into a permission request so the app can render
|
|
31
|
+
* the real options instead of an inert tool chip nobody can answer.
|
|
32
|
+
*/
|
|
33
|
+
onDialogChange?: (dialog: PtyInteractiveDialog | null) => void;
|
|
18
34
|
}
|
|
19
35
|
export declare class PtyQuery implements AsyncGenerator<SDKMessage, void> {
|
|
20
36
|
private readonly transport;
|
|
@@ -23,6 +39,7 @@ export declare class PtyQuery implements AsyncGenerator<SDKMessage, void> {
|
|
|
23
39
|
private readonly transcriptPath;
|
|
24
40
|
private readonly logger;
|
|
25
41
|
private readonly reader;
|
|
42
|
+
private readonly onDialogChange;
|
|
26
43
|
private readonly outQueue;
|
|
27
44
|
private readonly outResolvers;
|
|
28
45
|
private done;
|
|
@@ -103,6 +120,15 @@ export declare class PtyQuery implements AsyncGenerator<SDKMessage, void> {
|
|
|
103
120
|
* agent running by the time the input loop sees it: silence here is a forever-spinner.
|
|
104
121
|
*/
|
|
105
122
|
private buildNothingDeliverableResult;
|
|
123
|
+
/** Tell the provider the dialog state changed; never let a listener throw into the loop. */
|
|
124
|
+
private notifyDialogChange;
|
|
125
|
+
/** The dialog the TUI is waiting on, if any. */
|
|
126
|
+
interactiveDialog(): PtyInteractiveDialog | null;
|
|
127
|
+
/**
|
|
128
|
+
* Answer the pending dialog by option index (0-based), the way the app's question card
|
|
129
|
+
* does. Returns false when there is no dialog or the keystrokes never registered.
|
|
130
|
+
*/
|
|
131
|
+
answerDialogByIndex(index: number): Promise<boolean>;
|
|
106
132
|
/**
|
|
107
133
|
* Try to answer the pending TUI dialog with the user's reply. A reply that names an
|
|
108
134
|
* option (its 1-based number or its label) becomes Down-arrow presses + Enter, the same
|
|
@@ -111,6 +137,12 @@ export declare class PtyQuery implements AsyncGenerator<SDKMessage, void> {
|
|
|
111
137
|
* into a silent decline.
|
|
112
138
|
*/
|
|
113
139
|
private answerPendingDialog;
|
|
140
|
+
/**
|
|
141
|
+
* Drive the dialog's own keys: Down to the option, Enter to confirm. Confirmation is the
|
|
142
|
+
* tool_result landing in the transcript (which clears pendingDialog) - an optimistic flag
|
|
143
|
+
* here would record intent as fact.
|
|
144
|
+
*/
|
|
145
|
+
private sendDialogAnswer;
|
|
114
146
|
/** The agent is waiting on a dialog; tell the sender what it asks and how to answer. */
|
|
115
147
|
private buildDialogPendingResult;
|
|
116
148
|
private buildSubmitFailedResult;
|
|
@@ -263,6 +263,7 @@ export class PtyQuery {
|
|
|
263
263
|
this.transcriptPath = opts.transcriptPath;
|
|
264
264
|
this.logger = opts.logger;
|
|
265
265
|
this.stallTimeoutMs = opts.stallTimeoutMs ?? TURN_STALL_TIMEOUT_MS;
|
|
266
|
+
this.onDialogChange = opts.onDialogChange ?? null;
|
|
266
267
|
this.reader = new TranscriptSdkReader({
|
|
267
268
|
transcriptPath: opts.transcriptPath,
|
|
268
269
|
onMessage: (m) => this.onTranscriptMessage(m),
|
|
@@ -417,7 +418,10 @@ export class PtyQuery {
|
|
|
417
418
|
if (this.done)
|
|
418
419
|
return;
|
|
419
420
|
this.done = true;
|
|
421
|
+
const hadDialog = this.pendingDialog !== null;
|
|
420
422
|
this.pendingDialog = null;
|
|
423
|
+
if (hadDialog)
|
|
424
|
+
this.notifyDialogChange();
|
|
421
425
|
this.cancelReadiness?.();
|
|
422
426
|
if (this.turnEndTimer)
|
|
423
427
|
clearTimeout(this.turnEndTimer);
|
|
@@ -602,6 +606,30 @@ export class PtyQuery {
|
|
|
602
606
|
],
|
|
603
607
|
};
|
|
604
608
|
}
|
|
609
|
+
/** Tell the provider the dialog state changed; never let a listener throw into the loop. */
|
|
610
|
+
notifyDialogChange() {
|
|
611
|
+
if (!this.onDialogChange)
|
|
612
|
+
return;
|
|
613
|
+
try {
|
|
614
|
+
this.onDialogChange(this.pendingDialog ? { ...this.pendingDialog } : null);
|
|
615
|
+
}
|
|
616
|
+
catch (err) {
|
|
617
|
+
this.logger.warn({ err }, "PtyQuery: dialog listener threw");
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
/** The dialog the TUI is waiting on, if any. */
|
|
621
|
+
interactiveDialog() {
|
|
622
|
+
return this.pendingDialog ? { ...this.pendingDialog } : null;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Answer the pending dialog by option index (0-based), the way the app's question card
|
|
626
|
+
* does. Returns false when there is no dialog or the keystrokes never registered.
|
|
627
|
+
*/
|
|
628
|
+
async answerDialogByIndex(index) {
|
|
629
|
+
if (!this.pendingDialog || index < 0)
|
|
630
|
+
return false;
|
|
631
|
+
return await this.sendDialogAnswer(this.pendingDialog, index);
|
|
632
|
+
}
|
|
605
633
|
/**
|
|
606
634
|
* Try to answer the pending TUI dialog with the user's reply. A reply that names an
|
|
607
635
|
* option (its 1-based number or its label) becomes Down-arrow presses + Enter, the same
|
|
@@ -619,28 +647,37 @@ export class PtyQuery {
|
|
|
619
647
|
this.emit(this.buildDialogPendingResult(dialog));
|
|
620
648
|
return;
|
|
621
649
|
}
|
|
650
|
+
const answered = await this.sendDialogAnswer(dialog, index);
|
|
651
|
+
if (!answered) {
|
|
652
|
+
this.emit(this.buildDialogPendingResult(dialog, true));
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Drive the dialog's own keys: Down to the option, Enter to confirm. Confirmation is the
|
|
657
|
+
* tool_result landing in the transcript (which clears pendingDialog) - an optimistic flag
|
|
658
|
+
* here would record intent as fact.
|
|
659
|
+
*/
|
|
660
|
+
async sendDialogAnswer(dialog, index) {
|
|
622
661
|
this.recordLine(`--- answering ${dialog.name} with option ${index + 1} ---`);
|
|
623
662
|
for (let i = 0; i < index && !this.done; i++) {
|
|
624
663
|
await this.transport.writeRaw?.("\u001b[B");
|
|
625
664
|
await delay(DIALOG_KEY_DELAY_MS);
|
|
626
665
|
}
|
|
627
666
|
await this.transport.writeRaw?.("\r");
|
|
628
|
-
// Confirmation is the tool_result landing in the transcript (trackInteractiveDialog
|
|
629
|
-
// clears pendingDialog). Optimistic flags would record intent as fact.
|
|
630
667
|
const deadline = monotonicNowMs() + DIALOG_ANSWER_CONFIRM_MS;
|
|
631
668
|
while (this.pendingDialog && !this.done && monotonicNowMs() < deadline) {
|
|
632
669
|
await delay(250);
|
|
633
670
|
}
|
|
634
671
|
if (this.pendingDialog) {
|
|
635
672
|
this.recordLine(`--- ${dialog.name} answer did not register ---`);
|
|
636
|
-
|
|
637
|
-
return;
|
|
673
|
+
return false;
|
|
638
674
|
}
|
|
639
675
|
// Answer accepted: the turn is live again, restart the liveness clock.
|
|
640
676
|
this.turnStartedAt = monotonicNowMs();
|
|
641
677
|
this.turnInFlight = true;
|
|
642
678
|
this.armStallTimer();
|
|
643
679
|
this.startHeartbeat();
|
|
680
|
+
return true;
|
|
644
681
|
}
|
|
645
682
|
/** The agent is waiting on a dialog; tell the sender what it asks and how to answer. */
|
|
646
683
|
buildDialogPendingResult(dialog, answerFailed = false) {
|
|
@@ -952,14 +989,17 @@ export class PtyQuery {
|
|
|
952
989
|
this.pendingDialog = {
|
|
953
990
|
toolUseId: b.id,
|
|
954
991
|
name: b.name,
|
|
992
|
+
input: isRecord(b.input) ? b.input : {},
|
|
955
993
|
options: extractDialogOptions(b.name, b.input),
|
|
956
994
|
};
|
|
957
995
|
this.recordLine(`--- interactive dialog pending: ${b.name} ---`);
|
|
996
|
+
this.notifyDialogChange();
|
|
958
997
|
}
|
|
959
998
|
const pending = this.pendingDialog;
|
|
960
999
|
if (pending && b.type === "tool_result" && b.tool_use_id === pending.toolUseId) {
|
|
961
1000
|
this.recordLine(`--- interactive dialog answered: ${pending.name} ---`);
|
|
962
1001
|
this.pendingDialog = null;
|
|
1002
|
+
this.notifyDialogChange();
|
|
963
1003
|
}
|
|
964
1004
|
}
|
|
965
1005
|
}
|
|
@@ -1304,6 +1344,9 @@ function matchDialogOption(text, options) {
|
|
|
1304
1344
|
const byLabel = options.findIndex((o) => o.trim().toLowerCase() === lowered);
|
|
1305
1345
|
return byLabel >= 0 ? byLabel : null;
|
|
1306
1346
|
}
|
|
1347
|
+
function isRecord(value) {
|
|
1348
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1349
|
+
}
|
|
1307
1350
|
/** Extensions for the media types the app can send; anything unknown stages as .png. */
|
|
1308
1351
|
const IMAGE_MEDIA_TYPE_EXT = {
|
|
1309
1352
|
"image/jpeg": "jpg",
|
|
@@ -1103,7 +1103,7 @@ __d(function(g,r,_i,a,m,_e,d){"use strict";function e(e){return e&&e.__esModule?
|
|
|
1103
1103
|
__d(function(g,r,i,a,m,_e,d){"use strict";function e(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(_e,'__esModule',{value:!0}),Object.defineProperty(_e,"default",{enumerable:!0,get:function(){return N}}),Object.defineProperty(_e,"AppOwnership",{enumerable:!0,get:function(){return l.AppOwnership}}),Object.defineProperty(_e,"ExecutionEnvironment",{enumerable:!0,get:function(){return l.ExecutionEnvironment}}),Object.defineProperty(_e,"UserInterfaceIdiom",{enumerable:!0,get:function(){return l.UserInterfaceIdiom}});var n=e(r(d[0])),t=r(d[1]);r(d[2]);var u=e(r(d[3])),l=r(d[4]),o=e(r(d[5]));o.default||console.warn("No native ExponentConstants module found, are you sure the expo-constants's module is linked properly?");const s=(0,t.requireOptionalNativeModule)('ExpoUpdates');let f=null;if(s){let e;s.manifest?e=s.manifest:s.manifestString&&(e=JSON.parse(s.manifestString)),e&&Object.keys(e).length>0&&(f=e)}let c=null;if(u.default.EXDevLauncher){let e;u.default.EXDevLauncher.manifestString&&(e=JSON.parse(u.default.EXDevLauncher.manifestString)),e&&Object.keys(e).length>0&&(c=e)}let p=null;if(o.default&&o.default.manifest){const e=o.default.manifest;p='string'==typeof e?JSON.parse(e):e}let b=f??c??p;const E=o.default||{},{appOwnership:O}=E,x=(0,n.default)(E,["name","appOwnership"]),v=Object.assign({},x,{appOwnership:O??null});function _(e){return!h(e)}function h(e){return'metadata'in e}function S(e=!1){if(!b){const e=null===b?'null':'undefined';if(x.executionEnvironment,l.ExecutionEnvironment.Bare,x.executionEnvironment===l.ExecutionEnvironment.StoreClient||x.executionEnvironment===l.ExecutionEnvironment.Standalone)throw new t.CodedError('ERR_CONSTANTS_MANIFEST_UNAVAILABLE',`Constants.manifest is ${e}, must be an object.`)}return b}Object.defineProperties(v,{__unsafeNoWarnManifest:{get(){const e=S(!0);return e&&_(e)?e:null},enumerable:!1},__unsafeNoWarnManifest2:{get(){const e=S(!0);return e&&h(e)?e:null},enumerable:!1},manifest:{get(){const e=S();return e&&_(e)?e:null},enumerable:!0},manifest2:{get(){const e=S();return e&&h(e)?e:null},enumerable:!0},expoConfig:{get(){const e=S(!0);return e?s&&s.isEmbeddedLaunch?p:h(e)?e.extra?.expoClient??null:_(e)?e:null:null},enumerable:!0},expoGoConfig:{get(){const e=S(!0);return e?h(e)?e.extra?.expoGo??null:_(e)?e:null:null},enumerable:!0},easConfig:{get(){const e=S(!0);return e?h(e)?e.extra?.eas??null:_(e)?e:null:null},enumerable:!0},__rawManifest_TEST:{get:()=>b,set(e){b=e},enumerable:!1}});var N=v},1006,[35,4,25,1007,1008,1009]);
|
|
1104
1104
|
__d(function(g,r,i,a,m,_e,d){"use strict";Object.defineProperty(_e,'__esModule',{value:!0}),Object.defineProperty(_e,"default",{enumerable:!0,get:function(){return u}});var e,t=r(d[0]),u={UIManager:((e=t)&&e.__esModule?e:{default:e}).default}},1007,[159]);
|
|
1105
1105
|
__d(function(g,r,i,a,m,e,d){"use strict";var t,n,o;Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"AppOwnership",{enumerable:!0,get:function(){return t}}),Object.defineProperty(e,"ExecutionEnvironment",{enumerable:!0,get:function(){return n}}),Object.defineProperty(e,"UserInterfaceIdiom",{enumerable:!0,get:function(){return o}}),(function(t){t.Expo="expo"})(t||(t={})),(function(t){t.Bare="bare",t.Standalone="standalone",t.StoreClient="storeClient"})(n||(n={})),(function(t){t.Handset="handset",t.Tablet="tablet",t.Desktop="desktop",t.TV="tv",t.Unsupported="unsupported"})(o||(o={}))},1008,[]);
|
|
1106
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return s}});var t=r(d[0]);const n=(Date.now()+'-'+Math.floor(1e9*Math.random())).toString();function o(){if('undefined'!=typeof navigator&&'string'==typeof navigator.userAgent){const t=navigator.userAgent.toLowerCase();if(t.includes('edge'))return'Edge';if(t.includes('edg'))return'Chromium Edge';if(t.includes('opr')&&'opr'in window&&window.opr)return'Opera';if(t.includes('chrome')&&'chrome'in window&&window.chrome)return'Chrome';if(t.includes('trident'))return'IE';if(t.includes('firefox'))return'Firefox';if(t.includes('safari'))return'Safari'}}var s={get appOwnership(){return null},get executionEnvironment(){return t.ExecutionEnvironment.Bare},get sessionId(){return n},get isHeadless(){return'undefined'==typeof navigator||/\bHeadlessChrome\//.test(navigator.userAgent)},get expoVersion(){return this.manifest.sdkVersion||null},get linkingUri(){return'undefined'!=typeof location?location.origin:''},get expoRuntimeVersion(){return this.expoVersion},get deviceName(){return o()},get systemFonts(){return[]},get statusBarHeight(){return 0},get deviceYearClass(){return null},get manifest(){return"{\"name\":\"Paseo\",\"slug\":\"paseo-hyperdrive\",\"version\":\"0.3.
|
|
1106
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return s}});var t=r(d[0]);const n=(Date.now()+'-'+Math.floor(1e9*Math.random())).toString();function o(){if('undefined'!=typeof navigator&&'string'==typeof navigator.userAgent){const t=navigator.userAgent.toLowerCase();if(t.includes('edge'))return'Edge';if(t.includes('edg'))return'Chromium Edge';if(t.includes('opr')&&'opr'in window&&window.opr)return'Opera';if(t.includes('chrome')&&'chrome'in window&&window.chrome)return'Chrome';if(t.includes('trident'))return'IE';if(t.includes('firefox'))return'Firefox';if(t.includes('safari'))return'Safari'}}var s={get appOwnership(){return null},get executionEnvironment(){return t.ExecutionEnvironment.Bare},get sessionId(){return n},get isHeadless(){return'undefined'==typeof navigator||/\bHeadlessChrome\//.test(navigator.userAgent)},get expoVersion(){return this.manifest.sdkVersion||null},get linkingUri(){return'undefined'!=typeof location?location.origin:''},get expoRuntimeVersion(){return this.expoVersion},get deviceName(){return o()},get systemFonts(){return[]},get statusBarHeight(){return 0},get deviceYearClass(){return null},get manifest(){return"{\"name\":\"Paseo\",\"slug\":\"paseo-hyperdrive\",\"version\":\"0.3.26\",\"orientation\":\"portrait\",\"icon\":\"./assets/images/icon.png\",\"scheme\":\"paseo\",\"userInterfaceStyle\":\"automatic\",\"newArchEnabled\":true,\"web\":{\"output\":\"single\",\"favicon\":\"./assets/images/favicon.png\",\"shortName\":\"Paseo\",\"orientation\":\"portrait\",\"name\":\"Paseo\"},\"autolinking\":{\"searchPaths\":[\"../../node_modules\",\"./node_modules\"]},\"experiments\":{\"typedRoutes\":true,\"reactCompiler\":true,\"autolinkingModuleResolution\":true},\"extra\":{\"router\":{},\"eas\":{\"build\":{\"experimental\":{\"ios\":{\"appExtensions\":[{\"bundleIdentifier\":\"bot.hyperdrive.paseo.AgentActivity\",\"targetName\":\"AgentActivity\"}]}}}}},\"sdkVersion\":\"54.0.0\",\"platforms\":[\"ios\",\"android\",\"web\"]}"},get manifest2(){return null},get experienceUrl(){return'undefined'!=typeof location?location.origin:''},get debugMode(){return!1},getWebViewUserAgentAsync:async()=>'undefined'!=typeof navigator?navigator.userAgent:null}},1009,[1008]);
|
|
1107
1107
|
__d(function(g,r,i,a,m,_e,d){"use strict";Object.defineProperty(_e,'__esModule',{value:!0}),Object.defineProperty(_e,"default",{enumerable:!0,get:function(){return u}});var e,t=r(d[0]),n=r(d[1]),o=(e=n)&&e.__esModule?e:{default:e};async function u(){if(!o.default.unregisterForNotificationsAsync)throw new t.UnavailabilityError('ExpoNotifications','unregisterForNotificationsAsync');return o.default.unregisterForNotificationsAsync()}},1010,[4,1011]);
|
|
1108
1108
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return n}}),r(d[0]);let t=!1;var n={addListener:()=>(t||(console.warn("[expo-notifications] Listening to push token changes is not yet fully supported on web. Adding a listener will have no effect."),t=!0),{remove:()=>{}}),removeListener:()=>{},removeAllListeners:()=>{},emit:()=>{},listenerCount:()=>0}},1011,[4]);
|
|
1109
1109
|
__d(function(g,r,i,a,m,_e,_d){"use strict";function e(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(_e,'__esModule',{value:!0}),Object.defineProperty(_e,"default",{enumerable:!0,get:function(){return u}});var t=(function(e){if(e&&e.__esModule)return e;var t={};return e&&Object.keys(e).forEach(function(o){var n=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(t,o,n.get?n:{enumerable:!0,get:function(){return e[o]}})}),t.default=e,t})(r(_d[0])),o=e(r(_d[1])),n=r(_d[2]),c=r(_d[3]),s=e(r(_d[4])),d=e(r(_d[5]));const p='https://exp.host/--/api/v2/';async function u(e={}){const s=e.devicePushToken||await(0,d.default)(),u=e.deviceId||await h(),R=e.projectId||o.default.easConfig?.projectId||o.default.expoConfig?.extra?.eas?.projectId;if(!R)throw new n.CodedError('ERR_NOTIFICATIONS_NO_EXPERIENCE_ID',"No \"projectId\" found. If \"projectId\" can't be inferred from the manifest (for instance, in bare workflow), you have to pass it in yourself.");const w=e.applicationId||t.applicationId;if(!w)throw new n.CodedError('ERR_NOTIFICATIONS_NO_APPLICATION_ID',"No \"applicationId\" found. If it can't be inferred from native configuration by expo-application, you have to pass it in yourself.");const O=e.type||y(s),_=e.development||await I(),v=e.baseUrl??p,N=e.url??`${v}push/getExpoPushToken`,x={type:O,deviceId:u.toLowerCase(),development:_,appId:w,deviceToken:E(s),projectId:R},T=await fetch(N,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(x)}).catch(e=>{throw new n.CodedError('ERR_NOTIFICATIONS_NETWORK_ERROR',`Error encountered while fetching Expo token: ${e}.`)});if(!T.ok){const e=T.statusText||T.status;let t;try{t=await T.text()}catch{}throw new n.CodedError('ERR_NOTIFICATIONS_SERVER_ERROR',`Error encountered while fetching Expo token, expected an OK response, received: ${e} (body: "${t}").`)}const b=l(await f(T));try{e.url||e.baseUrl?console.debug("[expo-notifications] Since the URL endpoint to register in has been customized in the options, expo-notifications won't try to auto-update the device push token on the server."):await(0,c.setAutoServerRegistrationEnabledAsync)(!0)}catch(e){console.warn('[expo-notifications] Could not enable automatically registering new device tokens with the Expo notification service',e)}return{type:'expo',data:b}}async function f(e){try{return await e.json()}catch{try{throw new n.CodedError('ERR_NOTIFICATIONS_SERVER_ERROR',`Expected a JSON response from server when fetching Expo token, received body: ${JSON.stringify(await e.text())}.`)}catch{throw new n.CodedError('ERR_NOTIFICATIONS_SERVER_ERROR',`Expected a JSON response from server when fetching Expo token, received response: ${JSON.stringify(e)}.`)}}}function l(e){if(!e||'object'!=typeof e||!e.data||'object'!=typeof e.data||!e.data.expoPushToken||'string'!=typeof e.data.expoPushToken)throw new n.CodedError('ERR_NOTIFICATIONS_SERVER_ERROR',`Malformed response from server, expected "{ data: { expoPushToken: string } }", received: ${JSON.stringify(e,null,2)}.`);return e.data.expoPushToken}async function h(){try{if(!s.default.getInstallationIdAsync)throw new n.UnavailabilityError('ExpoServerRegistrationModule','getInstallationIdAsync');return await s.default.getInstallationIdAsync()}catch(e){throw new n.CodedError('ERR_NOTIF_DEVICE_ID',`Could not have fetched installation ID of the application: ${e}.`)}}function E(e){return'string'==typeof e.data?e.data:JSON.stringify(e.data)}async function I(){return!1}function y(e){switch(e.type){case'ios':return'apns';case'android':return'fcm';default:return e.type}}},1012,[1013,1006,4,1016,1020,1005]);
|
|
@@ -15044,7 +15044,7 @@ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{v
|
|
|
15044
15044
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"decodeOfferFragmentPayload",{enumerable:!0,get:function(){return n.decodeOfferFragmentPayload}}),Object.defineProperty(e,"buildDaemonWebSocketUrl",{enumerable:!0,get:function(){return t.buildDaemonWebSocketUrl}}),Object.defineProperty(e,"deriveLabelFromEndpoint",{enumerable:!0,get:function(){return t.deriveLabelFromEndpoint}}),Object.defineProperty(e,"extractHostPortFromWebSocketUrl",{enumerable:!0,get:function(){return t.extractHostPortFromWebSocketUrl}}),Object.defineProperty(e,"normalizeHostPort",{enumerable:!0,get:function(){return t.normalizeHostPort}}),Object.defineProperty(e,"parseConnectionUri",{enumerable:!0,get:function(){return t.parseConnectionUri}}),Object.defineProperty(e,"parseHostPort",{enumerable:!0,get:function(){return t.parseHostPort}}),Object.defineProperty(e,"serializeConnectionUri",{enumerable:!0,get:function(){return t.serializeConnectionUri}}),Object.defineProperty(e,"serializeConnectionUriForStorage",{enumerable:!0,get:function(){return t.serializeConnectionUriForStorage}}),Object.defineProperty(e,"shouldUseTlsForDefaultHostedRelay",{enumerable:!0,get:function(){return t.shouldUseTlsForDefaultHostedRelay}}),e.buildRelayWebSocketUrl=function(n){return(0,t.buildRelayWebSocketUrl)(Object.assign({},n,{role:"client"}))};var t=r(d[0]),n=r(d[1])},3399,[3379,3400]);
|
|
15045
15045
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"ConnectionOfferV2Schema",{enumerable:!0,get:function(){return t}}),Object.defineProperty(e,"ConnectionOfferSchema",{enumerable:!0,get:function(){return o}}),e.decodeOfferFragmentPayload=l,e.parseConnectionOfferFromUrl=function(n){const t=f(n);if(!t)return null;const c=l(t);return o.parse(c)};var n=r(d[0]);const t=n.z.object({v:n.z.literal(2),serverId:n.z.string().min(1),daemonPublicKeyB64:n.z.string().min(1),relay:n.z.object({endpoint:n.z.string().min(1),useTls:n.z.boolean().optional()})}),o=t;function c(n){const t=n.replace(/-/g,"+").replace(/_/g,"/"),o=t.padEnd(t.length+(4-t.length%4)%4,"="),c=globalThis.atob(o),l=Uint8Array.from(c,n=>n.charCodeAt(0));return new TextDecoder("utf-8",{fatal:!0}).decode(l)}function l(n){const t=c(n);return JSON.parse(t)}const u="#offer=";function f(n){const t=n.trim();if(!t)return null;const o=t.indexOf(u);if(-1===o)return null;const c=t.slice(o+u.length).trim();return c.length>0?c:null}},3400,[3282]);
|
|
15046
15046
|
__d(function(g,r,i,a,m,_e,d){"use strict";function e(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(_e,'__esModule',{value:!0}),_e.resolveAppVersion=function(){const e=u(t.default?.version);if(e)return e;const o=u(n.default.expoConfig?.version);if(o)return o;const f=u(n.default.manifest?.version);if(f)return f;return null};var n=e(r(d[0])),t=e(r(d[1]));function u(e){if("string"!=typeof e)return null;const n=e.trim();return 0===n.length?null:n}},3401,[1006,3402]);
|
|
15047
|
-
__d(function(e,t,r,a,o,i,n){o.exports={name:"@hyperdrive.bot/paseo-app",version:"0.3.
|
|
15047
|
+
__d(function(e,t,r,a,o,i,n){o.exports={name:"@hyperdrive.bot/paseo-app",version:"0.3.26",private:!0,main:"index.ts",scripts:{start:"npm run start:expo","start:expo":"cross-env APP_VARIANT=development expo start","reset-project":"node ./scripts/reset-project.js","build:terminal-webview":"node ./scripts/build-terminal-webview-html.mjs","eas-build-post-install":"npm --prefix ../.. run build:app-deps && npm run build:terminal-webview",android:"npm run android:development","android:development":"npm --prefix ../.. run build:client && cross-env APP_VARIANT=development expo prebuild --platform android --non-interactive && cross-env APP_VARIANT=development expo run:android --variant=debug","android:production":"npm --prefix ../.. run build:client && cross-env APP_VARIANT=production expo prebuild --platform android --non-interactive && cross-env APP_VARIANT=production expo run:android --variant=release","android:release":"npm run android:production","android:clear":"node -e \"require('node:fs').rmSync('android', { recursive: true, force: true })\"",ios:"npm --prefix ../.. run build:client && expo run:ios","ios:release":"npm --prefix ../.. run build:client && expo run:ios --configuration Release",web:"npm --prefix ../.. run build:client && concurrently --kill-others --names protocol,client,expo --prefix-colors yellow,blue,magenta \"npm --prefix ../.. run watch:protocol\" \"npm --prefix ../.. run watch:client\" \"npm run web:expo\"","web:expo":"expo start --web",lint:"expo lint",typecheck:"tsgo --noEmit",test:"vitest run","test:browser":"vitest run --project browser","test:e2e":"playwright test --project='Desktop Chrome'","test:e2e:real":"cross-env E2E_FORK_PASEO_HOME_FROM=../../.dev/paseo-home playwright test --project=real-provider","test:e2e:ui":"playwright test --ui","test:coverage":"vitest run --project unit --coverage",build:"npm run build:web","build:web":"npm --prefix ../.. run build:app-deps && expo export --platform web --source-maps","profile:workspace-tabs":"node ./scripts/profile-workspace-tabs.mjs","deploy:web":"npm run build:web && wrangler pages deploy dist --project-name paseo-app --branch main"},dependencies:{"@bacons/apple-targets":"4.0.6","@datadog/browser-rum":"^6.23.0","@datadog/browser-rum-react":"^6.23.0","@datadog/mobile-react-native":"^2.7.0","@datadog/mobile-react-native-session-replay":"^2.14.8","@dnd-kit/core":"^6.3.1","@dnd-kit/sortable":"^10.0.0","@dnd-kit/utilities":"^3.2.2","@expo/image-utils":"0.8.8","@expo/plist":"0.4.9","@expo/prebuild-config":"54.0.8","@floating-ui/react-native":"^0.10.7","@gorhom/bottom-sheet":"^5.2.14","@gorhom/portal":"^1.0.14","@hyperdrive.bot/paseo-client":"*","@hyperdrive.bot/paseo-expo-two-way-audio":"*","@hyperdrive.bot/paseo-extension-sdk":"*","@hyperdrive.bot/paseo-highlight":"*","@react-native-async-storage/async-storage":"2.2.0","@react-native-masked-view/masked-view":"^0.3.2","@react-native/normalize-colors":"^0.81.5","@react-navigation/native":"^7.1.8","@sentry/electron":"^6.11.0","@sentry/react-native":"^6.20.0","@tanstack/react-query":"^5.90.11","@tanstack/react-virtual":"^3.13.21","@xterm/addon-clipboard":"^0.3.0-beta.213","@xterm/addon-fit":"^0.12.0-beta.213","@xterm/addon-image":"^0.10.0-beta.213","@xterm/addon-ligatures":"0.11.0-beta.213","@xterm/addon-search":"^0.17.0-beta.213","@xterm/addon-unicode11":"^0.10.0-beta.213","@xterm/addon-web-links":"^0.13.0-beta.213","@xterm/addon-webgl":"^0.20.0-beta.212","@xterm/xterm":"^6.1.0-beta.213",buffer:"^6.0.3",expo:"^54.0.18","expo-asset":"~12.0.12","expo-audio":"~1.0.13","expo-background-fetch":"~14.0.9","expo-build-properties":"^1.0.9","expo-camera":"~17.0.10","expo-clipboard":"~8.0.7","expo-constants":"~18.0.9","expo-crypto":"^15.0.8","expo-dev-client":"^6.0.15","expo-document-picker":"~14.0.8","expo-file-system":"~19.0.17","expo-haptics":"~15.0.7","expo-image":"~3.0.10","expo-image-manipulator":"~14.0.8","expo-image-picker":"^17.0.8","expo-keep-awake":"^15.0.7","expo-linking":"~8.0.8","expo-localization":"~17.0.9","expo-notifications":"^0.32.16","expo-router":"~6.0.13","expo-sharing":"^14.0.8","expo-speech":"~14.0.8","expo-speech-recognition":"^56.0.1","expo-splash-screen":"~31.0.10","expo-system-ui":"~6.0.7","expo-task-manager":"~14.0.9","fast-deep-equal":"^3.1.3",htmlparser2:"^12.0.0",i18next:"^26.3.0","lucide-react-native":"^0.546.0","markdown-it":"^10.0.0","mnemonic-id":"^3.2.7",qrcode:"^1.5.4",react:"19.1.0","react-dom":"19.1.0","react-i18next":"^17.0.8","react-native":"0.81.5","react-native-draggable-flatlist":"^4.0.3","react-native-edge-to-edge":"^1.7.0","react-native-gesture-handler":"~2.28.0","react-native-keyboard-controller":"^1.21.7","react-native-markdown-display":"^7.0.2","react-native-nitro-modules":"0.35.5","react-native-reanimated":"~4.3.1","react-native-safe-area-context":"~5.6.0","react-native-screens":"~4.16.0","react-native-svg":"^15.14.0","react-native-uitextview":"^2.2.0","react-native-unistyles":"^3.2.4","react-native-web":"~0.21.0","react-native-webview":"^13.16.0","react-native-worklets":"~0.8.3","tiny-invariant":"^1.3.3","use-sync-external-store":"^1.6.0",zod:"^4.4.3",zustand:"^5.0.9"},devDependencies:{"@playwright/test":"^1.56.1","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","@types/chai":"^5.2.2","@types/markdown-it":"^14.1.2","@types/qrcode":"^1.5.6","@types/react":"~19.2.0","@types/ws":"^8.18.1","@vitest/browser":"^4.1.7","@vitest/browser-playwright":"^4.1.7","@vitest/coverage-v8":"^4.1.7","@xterm/headless":"^6.1.0-beta.213",dotenv:"^17.2.3",eslint:"^9.25.0","eslint-config-expo":"~10.0.0",jsdom:"^20.0.3","material-icon-theme":"^5.32.0",playwright:"^1.56.1","serve-sim":"^0.1.40",typescript:"~5.9.2",vitest:"^4.1.6",wrangler:"^4.105.0",ws:"^8.20.0"}}},3402,[]);
|
|
15048
15048
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.shouldUseDesktopDaemon=function(){return(0,n.isElectronRuntime)()},e.getDesktopDaemonStatus=async function(){return c(await(0,t.invokeDesktopCommand)("desktop_daemon_status"))},e.startDesktopDaemon=async function(){return c(await(0,t.invokeDesktopCommand)("start_desktop_daemon"))},e.stopDesktopDaemon=async function(n="manual_ipc"){return c(await(0,t.invokeDesktopCommand)("stop_desktop_daemon",{reason:n}))},e.restartDesktopDaemon=async function(){return c(await(0,t.invokeDesktopCommand)("restart_desktop_daemon"))},e.getDesktopDaemonLogs=async function(){return p(await(0,t.invokeDesktopCommand)("desktop_daemon_logs"))},e.getDesktopDaemonPairing=async function(){return k(await(0,t.invokeDesktopCommand)("desktop_daemon_pairing"))},e.getCliDaemonStatus=async function(){const n=await(0,t.invokeDesktopCommand)("cli_daemon_status");if("string"!=typeof n)throw new Error("Unexpected CLI daemon status response.");return n},e.listenToLocalTransportEvents=async function(t){const u=(0,n.getDesktopHost)()?.events?.on;if("function"!=typeof u)throw new Error("Desktop events API is unavailable.");const c=await u("local-daemon-transport-event",n=>{o(n)&&t({sessionId:s(n.sessionId)??"",kind:s(n.kind)??"error",text:s(n.text),binaryBase64:s(n.binaryBase64),code:l(n.code),reason:s(n.reason),error:s(n.error)})});return"function"==typeof c?c:()=>{}},e.openLocalTransportSession=async function(n){const o=await(0,t.invokeDesktopCommand)("open_local_daemon_transport",n);if("string"!=typeof o||0===o.trim().length)throw new Error("Unexpected local transport session response.");return o},e.sendLocalTransportMessage=async function(n){await(0,t.invokeDesktopCommand)("send_local_daemon_transport_message",Object.assign({sessionId:n.sessionId},n.text?{text:n.text}:{},n.binaryBase64?{binaryBase64:n.binaryBase64}:{}))},e.closeLocalTransportSession=async function(n){await(0,t.invokeDesktopCommand)("close_local_daemon_transport",{sessionId:n})},e.getCliInstallStatus=async function(){return f(await(0,t.invokeDesktopCommand)("get_cli_install_status"))},e.installCli=async function(){return f(await(0,t.invokeDesktopCommand)("install_cli"))},e.getSkillsStatus=async function(){return y(await(0,t.invokeDesktopCommand)("get_skills_status"))},e.installSkills=async function(){return y(await(0,t.invokeDesktopCommand)("install_skills"))},e.updateSkills=async function(){return y(await(0,t.invokeDesktopCommand)("update_skills"))},e.uninstallSkills=async function(){return y(await(0,t.invokeDesktopCommand)("uninstall_skills"))};var n=r(d[0]),t=r(d[1]);function o(n){return"object"==typeof n&&null!==n}function s(n){return"string"==typeof n&&n.trim().length>0?n:null}function l(n){return"number"==typeof n&&Number.isFinite(n)?n:null}function u(n){const t=s(n)?.toLowerCase();switch(t){case"starting":return"starting";case"running":return"running";case"errored":case"error":return"errored";default:return"stopped"}}function c(n){if(!o(n))throw new Error("Unexpected desktop daemon status response.");return{serverId:s(n.serverId)??"",status:u(n.status),listen:s(n.listen),hostname:s(n.hostname),pid:l(n.pid),home:s(n.home)??"",version:s(n.version),desktopManaged:!0===n.desktopManaged,error:s(n.error)}}function p(n){if(!o(n))throw new Error("Unexpected desktop daemon logs response.");return{logPath:s(n.logPath)??"",contents:"string"==typeof n.contents?n.contents:""}}function k(n){if(!o(n))throw new Error("Unexpected desktop daemon pairing response.");return{relayEnabled:!0===n.relayEnabled,url:s(n.url),qr:s(n.qr)}}function f(n){if(!o(n))throw new Error("Unexpected install status response.");return{installed:!0===n.installed}}function w(n){switch(n){case"not-installed":case"up-to-date":case"drift":return n;default:throw new Error(`Unexpected skills status state: ${String(n)}`)}}function _(n){if(!o(n))throw new Error("Unexpected skill op response.");const t=s(n.name);if(!t)throw new Error("Skill op missing name.");switch(n.kind){case"add":return{kind:"add",name:t};case"update":return{kind:"update",name:t};case"delete":return{kind:"delete",name:t};default:throw new Error(`Unexpected skill op kind: ${String(n.kind)}`)}}function y(n){if(!o(n))throw new Error("Unexpected skills status response.");const t=Array.isArray(n.ops)?n.ops.map(_):[];return{state:w(n.state),ops:t}}},3403,[3404,3406]);
|
|
15049
15049
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.getDesktopHost=n,e.isElectronRuntime=o,e.isElectronRuntimeMac=function(){if(!o())return!1;if("undefined"==typeof navigator)return!1;const t=n()?.platform?.toLowerCase();if("darwin"===t||"mac"===t||"macos"===t)return!0;const u=navigator.userAgent;return u.includes("Mac OS")||u.includes("Macintosh")},r(d[0]);var t=r(d[1]);function n(){return(0,t.getElectronHost)()}function o(){return null!==n()}},3404,[25,3405]);
|
|
15050
15050
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.getElectronHost=function(){if("undefined"==typeof window)return null;const t=window.paseoDesktop;if(!t||"object"!=typeof t)return null;return t}},3405,[]);
|
|
@@ -16539,5 +16539,5 @@ __d(function(g,r,_i,a,_m,_e,d){"use strict";var e,t=r(d[0]),n=this&&this.__creat
|
|
|
16539
16539
|
__r(975);
|
|
16540
16540
|
__r(341);
|
|
16541
16541
|
__r(0);
|
|
16542
|
-
//# sourceMappingURL=/_expo/static/js/web/index-
|
|
16543
|
-
//# debugId=
|
|
16542
|
+
//# sourceMappingURL=/_expo/static/js/web/index-045767cf5362f85583f2649254d4471a.js.map
|
|
16543
|
+
//# debugId=810a9939-800e-468d-a63e-6ad656f9655c
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -85,6 +85,6 @@
|
|
|
85
85
|
<body>
|
|
86
86
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
87
87
|
<div id="root"></div>
|
|
88
|
-
<script src="/_expo/static/js/web/index-
|
|
88
|
+
<script src="/_expo/static/js/web/index-045767cf5362f85583f2649254d4471a.js" defer></script>
|
|
89
89
|
</body>
|
|
90
90
|
</html>
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperdrive.bot/paseo-server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.26",
|
|
4
4
|
"description": "Paseo backend server",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist/server",
|
|
@@ -65,11 +65,11 @@
|
|
|
65
65
|
"@agentclientprotocol/sdk": "^0.17.1",
|
|
66
66
|
"@anthropic-ai/claude-agent-sdk": "^0.3.195",
|
|
67
67
|
"@anthropic-ai/sdk": "^0.104.2",
|
|
68
|
-
"@hyperdrive.bot/paseo-client": "0.3.
|
|
69
|
-
"@hyperdrive.bot/paseo-extension-sdk": "0.3.
|
|
70
|
-
"@hyperdrive.bot/paseo-highlight": "0.3.
|
|
71
|
-
"@hyperdrive.bot/paseo-protocol": "0.3.
|
|
72
|
-
"@hyperdrive.bot/paseo-relay": "0.3.
|
|
68
|
+
"@hyperdrive.bot/paseo-client": "0.3.26",
|
|
69
|
+
"@hyperdrive.bot/paseo-extension-sdk": "0.3.26",
|
|
70
|
+
"@hyperdrive.bot/paseo-highlight": "0.3.26",
|
|
71
|
+
"@hyperdrive.bot/paseo-protocol": "0.3.26",
|
|
72
|
+
"@hyperdrive.bot/paseo-relay": "0.3.26",
|
|
73
73
|
"@isaacs/ttlcache": "^2.1.4",
|
|
74
74
|
"@modelcontextprotocol/sdk": "^1.20.1",
|
|
75
75
|
"@opencode-ai/sdk": "1.2.6",
|
|
Binary file
|