@getpaseo/server 0.1.89 → 0.1.91-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/server/server/agent/agent-prompt.js +4 -1
  2. package/dist/server/server/agent/agent-sdk-types.d.ts +1 -0
  3. package/dist/server/server/agent/agent-storage.js +2 -9
  4. package/dist/server/server/agent/create-agent/create.js +10 -2
  5. package/dist/server/server/agent/create-agent-mode.d.ts +3 -8
  6. package/dist/server/server/agent/create-agent-mode.js +16 -2
  7. package/dist/server/server/agent/import-sessions.js +1 -1
  8. package/dist/server/server/agent/provider-snapshot-manager.d.ts +2 -1
  9. package/dist/server/server/agent/provider-snapshot-manager.js +18 -2
  10. package/dist/server/server/agent/providers/acp-agent.d.ts +3 -3
  11. package/dist/server/server/agent/providers/acp-agent.js +18 -13
  12. package/dist/server/server/agent/providers/claude/agent.js +3 -7
  13. package/dist/server/server/agent/providers/claude/project-dir.d.ts +1 -0
  14. package/dist/server/server/agent/providers/claude/project-dir.js +14 -0
  15. package/dist/server/server/agent/providers/codex-app-server-agent.js +16 -22
  16. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +2 -0
  17. package/dist/server/server/agent/providers/mock-load-test-agent.js +69 -2
  18. package/dist/server/server/agent/providers/opencode-agent.js +19 -8
  19. package/dist/server/server/agent/timeline-projection.js +30 -1
  20. package/dist/server/server/atomic-file.d.ts +3 -0
  21. package/dist/server/server/atomic-file.js +19 -0
  22. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +4 -1
  23. package/dist/server/server/bootstrap.js +2 -0
  24. package/dist/server/server/chat/chat-service.js +2 -4
  25. package/dist/server/server/daemon-keypair.js +2 -2
  26. package/dist/server/server/loop-service.d.ts +4 -0
  27. package/dist/server/server/loop-service.js +27 -9
  28. package/dist/server/server/persisted-config.js +3 -3
  29. package/dist/server/server/private-files.d.ts +0 -1
  30. package/dist/server/server/private-files.js +0 -5
  31. package/dist/server/server/schedule/service.d.ts +6 -0
  32. package/dist/server/server/schedule/service.js +41 -18
  33. package/dist/server/server/schedule/store.js +3 -2
  34. package/dist/server/server/server-id.js +3 -3
  35. package/dist/server/server/session.d.ts +5 -15
  36. package/dist/server/server/session.js +184 -107
  37. package/dist/server/server/speech/providers/local/worker-client.js +1 -11
  38. package/dist/server/server/workspace-bootstrap-dedupe.d.ts +34 -0
  39. package/dist/server/server/workspace-bootstrap-dedupe.js +23 -0
  40. package/dist/server/server/workspace-directory.d.ts +8 -0
  41. package/dist/server/server/workspace-directory.js +141 -15
  42. package/dist/server/server/workspace-registry.js +2 -6
  43. package/dist/server/utils/checkout-git.d.ts +0 -1
  44. package/dist/server/utils/checkout-git.js +23 -31
  45. package/dist/src/server/persisted-config.js +3 -3
  46. package/dist/src/server/private-files.js +0 -5
  47. package/package.json +9 -7
  48. package/dist/server/server/editor-targets.d.ts +0 -18
  49. package/dist/server/server/editor-targets.js +0 -109
@@ -1,5 +1,6 @@
1
1
  import { homedir } from "node:os";
2
2
  import { createPathEquivalenceMatcher } from "../../../utils/path.js";
3
+ import pLimit from "p-limit";
3
4
  import { z } from "zod";
4
5
  import { getAgentStreamEventTurnId, } from "../agent-sdk-types.js";
5
6
  import { isDefaultAgentCreateConfigUnattended, resolveDefaultAgentCreateConfig, } from "../create-agent-mode.js";
@@ -57,10 +58,17 @@ function withOpenCodeAutoAcceptFeature(featureValues, enabled) {
57
58
  }
58
59
  function resolveOpenCodeCreateConfig(input) {
59
60
  const legacyFullAccess = input.requestedMode === OPENCODE_LEGACY_FULL_ACCESS_MODE_ID;
60
- const inheritsUnattended = input.requestedMode === undefined && input.parent?.isUnattended === true;
61
- const requestedMode = legacyFullAccess ? OPENCODE_BUILD_MODE_ID : input.requestedMode;
61
+ const parent = input.parent;
62
+ const isUnattendedCreate = input.unattended || parent?.isUnattended === true;
63
+ const inheritsUnattended = input.requestedMode === undefined && isUnattendedCreate;
64
+ const inheritedOpenCodeMode = inheritsUnattended && parent?.provider === input.provider
65
+ ? (parent.modeId ?? undefined)
66
+ : undefined;
67
+ const requestedMode = legacyFullAccess
68
+ ? OPENCODE_BUILD_MODE_ID
69
+ : (input.requestedMode ?? inheritedOpenCodeMode);
62
70
  const featureValues = legacyFullAccess ||
63
- (inheritsUnattended && input.featureValues?.[OPENCODE_AUTO_ACCEPT_FEATURE_ID] === undefined)
71
+ (isUnattendedCreate && input.featureValues?.[OPENCODE_AUTO_ACCEPT_FEATURE_ID] === undefined)
64
72
  ? withOpenCodeAutoAcceptFeature(input.featureValues, true)
65
73
  : input.featureValues;
66
74
  if (inheritsUnattended && requestedMode === undefined) {
@@ -124,6 +132,8 @@ function resolveOpenCodePermissionReply(response) {
124
132
  }
125
133
  const MCP_ALREADY_PRESENT_ERROR_TOKENS = ["already", "exists", "connected"];
126
134
  const OPENCODE_PROVIDER_LIST_TIMEOUT_MS = 30000;
135
+ const OPENCODE_METADATA_CONCURRENCY = 4;
136
+ const openCodeMetadataLimit = pLimit(OPENCODE_METADATA_CONCURRENCY);
127
137
  const OPENCODE_HANDLED_BUILTIN_SLASH_COMMANDS = [
128
138
  { name: "compact", description: "Compact the current session", argumentHint: "" },
129
139
  { name: "summarize", description: "Compact the current session", argumentHint: "" },
@@ -918,7 +928,7 @@ export class OpenCodeAgentClient {
918
928
  try {
919
929
  // Background model discovery can be legitimately slow while OpenCode refreshes
920
930
  // provider state, so allow longer than turn execution paths.
921
- const response = await withTimeout(client.provider.list({ directory: options.cwd }), OPENCODE_PROVIDER_LIST_TIMEOUT_MS, `OpenCode provider.list timed out after ${OPENCODE_PROVIDER_LIST_TIMEOUT_MS / 1000}s - server may not be authenticated or connected to any providers`);
931
+ const response = await openCodeMetadataLimit(() => withTimeout(client.provider.list({ directory: options.cwd }), OPENCODE_PROVIDER_LIST_TIMEOUT_MS, `OpenCode provider.list timed out after ${OPENCODE_PROVIDER_LIST_TIMEOUT_MS / 1000}s - server may not be authenticated or connected to any providers`));
922
932
  if (response.error) {
923
933
  throw new Error(`Failed to fetch OpenCode providers: ${JSON.stringify(response.error)}`);
924
934
  }
@@ -964,7 +974,7 @@ export class OpenCodeAgentClient {
964
974
  const directory = options.cwd;
965
975
  const client = this.runtime.createClient({ baseUrl: url, directory });
966
976
  try {
967
- const response = await withTimeout(client.app.agents({ directory }), 10000, "OpenCode app.agents timed out after 10s");
977
+ const response = await openCodeMetadataLimit(() => withTimeout(client.app.agents({ directory }), 10000, "OpenCode app.agents timed out after 10s"));
968
978
  if (response.error || !response.data) {
969
979
  return DEFAULT_MODES;
970
980
  }
@@ -1102,7 +1112,7 @@ export class OpenCodeAgentClient {
1102
1112
  return normalizeOpenCodeConfig({ ...config, provider: "opencode" });
1103
1113
  }
1104
1114
  async populateModelContextWindowCache(client, cwd) {
1105
- const response = await client.provider.list({ directory: cwd });
1115
+ const response = await openCodeMetadataLimit(() => client.provider.list({ directory: cwd }));
1106
1116
  if (response.error || !response.data) {
1107
1117
  return;
1108
1118
  }
@@ -1794,6 +1804,7 @@ function appendOpenCodeQuestionAsked(event, state, events) {
1794
1804
  header: q.header,
1795
1805
  options,
1796
1806
  ...(q.multiple === true ? { multiSelect: true } : {}),
1807
+ allowOther: true,
1797
1808
  },
1798
1809
  ];
1799
1810
  });
@@ -2467,9 +2478,9 @@ class OpenCodeAgentSession {
2467
2478
  if (this.availableModesCache) {
2468
2479
  return this.availableModesCache;
2469
2480
  }
2470
- const response = await this.client.app.agents({
2481
+ const response = await openCodeMetadataLimit(() => this.client.app.agents({
2471
2482
  directory: this.config.cwd,
2472
- });
2483
+ }));
2473
2484
  const agents = response.error || !response.data ? [] : response.data;
2474
2485
  const discoveredModes = agents.filter(isSelectableOpenCodeAgent).map(mapOpenCodeAgentToMode);
2475
2486
  this.availableModesCache = mergeOpenCodeModes(discoveredModes);
@@ -270,7 +270,36 @@ export function selectProjectedTimelinePage(input) {
270
270
  const limit = input.limit === undefined ? 0 : Math.max(0, Math.floor(input.limit));
271
271
  const bounds = input.bounds ?? getTimelineBounds(input.rows);
272
272
  const projectedAll = projectTimelineRows({ rows: input.rows, mode: "projected" });
273
- if (projectedAll.length === 0 || !bounds) {
273
+ if (!bounds) {
274
+ return {
275
+ entries: [],
276
+ startSeq: null,
277
+ endSeq: null,
278
+ hasOlder: false,
279
+ hasNewer: false,
280
+ };
281
+ }
282
+ if (projectedAll.length === 0) {
283
+ if (input.direction === "after") {
284
+ const cursorSeq = input.cursorSeq ?? bounds.minSeq - 1;
285
+ return {
286
+ entries: [],
287
+ startSeq: null,
288
+ endSeq: null,
289
+ hasOlder: cursorSeq >= bounds.minSeq,
290
+ hasNewer: cursorSeq < bounds.maxSeq,
291
+ };
292
+ }
293
+ if (input.direction === "before") {
294
+ const cursorSeq = input.cursorSeq ?? bounds.maxSeq + 1;
295
+ return {
296
+ entries: [],
297
+ startSeq: null,
298
+ endSeq: null,
299
+ hasOlder: cursorSeq > bounds.minSeq,
300
+ hasNewer: cursorSeq <= bounds.maxSeq,
301
+ };
302
+ }
274
303
  return {
275
304
  entries: [],
276
305
  startSeq: null,
@@ -0,0 +1,3 @@
1
+ export declare function writeFileAtomic(filePath: string, data: string | NodeJS.ArrayBufferView): Promise<void>;
2
+ export declare function writeJsonFileAtomic(filePath: string, value: unknown): Promise<void>;
3
+ //# sourceMappingURL=atomic-file.d.ts.map
@@ -0,0 +1,19 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { promises as fs } from "node:fs";
3
+ import path from "node:path";
4
+ export async function writeFileAtomic(filePath, data) {
5
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
6
+ const tempPath = path.join(path.dirname(filePath), `.${path.basename(filePath)}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`);
7
+ try {
8
+ await fs.writeFile(tempPath, data, "utf8");
9
+ await fs.rename(tempPath, filePath);
10
+ }
11
+ catch (error) {
12
+ await fs.rm(tempPath, { force: true });
13
+ throw error;
14
+ }
15
+ }
16
+ export async function writeJsonFileAtomic(filePath, value) {
17
+ await writeFileAtomic(filePath, JSON.stringify(value, null, 2));
18
+ }
19
+ //# sourceMappingURL=atomic-file.js.map
@@ -34,7 +34,10 @@ export async function archiveIfSafe(input) {
34
34
  if (!snapshot) {
35
35
  return;
36
36
  }
37
- if (snapshot.git.isDirty === true || (snapshot.git.aheadOfOrigin ?? 0) > 0) {
37
+ if (snapshot.git.isDirty === true || snapshot.git.aheadOfOrigin === null) {
38
+ return;
39
+ }
40
+ if (snapshot.git.aheadOfOrigin > 0) {
38
41
  return;
39
42
  }
40
43
  const ownership = await deps.isPaseoOwnedWorktreeCwd(cwd, {
@@ -418,6 +418,7 @@ export async function createPaseoDaemon(config, rootLogger) {
418
418
  paseoHome: config.paseoHome,
419
419
  logger,
420
420
  agentManager,
421
+ providerSnapshotManager,
421
422
  });
422
423
  await loopService.initialize();
423
424
  logger.info({ elapsed: elapsed() }, "Loop service initialized");
@@ -426,6 +427,7 @@ export async function createPaseoDaemon(config, rootLogger) {
426
427
  logger,
427
428
  agentManager,
428
429
  agentStorage,
430
+ providerSnapshotManager,
429
431
  });
430
432
  await scheduleService.start();
431
433
  agentManager.setAgentArchivedCallback(async (agentId) => {
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { promises as fs } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { z } from "zod";
5
+ import { writeJsonFileAtomic } from "../atomic-file.js";
5
6
  import { ChatMessageSchema, ChatRoomDetailSchema, ChatRoomSchema, } from "@getpaseo/protocol/chat/types";
6
7
  const ChatStorePayloadSchema = z.object({
7
8
  rooms: z.array(ChatRoomSchema),
@@ -246,10 +247,7 @@ export class FileBackedChatService {
246
247
  .flat()
247
248
  .sort((left, right) => left.createdAt.localeCompare(right.createdAt)),
248
249
  };
249
- await fs.mkdir(path.dirname(this.filePath), { recursive: true });
250
- const tempPath = `${this.filePath}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;
251
- await fs.writeFile(tempPath, JSON.stringify(payload, null, 2), "utf8");
252
- await fs.rename(tempPath, this.filePath);
250
+ await writeJsonFileAtomic(this.filePath, payload);
253
251
  }
254
252
  findRoomByName(name) {
255
253
  const normalizedName = normalizeRoomName(name);
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { z } from "zod";
4
4
  import { generateKeyPair, exportPublicKey, exportSecretKey, importPublicKey, importSecretKey, } from "@getpaseo/relay/e2ee";
5
- import { ensurePrivateFile, writePrivateFileSync } from "./private-files.js";
5
+ import { ensurePrivateFile, writePrivateFileAtomicSync } from "./private-files.js";
6
6
  const KeyPairSchema = z.object({
7
7
  v: z.literal(2),
8
8
  publicKeyB64: z.string().min(1),
@@ -35,7 +35,7 @@ export async function loadOrCreateDaemonKeyPair(paseoHome, logger) {
35
35
  publicKeyB64,
36
36
  secretKeyB64,
37
37
  };
38
- writePrivateFileSync(filePath, JSON.stringify(payload, null, 2) + "\n");
38
+ writePrivateFileAtomicSync(filePath, JSON.stringify(payload, null, 2) + "\n");
39
39
  log?.info({ filePath }, "Saved daemon keypair");
40
40
  return { keyPair, publicKeyB64 };
41
41
  }
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import type { Logger } from "pino";
3
3
  import type { AgentManager } from "./agent/agent-manager.js";
4
4
  import type { AgentProvider } from "./agent/agent-sdk-types.js";
5
+ import type { ProviderSnapshotManager } from "./agent/provider-snapshot-manager.js";
5
6
  declare const LoopLogEntrySchema: z.ZodObject<{
6
7
  seq: z.ZodNumber;
7
8
  timestamp: z.ZodString;
@@ -493,6 +494,7 @@ export interface LoopLogsResult {
493
494
  entries: LoopLogEntry[];
494
495
  nextCursor: number;
495
496
  }
497
+ type CreateConfigResolver = Pick<ProviderSnapshotManager, "resolveCreateConfig">;
496
498
  export declare class LoopService {
497
499
  private readonly options;
498
500
  private readonly storePath;
@@ -505,6 +507,7 @@ export declare class LoopService {
505
507
  paseoHome: string;
506
508
  agentManager: AgentManager;
507
509
  logger: Logger;
510
+ providerSnapshotManager: CreateConfigResolver;
508
511
  });
509
512
  initialize(): Promise<void>;
510
513
  runLoop(input: LoopRunOptions): Promise<LoopRecord>;
@@ -518,6 +521,7 @@ export declare class LoopService {
518
521
  private runVerification;
519
522
  private buildWorkerConfig;
520
523
  private buildVerifierConfig;
524
+ private resolveProviderCreateConfig;
521
525
  private resolveFinalText;
522
526
  private toPrompt;
523
527
  private finishLoop;
@@ -2,10 +2,10 @@ import { randomUUID } from "node:crypto";
2
2
  import { promises as fs } from "node:fs";
3
3
  import path from "node:path";
4
4
  import { z } from "zod";
5
+ import { writeJsonFileAtomic } from "./atomic-file.js";
5
6
  import { curateAgentActivity } from "./agent/activity-curator.js";
6
7
  import { getStructuredAgentResponse } from "./agent/agent-response-loop.js";
7
8
  import { execCommand, platformShell } from "../utils/spawn.js";
8
- import { getUnattendedModeId } from "@getpaseo/protocol/provider-manifest";
9
9
  const LOOP_ID_LENGTH = 8;
10
10
  const DEFAULT_LOOP_PROVIDER = "claude";
11
11
  const MAX_VERIFY_OUTPUT_BYTES = 64 * 1024;
@@ -494,7 +494,7 @@ export class LoopService {
494
494
  await this.persist();
495
495
  }
496
496
  async runWorkerIteration(loop, iteration, signal) {
497
- const agent = await this.options.agentManager.createAgent(this.buildWorkerConfig(loop, iteration));
497
+ const agent = await this.options.agentManager.createAgent(await this.buildWorkerConfig(loop, iteration));
498
498
  iteration.workerAgentId = agent.id;
499
499
  loop.activeWorkerAgentId = agent.id;
500
500
  loop.updatedAt = nowIso();
@@ -591,7 +591,7 @@ export class LoopService {
591
591
  return true;
592
592
  }
593
593
  const startedAt = nowIso();
594
- const verifierAgent = await this.options.agentManager.createAgent(this.buildVerifierConfig(loop, iteration));
594
+ const verifierAgent = await this.options.agentManager.createAgent(await this.buildVerifierConfig(loop, iteration));
595
595
  iteration.verifierAgentId = verifierAgent.id;
596
596
  loop.activeVerifierAgentId = verifierAgent.id;
597
597
  loop.updatedAt = nowIso();
@@ -659,28 +659,47 @@ export class LoopService {
659
659
  }
660
660
  }
661
661
  }
662
- buildWorkerConfig(loop, iteration) {
662
+ async buildWorkerConfig(loop, iteration) {
663
663
  const provider = loop.workerProvider ?? loop.provider;
664
+ const resolvedUnattendedConfig = loop.modeId
665
+ ? { modeId: loop.modeId, featureValues: undefined }
666
+ : await this.resolveProviderCreateConfig({ provider, cwd: loop.cwd });
664
667
  return {
665
668
  provider,
666
669
  cwd: loop.cwd,
667
670
  model: loop.workerModel ?? loop.model ?? undefined,
668
- modeId: loop.modeId ?? getUnattendedModeId(provider),
671
+ modeId: resolvedUnattendedConfig.modeId,
672
+ featureValues: resolvedUnattendedConfig.featureValues,
669
673
  title: buildWorkerTitle(loop, iteration.index),
670
674
  internal: true,
671
675
  };
672
676
  }
673
- buildVerifierConfig(loop, iteration) {
677
+ async buildVerifierConfig(loop, iteration) {
674
678
  const provider = loop.verifierProvider ?? loop.provider;
679
+ const explicitModeId = loop.verifierModeId ?? loop.modeId;
680
+ const resolvedUnattendedConfig = explicitModeId
681
+ ? { modeId: explicitModeId, featureValues: undefined }
682
+ : await this.resolveProviderCreateConfig({ provider, cwd: loop.cwd });
675
683
  return {
676
684
  provider,
677
685
  cwd: loop.cwd,
678
686
  model: loop.verifierModel ?? loop.model ?? undefined,
679
- modeId: loop.verifierModeId ?? loop.modeId ?? getUnattendedModeId(provider),
687
+ modeId: resolvedUnattendedConfig.modeId,
688
+ featureValues: resolvedUnattendedConfig.featureValues,
680
689
  title: buildVerifierTitle(loop, iteration.index),
681
690
  internal: true,
682
691
  };
683
692
  }
693
+ resolveProviderCreateConfig(input) {
694
+ return this.options.providerSnapshotManager.resolveCreateConfig({
695
+ provider: input.provider,
696
+ cwd: input.cwd,
697
+ requestedMode: undefined,
698
+ featureValues: undefined,
699
+ parent: null,
700
+ unattended: true,
701
+ });
702
+ }
684
703
  resolveFinalText(timeline, finalText) {
685
704
  if (finalText.trim()) {
686
705
  return finalText;
@@ -739,9 +758,8 @@ export class LoopService {
739
758
  }
740
759
  async persist() {
741
760
  const nextPersist = this.persistQueue.then(async () => {
742
- await fs.mkdir(path.dirname(this.storePath), { recursive: true });
743
761
  const records = Array.from(this.loops.values()).sort((left, right) => left.createdAt.localeCompare(right.createdAt));
744
- await fs.writeFile(this.storePath, JSON.stringify(records, null, 2), "utf8");
762
+ await writeJsonFileAtomic(this.storePath, records);
745
763
  return;
746
764
  });
747
765
  this.persistQueue = nextPersist.catch(() => { });
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { z } from "zod";
4
4
  import { AgentProviderRuntimeSettingsMapSchema, migrateProviderSettings, ProviderOverridesSchema, } from "./agent/provider-launch-config.js";
5
- import { ensurePrivateFile, writePrivateFileSync } from "./private-files.js";
5
+ import { ensurePrivateFile, writePrivateFileAtomicSync } from "./private-files.js";
6
6
  export const LogLevelSchema = z.enum(["trace", "debug", "info", "warn", "error", "fatal"]);
7
7
  export const LogFormatSchema = z.enum(["pretty", "json"]);
8
8
  const LogConfigSchema = z
@@ -296,7 +296,7 @@ export function loadPersistedConfig(paseoHome, logger) {
296
296
  const configPath = getConfigPath(paseoHome);
297
297
  if (!existsSync(configPath)) {
298
298
  try {
299
- writePrivateFileSync(configPath, JSON.stringify(DEFAULT_PERSISTED_CONFIG, null, 2) + "\n");
299
+ writePrivateFileAtomicSync(configPath, JSON.stringify(DEFAULT_PERSISTED_CONFIG, null, 2) + "\n");
300
300
  log?.info(`Initialized config file at ${configPath}`);
301
301
  }
302
302
  catch (err) {
@@ -347,7 +347,7 @@ export function savePersistedConfig(paseoHome, config, logger) {
347
347
  throw new Error(`[Config] Invalid config to save:\n${issues}`);
348
348
  }
349
349
  try {
350
- writePrivateFileSync(configPath, JSON.stringify(result.data, null, 2) + "\n");
350
+ writePrivateFileAtomicSync(configPath, JSON.stringify(result.data, null, 2) + "\n");
351
351
  log?.info(`Saved to ${configPath}`);
352
352
  }
353
353
  catch (err) {
@@ -2,6 +2,5 @@ export declare const PRIVATE_DIRECTORY_MODE = 448;
2
2
  export declare const PRIVATE_FILE_MODE = 384;
3
3
  export declare function ensurePrivateDirectory(directoryPath: string): void;
4
4
  export declare function ensurePrivateFile(filePath: string): void;
5
- export declare function writePrivateFileSync(filePath: string, data: string | NodeJS.ArrayBufferView): void;
6
5
  export declare function writePrivateFileAtomicSync(filePath: string, data: string | NodeJS.ArrayBufferView): void;
7
6
  //# sourceMappingURL=private-files.d.ts.map
@@ -21,11 +21,6 @@ export function ensurePrivateDirectory(directoryPath) {
21
21
  export function ensurePrivateFile(filePath) {
22
22
  chmodBestEffort(filePath, PRIVATE_FILE_MODE);
23
23
  }
24
- export function writePrivateFileSync(filePath, data) {
25
- ensurePrivateDirectory(path.dirname(filePath));
26
- writeFileSync(filePath, data, { mode: PRIVATE_FILE_MODE });
27
- ensurePrivateFile(filePath);
28
- }
29
24
  export function writePrivateFileAtomicSync(filePath, data) {
30
25
  ensurePrivateDirectory(path.dirname(filePath));
31
26
  const tmpPath = path.join(path.dirname(filePath), `.${path.basename(filePath)}.${process.pid}.${randomUUID()}.tmp`);
@@ -1,12 +1,15 @@
1
1
  import type { Logger } from "pino";
2
2
  import { AgentManager } from "../agent/agent-manager.js";
3
3
  import type { AgentStorage } from "../agent/agent-storage.js";
4
+ import type { ProviderSnapshotManager } from "../agent/provider-snapshot-manager.js";
4
5
  import type { CreateScheduleInput, ScheduleExecutionResult, ScheduleRun, StoredSchedule, UpdateScheduleInput } from "@getpaseo/protocol/schedule/types";
6
+ type CreateConfigResolver = Pick<ProviderSnapshotManager, "resolveCreateConfig">;
5
7
  export interface ScheduleServiceOptions {
6
8
  paseoHome: string;
7
9
  logger: Logger;
8
10
  agentManager: AgentManager;
9
11
  agentStorage: AgentStorage;
12
+ providerSnapshotManager: CreateConfigResolver;
10
13
  now?: () => Date;
11
14
  runner?: (schedule: StoredSchedule, runId: string) => Promise<ScheduleExecutionResult>;
12
15
  }
@@ -15,6 +18,7 @@ export declare class ScheduleService {
15
18
  private readonly logger;
16
19
  private readonly agentManager;
17
20
  private readonly agentStorage;
21
+ private readonly createConfigResolver;
18
22
  private readonly now;
19
23
  private readonly runner;
20
24
  private readonly runningScheduleIds;
@@ -37,5 +41,7 @@ export declare class ScheduleService {
37
41
  private runSchedule;
38
42
  private finishRun;
39
43
  private executeSchedule;
44
+ private resolveProviderCreateConfig;
40
45
  }
46
+ export {};
41
47
  //# sourceMappingURL=service.d.ts.map
@@ -3,7 +3,7 @@ import { join } from "node:path";
3
3
  import { curateAgentActivity } from "../agent/activity-curator.js";
4
4
  import { ensureAgentLoaded } from "../agent/agent-loading.js";
5
5
  import { formatSystemNotificationPrompt } from "../agent/agent-prompt.js";
6
- import { getUnattendedModeId } from "@getpaseo/protocol/provider-manifest";
6
+ import { resolveCreateAgentTitles } from "../agent/create-agent-title.js";
7
7
  import { ScheduleStore } from "./store.js";
8
8
  import { computeNextRunAt, validateScheduleCadence } from "./cron.js";
9
9
  const SCHEDULE_TICK_INTERVAL_MS = 1000;
@@ -113,6 +113,7 @@ export class ScheduleService {
113
113
  this.logger = options.logger.child({ module: "schedule-service" });
114
114
  this.agentManager = options.agentManager;
115
115
  this.agentStorage = options.agentStorage;
116
+ this.createConfigResolver = options.providerSnapshotManager;
116
117
  this.now = options.now ?? (() => new Date());
117
118
  this.runner = options.runner ?? ((schedule, runId) => this.executeSchedule(schedule, runId));
118
119
  }
@@ -418,8 +419,8 @@ export class ScheduleService {
418
419
  await this.store.put(updated);
419
420
  }
420
421
  async executeSchedule(schedule, runId) {
421
- const wrappedPrompt = formatSystemNotificationPrompt(buildScheduleFireBody(schedule, runId));
422
422
  if (schedule.target.type === "agent") {
423
+ const wrappedPrompt = formatSystemNotificationPrompt(buildScheduleFireBody(schedule, runId));
423
424
  const record = await this.agentStorage.get(schedule.target.agentId);
424
425
  if (record?.archivedAt) {
425
426
  throw new Error(`Agent ${schedule.target.agentId} is archived`);
@@ -443,30 +444,49 @@ export class ScheduleService {
443
444
  }),
444
445
  };
445
446
  }
447
+ const targetConfig = schedule.target.config;
448
+ const resolvedUnattendedConfig = targetConfig.modeId
449
+ ? { modeId: targetConfig.modeId, featureValues: targetConfig.featureValues }
450
+ : await this.resolveProviderCreateConfig({
451
+ provider: targetConfig.provider,
452
+ cwd: targetConfig.cwd,
453
+ requestedMode: undefined,
454
+ featureValues: targetConfig.featureValues,
455
+ parent: null,
456
+ unattended: true,
457
+ });
446
458
  const config = {
447
- provider: schedule.target.config.provider,
448
- cwd: schedule.target.config.cwd,
449
- modeId: schedule.target.config.modeId ?? getUnattendedModeId(schedule.target.config.provider),
450
- model: schedule.target.config.model,
451
- thinkingOptionId: schedule.target.config.thinkingOptionId,
452
- title: schedule.target.config.title,
453
- approvalPolicy: schedule.target.config.approvalPolicy,
454
- sandboxMode: schedule.target.config.sandboxMode,
455
- networkAccess: schedule.target.config.networkAccess,
456
- webSearch: schedule.target.config.webSearch,
457
- featureValues: schedule.target.config.featureValues,
458
- extra: schedule.target.config.extra,
459
- systemPrompt: schedule.target.config.systemPrompt,
460
- mcpServers: schedule.target.config.mcpServers,
459
+ provider: targetConfig.provider,
460
+ cwd: targetConfig.cwd,
461
+ modeId: resolvedUnattendedConfig.modeId,
462
+ model: targetConfig.model,
463
+ thinkingOptionId: targetConfig.thinkingOptionId,
464
+ title: targetConfig.title,
465
+ approvalPolicy: targetConfig.approvalPolicy,
466
+ sandboxMode: targetConfig.sandboxMode,
467
+ networkAccess: targetConfig.networkAccess,
468
+ webSearch: targetConfig.webSearch,
469
+ featureValues: resolvedUnattendedConfig.featureValues,
470
+ extra: targetConfig.extra,
471
+ systemPrompt: targetConfig.systemPrompt,
472
+ mcpServers: targetConfig.mcpServers,
461
473
  };
474
+ const { provisionalTitle } = resolveCreateAgentTitles({
475
+ configTitle: config.title,
476
+ initialPrompt: schedule.prompt,
477
+ });
462
478
  const labels = {
463
479
  "paseo.schedule-id": schedule.id,
464
480
  "paseo.schedule-run": runId,
465
481
  };
466
- const agent = await this.agentManager.createAgent(config, undefined, { labels });
482
+ const agent = await this.agentManager.createAgent(config, undefined, {
483
+ labels,
484
+ initialPrompt: schedule.prompt,
485
+ initialTitle: provisionalTitle,
486
+ });
467
487
  let result;
468
488
  try {
469
- result = await this.agentManager.runAgent(agent.id, wrappedPrompt);
489
+ result = await this.agentManager.runAgent(agent.id, schedule.prompt);
470
490
  }
471
491
  catch (error) {
472
492
  try {
@@ -488,5 +508,8 @@ export class ScheduleService {
488
508
  }),
489
509
  };
490
510
  }
511
+ async resolveProviderCreateConfig(input) {
512
+ return this.createConfigResolver.resolveCreateConfig(input);
513
+ }
491
514
  }
492
515
  //# sourceMappingURL=service.js.map
@@ -1,7 +1,8 @@
1
1
  import { randomBytes } from "node:crypto";
2
- import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
2
+ import { mkdir, readFile, readdir, rm } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { StoredScheduleSchema } from "@getpaseo/protocol/schedule/types";
5
+ import { writeJsonFileAtomic } from "../atomic-file.js";
5
6
  function generateScheduleId() {
6
7
  return randomBytes(4).toString("hex");
7
8
  }
@@ -46,7 +47,7 @@ export class ScheduleStore {
46
47
  }
47
48
  async put(schedule) {
48
49
  await this.ensureDir();
49
- await writeFile(this.filePath(schedule.id), JSON.stringify(schedule, null, 2), "utf-8");
50
+ await writeJsonFileAtomic(this.filePath(schedule.id), schedule);
50
51
  }
51
52
  async delete(id) {
52
53
  await this.ensureDir();
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { randomBytes } from "node:crypto";
4
- import { ensurePrivateFile, writePrivateFileSync } from "./private-files.js";
4
+ import { ensurePrivateFile, writePrivateFileAtomicSync } from "./private-files.js";
5
5
  const SERVER_ID_FILENAME = "server-id";
6
6
  function getLogger(logger) {
7
7
  return logger?.child({ module: "server-id" });
@@ -31,7 +31,7 @@ export function getOrCreateServerId(paseoHome, options) {
31
31
  // Persist the override for consistent identity across restarts.
32
32
  if (!existsSync(serverIdPath)) {
33
33
  try {
34
- writePrivateFileSync(serverIdPath, `${envOverride}\n`);
34
+ writePrivateFileAtomicSync(serverIdPath, `${envOverride}\n`);
35
35
  log?.info({ serverId: envOverride }, "Persisted PASEO_SERVER_ID override");
36
36
  }
37
37
  catch (error) {
@@ -58,7 +58,7 @@ export function getOrCreateServerId(paseoHome, options) {
58
58
  }
59
59
  const created = generateServerId();
60
60
  try {
61
- writePrivateFileSync(serverIdPath, `${created}\n`);
61
+ writePrivateFileAtomicSync(serverIdPath, `${created}\n`);
62
62
  }
63
63
  catch (error) {
64
64
  log?.warn({ error }, "Failed to persist serverId (continuing with in-memory id)");
@@ -1,5 +1,5 @@
1
1
  import { type ClientCapability } from "@getpaseo/protocol/client-capabilities";
2
- import { type AgentSnapshotPayload, type SessionInboundMessage, type SessionOutboundMessage, type EditorTargetDescriptorPayload, type EditorTargetId, type WorkspaceSetupSnapshot } from "./messages.js";
2
+ import { type AgentSnapshotPayload, type SessionInboundMessage, type SessionOutboundMessage, type WorkspaceSetupSnapshot } from "./messages.js";
3
3
  import type { TerminalManager } from "../terminal/terminal-manager.js";
4
4
  import { type TerminalStreamFrame } from "@getpaseo/protocol/binary-frames/index";
5
5
  import type { SpeechToTextProvider, TextToSpeechProvider } from "./speech/speech-provider.js";
@@ -176,8 +176,6 @@ export declare class Session {
176
176
  private readonly terminalController;
177
177
  private inflightRequests;
178
178
  private peakInflightRequests;
179
- private readonly availableEditorTargetsCache;
180
- private readonly getMemoizedAvailableEditorTargets;
181
179
  private readonly checkoutDiffSubscriptions;
182
180
  private readonly workspaceGitWatchTargets;
183
181
  private readonly workspaceSetupSnapshots;
@@ -254,7 +252,6 @@ export declare class Session {
254
252
  private buildAgentPayload;
255
253
  private buildStoredAgentPayload;
256
254
  private isProviderVisibleToClient;
257
- private filterEditorsForClient;
258
255
  private agentThinkingOptionMatchesFilter;
259
256
  private matchesAgentStructuralFilter;
260
257
  private matchesAgentFilter;
@@ -471,27 +468,20 @@ export declare class Session {
471
468
  private handleFetchAgentHistory;
472
469
  private handleFetchRecentProviderSessions;
473
470
  private handleFetchWorkspacesRequest;
471
+ private buildBootstrapSnapshot;
474
472
  private registerWorkspaceForImportedAgent;
475
473
  private handleOpenProjectRequest;
476
474
  private buildWorkspaceScriptPayloadSnapshot;
477
475
  private resolveWorkspaceScriptGitMetadata;
478
476
  private emitWorkspaceScriptStatusUpdate;
479
- resolveAvailableEditorTargets(): Promise<EditorTargetDescriptorPayload[]>;
480
- getAvailableEditorTargets(): Promise<{
481
- id: string;
482
- label: string;
483
- }[]>;
484
- openEditorTarget(options: {
485
- editorId: EditorTargetId;
486
- path: string;
487
- }): Promise<void>;
488
477
  private handleStartWorkspaceScriptRequest;
489
- private handleListAvailableEditorsRequest;
490
- private handleOpenInEditorRequest;
478
+ private handleLegacyListAvailableEditorsRequest;
479
+ private handleLegacyOpenInEditorRequest;
491
480
  private handleCreatePaseoWorktreeRequest;
492
481
  private createPaseoWorktreeWorkflow;
493
482
  private handleWorkspaceSetupStatusRequest;
494
483
  private handleArchiveWorkspaceRequest;
484
+ private handleWorkspaceClearAttentionRequest;
495
485
  private handleFetchAgent;
496
486
  private shouldUseFullTimelineForProjectedPage;
497
487
  private selectCanonicalTimelineProjection;