mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0a0cb4a99 | ||
|
|
342e92d0c7 | ||
|
|
0170eba233 | ||
|
|
b6103a59da |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,5 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.85 - 2026-05-29
|
||||
|
||||
### Added
|
||||
|
||||
- **Opus 4.8 in the Claude model picker**, with a 1M-context variant
|
||||
|
||||
### Improved
|
||||
|
||||
- Archiving a worktree now keeps its agents under the archived list instead of removing them
|
||||
- Archiving an agent cleans up any schedules targeting it
|
||||
|
||||
## 0.1.84 - 2026-05-28
|
||||
|
||||
### Added
|
||||
|
||||
42
package-lock.json
generated
42
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "paseo",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "paseo",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"hasInstallScript": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
@@ -36303,7 +36303,7 @@
|
||||
},
|
||||
"packages/app": {
|
||||
"name": "@getpaseo/app",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
@@ -36528,12 +36528,12 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@getpaseo/cli",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.0.0",
|
||||
"@getpaseo/client": "0.1.84",
|
||||
"@getpaseo/protocol": "0.1.84",
|
||||
"@getpaseo/server": "0.1.84",
|
||||
"@getpaseo/client": "0.1.85",
|
||||
"@getpaseo/protocol": "0.1.85",
|
||||
"@getpaseo/server": "0.1.85",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.0.0",
|
||||
"mime-types": "^2.1.35",
|
||||
@@ -36779,10 +36779,10 @@
|
||||
},
|
||||
"packages/client": {
|
||||
"name": "@getpaseo/client",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"dependencies": {
|
||||
"@getpaseo/protocol": "0.1.84",
|
||||
"@getpaseo/relay": "0.1.84",
|
||||
"@getpaseo/protocol": "0.1.85",
|
||||
"@getpaseo/relay": "0.1.85",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -36802,7 +36802,7 @@
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@getpaseo/desktop",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@getpaseo/cli": "*",
|
||||
@@ -37054,7 +37054,7 @@
|
||||
},
|
||||
"packages/expo-two-way-audio": {
|
||||
"name": "@getpaseo/expo-two-way-audio",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.25",
|
||||
@@ -37090,7 +37090,7 @@
|
||||
},
|
||||
"packages/highlight": {
|
||||
"name": "@getpaseo/highlight",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.5.0",
|
||||
"@lezer/cpp": "^1.1.5",
|
||||
@@ -37319,7 +37319,7 @@
|
||||
},
|
||||
"packages/protocol": {
|
||||
"name": "@getpaseo/protocol",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"dependencies": {
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
@@ -37340,7 +37340,7 @@
|
||||
},
|
||||
"packages/relay": {
|
||||
"name": "@getpaseo/relay",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.5.1",
|
||||
"tweetnacl": "^1.0.3",
|
||||
@@ -37558,14 +37558,14 @@
|
||||
},
|
||||
"packages/server": {
|
||||
"name": "@getpaseo/server",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "^0.17.1",
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.2.133",
|
||||
"@getpaseo/client": "0.1.84",
|
||||
"@getpaseo/highlight": "0.1.84",
|
||||
"@getpaseo/protocol": "0.1.84",
|
||||
"@getpaseo/relay": "0.1.84",
|
||||
"@getpaseo/client": "0.1.85",
|
||||
"@getpaseo/highlight": "0.1.85",
|
||||
"@getpaseo/protocol": "0.1.85",
|
||||
"@getpaseo/relay": "0.1.85",
|
||||
"@isaacs/ttlcache": "^2.1.4",
|
||||
"@modelcontextprotocol/sdk": "^1.20.1",
|
||||
"@opencode-ai/sdk": "1.14.46",
|
||||
@@ -38337,7 +38337,7 @@
|
||||
},
|
||||
"packages/website": {
|
||||
"name": "@getpaseo/website",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "^1.29.1",
|
||||
"@cloudflare/workers-types": "^4.20260317.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "paseo",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"private": true,
|
||||
"description": "Paseo: voice-controlled development environment with OpenAI Realtime API",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/app",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"private": true,
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/cli",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"description": "Paseo CLI - control your AI coding agents from the command line",
|
||||
"bin": {
|
||||
"paseo": "bin/paseo"
|
||||
@@ -25,9 +25,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.0.0",
|
||||
"@getpaseo/client": "0.1.84",
|
||||
"@getpaseo/protocol": "0.1.84",
|
||||
"@getpaseo/server": "0.1.84",
|
||||
"@getpaseo/client": "0.1.85",
|
||||
"@getpaseo/protocol": "0.1.85",
|
||||
"@getpaseo/server": "0.1.85",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.0.0",
|
||||
"mime-types": "^2.1.35",
|
||||
|
||||
@@ -45,6 +45,16 @@ interface ProviderListRow {
|
||||
}
|
||||
|
||||
const EXPECTED_CLAUDE_MODELS = [
|
||||
{
|
||||
id: "claude-opus-4-8[1m]",
|
||||
model: "Opus 4.8 1M",
|
||||
descriptionFragment: "1M context window",
|
||||
},
|
||||
{
|
||||
id: "claude-opus-4-8",
|
||||
model: "Opus 4.8",
|
||||
descriptionFragment: "Latest release",
|
||||
},
|
||||
{
|
||||
id: "claude-opus-4-7[1m]",
|
||||
model: "Opus 4.7 1M",
|
||||
@@ -53,7 +63,7 @@ const EXPECTED_CLAUDE_MODELS = [
|
||||
{
|
||||
id: "claude-opus-4-7",
|
||||
model: "Opus 4.7",
|
||||
descriptionFragment: "Latest release",
|
||||
descriptionFragment: "Previous release",
|
||||
},
|
||||
{
|
||||
id: "claude-opus-4-6[1m]",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/client",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"description": "Paseo client SDK package",
|
||||
"files": [
|
||||
"dist",
|
||||
@@ -33,8 +33,8 @@
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@getpaseo/protocol": "0.1.84",
|
||||
"@getpaseo/relay": "0.1.84",
|
||||
"@getpaseo/protocol": "0.1.85",
|
||||
"@getpaseo/relay": "0.1.85",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/desktop",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"private": true,
|
||||
"description": "Paseo desktop app (Electron wrapper)",
|
||||
"homepage": "https://paseo.sh",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/expo-two-way-audio",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"description": "Native module for two way audio streaming",
|
||||
"keywords": [
|
||||
"ExpoTwoWayAudio",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/highlight",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"files": [
|
||||
"dist",
|
||||
"!dist/**/*.map"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/protocol",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"description": "Paseo shared protocol schemas and wire types",
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/relay",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"description": "Paseo relay for bridging daemon and client connections",
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/server",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"description": "Paseo backend server",
|
||||
"files": [
|
||||
"dist/server",
|
||||
@@ -57,10 +57,10 @@
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "^0.17.1",
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.2.133",
|
||||
"@getpaseo/client": "0.1.84",
|
||||
"@getpaseo/highlight": "0.1.84",
|
||||
"@getpaseo/protocol": "0.1.84",
|
||||
"@getpaseo/relay": "0.1.84",
|
||||
"@getpaseo/client": "0.1.85",
|
||||
"@getpaseo/highlight": "0.1.85",
|
||||
"@getpaseo/protocol": "0.1.85",
|
||||
"@getpaseo/relay": "0.1.85",
|
||||
"@isaacs/ttlcache": "^2.1.4",
|
||||
"@modelcontextprotocol/sdk": "^1.20.1",
|
||||
"@opencode-ai/sdk": "1.14.46",
|
||||
|
||||
@@ -1966,6 +1966,41 @@ test("archiveSnapshot clears persisted attention and normalizes running status",
|
||||
expect(persisted?.attentionTimestamp).toBeNull();
|
||||
});
|
||||
|
||||
test("archiveSnapshot dispatches archived state for stored-only agents", async () => {
|
||||
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-archive-snapshot-dispatch-"));
|
||||
const storagePath = join(workdir, "agents");
|
||||
const storage = new AgentStorage(storagePath, logger);
|
||||
const manager = new AgentManager({
|
||||
clients: { codex: new TestAgentClient() },
|
||||
registry: storage,
|
||||
logger,
|
||||
});
|
||||
|
||||
const created = await manager.createAgent({
|
||||
provider: "codex",
|
||||
cwd: workdir,
|
||||
title: "Stored archive dispatch",
|
||||
});
|
||||
await manager.closeAgent(created.id);
|
||||
|
||||
const events: ManagedAgent[] = [];
|
||||
manager.subscribe(
|
||||
(event) => {
|
||||
if (event.type === "agent_state" && event.agent.id === created.id) {
|
||||
events.push(event.agent);
|
||||
}
|
||||
},
|
||||
{ agentId: created.id, replayState: false },
|
||||
);
|
||||
|
||||
await manager.archiveSnapshot(created.id, new Date().toISOString());
|
||||
|
||||
expect(events.length).toBeGreaterThanOrEqual(1);
|
||||
const last = events[events.length - 1];
|
||||
expect(last.id).toBe(created.id);
|
||||
expect(last.lifecycle).toBe("closed");
|
||||
});
|
||||
|
||||
test("reloadAgentSession cancels active run and resumes existing session once thread_started is observed", async () => {
|
||||
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-reload-active-"));
|
||||
const storagePath = join(workdir, "agents");
|
||||
@@ -4064,6 +4099,60 @@ test("archiveAgent persists archivedAt and updatedAt before emitting closed stat
|
||||
expect(lifecycles.slice(-2)).toEqual(["idle", "closed"]);
|
||||
});
|
||||
|
||||
test("fires onAgentArchived for archived parent and cascaded children", async () => {
|
||||
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-archived-hook-cascade-"));
|
||||
const storagePath = join(workdir, "agents");
|
||||
const storage = new AgentStorage(storagePath, logger);
|
||||
const archivedIds: string[] = [];
|
||||
const manager = new AgentManager({
|
||||
clients: { codex: new TestAgentClient() },
|
||||
registry: storage,
|
||||
logger,
|
||||
});
|
||||
manager.setAgentArchivedCallback((agentId) => {
|
||||
archivedIds.push(agentId);
|
||||
});
|
||||
|
||||
const liveParent = await manager.createAgent({
|
||||
provider: "codex",
|
||||
cwd: workdir,
|
||||
title: "Parent",
|
||||
});
|
||||
const liveChild = await manager.createAgent(
|
||||
{ provider: "codex", cwd: workdir, title: "Child" },
|
||||
undefined,
|
||||
{ labels: { [PARENT_AGENT_ID_LABEL]: liveParent.id } },
|
||||
);
|
||||
|
||||
await manager.archiveAgent(liveParent.id);
|
||||
expect([...archivedIds].sort()).toEqual([liveChild.id, liveParent.id].sort());
|
||||
});
|
||||
|
||||
test("fires onAgentArchived for stored-only snapshot archives", async () => {
|
||||
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-archived-hook-snapshot-"));
|
||||
const storagePath = join(workdir, "agents");
|
||||
const storage = new AgentStorage(storagePath, logger);
|
||||
const archivedIds: string[] = [];
|
||||
const manager = new AgentManager({
|
||||
clients: { codex: new TestAgentClient() },
|
||||
registry: storage,
|
||||
logger,
|
||||
});
|
||||
manager.setAgentArchivedCallback((agentId) => {
|
||||
archivedIds.push(agentId);
|
||||
});
|
||||
|
||||
const storedOnly = await manager.createAgent({
|
||||
provider: "codex",
|
||||
cwd: workdir,
|
||||
title: "Stored only",
|
||||
});
|
||||
await manager.closeAgent(storedOnly.id);
|
||||
|
||||
await manager.archiveSnapshot(storedOnly.id, new Date().toISOString());
|
||||
expect(archivedIds).toEqual([storedOnly.id]);
|
||||
});
|
||||
|
||||
test("archiveAgent cascade archives in-memory children with the full archive contract", async () => {
|
||||
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-cascade-contract-"));
|
||||
const storagePath = join(workdir, "agents");
|
||||
|
||||
@@ -155,6 +155,8 @@ export type AgentAttentionCallback = (params: {
|
||||
reason: "finished" | "error" | "permission";
|
||||
}) => void;
|
||||
|
||||
export type AgentArchivedCallback = (agentId: string) => Promise<void> | void;
|
||||
|
||||
export interface ProviderAvailability {
|
||||
provider: AgentProvider;
|
||||
available: boolean;
|
||||
@@ -427,6 +429,7 @@ export class AgentManager {
|
||||
private mcpBaseUrl: string | null;
|
||||
private appendSystemPrompt: string;
|
||||
private onAgentAttention?: AgentAttentionCallback;
|
||||
private onAgentArchived?: AgentArchivedCallback;
|
||||
private logger: Logger;
|
||||
private readonly rescueTimeouts: Required<AgentManagerRescueTimeouts>;
|
||||
|
||||
@@ -487,6 +490,10 @@ export class AgentManager {
|
||||
this.onAgentAttention = callback;
|
||||
}
|
||||
|
||||
setAgentArchivedCallback(callback: AgentArchivedCallback): void {
|
||||
this.onAgentArchived = callback;
|
||||
}
|
||||
|
||||
setMcpBaseUrl(url: string | null): void {
|
||||
this.mcpBaseUrl = url;
|
||||
}
|
||||
@@ -1119,9 +1126,23 @@ export class AgentManager {
|
||||
this.dispatchArchivedStoredAgent(archivedRecord);
|
||||
}
|
||||
|
||||
await this.fireAgentArchived(record.id);
|
||||
|
||||
return archivedRecord;
|
||||
}
|
||||
|
||||
private async fireAgentArchived(agentId: string): Promise<void> {
|
||||
const callback = this.onAgentArchived;
|
||||
if (!callback) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await callback(agentId);
|
||||
} catch (error) {
|
||||
this.logger.warn({ err: error, agentId }, "onAgentArchived callback failed");
|
||||
}
|
||||
}
|
||||
|
||||
private dispatchArchivedStoredAgent(record: StoredAgentRecord): void {
|
||||
const updatedAt = new Date(record.updatedAt);
|
||||
this.dispatch({
|
||||
@@ -1303,6 +1324,14 @@ export class AgentManager {
|
||||
|
||||
await this.archiveNativeSessionBestEffort(record.provider, record.persistence);
|
||||
|
||||
if (this.agents.has(agentId)) {
|
||||
this.notifyAgentState(agentId);
|
||||
} else if (!nextRecord.internal) {
|
||||
this.dispatchArchivedStoredAgent(nextRecord);
|
||||
}
|
||||
|
||||
await this.fireAgentArchived(agentId);
|
||||
|
||||
return nextRecord;
|
||||
}
|
||||
|
||||
|
||||
@@ -204,7 +204,6 @@ export class CreateAgentLifecycleDispatch {
|
||||
agentManager: this.dependencies.agentManager,
|
||||
agentStorage: this.dependencies.agentStorage,
|
||||
archiveWorkspaceRecord: this.dependencies.archiveWorkspaceRecord,
|
||||
emit: this.dependencies.emit,
|
||||
emitWorkspaceUpdatesForWorkspaceIds: this.dependencies.emitWorkspaceUpdatesForWorkspaceIds,
|
||||
markWorkspaceArchiving: this.dependencies.markWorkspaceArchiving,
|
||||
clearWorkspaceArchiving: this.dependencies.clearWorkspaceArchiving,
|
||||
|
||||
@@ -1447,7 +1447,6 @@ describe("create_agent MCP tool", () => {
|
||||
const emitWorkspaceUpdatesForWorkspaceIds = vi.fn(async () => undefined);
|
||||
const markWorkspaceArchiving = vi.fn();
|
||||
const clearWorkspaceArchiving = vi.fn();
|
||||
const emitSessionMessage = vi.fn();
|
||||
const server = await createAgentMcpServer({
|
||||
agentManager,
|
||||
agentStorage,
|
||||
@@ -1462,7 +1461,6 @@ describe("create_agent MCP tool", () => {
|
||||
emitWorkspaceUpdatesForWorkspaceIds,
|
||||
markWorkspaceArchiving,
|
||||
clearWorkspaceArchiving,
|
||||
emitSessionMessage,
|
||||
github: createGitHubServiceStub(),
|
||||
logger,
|
||||
});
|
||||
@@ -1547,7 +1545,6 @@ describe("create_agent MCP tool", () => {
|
||||
emitWorkspaceUpdatesForWorkspaceIds: vi.fn(async () => undefined),
|
||||
markWorkspaceArchiving: vi.fn(),
|
||||
clearWorkspaceArchiving: vi.fn(),
|
||||
emitSessionMessage: vi.fn(),
|
||||
github: createGitHubServiceStub(),
|
||||
logger,
|
||||
});
|
||||
|
||||
@@ -97,7 +97,6 @@ export interface AgentMcpServerOptions {
|
||||
emitWorkspaceUpdatesForWorkspaceIds?: ArchivePaseoWorktreeDependencies["emitWorkspaceUpdatesForWorkspaceIds"];
|
||||
markWorkspaceArchiving?: ArchivePaseoWorktreeDependencies["markWorkspaceArchiving"];
|
||||
clearWorkspaceArchiving?: ArchivePaseoWorktreeDependencies["clearWorkspaceArchiving"];
|
||||
emitSessionMessage?: ArchivePaseoWorktreeDependencies["emit"];
|
||||
createPaseoWorktree?: CreatePaseoWorktreeWorkflowFn;
|
||||
paseoHome?: string;
|
||||
/**
|
||||
@@ -2323,10 +2322,6 @@ function archiveWorktreeDependencies(
|
||||
if (!options.clearWorkspaceArchiving) {
|
||||
throw new Error("Workspace archiving clearer is required to archive worktrees");
|
||||
}
|
||||
if (!options.emitSessionMessage) {
|
||||
throw new Error("Session message emitter is required to archive worktrees");
|
||||
}
|
||||
|
||||
return {
|
||||
paseoHome: options.paseoHome,
|
||||
github: options.github,
|
||||
@@ -2334,7 +2329,6 @@ function archiveWorktreeDependencies(
|
||||
agentManager: context.agentManager,
|
||||
agentStorage: context.agentStorage,
|
||||
archiveWorkspaceRecord: options.archiveWorkspaceRecord,
|
||||
emit: options.emitSessionMessage,
|
||||
emitWorkspaceUpdatesForWorkspaceIds: options.emitWorkspaceUpdatesForWorkspaceIds,
|
||||
markWorkspaceArchiving: options.markWorkspaceArchiving,
|
||||
clearWorkspaceArchiving: options.clearWorkspaceArchiving,
|
||||
|
||||
@@ -401,6 +401,8 @@ describe("ClaudeAgentClient.listModels", () => {
|
||||
const models = await client.listModels({ cwd: "/tmp/claude-models", force: false });
|
||||
|
||||
expect(models.map((m) => m.id)).toEqual([
|
||||
"claude-opus-4-8[1m]",
|
||||
"claude-opus-4-8",
|
||||
"claude-opus-4-7[1m]",
|
||||
"claude-opus-4-7",
|
||||
"claude-opus-4-6[1m]",
|
||||
@@ -416,7 +418,7 @@ describe("ClaudeAgentClient.listModels", () => {
|
||||
}
|
||||
|
||||
const defaultModel = models.find((m) => m.isDefault);
|
||||
expect(defaultModel?.id).toBe("claude-opus-4-6");
|
||||
expect(defaultModel?.id).toBe("claude-opus-4-8");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ describe("getClaudeModels", () => {
|
||||
it("returns all claude models", () => {
|
||||
const models = getClaudeModels();
|
||||
expect(models.map((m) => m.id)).toEqual([
|
||||
"claude-opus-4-8[1m]",
|
||||
"claude-opus-4-8",
|
||||
"claude-opus-4-7[1m]",
|
||||
"claude-opus-4-7",
|
||||
"claude-opus-4-6[1m]",
|
||||
@@ -49,7 +51,7 @@ describe("getClaudeModels", () => {
|
||||
const models = getClaudeModels();
|
||||
const defaults = models.filter((m) => m.isDefault);
|
||||
expect(defaults).toHaveLength(1);
|
||||
expect(defaults[0].id).toBe("claude-opus-4-6");
|
||||
expect(defaults[0].id).toBe("claude-opus-4-8");
|
||||
});
|
||||
|
||||
it("returns fresh copies each call", () => {
|
||||
|
||||
@@ -12,7 +12,7 @@ const CLAUDE_THINKING_OPTIONS = [
|
||||
{ id: "max", label: "Max" },
|
||||
] as const;
|
||||
|
||||
const CLAUDE_OPUS_4_7_THINKING_OPTIONS = [
|
||||
const CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS = [
|
||||
{ id: "low", label: "Low" },
|
||||
{ id: "medium", label: "Medium" },
|
||||
{ id: "high", label: "High" },
|
||||
@@ -21,19 +21,34 @@ const CLAUDE_OPUS_4_7_THINKING_OPTIONS = [
|
||||
] as const;
|
||||
|
||||
const CLAUDE_MODELS: AgentModelDefinition[] = [
|
||||
{
|
||||
provider: "claude",
|
||||
id: "claude-opus-4-8[1m]",
|
||||
label: "Opus 4.8 1M",
|
||||
description: "Opus 4.8 with 1M context window",
|
||||
thinkingOptions: [...CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS],
|
||||
},
|
||||
{
|
||||
provider: "claude",
|
||||
id: "claude-opus-4-8",
|
||||
label: "Opus 4.8",
|
||||
description: "Opus 4.8 · Latest release",
|
||||
isDefault: true,
|
||||
thinkingOptions: [...CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS],
|
||||
},
|
||||
{
|
||||
provider: "claude",
|
||||
id: "claude-opus-4-7[1m]",
|
||||
label: "Opus 4.7 1M",
|
||||
description: "Opus 4.7 with 1M context window",
|
||||
thinkingOptions: [...CLAUDE_OPUS_4_7_THINKING_OPTIONS],
|
||||
thinkingOptions: [...CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS],
|
||||
},
|
||||
{
|
||||
provider: "claude",
|
||||
id: "claude-opus-4-7",
|
||||
label: "Opus 4.7",
|
||||
description: "Opus 4.7 · Latest release",
|
||||
thinkingOptions: [...CLAUDE_OPUS_4_7_THINKING_OPTIONS],
|
||||
description: "Opus 4.7 · Previous release",
|
||||
thinkingOptions: [...CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS],
|
||||
},
|
||||
{
|
||||
provider: "claude",
|
||||
@@ -47,7 +62,6 @@ const CLAUDE_MODELS: AgentModelDefinition[] = [
|
||||
id: "claude-opus-4-6",
|
||||
label: "Opus 4.6",
|
||||
description: "Opus 4.6 · Most capable for complex work",
|
||||
isDefault: true,
|
||||
thinkingOptions: [...CLAUDE_THINKING_OPTIONS],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -97,7 +97,6 @@ function createHarness(overrides?: {
|
||||
markWorkspaceArchiving: vi.fn(),
|
||||
clearWorkspaceArchiving: vi.fn(),
|
||||
emitWorkspaceUpdatesForWorkspaceIds: vi.fn(),
|
||||
emitSessionMessage: vi.fn(),
|
||||
};
|
||||
const archivePaseoWorktree = vi.fn(
|
||||
overrides?.archivePaseoWorktree ?? (async () => undefined),
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { Logger } from "pino";
|
||||
import type { AgentManager } from "../agent/agent-manager.js";
|
||||
import type { AgentStorage } from "../agent/agent-storage.js";
|
||||
import type { DaemonConfigStore } from "../daemon-config-store.js";
|
||||
import type { SessionOutboundMessage } from "../messages.js";
|
||||
import { archivePaseoWorktree, killTerminalsUnderPath } from "../paseo-worktree-archive-service.js";
|
||||
import { isSameOrDescendantPath } from "../path-utils.js";
|
||||
import type {
|
||||
@@ -26,7 +25,6 @@ export interface AutoArchiveArchiveOptions {
|
||||
markWorkspaceArchiving: (workspaceIds: Iterable<string>, archivingAt: string) => void;
|
||||
clearWorkspaceArchiving: (workspaceIds: Iterable<string>) => void;
|
||||
emitWorkspaceUpdatesForWorkspaceIds: (workspaceIds: Iterable<string>) => Promise<void>;
|
||||
emitSessionMessage: (message: SessionOutboundMessage) => void;
|
||||
}
|
||||
|
||||
export interface ArchiveIfSafeDependencies {
|
||||
@@ -97,7 +95,6 @@ export async function archiveIfSafe(input: {
|
||||
agentManager: options.agentManager,
|
||||
agentStorage: options.agentStorage,
|
||||
archiveWorkspaceRecord: options.archiveWorkspaceRecord,
|
||||
emit: options.emitSessionMessage,
|
||||
emitWorkspaceUpdatesForWorkspaceIds: options.emitWorkspaceUpdatesForWorkspaceIds,
|
||||
markWorkspaceArchiving: options.markWorkspaceArchiving,
|
||||
clearWorkspaceArchiving: options.clearWorkspaceArchiving,
|
||||
|
||||
@@ -587,6 +587,13 @@ export async function createPaseoDaemon(
|
||||
agentStorage,
|
||||
});
|
||||
await scheduleService.start();
|
||||
agentManager.setAgentArchivedCallback(async (agentId) => {
|
||||
try {
|
||||
await scheduleService.deleteForAgent(agentId);
|
||||
} catch (error) {
|
||||
logger.warn({ err: error, agentId }, "Failed to delete schedules for archived agent");
|
||||
}
|
||||
});
|
||||
logger.info({ elapsed: elapsed() }, "Schedule service initialized");
|
||||
logger.info({ elapsed: elapsed() }, "Loading persisted agent registry");
|
||||
const persistedRecords = await agentStorage.list();
|
||||
@@ -651,7 +658,6 @@ export async function createPaseoDaemon(
|
||||
markWorkspaceArchiving: markWorkspaceArchivingExternal,
|
||||
clearWorkspaceArchiving: clearWorkspaceArchivingExternal,
|
||||
emitWorkspaceUpdatesForWorkspaceIds: emitWorkspaceUpdatesExternal,
|
||||
emitSessionMessage: emitExternalSessionMessage,
|
||||
});
|
||||
|
||||
const mcpEnabled = config.mcpEnabled ?? true;
|
||||
@@ -674,7 +680,6 @@ export async function createPaseoDaemon(
|
||||
emitWorkspaceUpdatesForWorkspaceIds: emitWorkspaceUpdatesExternal,
|
||||
markWorkspaceArchiving: markWorkspaceArchivingExternal,
|
||||
clearWorkspaceArchiving: clearWorkspaceArchivingExternal,
|
||||
emitSessionMessage: emitExternalSessionMessage,
|
||||
createPaseoWorktree: async (input, serviceOptions) => {
|
||||
return createPaseoWorktreeWorkflow(
|
||||
{
|
||||
|
||||
@@ -2,23 +2,19 @@ import type { Logger } from "pino";
|
||||
|
||||
import type { AgentManager } from "./agent/agent-manager.js";
|
||||
import type { AgentStorage, StoredAgentRecord } from "./agent/agent-storage.js";
|
||||
import type { SessionOutboundMessage } from "./messages.js";
|
||||
import type { WorkspaceGitService } from "./workspace-git-service.js";
|
||||
import { normalizeWorkspaceId as normalizePersistedWorkspaceId } from "./workspace-registry-model.js";
|
||||
import type { GitHubService } from "../services/github-service.js";
|
||||
import { deletePaseoWorktree, resolvePaseoWorktreeRootForCwd } from "../utils/worktree.js";
|
||||
import type { TerminalManager } from "../terminal/terminal-manager.js";
|
||||
|
||||
type EmitSessionMessage = (message: SessionOutboundMessage) => void;
|
||||
|
||||
export interface ArchivePaseoWorktreeDependencies {
|
||||
paseoHome?: string;
|
||||
github: GitHubService;
|
||||
workspaceGitService: Pick<WorkspaceGitService, "getSnapshot">;
|
||||
agentManager: Pick<AgentManager, "listAgents" | "closeAgent">;
|
||||
agentStorage: Pick<AgentStorage, "list" | "remove">;
|
||||
agentManager: Pick<AgentManager, "listAgents" | "archiveAgent" | "archiveSnapshot">;
|
||||
agentStorage: Pick<AgentStorage, "list">;
|
||||
archiveWorkspaceRecord: (workspaceId: string) => Promise<void>;
|
||||
emit: EmitSessionMessage;
|
||||
emitWorkspaceUpdatesForWorkspaceIds: (workspaceIds: Iterable<string>) => Promise<void>;
|
||||
markWorkspaceArchiving: (workspaceIds: Iterable<string>, archivingAt: string) => void;
|
||||
clearWorkspaceArchiving: (workspaceIds: Iterable<string>) => void;
|
||||
@@ -52,7 +48,7 @@ export async function archivePaseoWorktree(
|
||||
targetPath = resolvedWorktree.worktreePath;
|
||||
}
|
||||
|
||||
const removedAgents = new Set<string>();
|
||||
const archivedAgents = new Set<string>();
|
||||
const affectedWorkspaceCwds = new Set<string>([targetPath]);
|
||||
const affectedWorkspaceIds = new Set<string>([normalizePersistedWorkspaceId(targetPath)]);
|
||||
|
||||
@@ -60,7 +56,7 @@ export async function archivePaseoWorktree(
|
||||
.listAgents()
|
||||
.filter((agent) => dependencies.isPathWithinRoot(targetPath, agent.cwd));
|
||||
for (const agent of liveAgents) {
|
||||
removedAgents.add(agent.id);
|
||||
archivedAgents.add(agent.id);
|
||||
affectedWorkspaceCwds.add(agent.cwd);
|
||||
affectedWorkspaceIds.add(normalizePersistedWorkspaceId(agent.cwd));
|
||||
}
|
||||
@@ -74,58 +70,40 @@ export async function archivePaseoWorktree(
|
||||
"Failed to list stored agents during worktree archive; continuing",
|
||||
);
|
||||
}
|
||||
const liveAgentIds = new Set(liveAgents.map((agent) => agent.id));
|
||||
const matchingStoredRecords = storedRecords.filter((record) =>
|
||||
dependencies.isPathWithinRoot(targetPath, record.cwd),
|
||||
);
|
||||
for (const record of matchingStoredRecords) {
|
||||
removedAgents.add(record.id);
|
||||
archivedAgents.add(record.id);
|
||||
affectedWorkspaceCwds.add(record.cwd);
|
||||
affectedWorkspaceIds.add(normalizePersistedWorkspaceId(record.cwd));
|
||||
}
|
||||
|
||||
const agentIdsToRemoveFromStorage = new Set<string>([
|
||||
...liveAgents.map((agent) => agent.id),
|
||||
...matchingStoredRecords.map((record) => record.id),
|
||||
]);
|
||||
|
||||
const affectedWorkspaceIdList = Array.from(affectedWorkspaceIds);
|
||||
dependencies.markWorkspaceArchiving(affectedWorkspaceIdList, new Date().toISOString());
|
||||
|
||||
try {
|
||||
await dependencies.emitWorkspaceUpdatesForWorkspaceIds(affectedWorkspaceIdList);
|
||||
|
||||
const teardownResults = await Promise.allSettled([
|
||||
...liveAgents.map((agent) => dependencies.agentManager.closeAgent(agent.id)),
|
||||
const archivedAt = new Date().toISOString();
|
||||
const archiveResults = await Promise.allSettled([
|
||||
...liveAgents.map((agent) => dependencies.agentManager.archiveAgent(agent.id)),
|
||||
...matchingStoredRecords
|
||||
.filter((record) => !liveAgentIds.has(record.id) && !record.archivedAt)
|
||||
.map((record) => dependencies.agentManager.archiveSnapshot(record.id, archivedAt)),
|
||||
dependencies.killTerminalsUnderPath(targetPath),
|
||||
]);
|
||||
|
||||
for (const result of teardownResults) {
|
||||
for (const result of archiveResults) {
|
||||
if (result.status === "rejected") {
|
||||
dependencies.sessionLogger?.warn(
|
||||
{ err: result.reason, targetPath },
|
||||
"Worktree teardown step failed during archive; continuing",
|
||||
"Worktree archive teardown step failed; continuing",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const agentIdsToRemove = Array.from(agentIdsToRemoveFromStorage);
|
||||
const storageRemovalResults = await Promise.allSettled(
|
||||
agentIdsToRemove.map((agentId) => dependencies.agentStorage.remove(agentId)),
|
||||
);
|
||||
storageRemovalResults.forEach((result, index) => {
|
||||
if (result.status === "fulfilled") {
|
||||
return;
|
||||
}
|
||||
dependencies.sessionLogger?.warn(
|
||||
{
|
||||
err: result.reason,
|
||||
agentId: agentIdsToRemove[index],
|
||||
targetPath,
|
||||
},
|
||||
"Failed to remove archived worktree agent from storage; continuing",
|
||||
);
|
||||
});
|
||||
|
||||
await deletePaseoWorktree({
|
||||
cwd: options.repoRoot,
|
||||
worktreePath: targetPath,
|
||||
@@ -163,22 +141,12 @@ export async function archivePaseoWorktree(
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
for (const agentId of removedAgents) {
|
||||
dependencies.emit({
|
||||
type: "agent_deleted",
|
||||
payload: {
|
||||
agentId,
|
||||
requestId: options.requestId,
|
||||
},
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
dependencies.clearWorkspaceArchiving(affectedWorkspaceIdList);
|
||||
await dependencies.emitWorkspaceUpdatesForWorkspaceIds(affectedWorkspaceIdList);
|
||||
}
|
||||
|
||||
return Array.from(removedAgents);
|
||||
return Array.from(archivedAgents);
|
||||
}
|
||||
|
||||
export async function killTerminalsUnderPath(
|
||||
|
||||
@@ -960,4 +960,45 @@ describe("ScheduleService", () => {
|
||||
|
||||
await expect(service.runOnce(created.id)).rejects.toThrow("already completed");
|
||||
});
|
||||
|
||||
test("deleteForAgent removes only schedules targeting that agent", async () => {
|
||||
const service = new ScheduleService({
|
||||
paseoHome: tempDir,
|
||||
logger: createTestLogger(),
|
||||
agentManager: new AgentManager({ logger: createTestLogger() }),
|
||||
agentStorage,
|
||||
now: () => now,
|
||||
runner: async () => ({ agentId: null, output: "ok" }),
|
||||
});
|
||||
|
||||
const targetAgentId = "11111111-1111-4111-8111-111111111111";
|
||||
const otherAgentId = "22222222-2222-4222-8222-222222222222";
|
||||
|
||||
const targeted = await service.create({
|
||||
prompt: "ping the doomed agent",
|
||||
cadence: { type: "every", everyMs: 60_000 },
|
||||
target: { type: "agent", agentId: targetAgentId },
|
||||
});
|
||||
const otherTargeted = await service.create({
|
||||
prompt: "ping the other agent",
|
||||
cadence: { type: "every", everyMs: 60_000 },
|
||||
target: { type: "agent", agentId: otherAgentId },
|
||||
});
|
||||
const newAgentSchedule = await service.create({
|
||||
prompt: "spawn a fresh agent",
|
||||
cadence: { type: "every", everyMs: 60_000 },
|
||||
target: {
|
||||
type: "new-agent",
|
||||
config: { provider: "claude", cwd: tempDir },
|
||||
},
|
||||
});
|
||||
|
||||
const deleted = await service.deleteForAgent(targetAgentId);
|
||||
expect(deleted).toBe(1);
|
||||
|
||||
const remaining = await service.list();
|
||||
const remainingIds = remaining.map((schedule) => schedule.id).sort();
|
||||
expect(remainingIds).toEqual([otherTargeted.id, newAgentSchedule.id].sort());
|
||||
expect(remainingIds).not.toContain(targeted.id);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -311,6 +311,28 @@ export class ScheduleService {
|
||||
await this.store.delete(id);
|
||||
}
|
||||
|
||||
async deleteForAgent(agentId: string): Promise<number> {
|
||||
const schedules = await this.store.list();
|
||||
const matches = schedules.filter(
|
||||
(schedule) => schedule.target.type === "agent" && schedule.target.agentId === agentId,
|
||||
);
|
||||
const results = await Promise.allSettled(
|
||||
matches.map((schedule) => this.store.delete(schedule.id)),
|
||||
);
|
||||
let deleted = 0;
|
||||
for (const [index, result] of results.entries()) {
|
||||
if (result.status === "fulfilled") {
|
||||
deleted += 1;
|
||||
} else {
|
||||
this.logger.warn(
|
||||
{ err: result.reason, scheduleId: matches[index].id, agentId },
|
||||
"Failed to delete schedule for archived agent; continuing",
|
||||
);
|
||||
}
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
async runOnce(id: string): Promise<StoredSchedule> {
|
||||
const schedule = await this.inspect(id);
|
||||
if (schedule.status === "completed") {
|
||||
|
||||
@@ -471,10 +471,9 @@ describe("create-agent worktree setup boundary", () => {
|
||||
});
|
||||
});
|
||||
|
||||
function createAgentStorageStub(): Pick<AgentStorage, "list" | "remove"> {
|
||||
function createAgentStorageStub(): Pick<AgentStorage, "list"> {
|
||||
return {
|
||||
list: async (): Promise<StoredAgentRecord[]> => [],
|
||||
remove: vi.fn(async () => {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1726,10 +1725,14 @@ describe("archivePaseoWorktree", () => {
|
||||
|
||||
const teardownStartTimes: Record<string, number> = {};
|
||||
const teardownEndTimes: Record<string, number> = {};
|
||||
const closeAgentSpy = vi.fn(async (agentId: string) => {
|
||||
const archiveAgentSpy = vi.fn(async (agentId: string) => {
|
||||
teardownStartTimes[agentId] = Date.now();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
teardownEndTimes[agentId] = Date.now();
|
||||
return { archivedAt: new Date().toISOString() };
|
||||
});
|
||||
const archiveSnapshotSpy = vi.fn(async () => {
|
||||
throw new Error("not expected for live agents");
|
||||
});
|
||||
const killTerminalsUnderPath = vi.fn(async () => {
|
||||
teardownStartTimes.__terminals = Date.now();
|
||||
@@ -1737,8 +1740,7 @@ describe("archivePaseoWorktree", () => {
|
||||
teardownEndTimes.__terminals = Date.now();
|
||||
});
|
||||
|
||||
const emitted: SessionOutboundMessage[] = [];
|
||||
const removedAgents = await archivePaseoWorktree(
|
||||
const archivedAgents = await archivePaseoWorktree(
|
||||
{
|
||||
paseoHome,
|
||||
github: createGitHubServiceStub(),
|
||||
@@ -1747,11 +1749,11 @@ describe("archivePaseoWorktree", () => {
|
||||
createManagedAgentForArchive({ id: "agent-1", cwd: created.worktreePath }),
|
||||
createManagedAgentForArchive({ id: "agent-2", cwd: created.worktreePath }),
|
||||
],
|
||||
closeAgent: closeAgentSpy,
|
||||
archiveAgent: archiveAgentSpy,
|
||||
archiveSnapshot: archiveSnapshotSpy,
|
||||
},
|
||||
agentStorage: createAgentStorageStub(),
|
||||
archiveWorkspaceRecord: vi.fn(async () => {}),
|
||||
emit: (msg) => emitted.push(msg),
|
||||
...createWorkspaceArchivingDeps(),
|
||||
isPathWithinRoot: createIsPathWithinRoot(),
|
||||
killTerminalsUnderPath,
|
||||
@@ -1764,9 +1766,10 @@ describe("archivePaseoWorktree", () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(removedAgents).toEqual(expect.arrayContaining(["agent-1", "agent-2"]));
|
||||
expect(archivedAgents).toEqual(expect.arrayContaining(["agent-1", "agent-2"]));
|
||||
expect(existsSync(created.worktreePath)).toBe(false);
|
||||
expect(closeAgentSpy).toHaveBeenCalledTimes(2);
|
||||
expect(archiveAgentSpy).toHaveBeenCalledTimes(2);
|
||||
expect(archiveSnapshotSpy).not.toHaveBeenCalled();
|
||||
expect(killTerminalsUnderPath).toHaveBeenCalledWith(created.worktreePath);
|
||||
|
||||
// All teardown work must overlap — sequential would take ~300ms, parallel ~100ms.
|
||||
@@ -1834,10 +1837,14 @@ describe("archivePaseoWorktree", () => {
|
||||
}
|
||||
events.push(`emit:${Array.from(workspaceIds).join(",")}`);
|
||||
});
|
||||
const closeAgent = vi.fn(async () => {
|
||||
const archiveAgent = vi.fn(async () => {
|
||||
events.push("close:start");
|
||||
await emitWorkspaceUpdatesForWorkspaceIds(affectedIds);
|
||||
events.push("close:end");
|
||||
return { archivedAt: new Date().toISOString() };
|
||||
});
|
||||
const archiveSnapshot = vi.fn(async () => {
|
||||
throw new Error("not expected for live agents");
|
||||
});
|
||||
|
||||
await handlePaseoWorktreeArchiveRequest(
|
||||
@@ -1850,7 +1857,8 @@ describe("archivePaseoWorktree", () => {
|
||||
},
|
||||
agentManager: {
|
||||
listAgents: () => [liveAgent],
|
||||
closeAgent,
|
||||
archiveAgent,
|
||||
archiveSnapshot,
|
||||
},
|
||||
agentStorage: createAgentStorageStub(),
|
||||
archiveWorkspaceRecord: vi.fn(async (workspaceId: string) => {
|
||||
@@ -1956,11 +1964,13 @@ describe("archivePaseoWorktree", () => {
|
||||
workspaceGitService: { getSnapshot: vi.fn(async () => null) },
|
||||
agentManager: {
|
||||
listAgents: () => [],
|
||||
closeAgent: vi.fn(async () => {}),
|
||||
archiveAgent: vi.fn(async () => ({ archivedAt: new Date().toISOString() })),
|
||||
archiveSnapshot: vi.fn(async () => {
|
||||
throw new Error("not expected for empty agent list");
|
||||
}),
|
||||
},
|
||||
agentStorage: createAgentStorageStub(),
|
||||
archiveWorkspaceRecord,
|
||||
emit: vi.fn(),
|
||||
emitWorkspaceUpdatesForWorkspaceIds: vi.fn(async (workspaceIds: Iterable<string>) => {
|
||||
for (const workspaceId of workspaceIds) {
|
||||
emittedUpdates.push({
|
||||
@@ -2030,11 +2040,13 @@ describe("archivePaseoWorktree", () => {
|
||||
github: createGitHubServiceStub(),
|
||||
agentManager: {
|
||||
listAgents: () => [],
|
||||
closeAgent: vi.fn(async () => {}),
|
||||
archiveAgent: vi.fn(async () => ({ archivedAt: new Date().toISOString() })),
|
||||
archiveSnapshot: vi.fn(async () => {
|
||||
throw new Error("not expected for empty agent list");
|
||||
}),
|
||||
},
|
||||
agentStorage: createAgentStorageStub(),
|
||||
archiveWorkspaceRecord: vi.fn(async () => {}),
|
||||
emit: vi.fn(),
|
||||
...createWorkspaceArchivingDeps(),
|
||||
isPathWithinRoot: createIsPathWithinRoot(),
|
||||
killTerminalsUnderPath,
|
||||
@@ -2075,11 +2087,13 @@ describe("archivePaseoWorktree", () => {
|
||||
workspaceGitService: workspaceGitService as unknown as WorkspaceGitService,
|
||||
agentManager: {
|
||||
listAgents: () => [],
|
||||
closeAgent: vi.fn(async () => {}),
|
||||
archiveAgent: vi.fn(async () => ({ archivedAt: new Date().toISOString() })),
|
||||
archiveSnapshot: vi.fn(async () => {
|
||||
throw new Error("not expected for empty agent list");
|
||||
}),
|
||||
},
|
||||
agentStorage: createAgentStorageStub(),
|
||||
archiveWorkspaceRecord: vi.fn(async () => {}),
|
||||
emit: vi.fn(),
|
||||
...createWorkspaceArchivingDeps(),
|
||||
isPathWithinRoot: createIsPathWithinRoot(),
|
||||
killTerminalsUnderPath: vi.fn(async () => {}),
|
||||
@@ -2126,7 +2140,10 @@ describe("archivePaseoWorktree", () => {
|
||||
github: createGitHubServiceStub(),
|
||||
agentManager: {
|
||||
listAgents: () => [],
|
||||
closeAgent: vi.fn(async () => {}),
|
||||
archiveAgent: vi.fn(async () => ({ archivedAt: new Date().toISOString() })),
|
||||
archiveSnapshot: vi.fn(async () => {
|
||||
throw new Error("not expected for empty agent list");
|
||||
}),
|
||||
},
|
||||
agentStorage: createAgentStorageStub(),
|
||||
archiveWorkspaceRecord: vi.fn(async () => {}),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getpaseo/website",
|
||||
"version": "0.1.84",
|
||||
"version": "0.1.85",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user