@xfey/tutti 0.1.53 → 0.1.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +5 -2
  2. package/desktop-assets/README.md +13 -0
  3. package/desktop-assets/Tutti-square.png +0 -0
  4. package/desktop-assets/Tutti.icns +0 -0
  5. package/desktop-assets/macos-handler.applescript +24 -0
  6. package/dist/artifacts/index.d.ts +3 -3
  7. package/dist/artifacts/index.js +3 -3
  8. package/dist/artifacts/live-manifest.d.ts +23 -0
  9. package/dist/artifacts/live-manifest.js +115 -0
  10. package/dist/artifacts/preview-runtime.d.ts +34 -36
  11. package/dist/artifacts/preview-runtime.js +215 -273
  12. package/dist/artifacts/static-preview.d.ts +2 -1
  13. package/dist/artifacts/static-preview.js +19 -21
  14. package/dist/control-plane/index.d.ts +1 -0
  15. package/dist/control-plane/index.js +13 -2
  16. package/dist/control-plane/types.d.ts +4 -0
  17. package/dist/server-shell/cli/args.d.ts +7 -0
  18. package/dist/server-shell/cli/args.js +32 -0
  19. package/dist/server-shell/cli/cli.js +76 -1
  20. package/dist/server-shell/cli/errors.d.ts +1 -1
  21. package/dist/server-shell/cli/host-server-runtime.js +20 -0
  22. package/dist/server-shell/cli/version.d.ts +6 -0
  23. package/dist/server-shell/cli/version.js +11 -2
  24. package/dist/server-shell/desktop-integration/index.d.ts +5 -0
  25. package/dist/server-shell/desktop-integration/index.js +5 -0
  26. package/dist/server-shell/desktop-integration/linux.d.ts +12 -0
  27. package/dist/server-shell/desktop-integration/linux.js +186 -0
  28. package/dist/server-shell/desktop-integration/macos.d.ts +9 -0
  29. package/dist/server-shell/desktop-integration/macos.js +138 -0
  30. package/dist/server-shell/desktop-integration/manager.d.ts +40 -0
  31. package/dist/server-shell/desktop-integration/manager.js +223 -0
  32. package/dist/server-shell/desktop-integration/platform.d.ts +23 -0
  33. package/dist/server-shell/desktop-integration/platform.js +21 -0
  34. package/dist/server-shell/desktop-integration/protocol.d.ts +9 -0
  35. package/dist/server-shell/desktop-integration/protocol.js +28 -0
  36. package/dist/server-shell/desktop-integration/record.d.ts +17 -0
  37. package/dist/server-shell/desktop-integration/record.js +74 -0
  38. package/dist/server-shell/http/routes/project-api/artifacts-routes.js +43 -110
  39. package/dist/server-shell/http/routes/project-api/openapi-artifacts-routes.d.ts +5 -8
  40. package/dist/server-shell/http/routes/project-api/openapi-artifacts-routes.js +5 -33
  41. package/dist/server-shell/http/routes/project-api/openapi.d.ts +17 -8
  42. package/dist/server-shell/http/routes/project-api/types.d.ts +3 -2
  43. package/dist/server-shell/local-console/invocation-context.d.ts +7 -0
  44. package/dist/server-shell/local-console/invocation-context.js +8 -9
  45. package/dist/server-shell/local-console/managed-console.d.ts +1 -0
  46. package/dist/server-shell/local-console/managed-console.js +10 -5
  47. package/dist/server-shell/local-console/project-service.js +1 -1
  48. package/dist/server-shell/local-console/server.js +23 -6
  49. package/node_modules/@tutti/shared/dist/schemas/api/artifacts.d.ts +7 -88
  50. package/node_modules/@tutti/shared/dist/schemas/api/artifacts.js +3 -48
  51. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -1
  52. package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -1
  53. package/node_modules/@tutti/shared/dist/schemas/api/types.d.ts +1 -10
  54. package/package.json +2 -1
  55. package/web/assets/{homepage-motion-scene-F4ibPvI9.js → homepage-motion-scene-D0-wLq3D.js} +1 -1
  56. package/web/assets/{index-B1mBtL9x.js → index-BAsLSZ5U.js} +14 -14
  57. package/web/assets/index-DMaiDZ9k.css +1 -0
  58. package/web/assets/tutti_avatar-_0Yc-cMJ.png +0 -0
  59. package/web/index.html +2 -2
  60. package/dist/artifacts/manifest.d.ts +0 -41
  61. package/dist/artifacts/manifest.js +0 -169
  62. package/web/assets/index-OFlcQ3eS.css +0 -1
  63. package/web/assets/tutti_avatar-BBhaZGi3.png +0 -0
package/README.md CHANGED
@@ -8,6 +8,7 @@
8
8
 
9
9
  - `tutti launch` 后的项目绑定、恢复和接管入口
10
10
  - 裸 `tutti` 经 lifecycle lock 启动 / 复用的版本感知 loopback Local Console、独立 invocation context,以及既有项目 Host 编排
11
+ - 首次 eligible 裸 `tutti`、显式 `tutti desktop` 与严格 `tutti://projects` bridge 共用的用户级 desktop integration manager
11
12
  - Fastify API、SSE、packaged static Web 产物服务和 server 生命周期
12
13
  - SQLite store、migrations、repository 与协作真相读写
13
14
  - `control-plane`、scheduler、`procedure-engine`、`run-engine`、`workspace-ops` 与 OpenAI provider 接入
@@ -18,18 +19,20 @@
18
19
  - `src/`:server 代码根目录。
19
20
  - `prompts/`:大模型 prompt、指令模板和 Codex 执行模板的统一保存目录。
20
21
  - `migrations/`:本地 `tutti.sqlite` 的 SQL migrations。
22
+ - `desktop-assets/`:随 npm package 发布的 macOS AppleScriptObjC handler、白底 squircle desktop PNG / ICNS 与资产说明。
21
23
  - `cli-package.mjs`:生成临时 staging `@xfey/tutti` package artifact 的脚本。
22
24
  - `prepare-package-assets.mjs`:把 Web build output 和内部 runtime package 复制到 staging package 所需位置。
23
25
  - `pack-dry-run.mjs`:构建 staging package 并执行 `npm pack --dry-run --json` 文件列表校验。
24
26
  - `smoke-packed-cli.mjs`:安装并验证 packed CLI tarball 的本地 smoke,包括 CLI help / version、runtime deps 和 QR dependency。
27
+ - `smoke-desktop-protocol.mjs`:在真实 `~/Applications` 下使用唯一临时 bundle / scheme 验证 macOS 图标点击与 LaunchServices URL event,并在结束时注销、清理。
25
28
 
26
29
  ## 当前状态
27
30
 
28
- - 已具备 Fastify host shell、后台 host manager CLI 套件、带 `service status / stop / restart`、卸载前 `shutdown`、并发启动锁、版本替换、独立 browser context、idle / package update cleanup 与私有日志的机器级 Local Console、Dev Runner、Host Project API、SSE、SQLite store、collaboration-state、workspace read-state、project timeline observability helper、Control Plane、Procedure / Run、workspace-ops、checks、Relay staged upload finalize、user skills 文件服务、artifacts 可视化产物查看层和 OpenAI / Codex provider 接入。
31
+ - 已具备 Fastify host shell、后台 host manager CLI 套件、用户级 desktop integration / strict `tutti://projects` bridge、带 `service status / stop / restart`、卸载前 `shutdown`、并发启动锁、版本替换、strict terminal / desktop browser context、idle / package update cleanup 与私有日志的机器级 Local Console、Dev Runner、Host Project API、SSE、SQLite store、collaboration-state、workspace read-state、project timeline observability helper、Control Plane、Procedure / Run、workspace-ops、checks、Relay staged upload finalize、user skills 文件服务、artifacts 可视化产物查看层和 OpenAI / Codex provider 接入。
29
32
  - 新 Host project 的空群聊会由 collaboration-state 幂等写入一条 Tutti 欢迎消息;它不经过 browser message command,不触发 `@tutti`、Chat read-state、Scratchpad 或 Timeline / execution 流程。
30
33
  - Host server 与 Local Console 支持在显式 `webStatic.root` 或 packaged `web/` 存在时服务 Web 静态产物;`/api/*`、SSE、health、host-local control 和 `/local-console/*` API 不被 SPA fallback 吞掉。
31
34
  - Root `pack:dry-run` 会先清理 build output、重新构建,再复制 `apps/web/dist` 到 package-local `web/`,生成临时 staging `@xfey/tutti` artifact,并校验 npm pack 文件列表包含 CLI、migrations、prompts、Web index、bundled `@tutti/shared` / `@tutti/relay-client` 以及它们的外部 runtime dependencies,同时排除源码、source map、日志、SQLite、`.env`、`.tutti-dev` 与测试产物。
32
- - Root `smoke:packed-cli` 同样从干净 build output 生成 staging `@xfey/tutti` tarball、在临时目录安装,并验证 SQLite native binding、`tutti --help` / `tutti service --help` / `tutti service status` / `tutti shutdown --help` / `tutti launch --help` / `tutti archive --help` / `tutti --version`、migrations、prompts、Web static index、bundled internal dependencies、bundled external runtime dependencies、CLI QR dependency、仓库锁定的 `@openai/codex` binary 可执行性和临时全局安装路径;该 smoke 不需要 Tutti source repo 存在。
35
+ - Root `smoke:packed-cli` 同样从干净 build output 生成 staging `@xfey/tutti` tarball、在临时目录安装,并验证 SQLite native binding、`tutti --help` / desktop help / `tutti service --help` / `tutti service status` / `tutti shutdown --help` / `tutti launch --help` / `tutti archive --help` / `tutti --version`、desktop assets、migrations、prompts、Web static index、bundled internal dependencies、bundled external runtime dependencies、CLI QR dependency、仓库锁定的 `@openai/codex` binary 可执行性和临时全局安装路径;该 smoke 不需要 Tutti source repo 存在。
33
36
  - 对外发布必须把同一 staging package 通过 `npm pack` 生成的已核验 `.tgz` 交给 `npm publish`,不得直接发布 staging 目录;npm 的目录发布路径可能重新收集文件并遗漏 staging 内的 bundled dependencies。发布后必须从 registry 临时执行 CLI version / help smoke。
34
37
  - `prompts/` 是所有模型-facing prompt、指令模板和 Codex 执行模板的统一落点;长 prompt 不内联在 TypeScript 中。
35
38
  - Host Project API 只信任 Relay tunnel metadata 注入的 `relay_session_context`;direct loopback 缺少可信 context 时不作为浏览器工作区入口。
@@ -0,0 +1,13 @@
1
+ # Desktop assets
2
+
3
+ This directory contains package-owned assets used by the user-level Tutti desktop integration.
4
+
5
+ - `macos-handler.applescript` is compiled into `~/Applications/Tutti.app` by the packaged CLI. Its
6
+ AppleScriptObjC handler launches the hidden desktop bridge through `NSTask`, with a fixed
7
+ `tutti://projects` desktop intent and no shell invocation.
8
+ - `Tutti-square.png` is the 1024px desktop icon: a white macOS-style continuous-corner squircle
9
+ with the canonical Tutti wordmark enlarged inside a safe inset. Linux uses the same visual.
10
+ - `Tutti.icns` is the multiresolution macOS app icon generated from that desktop PNG.
11
+
12
+ The assets are shipped inside `@xfey/tutti`; installation never downloads runtime files. They do
13
+ not contain project paths, credentials, tokens, Relay sessions, or Local Console endpoints.
Binary file
Binary file
@@ -0,0 +1,24 @@
1
+ use framework "Foundation"
2
+ use scripting additions
3
+
4
+ property nodeExecutable : __TUTTI_NODE_EXECUTABLE_STRING__
5
+ property cliEntrypoint : __TUTTI_CLI_ENTRYPOINT_STRING__
6
+ property projectsUrl : "tutti://projects"
7
+
8
+ on launchTutti(targetUrl)
9
+ set task to current application's NSTask's alloc()'s init()
10
+ task's setLaunchPath:nodeExecutable
11
+ task's setArguments:{cliEntrypoint, "internal", "desktop-open", targetUrl}
12
+ task's setStandardInput:(current application's NSFileHandle's fileHandleWithNullDevice())
13
+ task's setStandardOutput:(current application's NSFileHandle's fileHandleWithNullDevice())
14
+ task's setStandardError:(current application's NSFileHandle's fileHandleWithNullDevice())
15
+ task's |launch|()
16
+ end launchTutti
17
+
18
+ on run
19
+ launchTutti(projectsUrl)
20
+ end run
21
+
22
+ on open location targetUrl
23
+ launchTutti(targetUrl)
24
+ end open location
@@ -1,6 +1,6 @@
1
- export { ARTIFACT_MANIFEST_PATH, ARTIFACT_PREVIEW_BASE_PATH, buildArtifactPreviewUrl, readArtifactDeclaration, readArtifactProjection, type ArtifactDeclaration, type DeclaredArtifactRuntime, type ReadArtifactDeclarationOptions, } from "./manifest.js";
1
+ export { readLiveArtifactDeclaration, type LiveArtifactDeclaration, } from "./live-manifest.js";
2
2
  export { validateCandidateArtifact, type ArtifactValidationDiagnostic, type ArtifactValidationDiagnosticSource, type ArtifactValidationReasonCode, type CandidateArtifactValidationFailure, type CandidateArtifactValidationResult, type ValidateCandidateArtifactOptions, } from "./candidate-validator.js";
3
- export { parseArtifactManifestContract, type ArtifactContractError, type ArtifactContractResult, type ValidatedArtifactContract, type ValidatedArtifactRuntime, } from "./manifest-contract.js";
4
- export { ARTIFACT_PREVIEW_REQUEST_BODY_LIMIT_BYTES, ARTIFACT_PREVIEW_RESPONSE_BODY_LIMIT_BYTES, ARTIFACT_PREVIEW_DEFAULT_BASE_PATH, ArtifactPreviewManager, isArtifactPreviewHttpMethod, type ArtifactPreviewCommandResult, type ArtifactPreviewHeartbeatResult, type ArtifactPreviewHttpMethod, type ArtifactPreviewManagerOptions, type ArtifactPreviewProcessPlan, type ArtifactPreviewStartResult, type ArtifactPreviewStopResult, type ArtifactServerPreviewResponse, } from "./preview-runtime.js";
3
+ export { ARTIFACT_MANIFEST_PATH, parseArtifactManifestContract, type ArtifactContractError, type ArtifactContractResult, type ValidatedArtifactContract, type ValidatedArtifactRuntime, } from "./manifest-contract.js";
4
+ export { ARTIFACT_PREVIEW_BASE_PATH, ARTIFACT_PREVIEW_REQUEST_BODY_LIMIT_BYTES, ARTIFACT_PREVIEW_RESPONSE_BODY_LIMIT_BYTES, ARTIFACT_PREVIEW_DEFAULT_BASE_PATH, ArtifactPreviewManager, isArtifactPreviewHttpMethod, type ArtifactPreviewLeaseOptions, type ArtifactPreviewHttpMethod, type ArtifactPreviewManagerOptions, type ArtifactPreviewProcessPlan, type ArtifactServerPreviewResponse, } from "./preview-runtime.js";
5
5
  export { ARTIFACT_PREVIEW_CSP, readArtifactStaticPreview, rewriteArtifactPreviewResourceUrls, type ArtifactStaticPreviewFile, type ReadArtifactStaticPreviewOptions, } from "./static-preview.js";
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1,6 +1,6 @@
1
- export { ARTIFACT_MANIFEST_PATH, ARTIFACT_PREVIEW_BASE_PATH, buildArtifactPreviewUrl, readArtifactDeclaration, readArtifactProjection, } from "./manifest.js";
1
+ export { readLiveArtifactDeclaration, } from "./live-manifest.js";
2
2
  export { validateCandidateArtifact, } from "./candidate-validator.js";
3
- export { parseArtifactManifestContract, } from "./manifest-contract.js";
4
- export { ARTIFACT_PREVIEW_REQUEST_BODY_LIMIT_BYTES, ARTIFACT_PREVIEW_RESPONSE_BODY_LIMIT_BYTES, ARTIFACT_PREVIEW_DEFAULT_BASE_PATH, ArtifactPreviewManager, isArtifactPreviewHttpMethod, } from "./preview-runtime.js";
3
+ export { ARTIFACT_MANIFEST_PATH, parseArtifactManifestContract, } from "./manifest-contract.js";
4
+ export { ARTIFACT_PREVIEW_BASE_PATH, ARTIFACT_PREVIEW_REQUEST_BODY_LIMIT_BYTES, ARTIFACT_PREVIEW_RESPONSE_BODY_LIMIT_BYTES, ARTIFACT_PREVIEW_DEFAULT_BASE_PATH, ArtifactPreviewManager, isArtifactPreviewHttpMethod, } from "./preview-runtime.js";
5
5
  export { ARTIFACT_PREVIEW_CSP, readArtifactStaticPreview, rewriteArtifactPreviewResourceUrls, } from "./static-preview.js";
6
6
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,23 @@
1
+ import type { ArtifactManifest, ArtifactProjection } from "@tutti/shared/schemas/api";
2
+ import { type ValidatedArtifactRuntime } from "./manifest-contract.js";
3
+ type ArtifactInvalidProjection = Extract<ArtifactProjection, {
4
+ status: "invalid";
5
+ }>;
6
+ export type LiveArtifactDeclaration = {
7
+ status: "not_declared";
8
+ projection: Extract<ArtifactProjection, {
9
+ status: "not_declared";
10
+ }>;
11
+ } | {
12
+ status: "invalid";
13
+ projection: ArtifactInvalidProjection;
14
+ } | {
15
+ status: "declared";
16
+ manifest: ArtifactManifest;
17
+ runtime: ValidatedArtifactRuntime;
18
+ };
19
+ export declare function readLiveArtifactDeclaration(options: {
20
+ workspaceRoot: string;
21
+ }): LiveArtifactDeclaration;
22
+ export {};
23
+ //# sourceMappingURL=live-manifest.d.ts.map
@@ -0,0 +1,115 @@
1
+ import { lstatSync, readFileSync, realpathSync } from "node:fs";
2
+ import { isAbsolute, join, relative, resolve } from "node:path";
3
+ import { ARTIFACT_MANIFEST_PATH, MAX_ARTIFACT_MANIFEST_BYTES, parseArtifactManifestContract, } from "./manifest-contract.js";
4
+ function truncateMessage(message) {
5
+ const normalized = message.replace(/\s+/gu, " ").trim();
6
+ return normalized.length <= 220 ? normalized : `${normalized.slice(0, 217)}...`;
7
+ }
8
+ function invalidArtifact(code, message) {
9
+ return {
10
+ status: "invalid",
11
+ projection: {
12
+ status: "invalid",
13
+ error: {
14
+ code,
15
+ message: truncateMessage(message),
16
+ },
17
+ },
18
+ };
19
+ }
20
+ function isContainedPath(root, target) {
21
+ const relativePath = relative(root, target);
22
+ return relativePath === "" || (!relativePath.startsWith("..") && !isAbsolute(relativePath));
23
+ }
24
+ function requireContainedPath(options) {
25
+ try {
26
+ const target = realpathSync.native(resolve(options.workspaceRealPath, options.repoPath));
27
+ const stat = lstatSync(target);
28
+ const expectedKind = options.kind === "file" ? stat.isFile() : stat.isDirectory();
29
+ if (!isContainedPath(options.workspaceRealPath, target) || !expectedKind) {
30
+ return invalidArtifact("invalid_path", `${options.label} is not a contained ${options.kind}`);
31
+ }
32
+ return null;
33
+ }
34
+ catch {
35
+ return invalidArtifact("not_found", `${options.label} does not exist`);
36
+ }
37
+ }
38
+ export function readLiveArtifactDeclaration(options) {
39
+ let workspaceRealPath;
40
+ try {
41
+ workspaceRealPath = realpathSync.native(options.workspaceRoot);
42
+ }
43
+ catch {
44
+ return invalidArtifact("workspace_unavailable", "Project workspace is unavailable");
45
+ }
46
+ const manifestPath = join(workspaceRealPath, ARTIFACT_MANIFEST_PATH);
47
+ let manifestStat;
48
+ try {
49
+ manifestStat = lstatSync(manifestPath);
50
+ }
51
+ catch (error) {
52
+ if (error.code === "ENOENT") {
53
+ return {
54
+ status: "not_declared",
55
+ projection: { status: "not_declared" },
56
+ };
57
+ }
58
+ return invalidArtifact("manifest_unavailable", "Artifact manifest cannot be read");
59
+ }
60
+ if (!manifestStat.isFile()) {
61
+ return invalidArtifact("invalid_manifest", "Artifact manifest path is not a regular file");
62
+ }
63
+ if (manifestStat.size > MAX_ARTIFACT_MANIFEST_BYTES) {
64
+ return invalidArtifact("too_large", "Artifact manifest is too large");
65
+ }
66
+ let manifestContent;
67
+ try {
68
+ manifestContent = readFileSync(manifestPath);
69
+ }
70
+ catch {
71
+ return invalidArtifact("manifest_unavailable", "Artifact manifest cannot be read");
72
+ }
73
+ const parsed = parseArtifactManifestContract(manifestContent);
74
+ if (!parsed.ok) {
75
+ return invalidArtifact(parsed.error.code, parsed.error.message);
76
+ }
77
+ const runtime = parsed.declaration.runtime;
78
+ if (runtime.kind === "static") {
79
+ const rootError = requireContainedPath({
80
+ workspaceRealPath,
81
+ repoPath: runtime.root_path,
82
+ kind: "directory",
83
+ label: "Static artifact root",
84
+ });
85
+ if (rootError !== null) {
86
+ return rootError;
87
+ }
88
+ const entryError = requireContainedPath({
89
+ workspaceRealPath,
90
+ repoPath: runtime.entry_repo_path,
91
+ kind: "file",
92
+ label: "Static artifact entry",
93
+ });
94
+ if (entryError !== null) {
95
+ return entryError;
96
+ }
97
+ }
98
+ else {
99
+ const cwdError = requireContainedPath({
100
+ workspaceRealPath,
101
+ repoPath: runtime.cwd_path,
102
+ kind: "directory",
103
+ label: "Server artifact cwd",
104
+ });
105
+ if (cwdError !== null) {
106
+ return cwdError;
107
+ }
108
+ }
109
+ return {
110
+ status: "declared",
111
+ manifest: parsed.declaration.manifest,
112
+ runtime,
113
+ };
114
+ }
115
+ //# sourceMappingURL=live-manifest.js.map
@@ -1,21 +1,7 @@
1
1
  import type { ChildProcessWithoutNullStreams } from "node:child_process";
2
- import type { ArtifactProjection, GetArtifactsResponse, HeartbeatArtifactPreviewDisposition, StartArtifactPreviewDisposition, StopArtifactPreviewDisposition } from "@tutti/shared/schemas/api";
2
+ import type { GetArtifactsResponse } from "@tutti/shared/schemas/api";
3
3
  import { type ArtifactPreviewProcessPlan, type ArtifactProcessRuntime } from "./process-boundary.js";
4
- export type ArtifactPreviewCommandResult = {
5
- artifact: ArtifactProjection;
6
- };
7
- export type ArtifactPreviewStartResult = {
8
- disposition: StartArtifactPreviewDisposition;
9
- result: ArtifactPreviewCommandResult;
10
- };
11
- export type ArtifactPreviewHeartbeatResult = {
12
- disposition: HeartbeatArtifactPreviewDisposition;
13
- result: ArtifactPreviewCommandResult;
14
- };
15
- export type ArtifactPreviewStopResult = {
16
- disposition: StopArtifactPreviewDisposition;
17
- result: ArtifactPreviewCommandResult;
18
- };
4
+ import { type ArtifactStaticPreviewFile } from "./static-preview.js";
19
5
  export type ArtifactServerPreviewResponse = {
20
6
  status_code: number;
21
7
  headers: Record<string, string>;
@@ -23,7 +9,6 @@ export type ArtifactServerPreviewResponse = {
23
9
  };
24
10
  export type ArtifactPreviewHttpMethod = "GET" | "HEAD" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS";
25
11
  export type ArtifactPreviewManagerOptions = {
26
- now?: () => Date;
27
12
  baseEnv?: NodeJS.ProcessEnv;
28
13
  spawnProcess?: (plan: ArtifactPreviewProcessPlan) => ChildProcessWithoutNullStreams;
29
14
  terminateProcess?: (child: ChildProcessWithoutNullStreams) => Promise<void>;
@@ -43,11 +28,15 @@ export type ArtifactPreviewManagerOptions = {
43
28
  responseBodyLimitBytes?: number;
44
29
  idleStopTtlMs?: number;
45
30
  };
31
+ export type ArtifactPreviewLeaseOptions = {
32
+ viewerId: string;
33
+ workspaceRoot: string;
34
+ };
46
35
  export declare const ARTIFACT_PREVIEW_REQUEST_BODY_LIMIT_BYTES: number;
47
36
  export declare const ARTIFACT_PREVIEW_RESPONSE_BODY_LIMIT_BYTES: number;
37
+ export declare const ARTIFACT_PREVIEW_BASE_PATH: "/artifacts/preview";
48
38
  export declare function isArtifactPreviewHttpMethod(method: string): method is ArtifactPreviewHttpMethod;
49
39
  export declare class ArtifactPreviewManager {
50
- private readonly now;
51
40
  private readonly baseEnv;
52
41
  private readonly spawnProcess;
53
42
  private readonly terminateProcess;
@@ -67,25 +56,26 @@ export declare class ArtifactPreviewManager {
67
56
  private readonly responseBodyLimitBytes;
68
57
  private readonly idleStopTtlMs;
69
58
  private readonly pendingTasks;
59
+ private readonly leases;
60
+ private leaseSweepTimer;
70
61
  private state;
71
- private nextInstanceSequence;
62
+ private declaration;
63
+ private lastProjection;
64
+ private workspaceUpdating;
65
+ private nextGenerationSequence;
72
66
  constructor(options?: ArtifactPreviewManagerOptions);
73
- readProjection(options: {
74
- workspaceRoot: string;
67
+ readProjection(options?: {
68
+ workspaceRoot?: string;
75
69
  previewBasePath?: string;
76
70
  }): GetArtifactsResponse;
77
- start(options: {
71
+ initializeWorkspace(options: {
78
72
  workspaceRoot: string;
79
- previewBasePath?: string;
80
- }): ArtifactPreviewStartResult;
81
- heartbeat(options: {
73
+ }): void;
74
+ renewLease(options: ArtifactPreviewLeaseOptions): void;
75
+ beginWorkspaceUpdate(): void;
76
+ settleWorkspaceUpdate(options: {
82
77
  workspaceRoot: string;
83
- previewBasePath?: string;
84
- }): ArtifactPreviewHeartbeatResult;
85
- stop(options: {
86
- workspaceRoot: string;
87
- previewBasePath?: string;
88
- }): ArtifactPreviewStopResult;
78
+ }): void;
89
79
  fetchServerPreview(options: {
90
80
  workspaceRoot: string;
91
81
  path: string | undefined;
@@ -94,22 +84,30 @@ export declare class ArtifactPreviewManager {
94
84
  headers?: Record<string, string | undefined>;
95
85
  body?: Buffer;
96
86
  }): Promise<ArtifactServerPreviewResponse>;
97
- sweepIdle(): void;
87
+ readStaticPreview(options: {
88
+ workspaceRoot: string;
89
+ path: string | undefined;
90
+ query?: string;
91
+ }): ArtifactStaticPreviewFile;
98
92
  stopAll(): Promise<void>;
93
+ private currentProjection;
94
+ private ensurePreview;
95
+ private refreshDeclaration;
96
+ private applyDeclaration;
97
+ private createIdleState;
99
98
  private startProcess;
100
99
  private launchProcess;
101
100
  private attachProcessListeners;
102
101
  private waitUntilReady;
103
102
  private probeReadyEntry;
104
- private recordHeartbeat;
105
- private scheduleIdleSweep;
106
- private stopStaleRuntime;
103
+ private pruneExpiredLeases;
104
+ private scheduleLeaseSweep;
107
105
  private stopCurrentProcess;
108
106
  private failState;
109
107
  private disposeStateProcess;
110
108
  private cleanupStateRuntime;
111
109
  private trackTask;
112
- private nextInstanceId;
110
+ private nextGeneration;
113
111
  }
114
112
  export type { ArtifactPreviewProcessPlan } from "./process-boundary.js";
115
113
  export declare const ARTIFACT_PREVIEW_DEFAULT_BASE_PATH: "/artifacts/preview";