@tt-a1i/hive 1.1.5 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +101 -0
- package/README.en.md +33 -0
- package/README.md +16 -0
- package/dist/src/cli/hive-update.d.ts +15 -0
- package/dist/src/cli/hive-update.js +81 -0
- package/dist/src/cli/hive.js +21 -5
- package/dist/src/server/agent-run-store.d.ts +1 -1
- package/dist/src/server/app.d.ts +3 -1
- package/dist/src/server/app.js +14 -1
- package/dist/src/server/open-target-commands.d.ts +53 -0
- package/dist/src/server/open-target-commands.js +176 -0
- package/dist/src/server/package-version.d.ts +15 -0
- package/dist/src/server/package-version.js +15 -0
- package/dist/src/server/route-types.d.ts +6 -0
- package/dist/src/server/routes-open-workspace.d.ts +2 -0
- package/dist/src/server/routes-open-workspace.js +47 -0
- package/dist/src/server/routes.js +2 -0
- package/dist/src/server/version-service.js +4 -1
- package/dist/src/server/workspace-shell-runtime.js +34 -8
- package/dist/src/shared/open-targets.d.ts +20 -0
- package/dist/src/shared/open-targets.js +36 -0
- package/package.json +3 -3
- package/web/dist/assets/finder-C4Jmsb0B.png +0 -0
- package/web/dist/assets/ghostty-D-Js4rdm.png +0 -0
- package/web/dist/assets/index-CSEt-Qiy.js +66 -0
- package/web/dist/assets/index-RsXXnrVz.css +1 -0
- package/web/dist/assets/zed-C5BQT8X3.png +0 -0
- package/web/dist/icons/apple-touch-icon-180.png +0 -0
- package/web/dist/icons/icon-192.png +0 -0
- package/web/dist/icons/icon-32.png +0 -0
- package/web/dist/icons/icon-512-maskable.png +0 -0
- package/web/dist/icons/icon-512.png +0 -0
- package/web/dist/index.html +11 -3
- package/web/dist/manifest.webmanifest +60 -0
- package/web/dist/screenshots/wide-overview.png +0 -0
- package/web/dist/sw.js +99 -0
- package/web/dist/assets/index-BHCSrZ_0.js +0 -66
- package/web/dist/assets/index-BUjVAMN8.css +0 -1
|
@@ -2,6 +2,21 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
export const PACKAGE_NAME = '@tt-a1i/hive';
|
|
5
|
+
/**
|
|
6
|
+
* Canonical argv for the upgrade command. Sharing one source between the
|
|
7
|
+
* server's install hint (`version-service.ts`) and the CLI upgrade path
|
|
8
|
+
* (`hive-update.ts`) keeps the two from drifting if the package name ever
|
|
9
|
+
* moves.
|
|
10
|
+
*/
|
|
11
|
+
export const INSTALL_COMMAND_ARGS = ['install', '-g', `${PACKAGE_NAME}@latest`];
|
|
12
|
+
export const INSTALL_COMMAND_DISPLAY = `npm ${INSTALL_COMMAND_ARGS.join(' ')}`;
|
|
13
|
+
/**
|
|
14
|
+
* Windows ships npm as `npm.cmd` (a batch shim); Node's `child_process.spawn`
|
|
15
|
+
* will not resolve `.cmd` without `shell: true` or an explicit suffix, so the
|
|
16
|
+
* default `'npm'` produces ENOENT on Windows. Use this helper any time you
|
|
17
|
+
* spawn npm directly.
|
|
18
|
+
*/
|
|
19
|
+
export const getNpmCommand = (platform = process.platform) => platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
5
20
|
export const readPackageVersion = () => {
|
|
6
21
|
let dir = dirname(fileURLToPath(import.meta.url));
|
|
7
22
|
for (let depth = 0; depth < 8; depth += 1) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
2
|
import type { WorkerRole } from '../shared/types.js';
|
|
3
3
|
import type { PickFolderResponse } from './fs-pick-folder.js';
|
|
4
|
+
import type { OpenCommandResult, OpenWorkspaceInput as OpenWorkspaceServiceInput } from './open-target-commands.js';
|
|
4
5
|
import type { RuntimeStore } from './runtime-store.js';
|
|
5
6
|
import type { TasksFileService } from './tasks-file.js';
|
|
6
7
|
import type { VersionService } from './version-service.js';
|
|
@@ -48,12 +49,17 @@ export interface ConfigureAgentLaunchBody {
|
|
|
48
49
|
args?: string[];
|
|
49
50
|
command_preset_id?: string | null;
|
|
50
51
|
}
|
|
52
|
+
export interface OpenWorkspaceBody {
|
|
53
|
+
target_id: string;
|
|
54
|
+
}
|
|
55
|
+
export type OpenWorkspaceService = (input: OpenWorkspaceServiceInput) => Promise<OpenCommandResult>;
|
|
51
56
|
export interface RouteContext {
|
|
52
57
|
request: IncomingMessage;
|
|
53
58
|
response: ServerResponse;
|
|
54
59
|
store: RuntimeStore;
|
|
55
60
|
tasksFileService: TasksFileService;
|
|
56
61
|
pickFolderService: () => Promise<PickFolderResponse>;
|
|
62
|
+
openWorkspaceService: OpenWorkspaceService;
|
|
57
63
|
versionService: VersionService;
|
|
58
64
|
params: Record<string, string>;
|
|
59
65
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isOpenTargetId } from './open-target-commands.js';
|
|
2
|
+
import { getRequiredParam, readJsonBody, route, sendJson } from './route-helpers.js';
|
|
3
|
+
import { requireUiTokenFromRequest } from './ui-auth-helpers.js';
|
|
4
|
+
export const openWorkspaceRoutes = [
|
|
5
|
+
route('POST', '/api/workspaces/:workspaceId/open', async ({ openWorkspaceService, params, request, response, store }) => {
|
|
6
|
+
const workspaceId = getRequiredParam(response, params, 'workspaceId', 'Workspace id is required');
|
|
7
|
+
if (!workspaceId)
|
|
8
|
+
return;
|
|
9
|
+
requireUiTokenFromRequest(request, store.validateUiToken);
|
|
10
|
+
const body = await readJsonBody(request);
|
|
11
|
+
if (!isOpenTargetId(body.target_id)) {
|
|
12
|
+
sendJson(response, 400, { error: 'Unknown open target', target_id: body.target_id });
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
// store.getWorkspaceSnapshot throws raw Error("Workspace not found: ...")
|
|
16
|
+
// for missing workspaces — translate that to 404 here rather than letting
|
|
17
|
+
// app.ts catch it as a generic 500.
|
|
18
|
+
let workspacePath;
|
|
19
|
+
try {
|
|
20
|
+
workspacePath = store.getWorkspaceSnapshot(workspaceId).summary.path;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
sendJson(response, 404, { error: 'Workspace not found' });
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const result = await openWorkspaceService({
|
|
27
|
+
path: workspacePath,
|
|
28
|
+
targetId: body.target_id,
|
|
29
|
+
});
|
|
30
|
+
if (result.ok) {
|
|
31
|
+
sendJson(response, 200, {
|
|
32
|
+
ok: true,
|
|
33
|
+
effective_target_id: result.effectiveTargetId,
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Drop stderr from the wire response — defense in depth. The frontend
|
|
38
|
+
// never renders raw stderr (toast text is localized via error_code), so
|
|
39
|
+
// there's no reason to ship the OS-level message to the browser where
|
|
40
|
+
// it would live in the devtools network log.
|
|
41
|
+
sendJson(response, 502, {
|
|
42
|
+
ok: false,
|
|
43
|
+
effective_target_id: result.effectiveTargetId,
|
|
44
|
+
error_code: result.errorCode,
|
|
45
|
+
});
|
|
46
|
+
}),
|
|
47
|
+
];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { matchPath } from './route-helpers.js';
|
|
2
2
|
import { dispatchRoutes } from './routes-dispatches.js';
|
|
3
3
|
import { fsRoutes } from './routes-fs.js';
|
|
4
|
+
import { openWorkspaceRoutes } from './routes-open-workspace.js';
|
|
4
5
|
import { runtimeRoutes } from './routes-runtime.js';
|
|
5
6
|
import { settingsRoutes } from './routes-settings.js';
|
|
6
7
|
import { taskRoutes } from './routes-tasks.js';
|
|
@@ -10,6 +11,7 @@ import { versionRoutes } from './routes-version.js';
|
|
|
10
11
|
import { workspaceRoutes } from './routes-workspaces.js';
|
|
11
12
|
const routes = [
|
|
12
13
|
...workspaceRoutes,
|
|
14
|
+
...openWorkspaceRoutes,
|
|
13
15
|
...dispatchRoutes,
|
|
14
16
|
...versionRoutes,
|
|
15
17
|
...uiRoutes,
|
|
@@ -27,7 +27,10 @@ export const compareVersions = (left, right) => {
|
|
|
27
27
|
};
|
|
28
28
|
const buildVersionInfo = (currentVersion, latestVersion) => ({
|
|
29
29
|
current_version: currentVersion,
|
|
30
|
-
|
|
30
|
+
// Show `hive update` as the primary upgrade path now that the subcommand
|
|
31
|
+
// exists; it prints the npm fallback if its own spawn fails, so users
|
|
32
|
+
// running on Windows / Linux without a working npm in PATH still recover.
|
|
33
|
+
install_hint: 'hive update',
|
|
31
34
|
latest_version: latestVersion,
|
|
32
35
|
package_name: PACKAGE_NAME,
|
|
33
36
|
release_url: `https://www.npmjs.com/package/${PACKAGE_NAME}/v/${latestVersion}`,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
2
|
const WORKSPACE_SHELL_SUFFIX = ':shell';
|
|
3
|
+
const WORKSPACE_SHELL_LABEL = 'Shell';
|
|
4
|
+
const EXITED_SHELL_RETENTION_MS = 5000;
|
|
3
5
|
export const getWorkspaceShellAgentId = (workspaceId) => `${workspaceId}${WORKSPACE_SHELL_SUFFIX}`;
|
|
4
6
|
export const isWorkspaceShellAgentId = (agentId) => agentId.endsWith(WORKSPACE_SHELL_SUFFIX);
|
|
5
7
|
const shouldUseLoginShell = (command) => {
|
|
@@ -20,10 +22,10 @@ export const resolveWorkspaceShellLaunch = (env = process.env, platform = proces
|
|
|
20
22
|
};
|
|
21
23
|
export const createWorkspaceShellRuntime = (agentManager) => {
|
|
22
24
|
const labelsByRunId = new Map();
|
|
23
|
-
const nextShellNumberByWorkspaceId = new Map();
|
|
24
25
|
const workspaceIdsByRunId = new Map();
|
|
25
26
|
const runIdsByWorkspaceId = new Map();
|
|
26
27
|
const startedAtByRunId = new Map();
|
|
28
|
+
const exitCleanupTimersByRunId = new Map();
|
|
27
29
|
const requireManager = () => {
|
|
28
30
|
if (!agentManager)
|
|
29
31
|
throw new Error('Agent manager is required for workspace shell terminals');
|
|
@@ -43,6 +45,10 @@ export const createWorkspaceShellRuntime = (agentManager) => {
|
|
|
43
45
|
}
|
|
44
46
|
};
|
|
45
47
|
const detachRun = (runId) => {
|
|
48
|
+
const exitCleanupTimer = exitCleanupTimersByRunId.get(runId);
|
|
49
|
+
if (exitCleanupTimer)
|
|
50
|
+
clearTimeout(exitCleanupTimer);
|
|
51
|
+
exitCleanupTimersByRunId.delete(runId);
|
|
46
52
|
const workspaceId = workspaceIdsByRunId.get(runId);
|
|
47
53
|
if (workspaceId) {
|
|
48
54
|
const retained = (runIdsByWorkspaceId.get(workspaceId) ?? []).filter((id) => id !== runId);
|
|
@@ -61,11 +67,27 @@ export const createWorkspaceShellRuntime = (agentManager) => {
|
|
|
61
67
|
startedAtByRunId.set(runId, startedAt);
|
|
62
68
|
runIdsByWorkspaceId.set(workspaceId, [...(runIdsByWorkspaceId.get(workspaceId) ?? []), runId]);
|
|
63
69
|
};
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
const forgetShellRun = (runId) => {
|
|
71
|
+
detachRun(runId);
|
|
72
|
+
try {
|
|
73
|
+
requireManager().removeRun(runId);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// The PTY manager may have already dropped the run.
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const handleShellExit = (runId) => {
|
|
80
|
+
if (!hasRun(runId) || exitCleanupTimersByRunId.has(runId))
|
|
81
|
+
return;
|
|
82
|
+
const timer = setTimeout(() => {
|
|
83
|
+
exitCleanupTimersByRunId.delete(runId);
|
|
84
|
+
if (hasRun(runId))
|
|
85
|
+
forgetShellRun(runId);
|
|
86
|
+
}, EXITED_SHELL_RETENTION_MS);
|
|
87
|
+
timer.unref?.();
|
|
88
|
+
exitCleanupTimersByRunId.set(runId, timer);
|
|
68
89
|
};
|
|
90
|
+
const isListedRun = (run) => run.status === 'starting' || run.status === 'running';
|
|
69
91
|
const stopPtyRun = (runId) => {
|
|
70
92
|
requireManager().stopRun(runId);
|
|
71
93
|
};
|
|
@@ -92,7 +114,9 @@ export const createWorkspaceShellRuntime = (agentManager) => {
|
|
|
92
114
|
workspaceIdsByRunId.clear();
|
|
93
115
|
startedAtByRunId.clear();
|
|
94
116
|
labelsByRunId.clear();
|
|
95
|
-
|
|
117
|
+
for (const timer of exitCleanupTimersByRunId.values())
|
|
118
|
+
clearTimeout(timer);
|
|
119
|
+
exitCleanupTimersByRunId.clear();
|
|
96
120
|
},
|
|
97
121
|
closeRun(workspaceId, runId) {
|
|
98
122
|
if (workspaceIdsByRunId.get(runId) !== workspaceId)
|
|
@@ -110,7 +134,6 @@ export const createWorkspaceShellRuntime = (agentManager) => {
|
|
|
110
134
|
}
|
|
111
135
|
}
|
|
112
136
|
runIdsByWorkspaceId.delete(workspaceId);
|
|
113
|
-
nextShellNumberByWorkspaceId.delete(workspaceId);
|
|
114
137
|
},
|
|
115
138
|
getLiveRun(runId) {
|
|
116
139
|
if (!hasRun(runId))
|
|
@@ -122,6 +145,8 @@ export const createWorkspaceShellRuntime = (agentManager) => {
|
|
|
122
145
|
return (runIdsByWorkspaceId.get(workspaceId) ?? []).flatMap((runId) => {
|
|
123
146
|
try {
|
|
124
147
|
const run = toLiveRun(runId);
|
|
148
|
+
if (!isListedRun(run))
|
|
149
|
+
return [];
|
|
125
150
|
return [
|
|
126
151
|
{
|
|
127
152
|
agent_id: getWorkspaceShellAgentId(workspaceId),
|
|
@@ -163,8 +188,9 @@ export const createWorkspaceShellRuntime = (agentManager) => {
|
|
|
163
188
|
TERM: 'xterm-256color',
|
|
164
189
|
TERM_PROGRAM: 'hive-shell',
|
|
165
190
|
},
|
|
191
|
+
onExit: ({ runId }) => handleShellExit(runId),
|
|
166
192
|
});
|
|
167
|
-
attachRun(workspace.id, run.runId,
|
|
193
|
+
attachRun(workspace.id, run.runId, WORKSPACE_SHELL_LABEL, startedAt);
|
|
168
194
|
return { ...run, startedAt };
|
|
169
195
|
},
|
|
170
196
|
stopRun(runId) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-cutting types for the "Open workspace in editor/app" feature.
|
|
3
|
+
* Both the server (command construction in `src/server/open-target-commands.ts`)
|
|
4
|
+
* and the web client (button + preference store in `web/src/workspace/open-targets.ts`)
|
|
5
|
+
* pull the union and platform whitelist from here so they cannot drift.
|
|
6
|
+
*/
|
|
7
|
+
export type OpenTargetId = 'vscode' | 'vscode-insiders' | 'cursor' | 'finder' | 'terminal' | 'ghostty' | 'zed';
|
|
8
|
+
export type OpenTargetPlatform = 'mac' | 'windows' | 'linux' | 'other';
|
|
9
|
+
export declare const OPEN_TARGET_IDS_BY_PLATFORM: Record<OpenTargetPlatform, readonly OpenTargetId[]>;
|
|
10
|
+
export declare const isOpenTargetId: (value: unknown) => value is OpenTargetId;
|
|
11
|
+
export declare const isOpenTargetSupported: (targetId: OpenTargetId, platform: OpenTargetPlatform) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* The id the server will actually attempt to launch. If the user's saved
|
|
14
|
+
* preference is unsupported on the current platform (e.g. they picked iTerm2
|
|
15
|
+
* on a Mac, then opened Hive on Windows), fall back to the platform default
|
|
16
|
+
* rather than erroring out — a stale preference shouldn't break the button.
|
|
17
|
+
*/
|
|
18
|
+
export declare const getEffectiveOpenTargetId: (targetId: OpenTargetId, platform: OpenTargetPlatform) => OpenTargetId;
|
|
19
|
+
export declare const getDefaultOpenTargetIdForPlatform: (platform: OpenTargetPlatform) => OpenTargetId;
|
|
20
|
+
export type OpenWorkspaceErrorCode = 'invalid-path' | 'invalid-target' | 'app-not-installed' | 'command-not-in-path' | 'unknown';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-cutting types for the "Open workspace in editor/app" feature.
|
|
3
|
+
* Both the server (command construction in `src/server/open-target-commands.ts`)
|
|
4
|
+
* and the web client (button + preference store in `web/src/workspace/open-targets.ts`)
|
|
5
|
+
* pull the union and platform whitelist from here so they cannot drift.
|
|
6
|
+
*/
|
|
7
|
+
// Note: there is no `cursor-insiders` here. Cursor stopped shipping a separate
|
|
8
|
+
// Nightly bundle / `cursor-nightly` binary in March 2024; the pre-release
|
|
9
|
+
// channel is now an in-app toggle on the regular Cursor.app.
|
|
10
|
+
//
|
|
11
|
+
// IntelliJ IDEA, Windsurf, and iTerm2 were intentionally dropped after 1.3.0:
|
|
12
|
+
// IntelliJ users typically launch from JetBrains Toolbox rather than a folder
|
|
13
|
+
// picker; Windsurf overlaps with Cursor/VS Code; iTerm2 overlaps with the
|
|
14
|
+
// built-in macOS Terminal entry.
|
|
15
|
+
export const OPEN_TARGET_IDS_BY_PLATFORM = {
|
|
16
|
+
mac: ['vscode', 'vscode-insiders', 'cursor', 'finder', 'terminal', 'ghostty', 'zed'],
|
|
17
|
+
windows: ['vscode', 'vscode-insiders', 'cursor', 'finder', 'zed'],
|
|
18
|
+
linux: ['vscode', 'vscode-insiders', 'cursor', 'finder', 'zed'],
|
|
19
|
+
other: ['vscode', 'vscode-insiders', 'finder'],
|
|
20
|
+
};
|
|
21
|
+
const ALL_TARGET_IDS = new Set(OPEN_TARGET_IDS_BY_PLATFORM.mac);
|
|
22
|
+
export const isOpenTargetId = (value) => typeof value === 'string' && ALL_TARGET_IDS.has(value);
|
|
23
|
+
export const isOpenTargetSupported = (targetId, platform) => OPEN_TARGET_IDS_BY_PLATFORM[platform].includes(targetId);
|
|
24
|
+
/**
|
|
25
|
+
* The id the server will actually attempt to launch. If the user's saved
|
|
26
|
+
* preference is unsupported on the current platform (e.g. they picked iTerm2
|
|
27
|
+
* on a Mac, then opened Hive on Windows), fall back to the platform default
|
|
28
|
+
* rather than erroring out — a stale preference shouldn't break the button.
|
|
29
|
+
*/
|
|
30
|
+
export const getEffectiveOpenTargetId = (targetId, platform) => isOpenTargetSupported(targetId, platform) ? targetId : getDefaultOpenTargetIdForPlatform(platform);
|
|
31
|
+
export const getDefaultOpenTargetIdForPlatform = (platform) => {
|
|
32
|
+
// `finder` exists for every platform and never fails closed.
|
|
33
|
+
if (platform === 'mac' || platform === 'windows' || platform === 'linux')
|
|
34
|
+
return 'finder';
|
|
35
|
+
return 'vscode';
|
|
36
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tt-a1i/hive",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Browser-native hive-mind for CLI coding agents — Claude Code, Codex, Gemini, and OpenCode collaborate as real PTY processes via a team protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.30.3",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
|
-
"url": "git+https://github.com/tt-a1i/hive.git"
|
|
20
|
+
"url": "git+https://github.com/tt-a1i/hive-private.git"
|
|
21
21
|
},
|
|
22
22
|
"bugs": {
|
|
23
23
|
"url": "https://github.com/tt-a1i/hive/issues"
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"postinstall": "node scripts/fix-runtime-artifacts.mjs",
|
|
61
61
|
"release:dry": "pnpm check && pnpm build && pnpm test && pnpm pack:check && pnpm pack:smoke",
|
|
62
62
|
"test": "vitest run",
|
|
63
|
-
"test:windows": "vitest run tests/unit/agent-command-resolver.test.ts tests/unit/session-capture-multi-cli.test.ts tests/unit/claude-session-support.test.ts tests/unit/worker-name-generator.test.ts tests/server/fs-pick-folder.test.ts tests/server/fs-browse.test.ts tests/server/schema-version.test.ts tests/server/runtime-rehydration.test.ts tests/web/workspace-picker.test.tsx tests/web/confirm-dialog.test.tsx tests/web/toast.test.tsx --no-file-parallelism --maxWorkers=1 --testTimeout=
|
|
63
|
+
"test:windows": "vitest run tests/unit/agent-command-resolver.test.ts tests/unit/session-capture-multi-cli.test.ts tests/unit/claude-session-support.test.ts tests/unit/worker-name-generator.test.ts tests/unit/open-target-commands.test.ts tests/unit/sw-template-substitution.test.ts tests/unit/build-sw-plugin.test.ts tests/server/fs-pick-folder.test.ts tests/server/fs-browse.test.ts tests/server/schema-version.test.ts tests/server/runtime-rehydration.test.ts tests/server/open-workspace-route.test.ts tests/server/static-pwa.test.ts tests/web/workspace-picker.test.tsx tests/web/confirm-dialog.test.tsx tests/web/toast.test.tsx tests/web/open-workspace-button.test.tsx tests/web/register-service-worker.test.ts tests/web/use-shortcut-action.test.ts tests/web/update-available-toast.test.tsx tests/web/runtime-offline-page.test.tsx tests/web/use-terminal-panel-height.test.ts tests/web/use-terminal-panel-tabs.test.ts tests/web/terminal-tabs.test.tsx tests/web/terminal-bottom-panel.test.tsx --no-file-parallelism --maxWorkers=1 --testTimeout=60000 --hookTimeout=60000",
|
|
64
64
|
"test:watch": "vitest"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
Binary file
|
|
Binary file
|