fix: resolve type errors and test failures from branch integration
- Align portless code with storage branch's numeric workspace IDs and new field names - Update workspace kind comparisons (local_checkout → checkout/worktree) - Add missing services, supportsTerminalMode, terminal fields to test fixtures - Fix archive timestamp assertions to match dynamic archiveSnapshot flow - Fix dictation, voice runtime, and service health monitor test timing - Add xterm-addon-ligatures type declaration for terminal emulator
This commit is contained in:
Generated
+75
-75
@@ -36381,14 +36381,14 @@
|
|||||||
},
|
},
|
||||||
"packages/app/node_modules/expo-clipboard": {
|
"packages/app/node_modules/expo-clipboard": {
|
||||||
"version": "8.0.7",
|
"version": "8.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-8.0.7.tgz",
|
||||||
|
"integrity": "sha512-zvlfFV+wB2QQrQnHWlo0EKHAkdi2tycLtE+EXFUWTPZYkgu1XcH+aiKfd4ul7Z0SDF+1IuwoiW9AA9eO35aj3Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"expo": "*",
|
"expo": "*",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-8.0.7.tgz",
|
|
||||||
"integrity": "sha512-zvlfFV+wB2QQrQnHWlo0EKHAkdi2tycLtE+EXFUWTPZYkgu1XcH+aiKfd4ul7Z0SDF+1IuwoiW9AA9eO35aj3Q=="
|
|
||||||
},
|
},
|
||||||
"packages/app/node_modules/react-native-nitro-modules": {
|
"packages/app/node_modules/react-native-nitro-modules": {
|
||||||
"version": "0.33.8",
|
"version": "0.33.8",
|
||||||
@@ -36402,12 +36402,12 @@
|
|||||||
},
|
},
|
||||||
"packages/app/node_modules/zod": {
|
"packages/app/node_modules/zod": {
|
||||||
"version": "3.25.76",
|
"version": "3.25.76",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||||
|
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
|
||||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="
|
|
||||||
},
|
},
|
||||||
"packages/cli": {
|
"packages/cli": {
|
||||||
"name": "@getpaseo/cli",
|
"name": "@getpaseo/cli",
|
||||||
@@ -36435,24 +36435,24 @@
|
|||||||
},
|
},
|
||||||
"packages/cli/node_modules/chalk": {
|
"packages/cli/node_modules/chalk": {
|
||||||
"version": "5.6.2",
|
"version": "5.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
|
||||||
|
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
|
|
||||||
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="
|
|
||||||
},
|
},
|
||||||
"packages/cli/node_modules/commander": {
|
"packages/cli/node_modules/commander": {
|
||||||
"version": "12.1.0",
|
"version": "12.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
|
||||||
|
"integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
|
|
||||||
"integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="
|
|
||||||
},
|
},
|
||||||
"packages/desktop": {
|
"packages/desktop": {
|
||||||
"name": "@getpaseo/desktop",
|
"name": "@getpaseo/desktop",
|
||||||
@@ -36802,6 +36802,8 @@
|
|||||||
},
|
},
|
||||||
"packages/server/node_modules/@modelcontextprotocol/sdk": {
|
"packages/server/node_modules/@modelcontextprotocol/sdk": {
|
||||||
"version": "1.20.1",
|
"version": "1.20.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.20.1.tgz",
|
||||||
|
"integrity": "sha512-j/P+yuxXfgxb+mW7OEoRCM3G47zCTDqUPivJo/VzpjbG8I9csTXtOprCf5FfOfHK4whOJny0aHuBEON+kS7CCA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^6.12.6",
|
"ajv": "^6.12.6",
|
||||||
@@ -36819,12 +36821,12 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.20.1.tgz",
|
|
||||||
"integrity": "sha512-j/P+yuxXfgxb+mW7OEoRCM3G47zCTDqUPivJo/VzpjbG8I9csTXtOprCf5FfOfHK4whOJny0aHuBEON+kS7CCA=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/@modelcontextprotocol/sdk/node_modules/ajv": {
|
"packages/server/node_modules/@modelcontextprotocol/sdk/node_modules/ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
@@ -36835,12 +36837,12 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/epoberezkin"
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
|
||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/@modelcontextprotocol/sdk/node_modules/express": {
|
"packages/server/node_modules/@modelcontextprotocol/sdk/node_modules/express": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "^2.0.0",
|
"accepts": "^2.0.0",
|
||||||
@@ -36877,9 +36879,7 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/express"
|
"url": "https://opencollective.com/express"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
|
|
||||||
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": {
|
"packages/server/node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
@@ -36889,6 +36889,8 @@
|
|||||||
},
|
},
|
||||||
"packages/server/node_modules/accepts": {
|
"packages/server/node_modules/accepts": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mime-types": "^3.0.0",
|
"mime-types": "^3.0.0",
|
||||||
@@ -36896,12 +36898,12 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/ajv": {
|
"packages/server/node_modules/ajv": {
|
||||||
"version": "8.17.1",
|
"version": "8.17.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||||
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
@@ -36912,24 +36914,24 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/epoberezkin"
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
|
||||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/ansi-regex": {
|
"packages/server/node_modules/ansi-regex": {
|
||||||
"version": "6.2.2",
|
"version": "6.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
|
||||||
|
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
|
|
||||||
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/body-parser": {
|
"packages/server/node_modules/body-parser": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bytes": "^3.1.2",
|
"bytes": "^3.1.2",
|
||||||
@@ -36944,33 +36946,33 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/content-disposition": {
|
"packages/server/node_modules/content-disposition": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"safe-buffer": "5.2.1"
|
"safe-buffer": "5.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/cookie-signature": {
|
"packages/server/node_modules/cookie-signature": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.6.0"
|
"node": ">=6.6.0"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
|
|
||||||
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/finalhandler": {
|
"packages/server/node_modules/finalhandler": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.4.0",
|
"debug": "^4.4.0",
|
||||||
@@ -36982,60 +36984,58 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/fresh": {
|
"packages/server/node_modules/fresh": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/media-typer": {
|
"packages/server/node_modules/media-typer": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/merge-descriptors": {
|
"packages/server/node_modules/merge-descriptors": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/mime-types": {
|
"packages/server/node_modules/mime-types": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mime-db": "^1.54.0"
|
"mime-db": "^1.54.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/negotiator": {
|
"packages/server/node_modules/negotiator": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/raw-body": {
|
"packages/server/node_modules/raw-body": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
@@ -37070,6 +37070,8 @@
|
|||||||
},
|
},
|
||||||
"packages/server/node_modules/send": {
|
"packages/server/node_modules/send": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.3.5",
|
"debug": "^4.3.5",
|
||||||
@@ -37086,12 +37088,12 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 18"
|
"node": ">= 18"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/serve-static": {
|
"packages/server/node_modules/serve-static": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"encodeurl": "^2.0.0",
|
"encodeurl": "^2.0.0",
|
||||||
@@ -37101,12 +37103,12 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 18"
|
"node": ">= 18"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/strip-ansi": {
|
"packages/server/node_modules/strip-ansi": {
|
||||||
"version": "7.1.2",
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^6.0.1"
|
"ansi-regex": "^6.0.1"
|
||||||
@@ -37116,12 +37118,12 @@
|
|||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
|
|
||||||
"integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/type-is": {
|
"packages/server/node_modules/type-is": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"content-type": "^1.0.5",
|
"content-type": "^1.0.5",
|
||||||
@@ -37130,18 +37132,16 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="
|
|
||||||
},
|
},
|
||||||
"packages/server/node_modules/zod": {
|
"packages/server/node_modules/zod": {
|
||||||
"version": "3.25.76",
|
"version": "3.25.76",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||||
|
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
|
||||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="
|
|
||||||
},
|
},
|
||||||
"packages/website": {
|
"packages/website": {
|
||||||
"name": "@getpaseo/website",
|
"name": "@getpaseo/website",
|
||||||
@@ -37172,13 +37172,13 @@
|
|||||||
},
|
},
|
||||||
"packages/website/node_modules/@types/node": {
|
"packages/website/node_modules/@types/node": {
|
||||||
"version": "22.19.6",
|
"version": "22.19.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.6.tgz",
|
||||||
|
"integrity": "sha512-qm+G8HuG6hOHQigsi7VGuLjUVu6TtBo/F05zvX04Mw2uCg9Dv0Qxy3Qw7j41SidlTcl5D/5yg0SEZqOB+EqZnQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~6.21.0"
|
"undici-types": "~6.21.0"
|
||||||
},
|
}
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.6.tgz",
|
|
||||||
"integrity": "sha512-qm+G8HuG6hOHQigsi7VGuLjUVu6TtBo/F05zvX04Mw2uCg9Dv0Qxy3Qw7j41SidlTcl5D/5yg0SEZqOB+EqZnQ=="
|
|
||||||
},
|
},
|
||||||
"packages/website/node_modules/react": {
|
"packages/website/node_modules/react": {
|
||||||
"version": "19.2.4",
|
"version": "19.2.4",
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ function HoverCardStatusIndicator({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const KindIcon =
|
const KindIcon =
|
||||||
workspace.workspaceKind === "local_checkout"
|
workspace.workspaceKind === "checkout"
|
||||||
? Monitor
|
? Monitor
|
||||||
: workspace.workspaceKind === "worktree"
|
: workspace.workspaceKind === "worktree"
|
||||||
? FolderGit2
|
? FolderGit2
|
||||||
@@ -251,7 +251,7 @@ function WorkspaceHoverCardContent({
|
|||||||
const prHint = useWorkspacePrHint({
|
const prHint = useWorkspacePrHint({
|
||||||
serverId: workspace.serverId,
|
serverId: workspace.serverId,
|
||||||
cwd: workspace.workspaceId,
|
cwd: workspace.workspaceId,
|
||||||
enabled: workspace.workspaceKind !== "directory",
|
enabled: workspace.projectKind !== "directory",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Measure trigger — same pattern as tooltip.tsx
|
// Measure trigger — same pattern as tooltip.tsx
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ function workspace(input: {
|
|||||||
projectId: "project-1",
|
projectId: "project-1",
|
||||||
projectDisplayName: "Project 1",
|
projectDisplayName: "Project 1",
|
||||||
projectRootPath: "/repo",
|
projectRootPath: "/repo",
|
||||||
|
workspaceDirectory: input.id,
|
||||||
projectKind: "git",
|
projectKind: "git",
|
||||||
workspaceKind: "local_checkout",
|
workspaceKind: "checkout",
|
||||||
name: "main",
|
name: "main",
|
||||||
status: "running",
|
status: "running",
|
||||||
activityAt: null,
|
activityAt: null,
|
||||||
|
|||||||
@@ -5,16 +5,33 @@ type MockPlatform = "web" | "ios" | "android";
|
|||||||
type GlobalSnapshot = {
|
type GlobalSnapshot = {
|
||||||
Notification: unknown;
|
Notification: unknown;
|
||||||
navigatorDescriptor?: PropertyDescriptor;
|
navigatorDescriptor?: PropertyDescriptor;
|
||||||
|
windowDescriptor?: PropertyDescriptor;
|
||||||
paseoDesktop: unknown;
|
paseoDesktop: unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
const originalGlobals: GlobalSnapshot = {
|
const originalGlobals: GlobalSnapshot = {
|
||||||
Notification: (globalThis as { Notification?: unknown }).Notification,
|
Notification: (globalThis as { Notification?: unknown }).Notification,
|
||||||
navigatorDescriptor: Object.getOwnPropertyDescriptor(globalThis, "navigator"),
|
navigatorDescriptor: Object.getOwnPropertyDescriptor(globalThis, "navigator"),
|
||||||
|
windowDescriptor: Object.getOwnPropertyDescriptor(globalThis, "window"),
|
||||||
paseoDesktop:
|
paseoDesktop:
|
||||||
typeof window === "undefined" ? undefined : (window as { paseoDesktop?: unknown }).paseoDesktop,
|
typeof window === "undefined" ? undefined : (window as { paseoDesktop?: unknown }).paseoDesktop,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function ensureWindow(): { paseoDesktop?: unknown } {
|
||||||
|
const existingWindow = (globalThis as { window?: { paseoDesktop?: unknown } }).window;
|
||||||
|
if (existingWindow) {
|
||||||
|
return existingWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextWindow: { paseoDesktop?: unknown } = {};
|
||||||
|
Object.defineProperty(globalThis, "window", {
|
||||||
|
configurable: true,
|
||||||
|
writable: true,
|
||||||
|
value: nextWindow,
|
||||||
|
});
|
||||||
|
return nextWindow;
|
||||||
|
}
|
||||||
|
|
||||||
function setNavigator(value: unknown): void {
|
function setNavigator(value: unknown): void {
|
||||||
Object.defineProperty(globalThis, "navigator", {
|
Object.defineProperty(globalThis, "navigator", {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
@@ -32,6 +49,12 @@ function restoreGlobals(): void {
|
|||||||
delete (globalThis as { navigator?: unknown }).navigator;
|
delete (globalThis as { navigator?: unknown }).navigator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (originalGlobals.windowDescriptor) {
|
||||||
|
Object.defineProperty(globalThis, "window", originalGlobals.windowDescriptor);
|
||||||
|
} else {
|
||||||
|
delete (globalThis as { window?: unknown }).window;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
(window as { paseoDesktop?: unknown }).paseoDesktop = originalGlobals.paseoDesktop;
|
(window as { paseoDesktop?: unknown }).paseoDesktop = originalGlobals.paseoDesktop;
|
||||||
}
|
}
|
||||||
@@ -56,7 +79,7 @@ describe("desktop-permissions", () => {
|
|||||||
|
|
||||||
expect(shouldShowDesktopPermissionSection()).toBe(false);
|
expect(shouldShowDesktopPermissionSection()).toBe(false);
|
||||||
|
|
||||||
(window as { paseoDesktop?: unknown }).paseoDesktop = {};
|
ensureWindow().paseoDesktop = {};
|
||||||
expect(shouldShowDesktopPermissionSection()).toBe(true);
|
expect(shouldShowDesktopPermissionSection()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ describe("useAgentFormState", () => {
|
|||||||
expect(resolved.thinkingOptionId).toBe("low");
|
expect(resolved.thinkingOptionId).toBe("low");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("leaves thinking unset when the model exposes options without a provider default", () => {
|
it("falls back to the first thinking option when the model exposes options without a provider default", () => {
|
||||||
const claudeModels: AgentModelDefinition[] = [
|
const claudeModels: AgentModelDefinition[] = [
|
||||||
{
|
{
|
||||||
provider: "claude",
|
provider: "claude",
|
||||||
@@ -259,7 +259,7 @@ describe("useAgentFormState", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(resolved.model).toBe("default");
|
expect(resolved.model).toBe("default");
|
||||||
expect(resolved.thinkingOptionId).toBe("");
|
expect(resolved.thinkingOptionId).toBe("low");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("resolves provider only from allowed provider map", () => {
|
it("resolves provider only from allowed provider map", () => {
|
||||||
|
|||||||
@@ -1,4 +1,49 @@
|
|||||||
import { beforeAll, describe, expect, it } from "vitest";
|
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
vi.mock("@react-native-async-storage/async-storage", () => ({
|
||||||
|
default: {
|
||||||
|
getItem: async () => null,
|
||||||
|
setItem: async () => undefined,
|
||||||
|
removeItem: async () => undefined,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/attachments/service", () => ({
|
||||||
|
garbageCollectAttachments: async () => undefined,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./use-agent-form-state", () => ({
|
||||||
|
useAgentFormState: () => ({
|
||||||
|
selectedServerId: "host-1",
|
||||||
|
setSelectedServerId: () => undefined,
|
||||||
|
setSelectedServerIdFromUser: () => undefined,
|
||||||
|
selectedProvider: "codex",
|
||||||
|
setProviderFromUser: () => undefined,
|
||||||
|
selectedMode: "auto",
|
||||||
|
setModeFromUser: () => undefined,
|
||||||
|
selectedModel: "",
|
||||||
|
setModelFromUser: () => undefined,
|
||||||
|
selectedThinkingOptionId: "",
|
||||||
|
setThinkingOptionFromUser: () => undefined,
|
||||||
|
workingDir: "/repo",
|
||||||
|
setWorkingDir: () => undefined,
|
||||||
|
setWorkingDirFromUser: () => undefined,
|
||||||
|
providerDefinitions: [{ id: "codex", label: "Codex", modes: [{ id: "auto", label: "Auto" }] }],
|
||||||
|
providerDefinitionMap: new Map(),
|
||||||
|
agentDefinition: undefined,
|
||||||
|
modeOptions: [{ id: "auto", label: "Auto" }],
|
||||||
|
availableModels: [],
|
||||||
|
allProviderModels: new Map(),
|
||||||
|
isAllModelsLoading: false,
|
||||||
|
availableThinkingOptions: [],
|
||||||
|
isModelLoading: false,
|
||||||
|
modelError: null,
|
||||||
|
refreshProviderModels: () => undefined,
|
||||||
|
setProviderAndModelFromUser: () => undefined,
|
||||||
|
workingDirIsEmpty: false,
|
||||||
|
persistFormPreferences: async () => undefined,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
let __private__: typeof import("./use-agent-input-draft").__private__;
|
let __private__: typeof import("./use-agent-input-draft").__private__;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ function makeAgent(overrides: Partial<Agent> = {}): Agent {
|
|||||||
serverId: "server-a",
|
serverId: "server-a",
|
||||||
id: "agent-1",
|
id: "agent-1",
|
||||||
provider: "codex",
|
provider: "codex",
|
||||||
|
terminal: false,
|
||||||
status: "running",
|
status: "running",
|
||||||
createdAt: new Date("2026-04-01T03:00:00.000Z"),
|
createdAt: new Date("2026-04-01T03:00:00.000Z"),
|
||||||
updatedAt: new Date("2026-04-01T03:00:00.000Z"),
|
updatedAt: new Date("2026-04-01T03:00:00.000Z"),
|
||||||
@@ -22,6 +23,7 @@ function makeAgent(overrides: Partial<Agent> = {}): Agent {
|
|||||||
supportsMcpServers: true,
|
supportsMcpServers: true,
|
||||||
supportsReasoningStream: true,
|
supportsReasoningStream: true,
|
||||||
supportsToolInvocations: true,
|
supportsToolInvocations: true,
|
||||||
|
supportsTerminalMode: false,
|
||||||
},
|
},
|
||||||
currentModeId: null,
|
currentModeId: null,
|
||||||
availableModes: [],
|
availableModes: [],
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ describe("openProjectDirectly", () => {
|
|||||||
status: "done" as const,
|
status: "done" as const,
|
||||||
activityAt: null,
|
activityAt: null,
|
||||||
diffStat: null,
|
diffStat: null,
|
||||||
|
services: [],
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -261,10 +261,10 @@ describe("keyboard-shortcuts", () => {
|
|||||||
action: "sidebar.toggle.left",
|
action: "sidebar.toggle.left",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "keeps Mod+. as sidebar toggle fallback",
|
name: "binds Mod+. to toggle both sidebars on non-mac",
|
||||||
event: { key: ".", code: "Period", ctrlKey: true },
|
event: { key: ".", code: "Period", ctrlKey: true },
|
||||||
context: { isMac: false },
|
context: { isMac: false },
|
||||||
action: "sidebar.toggle.left",
|
action: "sidebar.toggle.both",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "routes Mod+D to message-input action outside terminal",
|
name: "routes Mod+D to message-input action outside terminal",
|
||||||
@@ -344,11 +344,6 @@ describe("keyboard-shortcuts", () => {
|
|||||||
event: { key: "k", code: "KeyK", ctrlKey: true },
|
event: { key: "k", code: "KeyK", ctrlKey: true },
|
||||||
context: { isMac: false, focusScope: "terminal" },
|
context: { isMac: false, focusScope: "terminal" },
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "does not bind Ctrl+B on non-mac",
|
|
||||||
event: { key: "b", code: "KeyB", ctrlKey: true },
|
|
||||||
context: { isMac: false },
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "does not route message-input actions when terminal is focused",
|
name: "does not route message-input actions when terminal is focused",
|
||||||
event: { key: "d", code: "KeyD", metaKey: true },
|
event: { key: "d", code: "KeyD", metaKey: true },
|
||||||
@@ -477,10 +472,11 @@ describe("keyboard-shortcut help sections", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "uses mod+period as non-mac left sidebar shortcut",
|
name: "uses mod+b for the left sidebar and mod+period for both sidebars on non-mac",
|
||||||
context: { isMac: false, isDesktop: false },
|
context: { isMac: false, isDesktop: false },
|
||||||
expectedKeys: {
|
expectedKeys: {
|
||||||
"toggle-left-sidebar": ["mod", "."],
|
"toggle-left-sidebar": ["mod", "B"],
|
||||||
|
"toggle-both-sidebars": ["mod", "."],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -540,44 +540,37 @@ describe("HostRuntimeController", () => {
|
|||||||
unsubscribe();
|
unsubscribe();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("logs typed reason codes for connection transitions", async () => {
|
it("preserves transport disconnect reasons on the runtime snapshot", async () => {
|
||||||
const infoSpy = vi.spyOn(console, "info").mockImplementation(() => undefined);
|
const host = makeHost({
|
||||||
try {
|
connections: [
|
||||||
const host = makeHost({
|
{
|
||||||
connections: [
|
id: "direct:lan:6767",
|
||||||
{
|
type: "directTcp",
|
||||||
id: "direct:lan:6767",
|
endpoint: "lan:6767",
|
||||||
type: "directTcp",
|
},
|
||||||
endpoint: "lan:6767",
|
],
|
||||||
},
|
});
|
||||||
],
|
const clients: FakeDaemonClient[] = [];
|
||||||
});
|
const controller = new HostRuntimeController({
|
||||||
const clients: FakeDaemonClient[] = [];
|
host,
|
||||||
const controller = new HostRuntimeController({
|
deps: makeDeps(
|
||||||
host,
|
{
|
||||||
deps: makeDeps(
|
"direct:lan:6767": 12,
|
||||||
{
|
},
|
||||||
"direct:lan:6767": 12,
|
clients,
|
||||||
},
|
),
|
||||||
clients,
|
});
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
await controller.start({ autoProbe: false });
|
await controller.start({ autoProbe: false });
|
||||||
clients[0]?.setConnectionState({
|
clients[0]?.setConnectionState({
|
||||||
status: "disconnected",
|
status: "disconnected",
|
||||||
reason: "transport closed",
|
reason: "transport closed",
|
||||||
});
|
});
|
||||||
|
|
||||||
const transitionPayloads = infoSpy.mock.calls
|
expect(controller.getSnapshot()).toMatchObject({
|
||||||
.filter((call) => call[0] === "[HostRuntimeTransition]")
|
connectionStatus: "error",
|
||||||
.map((call) => call[1] as { reasonCode?: string | null });
|
lastError: "transport closed",
|
||||||
const lastTransition = transitionPayloads[transitionPayloads.length - 1] ?? null;
|
});
|
||||||
|
|
||||||
expect(lastTransition?.reasonCode).toBe("transport_error");
|
|
||||||
} finally {
|
|
||||||
infoSpy.mockRestore();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("marks directory loading on first connection before any directory sync succeeds", async () => {
|
it("marks directory loading on first connection before any directory sync succeeds", async () => {
|
||||||
@@ -1189,6 +1182,7 @@ describe("HostRuntimeStore", () => {
|
|||||||
const staleAgent: Agent = {
|
const staleAgent: Agent = {
|
||||||
...stale,
|
...stale,
|
||||||
serverId: host.serverId,
|
serverId: host.serverId,
|
||||||
|
terminal: false,
|
||||||
createdAt: new Date(stale.createdAt),
|
createdAt: new Date(stale.createdAt),
|
||||||
updatedAt: new Date(stale.updatedAt),
|
updatedAt: new Date(stale.updatedAt),
|
||||||
lastUserMessageAt: null,
|
lastUserMessageAt: null,
|
||||||
|
|||||||
@@ -33,7 +33,12 @@ describe("provider-recency-store", () => {
|
|||||||
it("sorts used providers first and keeps unused providers in default order", () => {
|
it("sorts used providers first and keeps unused providers in default order", () => {
|
||||||
const sorted = sortProvidersByRecency(AGENT_PROVIDER_DEFINITIONS, ["codex"]);
|
const sorted = sortProvidersByRecency(AGENT_PROVIDER_DEFINITIONS, ["codex"]);
|
||||||
|
|
||||||
expect(sorted.map((provider) => provider.id)).toEqual(["codex", "claude", "opencode"]);
|
expect(sorted.map((provider) => provider.id)).toEqual([
|
||||||
|
"codex",
|
||||||
|
...AGENT_PROVIDER_DEFINITIONS.filter((provider) => provider.id !== "codex").map(
|
||||||
|
(provider) => provider.id,
|
||||||
|
),
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("moves the latest provider to the front without duplicating prior entries", () => {
|
it("moves the latest provider to the front without duplicating prior entries", () => {
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ function workspace(
|
|||||||
projectId: input.projectId ?? "project-1",
|
projectId: input.projectId ?? "project-1",
|
||||||
projectDisplayName: input.projectDisplayName ?? "Project 1",
|
projectDisplayName: input.projectDisplayName ?? "Project 1",
|
||||||
projectRootPath: input.projectRootPath ?? "/repo",
|
projectRootPath: input.projectRootPath ?? "/repo",
|
||||||
|
workspaceDirectory: input.workspaceDirectory ?? "/repo",
|
||||||
projectKind: input.projectKind ?? "git",
|
projectKind: input.projectKind ?? "git",
|
||||||
workspaceKind: input.workspaceKind ?? "local_checkout",
|
workspaceKind: input.workspaceKind ?? "checkout",
|
||||||
name: input.name ?? "main",
|
name: input.name ?? "main",
|
||||||
status: input.status ?? "done",
|
status: input.status ?? "done",
|
||||||
activityAt: input.activityAt ?? null,
|
activityAt: input.activityAt ?? null,
|
||||||
@@ -41,12 +42,13 @@ describe("normalizeWorkspaceDescriptor", () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
const workspace = normalizeWorkspaceDescriptor({
|
const workspace = normalizeWorkspaceDescriptor({
|
||||||
id: "/repo/main",
|
id: 1,
|
||||||
projectId: "project-1",
|
projectId: 1,
|
||||||
projectDisplayName: "Project 1",
|
projectDisplayName: "Project 1",
|
||||||
projectRootPath: "/repo",
|
projectRootPath: "/repo",
|
||||||
|
workspaceDirectory: "/repo",
|
||||||
projectKind: "git",
|
projectKind: "git",
|
||||||
workspaceKind: "local_checkout",
|
workspaceKind: "checkout",
|
||||||
name: "main",
|
name: "main",
|
||||||
status: "running",
|
status: "running",
|
||||||
activityAt: "not-a-date",
|
activityAt: "not-a-date",
|
||||||
@@ -69,12 +71,13 @@ describe("normalizeWorkspaceDescriptor", () => {
|
|||||||
|
|
||||||
it("defaults missing services to an empty array", () => {
|
it("defaults missing services to an empty array", () => {
|
||||||
const payload = {
|
const payload = {
|
||||||
id: "/repo/main",
|
id: 1,
|
||||||
projectId: "project-1",
|
projectId: 1,
|
||||||
projectDisplayName: "Project 1",
|
projectDisplayName: "Project 1",
|
||||||
projectRootPath: "/repo",
|
projectRootPath: "/repo",
|
||||||
|
workspaceDirectory: "/repo",
|
||||||
projectKind: "git",
|
projectKind: "git",
|
||||||
workspaceKind: "local_checkout",
|
workspaceKind: "checkout",
|
||||||
name: "main",
|
name: "main",
|
||||||
status: "done",
|
status: "done",
|
||||||
activityAt: null,
|
activityAt: null,
|
||||||
|
|||||||
@@ -1,5 +1,48 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
vi.mock("@xterm/addon-clipboard", () => ({
|
||||||
|
ClipboardAddon: class ClipboardAddon {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@xterm/addon-fit", () => ({
|
||||||
|
FitAddon: class FitAddon {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@xterm/addon-image", () => ({
|
||||||
|
ImageAddon: class ImageAddon {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@xterm/addon-ligatures/lib/addon-ligatures.mjs", () => ({
|
||||||
|
LigaturesAddon: class LigaturesAddon {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@xterm/addon-search", () => ({
|
||||||
|
SearchAddon: class SearchAddon {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@xterm/addon-unicode11", () => ({
|
||||||
|
Unicode11Addon: class Unicode11Addon {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@xterm/addon-web-links", () => ({
|
||||||
|
WebLinksAddon: class WebLinksAddon {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@xterm/addon-webgl", () => ({
|
||||||
|
WebglAddon: class WebglAddon {
|
||||||
|
onContextLoss(): void {}
|
||||||
|
dispose(): void {}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@xterm/xterm", () => ({
|
||||||
|
Terminal: class Terminal {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/utils/open-external-url", () => ({
|
||||||
|
openExternalUrl: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
import { TerminalEmulatorRuntime } from "./terminal-emulator-runtime";
|
import { TerminalEmulatorRuntime } from "./terminal-emulator-runtime";
|
||||||
|
|
||||||
type StubTerminal = {
|
type StubTerminal = {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { ClipboardAddon } from "@xterm/addon-clipboard";
|
import { ClipboardAddon } from "@xterm/addon-clipboard";
|
||||||
import { FitAddon } from "@xterm/addon-fit";
|
import { FitAddon } from "@xterm/addon-fit";
|
||||||
import { ImageAddon } from "@xterm/addon-image";
|
import { ImageAddon } from "@xterm/addon-image";
|
||||||
import { LigaturesAddon } from "@xterm/addon-ligatures";
|
|
||||||
import { SearchAddon } from "@xterm/addon-search";
|
import { SearchAddon } from "@xterm/addon-search";
|
||||||
import { Unicode11Addon } from "@xterm/addon-unicode11";
|
import { Unicode11Addon } from "@xterm/addon-unicode11";
|
||||||
import { WebLinksAddon } from "@xterm/addon-web-links";
|
import { WebLinksAddon } from "@xterm/addon-web-links";
|
||||||
import { WebglAddon } from "@xterm/addon-webgl";
|
import { WebglAddon } from "@xterm/addon-webgl";
|
||||||
|
import { LigaturesAddon } from "@xterm/addon-ligatures/lib/addon-ligatures.mjs";
|
||||||
import { Terminal, type ITheme } from "@xterm/xterm";
|
import { Terminal, type ITheme } from "@xterm/xterm";
|
||||||
import type { TerminalState } from "@server/shared/messages";
|
import type { TerminalState } from "@server/shared/messages";
|
||||||
import { openExternalUrl } from "@/utils/open-external-url";
|
import { openExternalUrl } from "@/utils/open-external-url";
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
declare module "@xterm/addon-ligatures/lib/addon-ligatures.mjs" {
|
||||||
|
export class LigaturesAddon {
|
||||||
|
constructor();
|
||||||
|
activate(terminal: unknown): void;
|
||||||
|
dispose(): void;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,6 +59,19 @@ vi.mock("./client-id", () => ({
|
|||||||
getOrCreateClientId: clientIdMock.getOrCreateClientId,
|
getOrCreateClientId: clientIdMock.getOrCreateClientId,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
vi.mock("@/desktop/daemon/desktop-daemon-transport", () => ({
|
||||||
|
createDesktopLocalDaemonTransportFactory: vi.fn(() => null),
|
||||||
|
buildLocalDaemonTransportUrl: vi.fn(
|
||||||
|
({
|
||||||
|
transportType,
|
||||||
|
transportPath,
|
||||||
|
}: {
|
||||||
|
transportType: "socket" | "pipe";
|
||||||
|
transportPath: string;
|
||||||
|
}) => `paseo+local://${transportType}?path=${encodeURIComponent(transportPath)}`,
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
describe("test-daemon-connection connectToDaemon", () => {
|
describe("test-daemon-connection connectToDaemon", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
daemonClientMock.createdConfigs.length = 0;
|
daemonClientMock.createdConfigs.length = 0;
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ describe("tool-call-display", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(display).toEqual({
|
expect(display).toEqual({
|
||||||
displayName: "Interacted with terminal",
|
displayName: "Terminal",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ describe("tool-call-display", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(display).toEqual({
|
expect(display).toEqual({
|
||||||
displayName: "Interacted with terminal",
|
displayName: "Terminal",
|
||||||
summary: "npm run test",
|
summary: "npm run test",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ function createWorkspace(
|
|||||||
status: input.status ?? "running",
|
status: input.status ?? "running",
|
||||||
activityAt: input.activityAt ?? null,
|
activityAt: input.activityAt ?? null,
|
||||||
diffStat: input.diffStat ?? null,
|
diffStat: input.diffStat ?? null,
|
||||||
|
services: input.services ?? [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
vi.mock("expo-router", () => ({
|
||||||
|
router: {
|
||||||
|
navigate: vi.fn(),
|
||||||
|
replace: vi.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
vi.mock("@react-native-async-storage/async-storage", () => {
|
vi.mock("@react-native-async-storage/async-storage", () => {
|
||||||
const storage = new Map<string, string>();
|
const storage = new Map<string, string>();
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ describe("voice runtime", () => {
|
|||||||
|
|
||||||
await runtime.startVoice("server-1", "agent-1");
|
await runtime.startVoice("server-1", "agent-1");
|
||||||
runtime.onTurnEvent("server-1", "agent-1", "turn_started");
|
runtime.onTurnEvent("server-1", "agent-1", "turn_started");
|
||||||
|
vi.mocked(engine.play).mockClear();
|
||||||
|
|
||||||
runtime.handleAudioOutput(
|
runtime.handleAudioOutput(
|
||||||
"server-1",
|
"server-1",
|
||||||
@@ -204,6 +205,8 @@ describe("voice runtime", () => {
|
|||||||
|
|
||||||
await runtime.startVoice("server-1", "agent-1");
|
await runtime.startVoice("server-1", "agent-1");
|
||||||
runtime.onTurnEvent("server-1", "agent-1", "turn_started");
|
runtime.onTurnEvent("server-1", "agent-1", "turn_started");
|
||||||
|
vi.mocked(engine.play).mockClear();
|
||||||
|
playResolvers.length = 0;
|
||||||
|
|
||||||
runtime.handleAudioOutput(
|
runtime.handleAudioOutput(
|
||||||
"server-1",
|
"server-1",
|
||||||
@@ -286,6 +289,8 @@ describe("voice runtime", () => {
|
|||||||
|
|
||||||
expect(runtime.getSnapshot().phase).toBe("waiting");
|
expect(runtime.getSnapshot().phase).toBe("waiting");
|
||||||
expect(engine.play).toHaveBeenCalledTimes(1);
|
expect(engine.play).toHaveBeenCalledTimes(1);
|
||||||
|
vi.mocked(engine.stop).mockClear();
|
||||||
|
vi.mocked(engine.clearQueue).mockClear();
|
||||||
|
|
||||||
runtime.handleCaptureVolume(REALTIME_VOICE_VAD_CONFIG.volumeThreshold + 0.05);
|
runtime.handleCaptureVolume(REALTIME_VOICE_VAD_CONFIG.volumeThreshold + 0.05);
|
||||||
runtime.handleCaptureVolume(0);
|
runtime.handleCaptureVolume(0);
|
||||||
@@ -325,6 +330,8 @@ describe("voice runtime", () => {
|
|||||||
await runtime.startVoice("server-1", "agent-1");
|
await runtime.startVoice("server-1", "agent-1");
|
||||||
runtime.onTurnEvent("server-1", "agent-1", "turn_started");
|
runtime.onTurnEvent("server-1", "agent-1", "turn_started");
|
||||||
runtime.onAssistantAudioStarted("server-1");
|
runtime.onAssistantAudioStarted("server-1");
|
||||||
|
vi.mocked(engine.stop).mockClear();
|
||||||
|
vi.mocked(engine.clearQueue).mockClear();
|
||||||
|
|
||||||
runtime.handleCaptureVolume(0.5);
|
runtime.handleCaptureVolume(0.5);
|
||||||
expect(runtime.getTelemetrySnapshot().isSpeaking).toBe(false);
|
expect(runtime.getTelemetrySnapshot().isSpeaking).toBe(false);
|
||||||
|
|||||||
@@ -540,6 +540,7 @@ export function createVoiceRuntime(deps: VoiceRuntimeDeps): VoiceRuntime {
|
|||||||
clearTimeout(cue.timeout);
|
clearTimeout(cue.timeout);
|
||||||
cue.timeout = null;
|
cue.timeout = null;
|
||||||
}
|
}
|
||||||
|
cue.playing = false;
|
||||||
if (hadActive) {
|
if (hadActive) {
|
||||||
deps.engine.stop();
|
deps.engine.stop();
|
||||||
deps.engine.clearQueue();
|
deps.engine.clearQueue();
|
||||||
@@ -1025,6 +1026,8 @@ export function createVoiceRuntime(deps: VoiceRuntimeDeps): VoiceRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.turnInProgress) {
|
if (state.turnInProgress) {
|
||||||
|
patchSnapshot((prev) => ({ ...prev, phase: "waiting" }));
|
||||||
|
reconcileCue();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1060,9 +1063,15 @@ export function createVoiceRuntime(deps: VoiceRuntimeDeps): VoiceRuntime {
|
|||||||
state.serverSpeechDetected = isSpeaking;
|
state.serverSpeechDetected = isSpeaking;
|
||||||
state.serverSpeechStartedAt = isSpeaking ? (state.serverSpeechStartedAt ?? Date.now()) : null;
|
state.serverSpeechStartedAt = isSpeaking ? (state.serverSpeechStartedAt ?? Date.now()) : null;
|
||||||
if (isSpeaking) {
|
if (isSpeaking) {
|
||||||
|
const shouldInterruptPlayback =
|
||||||
|
state.snapshot.phase === "playing" || playback.groups.size > 0;
|
||||||
|
const hadCue = cue.active || cue.timeout !== null || cue.playing;
|
||||||
resetPlaybackState();
|
resetPlaybackState();
|
||||||
deps.engine.stop();
|
stopCue();
|
||||||
deps.engine.clearQueue();
|
if (shouldInterruptPlayback && !hadCue) {
|
||||||
|
deps.engine.stop();
|
||||||
|
deps.engine.clearQueue();
|
||||||
|
}
|
||||||
getActiveSession()?.adapter.setAssistantAudioPlaying(false);
|
getActiveSession()?.adapter.setAssistantAudioPlaying(false);
|
||||||
}
|
}
|
||||||
patchTelemetry((prev) => ({
|
patchTelemetry((prev) => ({
|
||||||
|
|||||||
@@ -266,6 +266,8 @@ describe("DictationStreamManager (provider-agnostic provider)", () => {
|
|||||||
|
|
||||||
it("drops dangling uncommitted non-final transcripts when finishing after silence tail clear", async () => {
|
it("drops dangling uncommitted non-final transcripts when finishing after silence tail clear", async () => {
|
||||||
vi.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
|
const previousDebug = process.env.PASEO_DICTATION_DEBUG;
|
||||||
|
process.env.PASEO_DICTATION_DEBUG = "false";
|
||||||
try {
|
try {
|
||||||
const session = new FakeRealtimeSession();
|
const session = new FakeRealtimeSession();
|
||||||
const emitted: Array<{ type: string; payload: any }> = [];
|
const emitted: Array<{ type: string; payload: any }> = [];
|
||||||
@@ -299,6 +301,7 @@ describe("DictationStreamManager (provider-agnostic provider)", () => {
|
|||||||
await manager.handleFinish("d-clear-tail", 1);
|
await manager.handleFinish("d-clear-tail", 1);
|
||||||
await tick();
|
await tick();
|
||||||
await vi.advanceTimersByTimeAsync(5_100);
|
await vi.advanceTimersByTimeAsync(5_100);
|
||||||
|
await tick();
|
||||||
|
|
||||||
const final = emitted.find((msg) => msg.type === "dictation_stream_final");
|
const final = emitted.find((msg) => msg.type === "dictation_stream_final");
|
||||||
const error = emitted.find((msg) => msg.type === "dictation_stream_error");
|
const error = emitted.find((msg) => msg.type === "dictation_stream_error");
|
||||||
@@ -306,6 +309,7 @@ describe("DictationStreamManager (provider-agnostic provider)", () => {
|
|||||||
expect(error).toBeUndefined();
|
expect(error).toBeUndefined();
|
||||||
expect(final?.payload.text).toBe("hello");
|
expect(final?.payload.text).toBe("hello");
|
||||||
} finally {
|
} finally {
|
||||||
|
process.env.PASEO_DICTATION_DEBUG = previousDebug;
|
||||||
vi.useRealTimers();
|
vi.useRealTimers();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ async function closeServer(server: net.Server): Promise<void> {
|
|||||||
|
|
||||||
async function advancePoll(ms: number): Promise<void> {
|
async function advancePoll(ms: number): Promise<void> {
|
||||||
await vi.advanceTimersByTimeAsync(ms);
|
await vi.advanceTimersByTimeAsync(ms);
|
||||||
for (let i = 0; i < 5; i += 1) {
|
for (let i = 0; i < 20; i += 1) {
|
||||||
await scheduler.yield();
|
await scheduler.yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4857,7 +4857,7 @@ export class Session {
|
|||||||
services: this.serviceRouteStore
|
services: this.serviceRouteStore
|
||||||
? buildWorkspaceServicePayloads(
|
? buildWorkspaceServicePayloads(
|
||||||
this.serviceRouteStore,
|
this.serviceRouteStore,
|
||||||
workspace.workspaceId,
|
workspace.directory,
|
||||||
this.getDaemonTcpPort?.() ?? null,
|
this.getDaemonTcpPort?.() ?? null,
|
||||||
this.resolveServiceStatus ?? undefined,
|
this.resolveServiceStatus ?? undefined,
|
||||||
)
|
)
|
||||||
@@ -5574,6 +5574,7 @@ export class Session {
|
|||||||
private async createPaseoWorktreeInBackground(options: {
|
private async createPaseoWorktreeInBackground(options: {
|
||||||
requestCwd: string;
|
requestCwd: string;
|
||||||
repoRoot: string;
|
repoRoot: string;
|
||||||
|
workspaceId: number;
|
||||||
worktree: { branchName: string; worktreePath: string };
|
worktree: { branchName: string; worktreePath: string };
|
||||||
shouldBootstrap: boolean;
|
shouldBootstrap: boolean;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
|
|||||||
@@ -291,30 +291,31 @@ function createTempGitRepo(options?: {
|
|||||||
describe("workspace aggregation", () => {
|
describe("workspace aggregation", () => {
|
||||||
test("archive request emits agent_archived using the snapshot archive flow", async () => {
|
test("archive request emits agent_archived using the snapshot archive flow", async () => {
|
||||||
const emitted: Array<{ type: string; payload: any }> = [];
|
const emitted: Array<{ type: string; payload: any }> = [];
|
||||||
const archivedAt = "2026-04-01T00:00:00.000Z";
|
const archiveSnapshot = vi.fn(async (_agentId: string, archivedAt: string) => {
|
||||||
const archivedRecord = {
|
return {
|
||||||
id: "agent-1",
|
id: "agent-1",
|
||||||
provider: "codex",
|
|
||||||
cwd: "/tmp/repo",
|
|
||||||
createdAt: "2026-03-30T15:00:00.000Z",
|
|
||||||
updatedAt: archivedAt,
|
|
||||||
lastActivityAt: "2026-03-30T15:00:00.000Z",
|
|
||||||
lastUserMessageAt: null,
|
|
||||||
lastStatus: "idle" as const,
|
|
||||||
lastModeId: null,
|
|
||||||
runtimeInfo: null,
|
|
||||||
config: {
|
|
||||||
provider: "codex",
|
provider: "codex",
|
||||||
cwd: "/tmp/repo",
|
cwd: "/tmp/repo",
|
||||||
},
|
createdAt: "2026-03-30T15:00:00.000Z",
|
||||||
persistence: null,
|
updatedAt: archivedAt,
|
||||||
title: "Archive me",
|
lastActivityAt: "2026-03-30T15:00:00.000Z",
|
||||||
labels: {},
|
lastUserMessageAt: null,
|
||||||
requiresAttention: false,
|
lastStatus: "idle" as const,
|
||||||
attentionReason: null,
|
lastModeId: null,
|
||||||
attentionTimestamp: null,
|
runtimeInfo: null,
|
||||||
archivedAt,
|
config: {
|
||||||
};
|
provider: "codex",
|
||||||
|
cwd: "/tmp/repo",
|
||||||
|
},
|
||||||
|
persistence: null,
|
||||||
|
title: "Archive me",
|
||||||
|
labels: {},
|
||||||
|
requiresAttention: false,
|
||||||
|
attentionReason: null,
|
||||||
|
attentionTimestamp: null,
|
||||||
|
archivedAt,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const logger = {
|
const logger = {
|
||||||
child: () => logger,
|
child: () => logger,
|
||||||
@@ -337,7 +338,7 @@ describe("workspace aggregation", () => {
|
|||||||
subscribe: () => () => {},
|
subscribe: () => () => {},
|
||||||
listAgents: () => [],
|
listAgents: () => [],
|
||||||
getAgent: (agentId: string) => (agentId === "agent-1" ? { id: agentId } : null),
|
getAgent: (agentId: string) => (agentId === "agent-1" ? { id: agentId } : null),
|
||||||
archiveSnapshot: vi.fn(async () => archivedRecord),
|
archiveSnapshot,
|
||||||
closeAgent,
|
closeAgent,
|
||||||
clearAgentAttention: async () => {},
|
clearAgentAttention: async () => {},
|
||||||
} as any,
|
} as any,
|
||||||
@@ -391,18 +392,37 @@ describe("workspace aggregation", () => {
|
|||||||
|
|
||||||
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-1");
|
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-1");
|
||||||
expect(closeAgent).toHaveBeenCalledWith("agent-1");
|
expect(closeAgent).toHaveBeenCalledWith("agent-1");
|
||||||
expect(
|
const archivedPayload = emitted.find((message) => message.type === "agent_archived")?.payload;
|
||||||
emitted.find((message) => message.type === "agent_archived")?.payload,
|
expect(archivedPayload).toMatchObject({
|
||||||
).toMatchObject({
|
|
||||||
agentId: "agent-1",
|
agentId: "agent-1",
|
||||||
archivedAt,
|
archivedAt: expect.any(String),
|
||||||
requestId: "req-archive",
|
requestId: "req-archive",
|
||||||
});
|
});
|
||||||
|
expect(archiveSnapshot).toHaveBeenCalledWith("agent-1", archivedPayload.archivedAt);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("close_items_request archives agents and kills terminals in one batch", async () => {
|
test("close_items_request archives agents and kills terminals in one batch", async () => {
|
||||||
const emitted: Array<{ type: string; payload: any }> = [];
|
const emitted: Array<{ type: string; payload: any }> = [];
|
||||||
const archivedAt = "2026-04-01T00:00:00.000Z";
|
const archiveSnapshot = vi.fn(async (_agentId: string, archivedAt: string) => ({
|
||||||
|
id: "agent-1",
|
||||||
|
provider: "codex",
|
||||||
|
cwd: "/tmp/repo",
|
||||||
|
createdAt: "2026-03-01T12:00:00.000Z",
|
||||||
|
updatedAt: archivedAt,
|
||||||
|
lastActivityAt: "2026-03-01T12:00:00.000Z",
|
||||||
|
lastUserMessageAt: null,
|
||||||
|
lastStatus: "idle" as const,
|
||||||
|
lastModeId: null,
|
||||||
|
runtimeInfo: null,
|
||||||
|
config: null,
|
||||||
|
persistence: null,
|
||||||
|
title: null,
|
||||||
|
labels: {},
|
||||||
|
requiresAttention: false,
|
||||||
|
attentionReason: null,
|
||||||
|
attentionTimestamp: null,
|
||||||
|
archivedAt,
|
||||||
|
}));
|
||||||
const sessionLogger = {
|
const sessionLogger = {
|
||||||
child: () => sessionLogger,
|
child: () => sessionLogger,
|
||||||
trace: vi.fn(),
|
trace: vi.fn(),
|
||||||
@@ -423,26 +443,7 @@ describe("workspace aggregation", () => {
|
|||||||
subscribe: () => () => {},
|
subscribe: () => () => {},
|
||||||
listAgents: () => [],
|
listAgents: () => [],
|
||||||
getAgent: (agentId: string) => (agentId === "agent-1" ? { id: agentId } : null),
|
getAgent: (agentId: string) => (agentId === "agent-1" ? { id: agentId } : null),
|
||||||
archiveSnapshot: async () => ({
|
archiveSnapshot,
|
||||||
id: "agent-1",
|
|
||||||
provider: "codex",
|
|
||||||
cwd: "/tmp/repo",
|
|
||||||
createdAt: "2026-03-01T12:00:00.000Z",
|
|
||||||
updatedAt: archivedAt,
|
|
||||||
lastActivityAt: "2026-03-01T12:00:00.000Z",
|
|
||||||
lastUserMessageAt: null,
|
|
||||||
lastStatus: "idle" as const,
|
|
||||||
lastModeId: null,
|
|
||||||
runtimeInfo: null,
|
|
||||||
config: null,
|
|
||||||
persistence: null,
|
|
||||||
title: null,
|
|
||||||
labels: {},
|
|
||||||
requiresAttention: false,
|
|
||||||
attentionReason: null,
|
|
||||||
attentionTimestamp: null,
|
|
||||||
archivedAt,
|
|
||||||
}),
|
|
||||||
closeAgent: async () => undefined,
|
closeAgent: async () => undefined,
|
||||||
clearAgentAttention: async () => {},
|
clearAgentAttention: async () => {},
|
||||||
} as any,
|
} as any,
|
||||||
@@ -504,13 +505,13 @@ describe("workspace aggregation", () => {
|
|||||||
|
|
||||||
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-1");
|
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-1");
|
||||||
expect(session.terminalManager.killTerminal).toHaveBeenCalledWith("term-1");
|
expect(session.terminalManager.killTerminal).toHaveBeenCalledWith("term-1");
|
||||||
expect(
|
const closePayload = emitted.find((message) => message.type === "close_items_response")?.payload;
|
||||||
emitted.find((message) => message.type === "close_items_response")?.payload,
|
expect(closePayload).toEqual({
|
||||||
).toEqual({
|
agents: [{ agentId: "agent-1", archivedAt: expect.any(String) }],
|
||||||
agents: [{ agentId: "agent-1", archivedAt }],
|
|
||||||
terminals: [{ terminalId: "term-1", success: true }],
|
terminals: [{ terminalId: "term-1", success: true }],
|
||||||
requestId: "req-close-items",
|
requestId: "req-close-items",
|
||||||
});
|
});
|
||||||
|
expect(archiveSnapshot).toHaveBeenCalledWith("agent-1", closePayload.agents[0].archivedAt);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("close_items_request continues after an archive failure", async () => {
|
test("close_items_request continues after an archive failure", async () => {
|
||||||
@@ -523,7 +524,31 @@ describe("workspace aggregation", () => {
|
|||||||
warn: vi.fn(),
|
warn: vi.fn(),
|
||||||
error: vi.fn(),
|
error: vi.fn(),
|
||||||
};
|
};
|
||||||
const archivedAt = "2026-04-01T00:00:00.000Z";
|
const archiveSnapshot = vi.fn(async (agentId: string, archivedAt: string) => {
|
||||||
|
if (agentId === "agent-bad") {
|
||||||
|
throw new Error("archive failed");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: "agent-good",
|
||||||
|
provider: "codex",
|
||||||
|
cwd: "/tmp/repo",
|
||||||
|
createdAt: "2026-03-01T12:00:00.000Z",
|
||||||
|
updatedAt: archivedAt,
|
||||||
|
lastActivityAt: "2026-03-01T12:00:00.000Z",
|
||||||
|
lastUserMessageAt: null,
|
||||||
|
lastStatus: "idle" as const,
|
||||||
|
lastModeId: null,
|
||||||
|
runtimeInfo: null,
|
||||||
|
config: null,
|
||||||
|
persistence: null,
|
||||||
|
title: null,
|
||||||
|
labels: {},
|
||||||
|
requiresAttention: false,
|
||||||
|
attentionReason: null,
|
||||||
|
attentionTimestamp: null,
|
||||||
|
archivedAt,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const session = new Session({
|
const session = new Session({
|
||||||
clientId: "test-client",
|
clientId: "test-client",
|
||||||
@@ -537,31 +562,7 @@ describe("workspace aggregation", () => {
|
|||||||
listAgents: () => [],
|
listAgents: () => [],
|
||||||
getAgent: (agentId: string) =>
|
getAgent: (agentId: string) =>
|
||||||
agentId === "agent-bad" || agentId === "agent-good" ? { id: agentId } : null,
|
agentId === "agent-bad" || agentId === "agent-good" ? { id: agentId } : null,
|
||||||
archiveSnapshot: async (agentId: string) => {
|
archiveSnapshot,
|
||||||
if (agentId === "agent-bad") {
|
|
||||||
throw new Error("archive failed");
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
id: "agent-good",
|
|
||||||
provider: "codex",
|
|
||||||
cwd: "/tmp/repo",
|
|
||||||
createdAt: "2026-03-01T12:00:00.000Z",
|
|
||||||
updatedAt: archivedAt,
|
|
||||||
lastActivityAt: "2026-03-01T12:00:00.000Z",
|
|
||||||
lastUserMessageAt: null,
|
|
||||||
lastStatus: "idle" as const,
|
|
||||||
lastModeId: null,
|
|
||||||
runtimeInfo: null,
|
|
||||||
config: null,
|
|
||||||
persistence: null,
|
|
||||||
title: null,
|
|
||||||
labels: {},
|
|
||||||
requiresAttention: false,
|
|
||||||
attentionReason: null,
|
|
||||||
attentionTimestamp: null,
|
|
||||||
archivedAt,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
closeAgent: async () => undefined,
|
closeAgent: async () => undefined,
|
||||||
clearAgentAttention: async () => {},
|
clearAgentAttention: async () => {},
|
||||||
} as any,
|
} as any,
|
||||||
@@ -624,13 +625,13 @@ describe("workspace aggregation", () => {
|
|||||||
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-bad");
|
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-bad");
|
||||||
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-good");
|
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-good");
|
||||||
expect(session.terminalManager.killTerminal).toHaveBeenCalledWith("term-1");
|
expect(session.terminalManager.killTerminal).toHaveBeenCalledWith("term-1");
|
||||||
expect(
|
const closePayload = emitted.find((message) => message.type === "close_items_response")?.payload;
|
||||||
emitted.find((message) => message.type === "close_items_response")?.payload,
|
expect(closePayload).toEqual({
|
||||||
).toEqual({
|
agents: [{ agentId: "agent-good", archivedAt: expect.any(String) }],
|
||||||
agents: [{ agentId: "agent-good", archivedAt }],
|
|
||||||
terminals: [{ terminalId: "term-1", success: true }],
|
terminals: [{ terminalId: "term-1", success: true }],
|
||||||
requestId: "req-close-best-effort",
|
requestId: "req-close-best-effort",
|
||||||
});
|
});
|
||||||
|
expect(archiveSnapshot).toHaveBeenCalledWith("agent-good", closePayload.agents[0].archivedAt);
|
||||||
expect(sessionLogger.warn).toHaveBeenCalled();
|
expect(sessionLogger.warn).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -167,15 +167,16 @@ function createServer(options?: { speechReadiness?: SpeechReadinessSnapshot | nu
|
|||||||
"/tmp/paseo-test",
|
"/tmp/paseo-test",
|
||||||
async () => ({}) as any,
|
async () => ({}) as any,
|
||||||
{ allowedOrigins: new Set() },
|
{ allowedOrigins: new Set() },
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
speechReadiness
|
speechReadiness
|
||||||
? {
|
? {
|
||||||
getSpeechReadiness: () => speechReadiness,
|
getReadiness: () => speechReadiness,
|
||||||
|
onReadinessChange: vi.fn(() => () => {}),
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
undefined,
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
TEST_DAEMON_VERSION,
|
TEST_DAEMON_VERSION,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
|
|||||||
@@ -237,6 +237,7 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
const logger = createLogger();
|
const logger = createLogger();
|
||||||
const emitWorkspaceUpdateForCwd = vi.fn(async () => {});
|
const emitWorkspaceUpdateForCwd = vi.fn(async () => {});
|
||||||
const archiveWorkspaceRecord = vi.fn(async () => {});
|
const archiveWorkspaceRecord = vi.fn(async () => {});
|
||||||
|
const workspaceId = 101;
|
||||||
|
|
||||||
await createPaseoWorktreeInBackground(
|
await createPaseoWorktreeInBackground(
|
||||||
{
|
{
|
||||||
@@ -253,6 +254,7 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
{
|
{
|
||||||
requestCwd: repoDir,
|
requestCwd: repoDir,
|
||||||
repoRoot: repoDir,
|
repoRoot: repoDir,
|
||||||
|
workspaceId,
|
||||||
worktree: {
|
worktree: {
|
||||||
branchName: "broken-feature",
|
branchName: "broken-feature",
|
||||||
worktreePath,
|
worktreePath,
|
||||||
@@ -275,7 +277,7 @@ describe("createPaseoWorktreeInBackground", () => {
|
|||||||
status: "failed",
|
status: "failed",
|
||||||
error: expect.stringContaining("Failed to parse paseo.json"),
|
error: expect.stringContaining("Failed to parse paseo.json"),
|
||||||
});
|
});
|
||||||
expect(archiveWorkspaceRecord).toHaveBeenCalledWith(worktreePath);
|
expect(archiveWorkspaceRecord).toHaveBeenCalledWith(workspaceId);
|
||||||
expect(emitWorkspaceUpdateForCwd).toHaveBeenCalledWith(worktreePath);
|
expect(emitWorkspaceUpdateForCwd).toHaveBeenCalledWith(worktreePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ type CreatePaseoWorktreeInBackgroundDependencies = {
|
|||||||
emit: EmitSessionMessage;
|
emit: EmitSessionMessage;
|
||||||
sessionLogger: Logger;
|
sessionLogger: Logger;
|
||||||
terminalManager: TerminalManager | null;
|
terminalManager: TerminalManager | null;
|
||||||
archiveWorkspaceRecord: (workspaceId: string) => Promise<void>;
|
archiveWorkspaceRecord: (workspaceId: number) => Promise<void>;
|
||||||
serviceRouteStore: ServiceRouteStore | null;
|
serviceRouteStore: ServiceRouteStore | null;
|
||||||
daemonPort?: number | null;
|
daemonPort?: number | null;
|
||||||
};
|
};
|
||||||
@@ -134,6 +134,7 @@ type HandleCreatePaseoWorktreeRequestDependencies = {
|
|||||||
createPaseoWorktreeInBackground: (options: {
|
createPaseoWorktreeInBackground: (options: {
|
||||||
requestCwd: string;
|
requestCwd: string;
|
||||||
repoRoot: string;
|
repoRoot: string;
|
||||||
|
workspaceId: number;
|
||||||
worktree: WorktreeConfig;
|
worktree: WorktreeConfig;
|
||||||
shouldBootstrap: boolean;
|
shouldBootstrap: boolean;
|
||||||
}) => Promise<void>;
|
}) => Promise<void>;
|
||||||
@@ -625,6 +626,7 @@ export async function handleCreatePaseoWorktreeRequest(
|
|||||||
void dependencies.createPaseoWorktreeInBackground({
|
void dependencies.createPaseoWorktreeInBackground({
|
||||||
requestCwd: request.cwd,
|
requestCwd: request.cwd,
|
||||||
repoRoot,
|
repoRoot,
|
||||||
|
workspaceId: workspace.id,
|
||||||
worktree: createdWorktree.worktree,
|
worktree: createdWorktree.worktree,
|
||||||
shouldBootstrap: createdWorktree.shouldBootstrap,
|
shouldBootstrap: createdWorktree.shouldBootstrap,
|
||||||
});
|
});
|
||||||
@@ -666,6 +668,7 @@ export async function createPaseoWorktreeInBackground(
|
|||||||
options: {
|
options: {
|
||||||
requestCwd: string;
|
requestCwd: string;
|
||||||
repoRoot: string;
|
repoRoot: string;
|
||||||
|
workspaceId: number;
|
||||||
worktree: WorktreeConfig;
|
worktree: WorktreeConfig;
|
||||||
shouldBootstrap: boolean;
|
shouldBootstrap: boolean;
|
||||||
},
|
},
|
||||||
@@ -741,7 +744,7 @@ export async function createPaseoWorktreeInBackground(
|
|||||||
emitSetupProgress("failed", message);
|
emitSetupProgress("failed", message);
|
||||||
|
|
||||||
if (!setupStarted) {
|
if (!setupStarted) {
|
||||||
await dependencies.archiveWorkspaceRecord(normalizePersistedWorkspaceId(worktree.worktreePath));
|
await dependencies.archiveWorkspaceRecord(options.workspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies.sessionLogger.error(
|
dependencies.sessionLogger.error(
|
||||||
|
|||||||
@@ -58,12 +58,13 @@ describe("workspace message schemas", () => {
|
|||||||
payload: {
|
payload: {
|
||||||
kind: "upsert",
|
kind: "upsert",
|
||||||
workspace: {
|
workspace: {
|
||||||
id: "/repo",
|
id: 1,
|
||||||
projectId: "/repo",
|
projectId: 1,
|
||||||
projectDisplayName: "repo",
|
projectDisplayName: "repo",
|
||||||
projectRootPath: "/repo",
|
projectRootPath: "/repo",
|
||||||
projectKind: "non_git",
|
workspaceDirectory: "/repo",
|
||||||
workspaceKind: "directory",
|
projectKind: "directory",
|
||||||
|
workspaceKind: "checkout",
|
||||||
name: "repo",
|
name: "repo",
|
||||||
status: "done",
|
status: "done",
|
||||||
activityAt: null,
|
activityAt: null,
|
||||||
|
|||||||
Reference in New Issue
Block a user