@getpaseo/server 0.1.84 → 0.1.86

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 (60) hide show
  1. package/dist/scripts/supervisor-entrypoint.js +1 -0
  2. package/dist/server/server/agent/agent-manager.d.ts +4 -0
  3. package/dist/server/server/agent/agent-manager.js +23 -0
  4. package/dist/server/server/agent/agent-metadata-generator.d.ts +9 -0
  5. package/dist/server/server/agent/agent-metadata-generator.js +11 -2
  6. package/dist/server/server/agent/agent-response-loop.d.ts +1 -1
  7. package/dist/server/server/agent/agent-response-loop.js +3 -13
  8. package/dist/server/server/agent/create-agent/create.d.ts +2 -0
  9. package/dist/server/server/agent/create-agent/create.js +7 -0
  10. package/dist/server/server/agent/create-agent-lifecycle-dispatch.js +0 -1
  11. package/dist/server/server/agent/import-sessions.d.ts +3 -0
  12. package/dist/server/server/agent/import-sessions.js +11 -0
  13. package/dist/server/server/agent/mcp-server.d.ts +0 -1
  14. package/dist/server/server/agent/mcp-server.js +0 -4
  15. package/dist/server/server/agent/providers/claude/agent.d.ts +2 -1
  16. package/dist/server/server/agent/providers/claude/agent.js +70 -0
  17. package/dist/server/server/agent/providers/claude/feature-definitions.d.ts +8 -0
  18. package/dist/server/server/agent/providers/claude/feature-definitions.js +36 -0
  19. package/dist/server/server/agent/providers/claude/models.js +19 -5
  20. package/dist/server/server/agent/providers/tool-call-detail-primitives.js +6 -3
  21. package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +5 -0
  22. package/dist/server/server/agent/providers/tool-call-mapper-utils.js +62 -0
  23. package/dist/server/server/agent/structured-generation-providers.d.ts +29 -0
  24. package/dist/server/server/agent/structured-generation-providers.js +192 -0
  25. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +0 -2
  26. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +0 -1
  27. package/dist/server/server/bootstrap.d.ts +7 -0
  28. package/dist/server/server/bootstrap.js +11 -2
  29. package/dist/server/server/config.js +1 -0
  30. package/dist/server/server/daemon-config-store.js +46 -6
  31. package/dist/server/server/daemon-worker.js +1 -0
  32. package/dist/server/server/file-explorer/service.js +4 -4
  33. package/dist/server/server/paseo-worktree-archive-service.d.ts +2 -6
  34. package/dist/server/server/paseo-worktree-archive-service.js +13 -33
  35. package/dist/server/server/persisted-config.d.ts +77 -22
  36. package/dist/server/server/persisted-config.js +13 -0
  37. package/dist/server/server/schedule/service.d.ts +1 -0
  38. package/dist/server/server/schedule/service.js +15 -0
  39. package/dist/server/server/session.d.ts +3 -2
  40. package/dist/server/server/session.js +77 -25
  41. package/dist/server/server/speech/providers/local/runtime.js +52 -133
  42. package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +9 -2
  43. package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +7 -0
  44. package/dist/server/server/speech/providers/local/worker-bytes.d.ts +4 -0
  45. package/dist/server/server/speech/providers/local/worker-bytes.js +9 -0
  46. package/dist/server/server/speech/providers/local/worker-client.d.ts +80 -0
  47. package/dist/server/server/speech/providers/local/worker-client.js +438 -0
  48. package/dist/server/server/speech/providers/local/worker-process.d.ts +2 -0
  49. package/dist/server/server/speech/providers/local/worker-process.js +270 -0
  50. package/dist/server/server/speech/providers/local/worker-protocol.d.ts +95 -0
  51. package/dist/server/server/speech/providers/local/worker-protocol.js +2 -0
  52. package/dist/server/server/websocket-server.js +2 -0
  53. package/dist/server/server/worktree-branch-name-generator.d.ts +9 -0
  54. package/dist/server/server/worktree-branch-name-generator.js +11 -2
  55. package/dist/server/utils/worktree.d.ts +1 -1
  56. package/dist/server/utils/worktree.js +2 -2
  57. package/dist/src/server/persisted-config.js +13 -0
  58. package/package.json +5 -10
  59. package/dist/server/utils/branch-slug.d.ts +0 -14
  60. package/dist/server/utils/branch-slug.js +0 -49
@@ -112,6 +112,68 @@ export function flattenReadContent(value) {
112
112
  }
113
113
  return (nonEmptyString(value.text) ?? nonEmptyString(value.content) ?? nonEmptyString(value.output));
114
114
  }
115
+ // Claude's Read tool returns `cat -n`-style content: each line prefixed with a
116
+ // right-aligned line number and a tab (`␣␣␣1\timport ...`). Other providers
117
+ // return raw source. We strip the gutter here so `read.content` is uniformly
118
+ // raw source across providers, and surface the first line number as `offset`
119
+ // so the client can rebuild the gutter itself. Guarded tightly (first line must
120
+ // match, near-total match ratio, strictly sequential numbering) so real source
121
+ // is never mistaken for a gutter.
122
+ const READ_GUTTER_LINE = /^\s*(\d+)\t(.*)$/;
123
+ export function stripReadLineNumberGutter(content) {
124
+ const text = nonEmptyString(content);
125
+ if (!text) {
126
+ return undefined;
127
+ }
128
+ const lines = text.replace(/\r\n/g, "\n").split("\n");
129
+ const stripped = [];
130
+ let nonEmpty = 0;
131
+ let matched = 0;
132
+ let startLine;
133
+ let prevNumber;
134
+ let sequential = true;
135
+ let firstNonEmptyMatched = false;
136
+ let sawNonEmpty = false;
137
+ for (const line of lines) {
138
+ if (line.length === 0) {
139
+ stripped.push(line);
140
+ continue;
141
+ }
142
+ nonEmpty += 1;
143
+ const match = line.match(READ_GUTTER_LINE);
144
+ if (!match) {
145
+ if (!sawNonEmpty) {
146
+ return undefined;
147
+ }
148
+ stripped.push(line);
149
+ sawNonEmpty = true;
150
+ continue;
151
+ }
152
+ if (!sawNonEmpty) {
153
+ firstNonEmptyMatched = true;
154
+ }
155
+ sawNonEmpty = true;
156
+ matched += 1;
157
+ const lineNumber = Number.parseInt(match[1], 10);
158
+ if (startLine === undefined) {
159
+ startLine = lineNumber;
160
+ }
161
+ if (prevNumber !== undefined && lineNumber !== prevNumber + 1) {
162
+ sequential = false;
163
+ }
164
+ prevNumber = lineNumber;
165
+ stripped.push(match[2]);
166
+ }
167
+ if (!firstNonEmptyMatched || !sequential || nonEmpty === 0) {
168
+ return undefined;
169
+ }
170
+ // Sequential numbering from the first line is already a strong signal; the
171
+ // ratio only rejects source that has a couple of coincidental matches.
172
+ if (matched / nonEmpty < 0.5) {
173
+ return undefined;
174
+ }
175
+ return { content: stripped.join("\n"), startLine };
176
+ }
115
177
  export function truncateDiffText(text, maxChars = 12000) {
116
178
  if (typeof text !== "string") {
117
179
  return undefined;
@@ -0,0 +1,29 @@
1
+ import type { AgentProvider } from "./agent-sdk-types.js";
2
+ import type { StructuredGenerationProvider } from "./agent-response-loop.js";
3
+ import type { ProviderSnapshotManager } from "./provider-snapshot-manager.js";
4
+ export interface StructuredGenerationDaemonConfig {
5
+ metadataGeneration?: {
6
+ providers?: Array<{
7
+ provider: string;
8
+ model?: string;
9
+ thinkingOptionId?: string;
10
+ }>;
11
+ };
12
+ }
13
+ export interface StructuredGenerationProviderIdentifier {
14
+ modelSubstring: string;
15
+ thinkingOptionId?: string;
16
+ }
17
+ export declare const DEFAULT_STRUCTURED_GENERATION_PROVIDERS: readonly StructuredGenerationProviderIdentifier[];
18
+ export interface ResolveStructuredGenerationProvidersOptions {
19
+ cwd: string;
20
+ providerSnapshotManager: Pick<ProviderSnapshotManager, "listProviders">;
21
+ daemonConfig?: StructuredGenerationDaemonConfig | null;
22
+ currentSelection?: {
23
+ provider?: AgentProvider | null;
24
+ model?: string | null;
25
+ thinkingOptionId?: string | null;
26
+ };
27
+ }
28
+ export declare function resolveStructuredGenerationProviders(options: ResolveStructuredGenerationProvidersOptions): Promise<StructuredGenerationProvider[]>;
29
+ //# sourceMappingURL=structured-generation-providers.d.ts.map
@@ -0,0 +1,192 @@
1
+ export const DEFAULT_STRUCTURED_GENERATION_PROVIDERS = [
2
+ { modelSubstring: "haiku" },
3
+ { modelSubstring: "gpt-5.4-mini", thinkingOptionId: "low" },
4
+ { modelSubstring: "minimax-m2.5" },
5
+ { modelSubstring: "nemotron-3-super" },
6
+ ];
7
+ export async function resolveStructuredGenerationProviders(options) {
8
+ const providerEntries = await options.providerSnapshotManager.listProviders({
9
+ cwd: options.cwd,
10
+ wait: true,
11
+ });
12
+ const enabledEntries = providerEntries.filter((entry) => entry.enabled);
13
+ const modelEntries = enabledEntries.filter((entry) => (entry.models?.length ?? 0) > 0);
14
+ const entriesByProvider = new Map(enabledEntries.map((entry) => [entry.provider, entry]));
15
+ const providers = [];
16
+ for (const configured of readConfiguredProviders(options.daemonConfig)) {
17
+ const resolvedConfigured = resolveConfiguredCandidate(configured, modelEntries, entriesByProvider);
18
+ if (!resolvedConfigured) {
19
+ continue;
20
+ }
21
+ providers.push(resolvedConfigured);
22
+ }
23
+ for (const identifier of DEFAULT_STRUCTURED_GENERATION_PROVIDERS) {
24
+ const resolved = resolveByModelSubstring(modelEntries, identifier);
25
+ if (resolved) {
26
+ providers.push(resolved);
27
+ }
28
+ }
29
+ const currentSelection = resolveCurrentSelection(options.currentSelection, modelEntries, entriesByProvider);
30
+ if (currentSelection) {
31
+ providers.push(currentSelection);
32
+ }
33
+ return dedupeProviders(providers);
34
+ }
35
+ function resolveCurrentSelection(selection, readyEntries, entriesByProvider) {
36
+ if (!selection) {
37
+ return null;
38
+ }
39
+ const provider = selection.provider?.trim();
40
+ if (!provider) {
41
+ return null;
42
+ }
43
+ const normalized = resolveConfiguredCandidate({
44
+ provider,
45
+ ...(selection.model ? { model: selection.model } : {}),
46
+ ...(selection.thinkingOptionId ? { thinkingOptionId: selection.thinkingOptionId } : {}),
47
+ }, readyEntries, entriesByProvider);
48
+ if (normalized) {
49
+ return normalized;
50
+ }
51
+ const explicitModel = selection.model?.trim();
52
+ if (explicitModel) {
53
+ return {
54
+ provider,
55
+ model: explicitModel,
56
+ ...(selection.thinkingOptionId ? { thinkingOptionId: selection.thinkingOptionId } : {}),
57
+ };
58
+ }
59
+ const model = selectDefaultModel(entriesByProvider.get(provider)?.models ?? []);
60
+ if (!model) {
61
+ return { provider };
62
+ }
63
+ const thinkingOptionId = resolveThinkingOptionId(model, selection.thinkingOptionId);
64
+ return {
65
+ provider,
66
+ model: model.id,
67
+ ...(thinkingOptionId ? { thinkingOptionId } : {}),
68
+ };
69
+ }
70
+ function resolveConfiguredCandidate(candidate, readyEntries, entriesByProvider) {
71
+ const provider = candidate.provider.trim();
72
+ if (!provider) {
73
+ return null;
74
+ }
75
+ const topLevelEntry = entriesByProvider.get(provider);
76
+ const configuredModel = candidate.model?.trim();
77
+ if (topLevelEntry) {
78
+ if (configuredModel) {
79
+ return {
80
+ provider,
81
+ model: configuredModel,
82
+ ...(candidate.thinkingOptionId ? { thinkingOptionId: candidate.thinkingOptionId } : {}),
83
+ };
84
+ }
85
+ const model = selectDefaultModel(topLevelEntry.models ?? []);
86
+ const thinkingOptionId = resolveThinkingOptionId(model, candidate.thinkingOptionId);
87
+ return {
88
+ provider,
89
+ ...(model ? { model: model.id } : {}),
90
+ ...(thinkingOptionId ? { thinkingOptionId } : {}),
91
+ };
92
+ }
93
+ if (!configuredModel) {
94
+ return {
95
+ provider,
96
+ ...(candidate.thinkingOptionId ? { thinkingOptionId: candidate.thinkingOptionId } : {}),
97
+ };
98
+ }
99
+ const nestedMatch = resolveNestedProviderModel(provider, configuredModel, readyEntries);
100
+ if (!nestedMatch) {
101
+ return {
102
+ provider,
103
+ model: configuredModel,
104
+ ...(candidate.thinkingOptionId ? { thinkingOptionId: candidate.thinkingOptionId } : {}),
105
+ };
106
+ }
107
+ const thinkingOptionId = resolveThinkingOptionId(nestedMatch.model, candidate.thinkingOptionId);
108
+ return {
109
+ provider: nestedMatch.provider,
110
+ model: nestedMatch.model.id,
111
+ ...(thinkingOptionId ? { thinkingOptionId } : {}),
112
+ };
113
+ }
114
+ function resolveNestedProviderModel(providerId, modelId, entries) {
115
+ const normalizedProviderId = providerId.trim().toLowerCase();
116
+ const normalizedModelId = modelId.trim().toLowerCase();
117
+ for (const entry of entries) {
118
+ for (const model of entry.models ?? []) {
119
+ const modelProviderId = readModelMetadataString(model, "providerId")?.toLowerCase();
120
+ const nestedModelId = readModelMetadataString(model, "modelId")?.toLowerCase();
121
+ if (modelProviderId !== normalizedProviderId) {
122
+ continue;
123
+ }
124
+ if (normalizedModelId === model.id.toLowerCase() ||
125
+ normalizedModelId === nestedModelId ||
126
+ model.id.toLowerCase() === `${normalizedProviderId}/${normalizedModelId}`) {
127
+ return { provider: entry.provider, model };
128
+ }
129
+ }
130
+ }
131
+ return null;
132
+ }
133
+ function resolveByModelSubstring(entries, identifier) {
134
+ const needle = identifier.modelSubstring.trim().toLowerCase();
135
+ if (!needle) {
136
+ return null;
137
+ }
138
+ for (const entry of entries) {
139
+ for (const model of entry.models ?? []) {
140
+ const haystacks = [model.id, model.label].map((value) => value.toLowerCase());
141
+ if (!haystacks.some((value) => value.includes(needle))) {
142
+ continue;
143
+ }
144
+ const thinkingOptionId = resolveThinkingOptionId(model, identifier.thinkingOptionId);
145
+ return {
146
+ provider: entry.provider,
147
+ model: model.id,
148
+ ...(thinkingOptionId ? { thinkingOptionId } : {}),
149
+ };
150
+ }
151
+ }
152
+ return null;
153
+ }
154
+ function readConfiguredProviders(daemonConfig) {
155
+ const metadataGeneration = daemonConfig?.metadataGeneration;
156
+ if (!metadataGeneration || typeof metadataGeneration !== "object") {
157
+ return [];
158
+ }
159
+ const providers = "providers" in metadataGeneration ? metadataGeneration.providers : undefined;
160
+ return Array.isArray(providers) ? providers : [];
161
+ }
162
+ function selectDefaultModel(models) {
163
+ return models.find((model) => model.isDefault) ?? models[0] ?? null;
164
+ }
165
+ function resolveThinkingOptionId(model, preferredThinkingOptionId) {
166
+ if (!model) {
167
+ return undefined;
168
+ }
169
+ if (preferredThinkingOptionId &&
170
+ model.thinkingOptions?.some((option) => option.id === preferredThinkingOptionId)) {
171
+ return preferredThinkingOptionId;
172
+ }
173
+ return model.defaultThinkingOptionId;
174
+ }
175
+ function dedupeProviders(providers) {
176
+ const seen = new Set();
177
+ const deduped = [];
178
+ for (const provider of providers) {
179
+ const key = [provider.provider, provider.model ?? "", provider.thinkingOptionId ?? ""].join("\0");
180
+ if (seen.has(key)) {
181
+ continue;
182
+ }
183
+ seen.add(key);
184
+ deduped.push(provider);
185
+ }
186
+ return deduped;
187
+ }
188
+ function readModelMetadataString(model, key) {
189
+ const value = model.metadata?.[key];
190
+ return typeof value === "string" && value.trim().length > 0 ? value : undefined;
191
+ }
192
+ //# sourceMappingURL=structured-generation-providers.js.map
@@ -2,7 +2,6 @@ import type { Logger } from "pino";
2
2
  import type { AgentManager } from "../agent/agent-manager.js";
3
3
  import type { AgentStorage } from "../agent/agent-storage.js";
4
4
  import type { DaemonConfigStore } from "../daemon-config-store.js";
5
- import type { SessionOutboundMessage } from "../messages.js";
6
5
  import { archivePaseoWorktree, killTerminalsUnderPath } from "../paseo-worktree-archive-service.js";
7
6
  import { isSameOrDescendantPath } from "../path-utils.js";
8
7
  import type { WorkspaceGitRuntimeSnapshot, WorkspaceGitServiceImpl } from "../workspace-git-service.js";
@@ -21,7 +20,6 @@ export interface AutoArchiveArchiveOptions {
21
20
  markWorkspaceArchiving: (workspaceIds: Iterable<string>, archivingAt: string) => void;
22
21
  clearWorkspaceArchiving: (workspaceIds: Iterable<string>) => void;
23
22
  emitWorkspaceUpdatesForWorkspaceIds: (workspaceIds: Iterable<string>) => Promise<void>;
24
- emitSessionMessage: (message: SessionOutboundMessage) => void;
25
23
  }
26
24
  export interface ArchiveIfSafeDependencies {
27
25
  archivePaseoWorktree: typeof archivePaseoWorktree;
@@ -49,7 +49,6 @@ export async function archiveIfSafe(input) {
49
49
  agentManager: options.agentManager,
50
50
  agentStorage: options.agentStorage,
51
51
  archiveWorkspaceRecord: options.archiveWorkspaceRecord,
52
- emit: options.emitSessionMessage,
53
52
  emitWorkspaceUpdatesForWorkspaceIds: options.emitWorkspaceUpdatesForWorkspaceIds,
54
53
  markWorkspaceArchiving: options.markWorkspaceArchiving,
55
54
  clearWorkspaceArchiving: options.clearWorkspaceArchiving,
@@ -76,6 +76,13 @@ export interface PaseoDaemonConfig {
76
76
  dictationFinalTimeoutMs?: number;
77
77
  downloadTokenTtlMs?: number;
78
78
  agentProviderSettings?: AgentProviderRuntimeSettingsMap;
79
+ metadataGeneration?: {
80
+ providers?: Array<{
81
+ provider: string;
82
+ model?: string;
83
+ thinkingOptionId?: string;
84
+ }>;
85
+ };
79
86
  providerOverrides?: Record<string, ProviderOverride>;
80
87
  log?: PersistedConfig["log"];
81
88
  onLifecycleIntent?: (intent: DaemonLifecycleIntent) => void;
@@ -169,6 +169,9 @@ export async function createPaseoDaemon(config, rootLogger) {
169
169
  ...(override.additionalModels ? { additionalModels: override.additionalModels } : {}),
170
170
  },
171
171
  ])),
172
+ metadataGeneration: {
173
+ providers: config.metadataGeneration?.providers ?? [],
174
+ },
172
175
  autoArchiveAfterMerge: config.autoArchiveAfterMerge ?? false,
173
176
  appendSystemPrompt: config.appendSystemPrompt ?? "",
174
177
  }, logger);
@@ -417,6 +420,14 @@ export async function createPaseoDaemon(config, rootLogger) {
417
420
  agentStorage,
418
421
  });
419
422
  await scheduleService.start();
423
+ agentManager.setAgentArchivedCallback(async (agentId) => {
424
+ try {
425
+ await scheduleService.deleteForAgent(agentId);
426
+ }
427
+ catch (error) {
428
+ logger.warn({ err: error, agentId }, "Failed to delete schedules for archived agent");
429
+ }
430
+ });
420
431
  logger.info({ elapsed: elapsed() }, "Schedule service initialized");
421
432
  logger.info({ elapsed: elapsed() }, "Loading persisted agent registry");
422
433
  const persistedRecords = await agentStorage.list();
@@ -467,7 +478,6 @@ export async function createPaseoDaemon(config, rootLogger) {
467
478
  markWorkspaceArchiving: markWorkspaceArchivingExternal,
468
479
  clearWorkspaceArchiving: clearWorkspaceArchivingExternal,
469
480
  emitWorkspaceUpdatesForWorkspaceIds: emitWorkspaceUpdatesExternal,
470
- emitSessionMessage: emitExternalSessionMessage,
471
481
  });
472
482
  const mcpEnabled = config.mcpEnabled ?? true;
473
483
  let agentMcpBaseUrl = null;
@@ -488,7 +498,6 @@ export async function createPaseoDaemon(config, rootLogger) {
488
498
  emitWorkspaceUpdatesForWorkspaceIds: emitWorkspaceUpdatesExternal,
489
499
  markWorkspaceArchiving: markWorkspaceArchivingExternal,
490
500
  clearWorkspaceArchiving: clearWorkspaceArchivingExternal,
491
- emitSessionMessage: emitExternalSessionMessage,
492
501
  createPaseoWorktree: async (input, serviceOptions) => {
493
502
  return createPaseoWorktreeWorkflow({
494
503
  paseoHome: config.paseoHome,
@@ -207,6 +207,7 @@ export function loadConfig(paseoHome, options) {
207
207
  voiceLlmProviderExplicit: voiceLlm.providerExplicit,
208
208
  voiceLlmModel: voiceLlm.model,
209
209
  agentProviderSettings: extractAgentProviderSettings(providerOverrides),
210
+ metadataGeneration: persisted.agents?.metadataGeneration,
210
211
  providerOverrides,
211
212
  log: resolveLogConfigFromEnv(env, persisted),
212
213
  };
@@ -114,8 +114,29 @@ export class DaemonConfigStore {
114
114
  }
115
115
  function mergeMutableConfigIntoPersistedConfig(params) {
116
116
  const { persisted, mutable } = params;
117
+ const metadataGenerationProviders = readMetadataGenerationProviders(mutable);
117
118
  const providerOverrides = applyMutableProviderConfigToOverrides(persisted.agents?.providers, mutable.providers);
118
119
  const persistedAgents = persisted.agents;
120
+ const persistedMetadataGeneration = {
121
+ providers: metadataGenerationProviders,
122
+ };
123
+ const shouldPersistMetadataGeneration = metadataGenerationProviders.length > 0 || persisted.agents?.metadataGeneration !== undefined;
124
+ let nextAgents = persisted.agents;
125
+ if (providerOverrides && Object.keys(providerOverrides).length > 0) {
126
+ nextAgents = {
127
+ ...persistedAgents,
128
+ providers: providerOverrides,
129
+ ...(shouldPersistMetadataGeneration
130
+ ? { metadataGeneration: persistedMetadataGeneration }
131
+ : {}),
132
+ };
133
+ }
134
+ else if (shouldPersistMetadataGeneration) {
135
+ nextAgents = {
136
+ ...persistedAgents,
137
+ metadataGeneration: persistedMetadataGeneration,
138
+ };
139
+ }
119
140
  return {
120
141
  ...persisted,
121
142
  daemon: {
@@ -127,12 +148,31 @@ function mergeMutableConfigIntoPersistedConfig(params) {
127
148
  autoArchiveAfterMerge: mutable.autoArchiveAfterMerge,
128
149
  appendSystemPrompt: mutable.appendSystemPrompt,
129
150
  },
130
- agents: providerOverrides && Object.keys(providerOverrides).length > 0
131
- ? {
132
- ...persistedAgents,
133
- providers: providerOverrides,
134
- }
135
- : persisted.agents,
151
+ agents: nextAgents,
136
152
  };
137
153
  }
154
+ function readMetadataGenerationProviders(mutable) {
155
+ const metadataGeneration = mutable.metadataGeneration;
156
+ if (!isRecord(metadataGeneration)) {
157
+ return [];
158
+ }
159
+ const providers = metadataGeneration["providers"];
160
+ if (!Array.isArray(providers)) {
161
+ return [];
162
+ }
163
+ return providers.flatMap((entry) => {
164
+ if (!isRecord(entry) || typeof entry["provider"] !== "string") {
165
+ return [];
166
+ }
167
+ return [
168
+ {
169
+ provider: entry["provider"],
170
+ ...(typeof entry["model"] === "string" ? { model: entry["model"] } : {}),
171
+ ...(typeof entry["thinkingOptionId"] === "string"
172
+ ? { thinkingOptionId: entry["thinkingOptionId"] }
173
+ : {}),
174
+ },
175
+ ];
176
+ });
177
+ }
138
178
  //# sourceMappingURL=daemon-config-store.js.map
@@ -2,6 +2,7 @@ import { createPaseoDaemon } from "./bootstrap.js";
2
2
  import { loadConfig } from "./config.js";
3
3
  import { resolvePaseoHome } from "./paseo-home.js";
4
4
  import { createRootLogger } from "./logger.js";
5
+ process.title = "Paseo Daemon";
5
6
  function bootstrapFromEnvironment() {
6
7
  try {
7
8
  const paseoHome = resolvePaseoHome();
@@ -1,6 +1,6 @@
1
1
  import { constants, promises as fs } from "fs";
2
2
  import path from "path";
3
- import { resolvePathFromBase } from "../path-utils.js";
3
+ import { expandUserPath, resolvePathFromBase } from "../path-utils.js";
4
4
  const TEXT_MIME_TYPES = {
5
5
  ".json": "application/json",
6
6
  };
@@ -168,7 +168,7 @@ export async function getDownloadableFileInfo({ root, relativePath }) {
168
168
  }
169
169
  }
170
170
  async function resolveScopedPath({ root, relativePath = ".", }) {
171
- const normalizedRoot = path.resolve(root);
171
+ const normalizedRoot = expandUserPath(root);
172
172
  const requestedPath = resolvePathFromBase(normalizedRoot, relativePath);
173
173
  const relative = path.relative(normalizedRoot, requestedPath);
174
174
  if (relative !== "" && (relative.startsWith("..") || path.isAbsolute(relative))) {
@@ -215,8 +215,8 @@ function isOutsideWorkspaceError(error) {
215
215
  return error instanceof Error && error.message === ACCESS_OUTSIDE_WORKSPACE_MESSAGE;
216
216
  }
217
217
  function normalizeRelativePath({ root, targetPath }) {
218
- const normalizedRoot = path.resolve(root);
219
- const normalizedTarget = path.resolve(targetPath);
218
+ const normalizedRoot = expandUserPath(root);
219
+ const normalizedTarget = expandUserPath(targetPath);
220
220
  const relative = path.relative(normalizedRoot, normalizedTarget);
221
221
  return relative === "" ? "." : relative.split(path.sep).join("/");
222
222
  }
@@ -1,19 +1,16 @@
1
1
  import type { Logger } from "pino";
2
2
  import type { AgentManager } from "./agent/agent-manager.js";
3
3
  import type { AgentStorage } from "./agent/agent-storage.js";
4
- import type { SessionOutboundMessage } from "./messages.js";
5
4
  import type { WorkspaceGitService } from "./workspace-git-service.js";
6
5
  import type { GitHubService } from "../services/github-service.js";
7
6
  import type { TerminalManager } from "../terminal/terminal-manager.js";
8
- type EmitSessionMessage = (message: SessionOutboundMessage) => void;
9
7
  export interface ArchivePaseoWorktreeDependencies {
10
8
  paseoHome?: string;
11
9
  github: GitHubService;
12
10
  workspaceGitService: Pick<WorkspaceGitService, "getSnapshot">;
13
- agentManager: Pick<AgentManager, "listAgents" | "closeAgent">;
14
- agentStorage: Pick<AgentStorage, "list" | "remove">;
11
+ agentManager: Pick<AgentManager, "listAgents" | "archiveAgent" | "archiveSnapshot">;
12
+ agentStorage: Pick<AgentStorage, "list">;
15
13
  archiveWorkspaceRecord: (workspaceId: string) => Promise<void>;
16
- emit: EmitSessionMessage;
17
14
  emitWorkspaceUpdatesForWorkspaceIds: (workspaceIds: Iterable<string>) => Promise<void>;
18
15
  markWorkspaceArchiving: (workspaceIds: Iterable<string>, archivingAt: string) => void;
19
16
  clearWorkspaceArchiving: (workspaceIds: Iterable<string>) => void;
@@ -39,5 +36,4 @@ export declare function archivePaseoWorktree(dependencies: ArchivePaseoWorktreeD
39
36
  requestId: string;
40
37
  }): Promise<string[]>;
41
38
  export declare function killTerminalsUnderPath(dependencies: KillTerminalsUnderPathDependencies, rootPath: string): Promise<void>;
42
- export {};
43
39
  //# sourceMappingURL=paseo-worktree-archive-service.d.ts.map
@@ -8,14 +8,14 @@ export async function archivePaseoWorktree(dependencies, options) {
8
8
  if (resolvedWorktree) {
9
9
  targetPath = resolvedWorktree.worktreePath;
10
10
  }
11
- const removedAgents = new Set();
11
+ const archivedAgents = new Set();
12
12
  const affectedWorkspaceCwds = new Set([targetPath]);
13
13
  const affectedWorkspaceIds = new Set([normalizePersistedWorkspaceId(targetPath)]);
14
14
  const liveAgents = dependencies.agentManager
15
15
  .listAgents()
16
16
  .filter((agent) => dependencies.isPathWithinRoot(targetPath, agent.cwd));
17
17
  for (const agent of liveAgents) {
18
- removedAgents.add(agent.id);
18
+ archivedAgents.add(agent.id);
19
19
  affectedWorkspaceCwds.add(agent.cwd);
20
20
  affectedWorkspaceIds.add(normalizePersistedWorkspaceId(agent.cwd));
21
21
  }
@@ -26,41 +26,30 @@ export async function archivePaseoWorktree(dependencies, options) {
26
26
  catch (error) {
27
27
  dependencies.sessionLogger?.warn({ err: error, targetPath }, "Failed to list stored agents during worktree archive; continuing");
28
28
  }
29
+ const liveAgentIds = new Set(liveAgents.map((agent) => agent.id));
29
30
  const matchingStoredRecords = storedRecords.filter((record) => dependencies.isPathWithinRoot(targetPath, record.cwd));
30
31
  for (const record of matchingStoredRecords) {
31
- removedAgents.add(record.id);
32
+ archivedAgents.add(record.id);
32
33
  affectedWorkspaceCwds.add(record.cwd);
33
34
  affectedWorkspaceIds.add(normalizePersistedWorkspaceId(record.cwd));
34
35
  }
35
- const agentIdsToRemoveFromStorage = new Set([
36
- ...liveAgents.map((agent) => agent.id),
37
- ...matchingStoredRecords.map((record) => record.id),
38
- ]);
39
36
  const affectedWorkspaceIdList = Array.from(affectedWorkspaceIds);
40
37
  dependencies.markWorkspaceArchiving(affectedWorkspaceIdList, new Date().toISOString());
41
38
  try {
42
39
  await dependencies.emitWorkspaceUpdatesForWorkspaceIds(affectedWorkspaceIdList);
43
- const teardownResults = await Promise.allSettled([
44
- ...liveAgents.map((agent) => dependencies.agentManager.closeAgent(agent.id)),
40
+ const archivedAt = new Date().toISOString();
41
+ const archiveResults = await Promise.allSettled([
42
+ ...liveAgents.map((agent) => dependencies.agentManager.archiveAgent(agent.id)),
43
+ ...matchingStoredRecords
44
+ .filter((record) => !liveAgentIds.has(record.id) && !record.archivedAt)
45
+ .map((record) => dependencies.agentManager.archiveSnapshot(record.id, archivedAt)),
45
46
  dependencies.killTerminalsUnderPath(targetPath),
46
47
  ]);
47
- for (const result of teardownResults) {
48
+ for (const result of archiveResults) {
48
49
  if (result.status === "rejected") {
49
- dependencies.sessionLogger?.warn({ err: result.reason, targetPath }, "Worktree teardown step failed during archive; continuing");
50
+ dependencies.sessionLogger?.warn({ err: result.reason, targetPath }, "Worktree archive teardown step failed; continuing");
50
51
  }
51
52
  }
52
- const agentIdsToRemove = Array.from(agentIdsToRemoveFromStorage);
53
- const storageRemovalResults = await Promise.allSettled(agentIdsToRemove.map((agentId) => dependencies.agentStorage.remove(agentId)));
54
- storageRemovalResults.forEach((result, index) => {
55
- if (result.status === "fulfilled") {
56
- return;
57
- }
58
- dependencies.sessionLogger?.warn({
59
- err: result.reason,
60
- agentId: agentIdsToRemove[index],
61
- targetPath,
62
- }, "Failed to remove archived worktree agent from storage; continuing");
63
- });
64
53
  await deletePaseoWorktree({
65
54
  cwd: options.repoRoot,
66
55
  worktreePath: targetPath,
@@ -89,21 +78,12 @@ export async function archivePaseoWorktree(dependencies, options) {
89
78
  dependencies.sessionLogger?.warn({ err: error, workspaceId }, "Failed to archive workspace record; worktree FS already removed");
90
79
  }
91
80
  }));
92
- for (const agentId of removedAgents) {
93
- dependencies.emit({
94
- type: "agent_deleted",
95
- payload: {
96
- agentId,
97
- requestId: options.requestId,
98
- },
99
- });
100
- }
101
81
  }
102
82
  finally {
103
83
  dependencies.clearWorkspaceArchiving(affectedWorkspaceIdList);
104
84
  await dependencies.emitWorkspaceUpdatesForWorkspaceIds(affectedWorkspaceIdList);
105
85
  }
106
- return Array.from(removedAgents);
86
+ return Array.from(archivedAgents);
107
87
  }
108
88
  export async function killTerminalsUnderPath(dependencies, rootPath) {
109
89
  const terminalManager = dependencies.terminalManager;