@getpaseo/server 0.1.88 → 0.1.89
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/agent-manager.js +4 -1
- package/dist/server/server/agent/agent-storage.d.ts +22 -22
- package/dist/server/server/agent/create-agent/create.d.ts +2 -0
- package/dist/server/server/agent/create-agent/create.js +16 -5
- package/dist/server/server/agent/create-agent-lifecycle-dispatch.d.ts +1 -0
- package/dist/server/server/agent/create-agent-lifecycle-dispatch.js +4 -0
- package/dist/server/server/agent/mcp-server.d.ts +1 -0
- package/dist/server/server/agent/mcp-server.js +113 -70
- package/dist/server/server/agent/providers/pi/agent.js +13 -0
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts +3 -0
- package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +1 -0
- package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +6 -1
- package/dist/server/server/bootstrap.d.ts +7 -2
- package/dist/server/server/bootstrap.js +152 -115
- package/dist/server/server/config.js +41 -0
- package/dist/server/server/loop-service.d.ts +22 -22
- package/dist/server/server/package-version.d.ts +2 -2
- package/dist/server/server/paseo-worktree-archive-service.d.ts +2 -0
- package/dist/server/server/paseo-worktree-archive-service.js +28 -9
- package/dist/server/server/persisted-config.d.ts +84 -28
- package/dist/server/server/persisted-config.js +17 -0
- package/dist/server/server/pid-lock.d.ts +2 -2
- package/dist/server/server/script-health-monitor.d.ts +4 -4
- package/dist/server/server/script-health-monitor.js +6 -6
- package/dist/server/server/script-proxy.d.ts +2 -39
- package/dist/server/server/script-proxy.js +1 -244
- package/dist/server/server/script-route-branch-handler.d.ts +2 -2
- package/dist/server/server/script-route-branch-handler.js +3 -37
- package/dist/server/server/script-status-projection.d.ts +6 -4
- package/dist/server/server/script-status-projection.js +85 -37
- package/dist/server/server/service-proxy.d.ts +237 -0
- package/dist/server/server/service-proxy.js +714 -0
- package/dist/server/server/session.d.ts +7 -3
- package/dist/server/server/session.js +22 -10
- package/dist/server/server/websocket-server.d.ts +7 -4
- package/dist/server/server/websocket-server.js +9 -4
- package/dist/server/server/workspace-directory.js +4 -0
- package/dist/server/server/workspace-git-service.d.ts +3 -0
- package/dist/server/server/workspace-git-service.js +53 -12
- package/dist/server/server/workspace-registry.d.ts +2 -2
- package/dist/server/server/workspace-service-env.d.ts +1 -0
- package/dist/server/server/workspace-service-env.js +23 -18
- package/dist/server/server/worktree/commands.d.ts +2 -0
- package/dist/server/server/worktree/commands.js +4 -1
- package/dist/server/server/worktree-bootstrap.d.ts +4 -3
- package/dist/server/server/worktree-bootstrap.js +14 -13
- package/dist/server/server/worktree-core.d.ts +1 -0
- package/dist/server/server/worktree-core.js +2 -0
- package/dist/server/server/worktree-session.d.ts +6 -2
- package/dist/server/server/worktree-session.js +3 -0
- package/dist/server/services/github-service.d.ts +1 -0
- package/dist/server/services/github-service.js +7 -1
- package/dist/server/utils/checkout-git.d.ts +6 -2
- package/dist/server/utils/checkout-git.js +17 -7
- package/dist/server/utils/worktree.d.ts +17 -12
- package/dist/server/utils/worktree.js +39 -22
- package/dist/src/server/persisted-config.js +17 -0
- package/package.json +5 -5
- package/dist/server/utils/script-hostname.d.ts +0 -8
- package/dist/server/utils/script-hostname.js +0 -14
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { stat } from "node:fs/promises";
|
|
4
4
|
import { AGENT_LIFECYCLE_STATUSES, } from "@getpaseo/protocol/agent-lifecycle";
|
|
5
|
-
import { PARENT_AGENT_ID_LABEL } from "@getpaseo/protocol/agent-labels";
|
|
5
|
+
import { isDelegatedAgent, PARENT_AGENT_ID_LABEL } from "@getpaseo/protocol/agent-labels";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { getAgentStreamEventTurnId, } from "./agent-sdk-types.js";
|
|
8
8
|
import { buildArchivedAgentRecord } from "./agent-archive.js";
|
|
@@ -2402,6 +2402,9 @@ export class AgentManager {
|
|
|
2402
2402
|
}
|
|
2403
2403
|
}
|
|
2404
2404
|
broadcastAgentAttention(agent, reason) {
|
|
2405
|
+
if (isDelegatedAgent(agent)) {
|
|
2406
|
+
return;
|
|
2407
|
+
}
|
|
2405
2408
|
this.onAgentAttention?.({
|
|
2406
2409
|
agentId: agent.id,
|
|
2407
2410
|
provider: agent.provider,
|
|
@@ -167,22 +167,12 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
|
|
|
167
167
|
archivedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
168
168
|
}, "strip", z.ZodTypeAny, {
|
|
169
169
|
cwd: string;
|
|
170
|
-
createdAt: string;
|
|
171
170
|
id: string;
|
|
172
171
|
provider: string;
|
|
172
|
+
createdAt: string;
|
|
173
173
|
updatedAt: string;
|
|
174
174
|
labels: Record<string, string>;
|
|
175
175
|
lastStatus: "error" | "running" | "initializing" | "idle" | "closed";
|
|
176
|
-
config?: {
|
|
177
|
-
modeId?: string | null | undefined;
|
|
178
|
-
model?: string | null | undefined;
|
|
179
|
-
thinkingOptionId?: string | null | undefined;
|
|
180
|
-
featureValues?: Record<string, unknown> | null | undefined;
|
|
181
|
-
extra?: Record<string, any> | null | undefined;
|
|
182
|
-
systemPrompt?: string | null | undefined;
|
|
183
|
-
mcpServers?: Record<string, any> | null | undefined;
|
|
184
|
-
} | null | undefined;
|
|
185
|
-
internal?: boolean | undefined;
|
|
186
176
|
title?: string | null | undefined;
|
|
187
177
|
persistence?: {
|
|
188
178
|
provider: string;
|
|
@@ -193,6 +183,15 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
|
|
|
193
183
|
lastActivityAt?: string | undefined;
|
|
194
184
|
lastUserMessageAt?: string | null | undefined;
|
|
195
185
|
lastModeId?: string | null | undefined;
|
|
186
|
+
config?: {
|
|
187
|
+
modeId?: string | null | undefined;
|
|
188
|
+
model?: string | null | undefined;
|
|
189
|
+
thinkingOptionId?: string | null | undefined;
|
|
190
|
+
featureValues?: Record<string, unknown> | null | undefined;
|
|
191
|
+
extra?: Record<string, any> | null | undefined;
|
|
192
|
+
systemPrompt?: string | null | undefined;
|
|
193
|
+
mcpServers?: Record<string, any> | null | undefined;
|
|
194
|
+
} | null | undefined;
|
|
196
195
|
runtimeInfo?: {
|
|
197
196
|
provider: string;
|
|
198
197
|
sessionId: string | null;
|
|
@@ -229,23 +228,14 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
|
|
|
229
228
|
requiresAttention?: boolean | undefined;
|
|
230
229
|
attentionReason?: "finished" | "error" | "permission" | null | undefined;
|
|
231
230
|
attentionTimestamp?: string | null | undefined;
|
|
231
|
+
internal?: boolean | undefined;
|
|
232
232
|
archivedAt?: string | null | undefined;
|
|
233
233
|
}, {
|
|
234
234
|
cwd: string;
|
|
235
|
-
createdAt: string;
|
|
236
235
|
id: string;
|
|
237
236
|
provider: string;
|
|
237
|
+
createdAt: string;
|
|
238
238
|
updatedAt: string;
|
|
239
|
-
config?: {
|
|
240
|
-
modeId?: string | null | undefined;
|
|
241
|
-
model?: string | null | undefined;
|
|
242
|
-
thinkingOptionId?: string | null | undefined;
|
|
243
|
-
featureValues?: Record<string, unknown> | null | undefined;
|
|
244
|
-
extra?: Record<string, any> | null | undefined;
|
|
245
|
-
systemPrompt?: string | null | undefined;
|
|
246
|
-
mcpServers?: Record<string, any> | null | undefined;
|
|
247
|
-
} | null | undefined;
|
|
248
|
-
internal?: boolean | undefined;
|
|
249
239
|
title?: string | null | undefined;
|
|
250
240
|
persistence?: {
|
|
251
241
|
provider: string;
|
|
@@ -258,6 +248,15 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
|
|
|
258
248
|
labels?: Record<string, string> | undefined;
|
|
259
249
|
lastStatus?: "error" | "running" | "initializing" | "idle" | "closed" | undefined;
|
|
260
250
|
lastModeId?: string | null | undefined;
|
|
251
|
+
config?: {
|
|
252
|
+
modeId?: string | null | undefined;
|
|
253
|
+
model?: string | null | undefined;
|
|
254
|
+
thinkingOptionId?: string | null | undefined;
|
|
255
|
+
featureValues?: Record<string, unknown> | null | undefined;
|
|
256
|
+
extra?: Record<string, any> | null | undefined;
|
|
257
|
+
systemPrompt?: string | null | undefined;
|
|
258
|
+
mcpServers?: Record<string, any> | null | undefined;
|
|
259
|
+
} | null | undefined;
|
|
261
260
|
runtimeInfo?: {
|
|
262
261
|
provider: string;
|
|
263
262
|
sessionId: string | null;
|
|
@@ -294,6 +293,7 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
|
|
|
294
293
|
requiresAttention?: boolean | undefined;
|
|
295
294
|
attentionReason?: "finished" | "error" | "permission" | null | undefined;
|
|
296
295
|
attentionTimestamp?: string | null | undefined;
|
|
296
|
+
internal?: boolean | undefined;
|
|
297
297
|
archivedAt?: string | null | undefined;
|
|
298
298
|
}>;
|
|
299
299
|
export type SerializableAgentConfig = Pick<AgentSessionConfig, "modeId" | "model" | "thinkingOptionId" | "featureValues" | "extra" | "systemPrompt" | "mcpServers">;
|
|
@@ -20,6 +20,7 @@ interface CreateAgentCommandDependencies {
|
|
|
20
20
|
agentStorage: AgentStorage;
|
|
21
21
|
logger: Logger;
|
|
22
22
|
paseoHome?: string;
|
|
23
|
+
worktreesRoot?: string;
|
|
23
24
|
workspaceGitService?: Pick<WorkspaceGitService, "getSnapshot" | "listWorktrees" | "resolveRepoRoot">;
|
|
24
25
|
terminalManager?: TerminalManager | null;
|
|
25
26
|
providerSnapshotManager: ProviderSnapshotManager;
|
|
@@ -63,6 +64,7 @@ export interface CreateAgentFromMcpInput {
|
|
|
63
64
|
mode?: string;
|
|
64
65
|
background: boolean;
|
|
65
66
|
notifyOnFinish: boolean;
|
|
67
|
+
detached?: boolean;
|
|
66
68
|
callerAgentId?: string;
|
|
67
69
|
callerContext?: {
|
|
68
70
|
lockedCwd?: string;
|
|
@@ -94,7 +94,12 @@ async function resolveMcpCreateAgent(dependencies, input) {
|
|
|
94
94
|
featureValues: input.features,
|
|
95
95
|
parent: parentAgent,
|
|
96
96
|
});
|
|
97
|
-
const labels = mergeLabels(
|
|
97
|
+
const labels = mergeLabels({
|
|
98
|
+
callerAgentId: input.callerAgentId,
|
|
99
|
+
detached: input.detached ?? false,
|
|
100
|
+
childAgentDefaultLabels: input.callerContext?.childAgentDefaultLabels,
|
|
101
|
+
labels: input.labels,
|
|
102
|
+
});
|
|
98
103
|
const trimmedPrompt = input.initialPrompt.trim();
|
|
99
104
|
return {
|
|
100
105
|
config: {
|
|
@@ -220,6 +225,7 @@ async function resolveMcpCwd(params) {
|
|
|
220
225
|
...(params.initialPrompt ? { firstAgentContext: { prompt: params.initialPrompt } } : {}),
|
|
221
226
|
runSetup: false,
|
|
222
227
|
paseoHome: dependencies.paseoHome,
|
|
228
|
+
worktreesRoot: dependencies.worktreesRoot,
|
|
223
229
|
},
|
|
224
230
|
createPaseoWorktree: dependencies.createPaseoWorktree,
|
|
225
231
|
resolveDefaultBranch: baseBranch ? async () => baseBranch : undefined,
|
|
@@ -260,12 +266,17 @@ async function createMcpWorktree(options) {
|
|
|
260
266
|
throw toWorktreeRequestError(error);
|
|
261
267
|
}
|
|
262
268
|
}
|
|
263
|
-
function mergeLabels(
|
|
269
|
+
function mergeLabels(params) {
|
|
264
270
|
const mergedLabels = {
|
|
265
|
-
...(
|
|
266
|
-
|
|
267
|
-
|
|
271
|
+
...(!params.detached && params.callerAgentId
|
|
272
|
+
? { [PARENT_AGENT_ID_LABEL]: params.callerAgentId }
|
|
273
|
+
: {}),
|
|
274
|
+
...params.childAgentDefaultLabels,
|
|
275
|
+
...params.labels,
|
|
268
276
|
};
|
|
277
|
+
if (params.detached) {
|
|
278
|
+
delete mergedLabels[PARENT_AGENT_ID_LABEL];
|
|
279
|
+
}
|
|
269
280
|
return Object.keys(mergedLabels).length > 0 ? mergedLabels : undefined;
|
|
270
281
|
}
|
|
271
282
|
//# sourceMappingURL=create.js.map
|
|
@@ -7,6 +7,7 @@ import type { AgentManager } from "./agent-manager.js";
|
|
|
7
7
|
import type { AgentStorage } from "./agent-storage.js";
|
|
8
8
|
interface CreateAgentLifecycleDispatchDependencies {
|
|
9
9
|
paseoHome: string;
|
|
10
|
+
worktreesRoot?: string;
|
|
10
11
|
agentManager: AgentManager;
|
|
11
12
|
agentStorage: AgentStorage;
|
|
12
13
|
github: GitHubService;
|
|
@@ -46,6 +46,7 @@ export class CreateAgentLifecycleDispatch {
|
|
|
46
46
|
firstAgentContext,
|
|
47
47
|
runSetup: false,
|
|
48
48
|
paseoHome: this.dependencies.paseoHome,
|
|
49
|
+
worktreesRoot: this.dependencies.worktreesRoot,
|
|
49
50
|
};
|
|
50
51
|
switch (target.mode) {
|
|
51
52
|
case "branch-off":
|
|
@@ -108,12 +109,14 @@ export class CreateAgentLifecycleDispatch {
|
|
|
108
109
|
async archiveAutoCreatedWorktree(options) {
|
|
109
110
|
const ownership = await isPaseoOwnedWorktreeCwd(options.worktreePath, {
|
|
110
111
|
paseoHome: this.dependencies.paseoHome,
|
|
112
|
+
worktreesRoot: this.dependencies.worktreesRoot,
|
|
111
113
|
});
|
|
112
114
|
if (!ownership.allowed) {
|
|
113
115
|
throw new Error("Auto-created worktree is not a Paseo-owned worktree");
|
|
114
116
|
}
|
|
115
117
|
await archivePaseoWorktree({
|
|
116
118
|
paseoHome: this.dependencies.paseoHome,
|
|
119
|
+
worktreesRoot: this.dependencies.worktreesRoot,
|
|
117
120
|
github: this.dependencies.github,
|
|
118
121
|
workspaceGitService: this.dependencies.workspaceGitService,
|
|
119
122
|
agentManager: this.dependencies.agentManager,
|
|
@@ -129,6 +132,7 @@ export class CreateAgentLifecycleDispatch {
|
|
|
129
132
|
targetPath: options.worktreePath,
|
|
130
133
|
repoRoot: options.repoRoot ?? ownership.repoRoot ?? null,
|
|
131
134
|
worktreesRoot: ownership.worktreeRoot,
|
|
135
|
+
worktreesBaseRoot: this.dependencies.worktreesRoot,
|
|
132
136
|
requestId: randomUUID(),
|
|
133
137
|
});
|
|
134
138
|
if (options.agentId) {
|
|
@@ -25,6 +25,7 @@ export interface AgentMcpServerOptions {
|
|
|
25
25
|
clearWorkspaceArchiving?: ArchivePaseoWorktreeDependencies["clearWorkspaceArchiving"];
|
|
26
26
|
createPaseoWorktree?: CreatePaseoWorktreeWorkflowFn;
|
|
27
27
|
paseoHome?: string;
|
|
28
|
+
worktreesRoot?: string;
|
|
28
29
|
/**
|
|
29
30
|
* ID of the agent that is connecting to this MCP server.
|
|
30
31
|
* Used for cwd/mode inheritance when agents spawn child agents.
|
|
@@ -300,6 +300,23 @@ export async function createAgentMcpServer(options) {
|
|
|
300
300
|
});
|
|
301
301
|
const registerRawTool = server.registerTool.bind(server);
|
|
302
302
|
const registerTool = (name, config, handler) => registerRawTool(name, relaxMcpToolOutputSchema(config), (async (args, extra) => addModelVisibleStructuredContent(await handler(args, extra))));
|
|
303
|
+
const buildCronScheduleCadence = (input) => {
|
|
304
|
+
const expression = input.cron?.trim() ?? "";
|
|
305
|
+
if (!expression) {
|
|
306
|
+
throw new Error("cron is required");
|
|
307
|
+
}
|
|
308
|
+
const timezone = normalizeScheduleTimeZoneArg(input.timezone);
|
|
309
|
+
return {
|
|
310
|
+
type: "cron",
|
|
311
|
+
expression,
|
|
312
|
+
...(timezone !== undefined ? { timezone } : {}),
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
const buildScheduleExpiry = (expiresIn) => {
|
|
316
|
+
return expiresIn === undefined
|
|
317
|
+
? undefined
|
|
318
|
+
: new Date(Date.now() + parseDurationString(expiresIn)).toISOString();
|
|
319
|
+
};
|
|
303
320
|
const resolveCallerAgent = () => {
|
|
304
321
|
if (!callerAgentId) {
|
|
305
322
|
return null;
|
|
@@ -325,7 +342,7 @@ export async function createAgentMcpServer(options) {
|
|
|
325
342
|
if (opts?.required) {
|
|
326
343
|
throw new Error("cwd is required");
|
|
327
344
|
}
|
|
328
|
-
throw new Error("cwd is required
|
|
345
|
+
throw new Error("cwd is required outside an agent-scoped session");
|
|
329
346
|
}
|
|
330
347
|
return expandUserPath(trimmedCwd);
|
|
331
348
|
};
|
|
@@ -469,7 +486,7 @@ export async function createAgentMcpServer(options) {
|
|
|
469
486
|
cwd: z
|
|
470
487
|
.string()
|
|
471
488
|
.optional()
|
|
472
|
-
.describe("Optional working directory. Defaults to
|
|
489
|
+
.describe("Optional working directory. Defaults to your current working directory."),
|
|
473
490
|
title: z
|
|
474
491
|
.string()
|
|
475
492
|
.trim()
|
|
@@ -484,16 +501,16 @@ export async function createAgentMcpServer(options) {
|
|
|
484
501
|
.trim()
|
|
485
502
|
.min(1, "initialPrompt is required")
|
|
486
503
|
.describe("Required first task to run immediately after creation."),
|
|
487
|
-
|
|
504
|
+
detached: z
|
|
488
505
|
.boolean()
|
|
489
506
|
.optional()
|
|
490
507
|
.default(false)
|
|
491
|
-
.describe("
|
|
508
|
+
.describe("If true, the created agent stands on its own: it does not appear in your subagent track and is not archived with you."),
|
|
492
509
|
notifyOnFinish: z
|
|
493
510
|
.boolean()
|
|
494
511
|
.optional()
|
|
495
|
-
.default(
|
|
496
|
-
.describe("
|
|
512
|
+
.default(true)
|
|
513
|
+
.describe("Get notified when the created agent finishes, errors, or needs permission. Set false only for truly fire-and-forget agents."),
|
|
497
514
|
};
|
|
498
515
|
const topLevelInputSchema = {
|
|
499
516
|
cwd: z
|
|
@@ -541,7 +558,7 @@ export async function createAgentMcpServer(options) {
|
|
|
541
558
|
.boolean()
|
|
542
559
|
.optional()
|
|
543
560
|
.default(false)
|
|
544
|
-
.describe("
|
|
561
|
+
.describe("Agent-scoped only: get notified when the created agent finishes, errors, or needs permission."),
|
|
545
562
|
};
|
|
546
563
|
const createAgentInputSchema = callerAgentId ? agentToAgentInputSchema : topLevelInputSchema;
|
|
547
564
|
const agentToAgentCreateAgentArgsSchema = z.object(agentToAgentInputSchema).strict();
|
|
@@ -574,7 +591,7 @@ export async function createAgentMcpServer(options) {
|
|
|
574
591
|
}
|
|
575
592
|
const handler = resolveSpeakHandler?.(callerAgentId) ?? null;
|
|
576
593
|
if (!handler) {
|
|
577
|
-
throw new Error(`No speak handler registered for
|
|
594
|
+
throw new Error(`No speak handler registered for your session '${callerAgentId}'`);
|
|
578
595
|
}
|
|
579
596
|
await handler({
|
|
580
597
|
text: args.text,
|
|
@@ -603,14 +620,30 @@ export async function createAgentMcpServer(options) {
|
|
|
603
620
|
availableModes: z.array(ProviderModeSchema),
|
|
604
621
|
lastMessage: z.string().nullable().optional(),
|
|
605
622
|
permission: AgentPermissionRequestPayloadSchema.nullable().optional(),
|
|
623
|
+
guidance: z.string().optional(),
|
|
606
624
|
},
|
|
607
625
|
}, async (args) => {
|
|
608
|
-
const
|
|
609
|
-
const {
|
|
626
|
+
const resolvedArgs = resolveCreateAgentToolArgs(args);
|
|
627
|
+
const { parsedArgs, worktree } = resolvedArgs;
|
|
628
|
+
let requestedBackground;
|
|
629
|
+
let notifyOnFinish;
|
|
630
|
+
let detached;
|
|
631
|
+
if (resolvedArgs.kind === "agent-scoped") {
|
|
632
|
+
requestedBackground = true;
|
|
633
|
+
notifyOnFinish = resolvedArgs.parsedArgs.notifyOnFinish;
|
|
634
|
+
detached = resolvedArgs.parsedArgs.detached;
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
requestedBackground = resolvedArgs.parsedArgs.background;
|
|
638
|
+
notifyOnFinish = resolvedArgs.parsedArgs.notifyOnFinish ?? false;
|
|
639
|
+
detached = false;
|
|
640
|
+
}
|
|
641
|
+
const { snapshot, background: createdInBackground, initialPromptStarted, } = await createAgentCommand({
|
|
610
642
|
agentManager,
|
|
611
643
|
agentStorage,
|
|
612
644
|
logger: childLogger,
|
|
613
645
|
paseoHome: options.paseoHome,
|
|
646
|
+
worktreesRoot: options.worktreesRoot,
|
|
614
647
|
workspaceGitService: options.workspaceGitService,
|
|
615
648
|
terminalManager,
|
|
616
649
|
providerSnapshotManager,
|
|
@@ -625,14 +658,15 @@ export async function createAgentMcpServer(options) {
|
|
|
625
658
|
features: parsedArgs.settings?.features,
|
|
626
659
|
labels: parsedArgs.labels,
|
|
627
660
|
mode: parsedArgs.settings?.modeId,
|
|
628
|
-
background:
|
|
629
|
-
notifyOnFinish
|
|
661
|
+
background: requestedBackground,
|
|
662
|
+
notifyOnFinish,
|
|
663
|
+
detached,
|
|
630
664
|
callerAgentId,
|
|
631
665
|
callerContext,
|
|
632
666
|
worktree,
|
|
633
667
|
});
|
|
634
668
|
try {
|
|
635
|
-
if (!
|
|
669
|
+
if (!createdInBackground && initialPromptStarted) {
|
|
636
670
|
const result = await waitForAgentWithTimeout(agentManager, snapshot.id, {
|
|
637
671
|
waitForActive: true,
|
|
638
672
|
});
|
|
@@ -659,8 +693,11 @@ export async function createAgentMcpServer(options) {
|
|
|
659
693
|
childLogger.error({ err: error, agentId: snapshot.id }, "Failed to run initial prompt");
|
|
660
694
|
throw error;
|
|
661
695
|
}
|
|
662
|
-
// Return immediately
|
|
696
|
+
// Return immediately for async creation.
|
|
663
697
|
const currentSnapshot = agentManager.getAgent(snapshot.id) ?? snapshot;
|
|
698
|
+
const guidance = callerAgentId && notifyOnFinish && initialPromptStarted
|
|
699
|
+
? "You will get notified when the created agent finishes, errors, or needs permission. Do not call wait_for_agent or poll for status; continue with other work until the notification arrives."
|
|
700
|
+
: undefined;
|
|
664
701
|
const response = {
|
|
665
702
|
content: [],
|
|
666
703
|
structuredContent: ensureValidJson({
|
|
@@ -672,6 +709,7 @@ export async function createAgentMcpServer(options) {
|
|
|
672
709
|
availableModes: currentSnapshot.availableModes,
|
|
673
710
|
lastMessage: null,
|
|
674
711
|
permission: null,
|
|
712
|
+
...(guidance ? { guidance } : {}),
|
|
675
713
|
}),
|
|
676
714
|
};
|
|
677
715
|
return response;
|
|
@@ -679,12 +717,14 @@ export async function createAgentMcpServer(options) {
|
|
|
679
717
|
function resolveCreateAgentToolArgs(args) {
|
|
680
718
|
if (callerAgentId) {
|
|
681
719
|
return {
|
|
720
|
+
kind: "agent-scoped",
|
|
682
721
|
parsedArgs: agentToAgentCreateAgentArgsSchema.parse(args),
|
|
683
722
|
worktree: undefined,
|
|
684
723
|
};
|
|
685
724
|
}
|
|
686
725
|
const parsedArgs = topLevelCreateAgentArgsSchema.parse(args);
|
|
687
726
|
return {
|
|
727
|
+
kind: "top-level",
|
|
688
728
|
parsedArgs,
|
|
689
729
|
worktree: resolveTopLevelCreateAgentWorktree(parsedArgs),
|
|
690
730
|
};
|
|
@@ -784,7 +824,7 @@ export async function createAgentMcpServer(options) {
|
|
|
784
824
|
.boolean()
|
|
785
825
|
.optional()
|
|
786
826
|
.default(false)
|
|
787
|
-
.describe("
|
|
827
|
+
.describe("Agent-scoped only: get notified when this run finishes, errors, or needs permission."),
|
|
788
828
|
},
|
|
789
829
|
outputSchema: {
|
|
790
830
|
success: z.boolean(),
|
|
@@ -1025,7 +1065,7 @@ export async function createAgentMcpServer(options) {
|
|
|
1025
1065
|
cwd: z
|
|
1026
1066
|
.string()
|
|
1027
1067
|
.optional()
|
|
1028
|
-
.describe("Optional working directory. Defaults to
|
|
1068
|
+
.describe("Optional working directory. Defaults to your current working directory."),
|
|
1029
1069
|
all: z.boolean().optional().describe("List terminals across all working directories."),
|
|
1030
1070
|
},
|
|
1031
1071
|
outputSchema: {
|
|
@@ -1058,7 +1098,7 @@ export async function createAgentMcpServer(options) {
|
|
|
1058
1098
|
cwd: z
|
|
1059
1099
|
.string()
|
|
1060
1100
|
.optional()
|
|
1061
|
-
.describe("Optional working directory. Defaults to
|
|
1101
|
+
.describe("Optional working directory. Defaults to your current working directory."),
|
|
1062
1102
|
name: z.string().optional().describe("Optional terminal name."),
|
|
1063
1103
|
},
|
|
1064
1104
|
outputSchema: TerminalSummarySchema.shape,
|
|
@@ -1168,79 +1208,80 @@ export async function createAgentMcpServer(options) {
|
|
|
1168
1208
|
});
|
|
1169
1209
|
registerTool("create_schedule", {
|
|
1170
1210
|
title: "Create schedule",
|
|
1171
|
-
description: "Create a recurring schedule that
|
|
1211
|
+
description: "Create a recurring schedule that starts a new agent on a cron cadence.",
|
|
1172
1212
|
inputSchema: {
|
|
1173
1213
|
prompt: z.string().trim().min(1, "prompt is required"),
|
|
1174
|
-
|
|
1175
|
-
cron: z.string().optional(),
|
|
1214
|
+
cron: z.string().trim().min(1, "cron is required"),
|
|
1176
1215
|
timezone: z
|
|
1177
1216
|
.string()
|
|
1178
1217
|
.trim()
|
|
1179
1218
|
.min(1)
|
|
1180
1219
|
.optional()
|
|
1181
|
-
.describe("IANA time zone for cron cadence
|
|
1220
|
+
.describe("IANA time zone for the cron cadence. For example: America/New_York."),
|
|
1182
1221
|
name: z.string().optional(),
|
|
1183
|
-
|
|
1184
|
-
provider: AgentProviderEnum.optional().describe("Provider, or provider/model (for example: codex or codex/gpt-5.4)."),
|
|
1222
|
+
provider: AgentProviderEnum.describe("Provider, or provider/model (for example: codex or codex/gpt-5.4)."),
|
|
1185
1223
|
cwd: z.string().optional(),
|
|
1186
1224
|
maxRuns: z.number().int().positive().optional(),
|
|
1187
1225
|
expiresIn: z.string().optional(),
|
|
1188
1226
|
},
|
|
1189
1227
|
outputSchema: ScheduleSummarySchema.shape,
|
|
1190
|
-
}, async ({ prompt,
|
|
1228
|
+
}, async ({ prompt, cron, timezone, name, provider, cwd, maxRuns, expiresIn }) => {
|
|
1191
1229
|
if (!scheduleService) {
|
|
1192
1230
|
throw new Error("Schedule service is not configured");
|
|
1193
1231
|
}
|
|
1194
|
-
const
|
|
1195
|
-
const
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1232
|
+
const expiresAt = buildScheduleExpiry(expiresIn);
|
|
1233
|
+
const schedule = await scheduleService.create({
|
|
1234
|
+
prompt: prompt.trim(),
|
|
1235
|
+
cadence: buildCronScheduleCadence({
|
|
1236
|
+
cron,
|
|
1237
|
+
...(timezone !== undefined ? { timezone } : {}),
|
|
1238
|
+
}),
|
|
1239
|
+
target: resolveNewAgentScheduleTarget({ provider, cwd }),
|
|
1240
|
+
...(name?.trim() ? { name: name.trim() } : {}),
|
|
1241
|
+
...(maxRuns === undefined ? {} : { maxRuns }),
|
|
1242
|
+
...(expiresAt === undefined ? {} : { expiresAt }),
|
|
1243
|
+
});
|
|
1244
|
+
return {
|
|
1245
|
+
content: [],
|
|
1246
|
+
structuredContent: ensureValidJson(toScheduleSummary(schedule)),
|
|
1247
|
+
};
|
|
1248
|
+
});
|
|
1249
|
+
registerTool("create_heartbeat", {
|
|
1250
|
+
title: "Create heartbeat",
|
|
1251
|
+
description: "Create a recurring heartbeat that sends you a prompt on a cron cadence.",
|
|
1252
|
+
inputSchema: {
|
|
1253
|
+
prompt: z.string().trim().min(1, "prompt is required"),
|
|
1254
|
+
cron: z.string().trim().min(1, "cron is required"),
|
|
1255
|
+
timezone: z
|
|
1256
|
+
.string()
|
|
1257
|
+
.trim()
|
|
1258
|
+
.min(1)
|
|
1259
|
+
.optional()
|
|
1260
|
+
.describe("IANA time zone for the cron cadence. For example: America/New_York."),
|
|
1261
|
+
name: z.string().optional(),
|
|
1262
|
+
maxRuns: z.number().int().positive().optional(),
|
|
1263
|
+
expiresIn: z.string().optional(),
|
|
1264
|
+
},
|
|
1265
|
+
outputSchema: ScheduleSummarySchema.shape,
|
|
1266
|
+
}, async ({ prompt, cron, timezone, name, maxRuns, expiresIn }) => {
|
|
1267
|
+
if (!scheduleService) {
|
|
1268
|
+
throw new Error("Schedule service is not configured");
|
|
1200
1269
|
}
|
|
1201
|
-
if (
|
|
1202
|
-
throw new Error("
|
|
1270
|
+
if (!callerAgentId) {
|
|
1271
|
+
throw new Error("create_heartbeat requires an agent-scoped session");
|
|
1203
1272
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
const callerAgent = resolveCallerAgent();
|
|
1207
|
-
if (!callerAgentId || !callerAgent) {
|
|
1208
|
-
throw new Error("target=self requires a caller agent");
|
|
1209
|
-
}
|
|
1210
|
-
const trimmedCwd = cwd?.trim();
|
|
1211
|
-
if (trimmedCwd && expandUserPath(trimmedCwd) !== callerAgent.cwd) {
|
|
1212
|
-
throw new Error("cwd can only differ from the caller agent when target=new-agent");
|
|
1213
|
-
}
|
|
1214
|
-
if (provider !== undefined) {
|
|
1215
|
-
const resolved = resolveScheduleProviderAndModel({
|
|
1216
|
-
provider,
|
|
1217
|
-
defaultProvider: callerAgent.provider,
|
|
1218
|
-
});
|
|
1219
|
-
if (resolved.provider !== callerAgent.provider ||
|
|
1220
|
-
(resolved.model !== undefined && resolved.model !== callerAgent.config.model)) {
|
|
1221
|
-
throw new Error("provider can only differ from the caller agent when target=new-agent");
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
return { type: "agent", agentId: callerAgentId };
|
|
1225
|
-
})()
|
|
1226
|
-
: (() => {
|
|
1227
|
-
return resolveNewAgentScheduleTarget({ provider, cwd });
|
|
1228
|
-
})();
|
|
1273
|
+
resolveCallerAgent();
|
|
1274
|
+
const expiresAt = buildScheduleExpiry(expiresIn);
|
|
1229
1275
|
const schedule = await scheduleService.create({
|
|
1230
1276
|
prompt: prompt.trim(),
|
|
1231
|
-
cadence:
|
|
1232
|
-
|
|
1233
|
-
: {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
...(normalizedTimeZone !== undefined ? { timezone: normalizedTimeZone } : {}),
|
|
1237
|
-
},
|
|
1238
|
-
target: scheduleTarget,
|
|
1277
|
+
cadence: buildCronScheduleCadence({
|
|
1278
|
+
cron,
|
|
1279
|
+
...(timezone !== undefined ? { timezone } : {}),
|
|
1280
|
+
}),
|
|
1281
|
+
target: { type: "agent", agentId: callerAgentId },
|
|
1239
1282
|
...(name?.trim() ? { name: name.trim() } : {}),
|
|
1240
1283
|
...(maxRuns === undefined ? {} : { maxRuns }),
|
|
1241
|
-
...(
|
|
1242
|
-
? {}
|
|
1243
|
-
: { expiresAt: new Date(Date.now() + parseDurationString(expiresIn)).toISOString() }),
|
|
1284
|
+
...(expiresAt === undefined ? {} : { expiresAt }),
|
|
1244
1285
|
});
|
|
1245
1286
|
return {
|
|
1246
1287
|
content: [],
|
|
@@ -1518,7 +1559,7 @@ export async function createAgentMcpServer(options) {
|
|
|
1518
1559
|
cwd: z
|
|
1519
1560
|
.string()
|
|
1520
1561
|
.optional()
|
|
1521
|
-
.describe("Optional repository cwd. Defaults to
|
|
1562
|
+
.describe("Optional repository cwd. Defaults to your current working directory."),
|
|
1522
1563
|
},
|
|
1523
1564
|
outputSchema: {
|
|
1524
1565
|
worktrees: z.array(WorktreeSummarySchema),
|
|
@@ -1578,6 +1619,7 @@ export async function createAgentMcpServer(options) {
|
|
|
1578
1619
|
const repoRoot = resolveScopedCwd(cwd, { required: true });
|
|
1579
1620
|
const commandResult = await createPaseoWorktreeCommand({
|
|
1580
1621
|
paseoHome: options.paseoHome,
|
|
1622
|
+
worktreesRoot: options.worktreesRoot,
|
|
1581
1623
|
createPaseoWorktreeWorkflow: options.createPaseoWorktree,
|
|
1582
1624
|
}, createMcpWorktreeCommandInput(repoRoot, target));
|
|
1583
1625
|
if (!commandResult.ok) {
|
|
@@ -1603,7 +1645,7 @@ export async function createAgentMcpServer(options) {
|
|
|
1603
1645
|
cwd: z
|
|
1604
1646
|
.string()
|
|
1605
1647
|
.optional()
|
|
1606
|
-
.describe("Optional repository cwd. Defaults to
|
|
1648
|
+
.describe("Optional repository cwd. Defaults to your current working directory."),
|
|
1607
1649
|
worktreePath: z.string().optional(),
|
|
1608
1650
|
worktreeSlug: z.string().optional(),
|
|
1609
1651
|
},
|
|
@@ -1778,6 +1820,7 @@ function archiveWorktreeDependencies(options, context) {
|
|
|
1778
1820
|
}
|
|
1779
1821
|
return {
|
|
1780
1822
|
paseoHome: options.paseoHome,
|
|
1823
|
+
worktreesRoot: options.worktreesRoot,
|
|
1781
1824
|
github: options.github,
|
|
1782
1825
|
workspaceGitService: options.workspaceGitService,
|
|
1783
1826
|
agentManager: context.agentManager,
|
|
@@ -1148,6 +1148,19 @@ export class PiRpcAgentSession {
|
|
|
1148
1148
|
}
|
|
1149
1149
|
}
|
|
1150
1150
|
handleMessageEnd(event, turnId) {
|
|
1151
|
+
if (event.message.role === "custom") {
|
|
1152
|
+
const text = getUserMessageText(event.message.content);
|
|
1153
|
+
if (text) {
|
|
1154
|
+
this.emit({
|
|
1155
|
+
type: "timeline",
|
|
1156
|
+
provider: PI_PROVIDER,
|
|
1157
|
+
turnId,
|
|
1158
|
+
item: { type: "assistant_message", text },
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
this.completeTurn(turnId, []);
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1151
1164
|
if (event.message.role !== "user") {
|
|
1152
1165
|
return;
|
|
1153
1166
|
}
|
|
@@ -22,6 +22,9 @@ export type PiAssistantContent = PiTextContent | PiThinkingContent | PiToolCallC
|
|
|
22
22
|
export type PiAgentMessage = {
|
|
23
23
|
role: "user";
|
|
24
24
|
content: string | Array<PiTextContent | PiImageContent>;
|
|
25
|
+
} | {
|
|
26
|
+
role: "custom";
|
|
27
|
+
content: string | Array<PiTextContent | PiImageContent>;
|
|
25
28
|
} | {
|
|
26
29
|
role: "assistant";
|
|
27
30
|
content: PiAssistantContent[];
|
|
@@ -10,6 +10,7 @@ import type { TerminalManager } from "../../terminal/terminal-manager.js";
|
|
|
10
10
|
import { isPaseoOwnedWorktreeCwd } from "../../utils/worktree.js";
|
|
11
11
|
export interface AutoArchiveArchiveOptions {
|
|
12
12
|
paseoHome: string;
|
|
13
|
+
worktreesRoot?: string;
|
|
13
14
|
daemonConfigStore: DaemonConfigStore;
|
|
14
15
|
workspaceGitService: WorkspaceGitServiceImpl;
|
|
15
16
|
github: GitHubService;
|
|
@@ -37,13 +37,17 @@ export async function archiveIfSafe(input) {
|
|
|
37
37
|
if (snapshot.git.isDirty === true || (snapshot.git.aheadOfOrigin ?? 0) > 0) {
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
|
-
const ownership = await deps.isPaseoOwnedWorktreeCwd(cwd, {
|
|
40
|
+
const ownership = await deps.isPaseoOwnedWorktreeCwd(cwd, {
|
|
41
|
+
paseoHome: options.paseoHome,
|
|
42
|
+
worktreesRoot: options.worktreesRoot,
|
|
43
|
+
});
|
|
41
44
|
if (!ownership.allowed) {
|
|
42
45
|
return;
|
|
43
46
|
}
|
|
44
47
|
try {
|
|
45
48
|
await deps.archivePaseoWorktree({
|
|
46
49
|
paseoHome: options.paseoHome,
|
|
50
|
+
worktreesRoot: options.worktreesRoot,
|
|
47
51
|
github: options.github,
|
|
48
52
|
workspaceGitService: options.workspaceGitService,
|
|
49
53
|
agentManager: options.agentManager,
|
|
@@ -64,6 +68,7 @@ export async function archiveIfSafe(input) {
|
|
|
64
68
|
targetPath: cwd,
|
|
65
69
|
repoRoot: ownership.repoRoot ?? null,
|
|
66
70
|
worktreesRoot: ownership.worktreeRoot,
|
|
71
|
+
worktreesBaseRoot: options.worktreesRoot,
|
|
67
72
|
requestId: "auto-archive-on-merge",
|
|
68
73
|
});
|
|
69
74
|
log.info({ cwd }, "Auto-archived worktree after PR merge");
|