@xfey/tutti 0.1.104 → 0.1.106

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 (64) hide show
  1. package/README.md +2 -2
  2. package/dist/approvals/decision-command.d.ts +124 -0
  3. package/dist/approvals/decision-command.js +20 -0
  4. package/dist/approvals/index.d.ts +1 -0
  5. package/dist/approvals/index.js +1 -0
  6. package/dist/approvals/manager.d.ts +3 -1
  7. package/dist/approvals/manager.js +9 -0
  8. package/dist/collaboration-ingestion/index.d.ts +3 -0
  9. package/dist/collaboration-ingestion/index.js +3 -0
  10. package/dist/collaboration-ingestion/managed-reference-snapshots.d.ts +27 -0
  11. package/dist/collaboration-ingestion/managed-reference-snapshots.js +45 -0
  12. package/dist/collaboration-ingestion/managed-reference-sources.d.ts +20 -0
  13. package/dist/collaboration-ingestion/managed-reference-sources.js +250 -0
  14. package/dist/collaboration-ingestion/reference-attachments.d.ts +22 -0
  15. package/dist/collaboration-ingestion/reference-attachments.js +132 -0
  16. package/dist/collaboration-ingestion/reference-files.d.ts +3 -2
  17. package/dist/collaboration-ingestion/reference-files.js +1 -0
  18. package/dist/platform-outbound/coordinator.d.ts +5 -2
  19. package/dist/platform-outbound/coordinator.js +95 -2
  20. package/dist/platform-outbound/repository.d.ts +17 -0
  21. package/dist/platform-outbound/repository.js +190 -5
  22. package/dist/platform-outbound/types.d.ts +13 -3
  23. package/dist/platform-outbound/worker.js +30 -14
  24. package/dist/server-shell/cli/host-lifecycle.js +3 -0
  25. package/dist/server-shell/cli/host-server-runtime.d.ts +4 -1
  26. package/dist/server-shell/cli/host-server-runtime.js +128 -40
  27. package/dist/server-shell/cli/relay-registration.js +3 -0
  28. package/dist/server-shell/http/host-tunnel.d.ts +4 -1
  29. package/dist/server-shell/http/host-tunnel.js +174 -3
  30. package/dist/server-shell/http/routes/project-api/approval-routes.js +13 -20
  31. package/dist/server-shell/http/routes/project-api/staged-uploads.d.ts +6 -0
  32. package/dist/server-shell/http/routes/project-api/staged-uploads.js +9 -2
  33. package/dist/server-shell/local-console/project-service.d.ts +2 -0
  34. package/dist/server-shell/local-console/project-service.js +37 -0
  35. package/dist/server-shell/local-console/server.js +4 -0
  36. package/dist/workspace-ops/index.d.ts +2 -2
  37. package/dist/workspace-ops/index.js +1 -1
  38. package/dist/workspace-ops/reference-files.d.ts +14 -1
  39. package/dist/workspace-ops/reference-files.js +167 -2
  40. package/dist/workspace-ops/types.d.ts +24 -0
  41. package/migrations/0018_platform_outbound_events.sql +111 -0
  42. package/migrations/0019_platform_outbound_card_content.sql +76 -0
  43. package/migrations/0020_managed_reference_sources.sql +34 -0
  44. package/migrations/README.md +4 -1
  45. package/node_modules/@tutti/relay-client/dist/host-control.d.ts +5 -2
  46. package/node_modules/@tutti/relay-client/dist/host-control.js +3 -0
  47. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +2 -2
  48. package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -1
  49. package/node_modules/@tutti/shared/dist/schemas/api/platform-sessions.d.ts +34 -0
  50. package/node_modules/@tutti/shared/dist/schemas/api/platform-sessions.js +37 -0
  51. package/node_modules/@tutti/shared/dist/schemas/internal/feishu-user-credentials.d.ts +22 -0
  52. package/node_modules/@tutti/shared/dist/schemas/internal/feishu-user-credentials.js +37 -0
  53. package/node_modules/@tutti/shared/dist/schemas/internal/index.d.ts +1 -0
  54. package/node_modules/@tutti/shared/dist/schemas/internal/index.js +1 -0
  55. package/node_modules/@tutti/shared/dist/schemas/internal/platform-integration.d.ts +1005 -49
  56. package/node_modules/@tutti/shared/dist/schemas/internal/platform-integration.js +434 -14
  57. package/package.json +1 -1
  58. package/prompts/skills/read-references/README.md +1 -1
  59. package/prompts/skills/read-references/SKILL.md +4 -2
  60. package/web/assets/{homepage-motion-scene-DEVrQ9aj.js → homepage-motion-scene-tfFEdV9Y.js} +1 -1
  61. package/web/assets/index-B7ZGIvOv.js +69 -0
  62. package/web/assets/{index-6i9Uk7fS.css → index-C2Mmj25S.css} +1 -1
  63. package/web/index.html +2 -2
  64. package/web/assets/index-Lxtst2sl.js +0 -69
@@ -3,11 +3,11 @@ export { WorkspaceOpsError } from "./errors.js";
3
3
  export { commitOwnedPaths, requireOwnedPathsWriteReady } from "./system-commits.js";
4
4
  export { collectProjectSourceDiff, createAcceptedCheckpoint, inspectProjectWorkspace, recoverAcceptedCheckpoint, } from "./project-workspace.js";
5
5
  export { initializeProjectDocs, readProjectDocsInitializationStatus, syncProjectDocs, } from "./project-docs.js";
6
- export { uploadReferenceFile } from "./reference-files.js";
6
+ export { readManagedReferenceSnapshotState, uploadReferenceFile, writeManagedReferenceSnapshot, } from "./reference-files.js";
7
7
  export { isReferenceFilePath, referenceFileCategoryForPath, referenceFolderGroupForPath, referenceMediaTypeForPath, } from "./reference-metadata.js";
8
8
  export { readReferenceFileEntries } from "./reference-tree.js";
9
9
  export { readReferenceSummaryEntries, readReferenceSummaryIndex, readReferenceSummaryTargets, referenceSummaryProjectionForEntry, updateReferenceSummaries, } from "./reference-summaries.js";
10
10
  export { readViewerAsset, readViewerFile, readViewerSnapshot, readViewerTree } from "./viewer.js";
11
11
  export type { WorkspaceOpsErrorCode } from "./errors.js";
12
- export type { AcceptedCheckpointRecoveryResult, AcceptedCheckpointResult, CreateAcceptedCheckpointOptions, InitializeProjectDocsOptions, InitializeProjectDocsResult, ProjectDocsInitializationContext, ProjectDocsInitializationDocument, ProjectDocsInitializationStatus, ProjectWorkspaceInspection, ReadViewerAssetOptions, ReadViewerFileOptions, ReadViewerTreeOptions, ReferenceFileCategory, ReferenceSummaryProjection, ReferenceSummaryRecord, ReferenceSummaryStatus, ReferenceSummaryTarget, RunDiffSummary, SyncProjectDocsResult, SyncProjectDocsUpdate, UpdateReferenceSummariesOptions, UpdateReferenceSummariesResult, UploadReferenceFileOptions, UploadReferenceFileResult, ViewerAssetResult, ViewerAssetVariant, ViewerEntryKind, ViewerFileContent, ViewerFileResult, ViewerRepoSnapshot, ViewerTreeEntry, ViewerTreeResult, WorkspaceViewerOptions, } from "./types.js";
12
+ export type { AcceptedCheckpointRecoveryResult, AcceptedCheckpointResult, CreateAcceptedCheckpointOptions, InitializeProjectDocsOptions, InitializeProjectDocsResult, ProjectDocsInitializationContext, ProjectDocsInitializationDocument, ProjectDocsInitializationStatus, ProjectWorkspaceInspection, ReadViewerAssetOptions, ReadViewerFileOptions, ReadViewerTreeOptions, ReferenceFileCategory, ReferenceSummaryProjection, ReferenceSummaryRecord, ReferenceSummaryStatus, ReferenceSummaryTarget, RunDiffSummary, SyncProjectDocsResult, SyncProjectDocsUpdate, UpdateReferenceSummariesOptions, UpdateReferenceSummariesResult, UploadReferenceFileOptions, UploadReferenceFileResult, WriteManagedReferenceSnapshotOptions, WriteManagedReferenceSnapshotResult, ManagedReferenceSnapshotState, ViewerAssetResult, ViewerAssetVariant, ViewerEntryKind, ViewerFileContent, ViewerFileResult, ViewerRepoSnapshot, ViewerTreeEntry, ViewerTreeResult, WorkspaceViewerOptions, } from "./types.js";
13
13
  //# sourceMappingURL=index.d.ts.map
@@ -3,7 +3,7 @@ export { WorkspaceOpsError } from "./errors.js";
3
3
  export { commitOwnedPaths, requireOwnedPathsWriteReady } from "./system-commits.js";
4
4
  export { collectProjectSourceDiff, createAcceptedCheckpoint, inspectProjectWorkspace, recoverAcceptedCheckpoint, } from "./project-workspace.js";
5
5
  export { initializeProjectDocs, readProjectDocsInitializationStatus, syncProjectDocs, } from "./project-docs.js";
6
- export { uploadReferenceFile } from "./reference-files.js";
6
+ export { readManagedReferenceSnapshotState, uploadReferenceFile, writeManagedReferenceSnapshot, } from "./reference-files.js";
7
7
  export { isReferenceFilePath, referenceFileCategoryForPath, referenceFolderGroupForPath, referenceMediaTypeForPath, } from "./reference-metadata.js";
8
8
  export { readReferenceFileEntries } from "./reference-tree.js";
9
9
  export { readReferenceSummaryEntries, readReferenceSummaryIndex, readReferenceSummaryTargets, referenceSummaryProjectionForEntry, updateReferenceSummaries, } from "./reference-summaries.js";
@@ -1,3 +1,16 @@
1
- import type { UploadReferenceFileOptions, UploadReferenceFileResult } from "./types.js";
1
+ import type { UploadReferenceFileOptions, UploadReferenceFileResult, WriteManagedReferenceSnapshotOptions, WriteManagedReferenceSnapshotResult, ManagedReferenceSnapshotState } from "./types.js";
2
2
  export declare function uploadReferenceFile(options: UploadReferenceFileOptions): UploadReferenceFileResult;
3
+ /**
4
+ * Writes a caller-managed logical Reference snapshot at one stable path.
5
+ *
6
+ * Platform adapters remain responsible for external source identity and
7
+ * revision discovery. Updates use the committed blob oid as a compare-and-set
8
+ * boundary so a stale adapter cannot overwrite a newer local snapshot.
9
+ */
10
+ export declare function writeManagedReferenceSnapshot(options: WriteManagedReferenceSnapshotOptions): WriteManagedReferenceSnapshotResult;
11
+ export declare function readManagedReferenceSnapshotState(options: {
12
+ workspaceRoot: string;
13
+ path: string;
14
+ now?: () => Date;
15
+ }): ManagedReferenceSnapshotState;
3
16
  //# sourceMappingURL=reference-files.d.ts.map
@@ -1,10 +1,13 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
3
  import { extname, join, posix } from "node:path";
3
4
  import { classifyViewerPath } from "@tutti/shared/utils";
4
- import { MAX_REFERENCE_UPLOAD_BYTES, REFERENCE_DIRECTORY_PATH, REFERENCE_INDEX_PATH, } from "./constants.js";
5
+ import { MAX_REFERENCE_UPLOAD_BYTES, REFERENCE_DIRECTORY_PATH, REFERENCE_IMAGES_DIRECTORY_PATH, REFERENCE_INDEX_PATH, } from "./constants.js";
5
6
  import { WorkspaceOpsError } from "./errors.js";
6
7
  import { classifyReferenceUpload } from "./reference-metadata.js";
7
8
  import { commitOwnedPaths, requireOwnedPathsWriteReady } from "./system-commits.js";
9
+ import { requireNormalizedViewerPath } from "./viewer-paths.js";
10
+ import { readBlob, requireFileEntry } from "./viewer-git.js";
8
11
  import { readViewerFile } from "./viewer.js";
9
12
  const MAX_REFERENCE_FILE_NAME_BYTES = 240;
10
13
  const WINDOWS_RESERVED_FILE_STEMS = /^(?:con|prn|aux|nul|clock\$|com[1-9]|lpt[1-9])$/iu;
@@ -199,4 +202,166 @@ export function uploadReferenceFile(options) {
199
202
  commit_oid: resolvedCommitOid,
200
203
  };
201
204
  }
205
+ function managedReferenceSnapshotPath(path) {
206
+ const repoPath = requireNormalizedViewerPath(path);
207
+ if (repoPath !== path || !repoPath.startsWith(`${REFERENCE_DIRECTORY_PATH}/`)) {
208
+ throw new WorkspaceOpsError("validation_failed", "Managed reference snapshot path must be normalized and inside the Reference directory");
209
+ }
210
+ if (repoPath === REFERENCE_INDEX_PATH) {
211
+ throw new WorkspaceOpsError("validation_failed", "Managed reference snapshot cannot replace the Reference index");
212
+ }
213
+ const fileName = posix.basename(repoPath);
214
+ if (normalizeReferenceFileName(fileName) !== fileName) {
215
+ throw new WorkspaceOpsError("validation_failed", "Managed reference snapshot file name is not normalized");
216
+ }
217
+ const directoryPath = posix.dirname(repoPath);
218
+ const category = repoPath.startsWith(`${REFERENCE_IMAGES_DIRECTORY_PATH}/`)
219
+ ? "image"
220
+ : "file";
221
+ return { repoPath, directoryPath, fileName, category };
222
+ }
223
+ function readManagedSnapshotPathEntry(path) {
224
+ try {
225
+ return lstatSync(path);
226
+ }
227
+ catch (error) {
228
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
229
+ return undefined;
230
+ }
231
+ throw new WorkspaceOpsError("forbidden", "Managed reference snapshot path could not be inspected", { reason_code: "managed_reference_snapshot_path_unavailable" });
232
+ }
233
+ }
234
+ function inspectManagedReferenceSnapshotFilesystemPath(options) {
235
+ const segments = options.repoPath.split("/");
236
+ let currentPath = options.workspaceRoot;
237
+ for (const [index, segment] of segments.entries()) {
238
+ currentPath = join(currentPath, segment);
239
+ const entry = readManagedSnapshotPathEntry(currentPath);
240
+ if (entry === undefined) {
241
+ return {
242
+ filesystemPath: join(options.workspaceRoot, ...segments),
243
+ exists: false,
244
+ };
245
+ }
246
+ if (entry.isSymbolicLink()) {
247
+ throw new WorkspaceOpsError("forbidden", "Managed reference snapshot path must not traverse a symbolic link", { reason_code: "managed_reference_snapshot_symlink" });
248
+ }
249
+ const isTarget = index === segments.length - 1;
250
+ if (!isTarget && !entry.isDirectory()) {
251
+ throw new WorkspaceOpsError("conflict", "Managed reference snapshot parent path is not a directory", { reason_code: "managed_reference_snapshot_parent_invalid" });
252
+ }
253
+ if (isTarget && !entry.isFile()) {
254
+ throw new WorkspaceOpsError("conflict", "Managed reference snapshot target is not a regular file", { reason_code: "managed_reference_snapshot_target_invalid" });
255
+ }
256
+ }
257
+ return {
258
+ filesystemPath: join(options.workspaceRoot, ...segments),
259
+ exists: true,
260
+ };
261
+ }
262
+ /**
263
+ * Writes a caller-managed logical Reference snapshot at one stable path.
264
+ *
265
+ * Platform adapters remain responsible for external source identity and
266
+ * revision discovery. Updates use the committed blob oid as a compare-and-set
267
+ * boundary so a stale adapter cannot overwrite a newer local snapshot.
268
+ */
269
+ export function writeManagedReferenceSnapshot(options) {
270
+ if (options.content.byteLength > MAX_REFERENCE_UPLOAD_BYTES) {
271
+ throw new WorkspaceOpsError("validation_failed", `Managed reference snapshot cannot exceed ${MAX_REFERENCE_UPLOAD_BYTES} bytes`);
272
+ }
273
+ const { repoPath, directoryPath, fileName, category } = managedReferenceSnapshotPath(options.path);
274
+ const pathState = inspectManagedReferenceSnapshotFilesystemPath({
275
+ workspaceRoot: options.workspaceRoot,
276
+ repoPath,
277
+ });
278
+ const filesystemPath = pathState.filesystemPath;
279
+ const indexOwnedPaths = pathState.exists ? [repoPath] : [REFERENCE_INDEX_PATH, repoPath];
280
+ requireOwnedPathsWriteReady(options.workspaceRoot, indexOwnedPaths);
281
+ let previous;
282
+ if (pathState.exists) {
283
+ previous = readViewerFile({
284
+ workspaceRoot: options.workspaceRoot,
285
+ path: repoPath,
286
+ ...(options.now === undefined ? {} : { now: options.now }),
287
+ });
288
+ if (options.expectedBlobOid === undefined) {
289
+ throw new WorkspaceOpsError("conflict", "Managed reference snapshot already exists", {
290
+ reason_code: "managed_reference_snapshot_exists",
291
+ });
292
+ }
293
+ if (previous.file.blob_oid !== options.expectedBlobOid) {
294
+ throw new WorkspaceOpsError("conflict", "Managed reference snapshot changed before this update", { reason_code: "managed_reference_snapshot_stale" });
295
+ }
296
+ if (sameFileContent(filesystemPath, options.content)) {
297
+ return {
298
+ disposition: "unchanged",
299
+ file: previous.file,
300
+ category,
301
+ index_path: REFERENCE_INDEX_PATH,
302
+ previous_blob_oid: previous.file.blob_oid,
303
+ commit_oid: previous.snapshot.head.oid,
304
+ };
305
+ }
306
+ }
307
+ else if (options.expectedBlobOid !== undefined) {
308
+ throw new WorkspaceOpsError("conflict", "Managed reference snapshot no longer exists", {
309
+ reason_code: "managed_reference_snapshot_missing",
310
+ });
311
+ }
312
+ mkdirSync(join(options.workspaceRoot, ...directoryPath.split("/")), { recursive: true });
313
+ writeFileSync(filesystemPath, options.content);
314
+ if (previous === undefined) {
315
+ appendReferenceIndexEntry({
316
+ workspaceRoot: options.workspaceRoot,
317
+ fileName,
318
+ repoPath,
319
+ category,
320
+ ...(options.note === undefined ? {} : { note: options.note }),
321
+ });
322
+ }
323
+ const commitOid = commitOwnedPaths({
324
+ workspaceRoot: options.workspaceRoot,
325
+ paths: indexOwnedPaths,
326
+ message: previous === undefined
327
+ ? `Add managed reference snapshot: ${fileName}`
328
+ : `Update managed reference snapshot: ${fileName}`,
329
+ });
330
+ const file = readViewerFile({
331
+ workspaceRoot: options.workspaceRoot,
332
+ path: repoPath,
333
+ ...(options.now === undefined ? {} : { now: options.now }),
334
+ });
335
+ return {
336
+ disposition: previous === undefined ? "created" : "updated",
337
+ file: file.file,
338
+ category,
339
+ index_path: REFERENCE_INDEX_PATH,
340
+ ...(previous === undefined ? {} : { previous_blob_oid: previous.file.blob_oid }),
341
+ ...(commitOid === null ? {} : { commit_oid: commitOid }),
342
+ };
343
+ }
344
+ export function readManagedReferenceSnapshotState(options) {
345
+ const { repoPath } = managedReferenceSnapshotPath(options.path);
346
+ const pathState = inspectManagedReferenceSnapshotFilesystemPath({
347
+ workspaceRoot: options.workspaceRoot,
348
+ repoPath,
349
+ });
350
+ requireOwnedPathsWriteReady(options.workspaceRoot, pathState.exists ? [repoPath] : [REFERENCE_INDEX_PATH, repoPath]);
351
+ if (!pathState.exists) {
352
+ return { exists: false, path: repoPath };
353
+ }
354
+ const entry = requireFileEntry({
355
+ workspaceRoot: options.workspaceRoot,
356
+ path: repoPath,
357
+ });
358
+ const content = readBlob(options.workspaceRoot, entry.oid, entry.size);
359
+ return {
360
+ exists: true,
361
+ path: repoPath,
362
+ blob_oid: entry.oid,
363
+ content_sha256: `sha256:${createHash("sha256").update(content).digest("hex")}`,
364
+ size_bytes: entry.size,
365
+ };
366
+ }
202
367
  //# sourceMappingURL=reference-files.js.map
@@ -123,6 +123,30 @@ export type UploadReferenceFileResult = {
123
123
  index_path: typeof REFERENCE_INDEX_PATH;
124
124
  commit_oid?: string;
125
125
  };
126
+ export type WriteManagedReferenceSnapshotOptions = WorkspaceViewerOptions & {
127
+ path: string;
128
+ content: Buffer;
129
+ expectedBlobOid?: string;
130
+ note?: string;
131
+ };
132
+ export type WriteManagedReferenceSnapshotResult = {
133
+ disposition: "created" | "updated" | "unchanged";
134
+ file: ViewerFileResult["file"];
135
+ category: ReferenceFileCategory;
136
+ index_path: typeof REFERENCE_INDEX_PATH;
137
+ previous_blob_oid?: string;
138
+ commit_oid?: string;
139
+ };
140
+ export type ManagedReferenceSnapshotState = {
141
+ exists: false;
142
+ path: string;
143
+ } | {
144
+ exists: true;
145
+ path: string;
146
+ blob_oid: string;
147
+ content_sha256: string;
148
+ size_bytes: number;
149
+ };
126
150
  export type UpdateReferenceSummariesOptions = WorkspaceViewerOptions & {
127
151
  summaries: ReferenceSummaryRecord[];
128
152
  };
@@ -0,0 +1,111 @@
1
+ CREATE TABLE platform_outbound_intents_v2 (
2
+ intent_ref TEXT PRIMARY KEY CHECK (intent_ref GLOB 'idem_*'),
3
+ platform TEXT NOT NULL CHECK (platform = 'feishu'),
4
+ installation_ref TEXT NOT NULL,
5
+ binding_ref TEXT NOT NULL,
6
+ event_kind TEXT NOT NULL CHECK (
7
+ event_kind IN ('chat_response', 'needs_input', 'task_completed', 'task_failed')
8
+ ),
9
+ event_key TEXT NOT NULL UNIQUE,
10
+ subject_kind TEXT NOT NULL CHECK (
11
+ subject_kind IN ('message', 'clarification_round', 'approval_request', 'task_result')
12
+ ),
13
+ subject_ref TEXT NOT NULL,
14
+ target_kind TEXT NOT NULL CHECK (target_kind IN ('project', 'work')),
15
+ trigger_message_id TEXT,
16
+ canonical_message_id TEXT UNIQUE,
17
+ content_text TEXT CHECK (content_text IS NULL OR length(content_text) BETWEEN 1 AND 4000),
18
+ disposition TEXT NOT NULL CHECK (
19
+ disposition IN ('pending', 'sending', 'retry_wait', 'handed_off', 'terminal')
20
+ ),
21
+ attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
22
+ next_attempt_at TEXT,
23
+ last_attempt_at TEXT,
24
+ delivery_ref TEXT,
25
+ error_code TEXT,
26
+ created_at TEXT NOT NULL,
27
+ updated_at TEXT NOT NULL,
28
+ handed_off_at TEXT,
29
+ FOREIGN KEY (trigger_message_id) REFERENCES messages(id) ON DELETE RESTRICT,
30
+ FOREIGN KEY (canonical_message_id) REFERENCES messages(id) ON DELETE RESTRICT,
31
+ CHECK (canonical_message_id IS NOT NULL OR content_text IS NOT NULL),
32
+ CHECK (
33
+ event_kind != 'chat_response'
34
+ OR (
35
+ trigger_message_id IS NOT NULL
36
+ AND canonical_message_id IS NOT NULL
37
+ AND subject_kind = 'message'
38
+ AND target_kind = 'project'
39
+ AND content_text IS NULL
40
+ )
41
+ ),
42
+ CHECK (
43
+ (disposition = 'handed_off' AND delivery_ref IS NOT NULL AND handed_off_at IS NOT NULL)
44
+ OR disposition != 'handed_off'
45
+ )
46
+ );
47
+
48
+ INSERT INTO platform_outbound_intents_v2 (
49
+ intent_ref,
50
+ platform,
51
+ installation_ref,
52
+ binding_ref,
53
+ event_kind,
54
+ event_key,
55
+ subject_kind,
56
+ subject_ref,
57
+ target_kind,
58
+ trigger_message_id,
59
+ canonical_message_id,
60
+ content_text,
61
+ disposition,
62
+ attempt_count,
63
+ next_attempt_at,
64
+ last_attempt_at,
65
+ delivery_ref,
66
+ error_code,
67
+ created_at,
68
+ updated_at,
69
+ handed_off_at
70
+ )
71
+ SELECT
72
+ intent_ref,
73
+ platform,
74
+ installation_ref,
75
+ binding_ref,
76
+ 'chat_response',
77
+ 'chat_response:' || canonical_message_id,
78
+ 'message',
79
+ canonical_message_id,
80
+ 'project',
81
+ trigger_message_id,
82
+ canonical_message_id,
83
+ NULL,
84
+ disposition,
85
+ attempt_count,
86
+ next_attempt_at,
87
+ last_attempt_at,
88
+ delivery_ref,
89
+ error_code,
90
+ created_at,
91
+ updated_at,
92
+ handed_off_at
93
+ FROM platform_outbound_intents;
94
+
95
+ DROP TABLE platform_outbound_intents;
96
+ ALTER TABLE platform_outbound_intents_v2 RENAME TO platform_outbound_intents;
97
+
98
+ CREATE INDEX platform_outbound_intents_due
99
+ ON platform_outbound_intents (disposition, next_attempt_at, created_at, intent_ref);
100
+
101
+ CREATE INDEX platform_outbound_intents_trigger
102
+ ON platform_outbound_intents (trigger_message_id, created_at, intent_ref);
103
+
104
+ CREATE INDEX platform_outbound_intents_event
105
+ ON platform_outbound_intents (event_kind, subject_kind, subject_ref, created_at);
106
+
107
+ CREATE TABLE platform_outbound_event_capture_state (
108
+ id INTEGER PRIMARY KEY CHECK (id = 1),
109
+ capture_after TEXT NOT NULL,
110
+ updated_at TEXT NOT NULL
111
+ );
@@ -0,0 +1,76 @@
1
+ CREATE TABLE platform_outbound_intents_v3 (
2
+ intent_ref TEXT PRIMARY KEY CHECK (intent_ref GLOB 'idem_*'),
3
+ platform TEXT NOT NULL CHECK (platform = 'feishu'),
4
+ installation_ref TEXT NOT NULL,
5
+ binding_ref TEXT NOT NULL,
6
+ event_kind TEXT NOT NULL CHECK (
7
+ event_kind IN ('chat_response', 'needs_input', 'task_completed', 'task_failed')
8
+ ),
9
+ event_key TEXT NOT NULL UNIQUE,
10
+ subject_kind TEXT NOT NULL CHECK (
11
+ subject_kind IN ('message', 'clarification_round', 'approval_request', 'task_result')
12
+ ),
13
+ subject_ref TEXT NOT NULL,
14
+ target_kind TEXT NOT NULL CHECK (target_kind IN ('project', 'work')),
15
+ trigger_message_id TEXT,
16
+ canonical_message_id TEXT UNIQUE,
17
+ content_text TEXT CHECK (content_text IS NULL OR length(content_text) BETWEEN 1 AND 4000),
18
+ content_json TEXT CHECK (content_json IS NULL OR length(content_json) BETWEEN 2 AND 32768),
19
+ disposition TEXT NOT NULL CHECK (
20
+ disposition IN ('pending', 'sending', 'retry_wait', 'handed_off', 'terminal')
21
+ ),
22
+ attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
23
+ next_attempt_at TEXT,
24
+ last_attempt_at TEXT,
25
+ delivery_ref TEXT,
26
+ error_code TEXT,
27
+ created_at TEXT NOT NULL,
28
+ updated_at TEXT NOT NULL,
29
+ handed_off_at TEXT,
30
+ FOREIGN KEY (trigger_message_id) REFERENCES messages(id) ON DELETE RESTRICT,
31
+ FOREIGN KEY (canonical_message_id) REFERENCES messages(id) ON DELETE RESTRICT,
32
+ CHECK (
33
+ canonical_message_id IS NOT NULL OR content_text IS NOT NULL OR content_json IS NOT NULL
34
+ ),
35
+ CHECK (content_text IS NULL OR content_json IS NULL),
36
+ CHECK (
37
+ event_kind != 'chat_response'
38
+ OR (
39
+ trigger_message_id IS NOT NULL
40
+ AND canonical_message_id IS NOT NULL
41
+ AND subject_kind = 'message'
42
+ AND target_kind = 'project'
43
+ AND content_text IS NULL
44
+ AND content_json IS NULL
45
+ )
46
+ ),
47
+ CHECK (
48
+ (disposition = 'handed_off' AND delivery_ref IS NOT NULL AND handed_off_at IS NOT NULL)
49
+ OR disposition != 'handed_off'
50
+ )
51
+ );
52
+
53
+ INSERT INTO platform_outbound_intents_v3 (
54
+ intent_ref, platform, installation_ref, binding_ref, event_kind, event_key,
55
+ subject_kind, subject_ref, target_kind, trigger_message_id, canonical_message_id,
56
+ content_text, content_json, disposition, attempt_count, next_attempt_at,
57
+ last_attempt_at, delivery_ref, error_code, created_at, updated_at, handed_off_at
58
+ )
59
+ SELECT
60
+ intent_ref, platform, installation_ref, binding_ref, event_kind, event_key,
61
+ subject_kind, subject_ref, target_kind, trigger_message_id, canonical_message_id,
62
+ content_text, NULL, disposition, attempt_count, next_attempt_at,
63
+ last_attempt_at, delivery_ref, error_code, created_at, updated_at, handed_off_at
64
+ FROM platform_outbound_intents;
65
+
66
+ DROP TABLE platform_outbound_intents;
67
+ ALTER TABLE platform_outbound_intents_v3 RENAME TO platform_outbound_intents;
68
+
69
+ CREATE INDEX platform_outbound_intents_due
70
+ ON platform_outbound_intents (disposition, next_attempt_at, created_at, intent_ref);
71
+
72
+ CREATE INDEX platform_outbound_intents_trigger
73
+ ON platform_outbound_intents (trigger_message_id, created_at, intent_ref);
74
+
75
+ CREATE INDEX platform_outbound_intents_event
76
+ ON platform_outbound_intents (event_kind, subject_kind, subject_ref, created_at);
@@ -0,0 +1,34 @@
1
+ CREATE TABLE managed_reference_sources (
2
+ source_ref TEXT PRIMARY KEY,
3
+ adapter_key TEXT NOT NULL,
4
+ reference_path TEXT NOT NULL UNIQUE,
5
+ accepted_revision_ref TEXT,
6
+ accepted_blob_oid TEXT,
7
+ accepted_content_sha256 TEXT,
8
+ last_operation_ref TEXT,
9
+ last_expected_blob_oid TEXT,
10
+ last_outcome TEXT CHECK (last_outcome IS NULL OR last_outcome IN ('created', 'updated', 'unchanged')),
11
+ pending_operation_ref TEXT,
12
+ pending_revision_ref TEXT,
13
+ pending_content_sha256 TEXT,
14
+ pending_expected_blob_oid TEXT,
15
+ side_effects_pending INTEGER NOT NULL DEFAULT 0 CHECK (side_effects_pending IN (0, 1)),
16
+ last_checked_at TEXT,
17
+ last_accepted_at TEXT,
18
+ created_at TEXT NOT NULL,
19
+ updated_at TEXT NOT NULL,
20
+ CHECK (
21
+ (accepted_revision_ref IS NULL AND accepted_blob_oid IS NULL AND accepted_content_sha256 IS NULL)
22
+ OR
23
+ (accepted_revision_ref IS NOT NULL AND accepted_blob_oid IS NOT NULL AND accepted_content_sha256 IS NOT NULL)
24
+ ),
25
+ CHECK (
26
+ (pending_operation_ref IS NULL AND pending_revision_ref IS NULL AND pending_content_sha256 IS NULL)
27
+ OR
28
+ (pending_operation_ref IS NOT NULL AND pending_revision_ref IS NOT NULL AND pending_content_sha256 IS NOT NULL)
29
+ )
30
+ );
31
+
32
+ CREATE INDEX managed_reference_sources_pending_idx
33
+ ON managed_reference_sources (side_effects_pending, updated_at)
34
+ WHERE side_effects_pending = 1;
@@ -30,10 +30,13 @@
30
30
  - `0015_control_plane_intents.sql`:新增 Control Plane durable dispatch intent,保存 bounded kind / owner / dedupe / lane、pending-to-running claim lease 与 terminal 状态,为 Clarification、Task Compile、Scratchpad、Reference Summary 和 Run 提供可恢复的 runtime handoff;同时用 immutable pending Task Compile submission row 固化 context capture 前的 workflow / main-chat cursor boundary,不保存 prompt、消息正文、provider output、secret 或 host path。
31
31
  - `0016_external_source_mappings.sql`:新增external installation / message identity到既有`messages.id`的一对一mapping和append-only revision observation;mapped message evidence、mapping identity与observations由trigger / FK保护,不保存raw platform payload、credential或短期URL。
32
32
  - `0017_platform_outbound_intents.sql`:新增Host-owned platform outbound intent;只引用canonical / trigger message与installation / binding locator,保存handoff attempt和terminal状态,不复制回复正文或保存conversation ref / credential。
33
+ - `0018_platform_outbound_events.sql`:把旧Chat response intent无损迁移为event-aware schema,新增stable event / subject / Project-or-Work target、approval bounded snapshot与首次status capture boundary;不回填升级前clarification / Task terminal消息。
34
+ - `0019_platform_outbound_card_content.sql`:把approval outbound snapshot从text扩展为经过internal schema验证的structured card content,同时无损保留既有intent、handoff与重试状态;不保存conversation、platform action或callback receipt。
35
+ - `0020_managed_reference_sources.sql`:保存opaque managed source / adapter /稳定Reference path、accepted revision / blob / digest、pending operation与写后副作用恢复checkpoint;不保存平台document locator、credential、正文、staged URL或Relay authority。
33
36
 
34
37
  ## 当前实现状态
35
38
 
36
- - `0001_init.sql` 至 `0017_platform_outbound_intents.sql` 已存在,代表当前 host project SQLite schema contract。`0014` 明确采用开发数据库重建策略,不提供旧 Scratchpad source/cursor 数据兼容;`0016`–`0017`是additive migration,不要求为既有internal Chat message或agent response回填external mapping / outbound intent。
39
+ - `0001_init.sql` 至 `0020_managed_reference_sources.sql` 已存在,代表当前 host project SQLite schema contract。`0014` 明确采用开发数据库重建策略,不提供旧 Scratchpad source/cursor 数据兼容;`0016`–`0017`不要求为既有internal Chat message或agent response回填external mapping / outbound intent,`0018`保留旧intent并以runtime capture boundary阻止历史status回填,`0019`无损加入structured card content,`0020`加入独立managed Reference recovery checkpoint
37
40
  - SQLite adapter、migration runner、checksum 校验、store metadata 初始化、transaction helper 与 command recovery scan helper 已实现。
38
41
  - 协作 repository 与 Control Plane 已实现第一批业务读写;Phase 7 首批已复用 `0001_init.sql` 中的 `tasks.latest_run_result_id`、`task_details.result_json` 与 `run_results` 表完成 Run result / checks / promotion 摘要持久化。Control Plane recovery resolver 与 task-bound continuation / retry 复用现有 schema;新 Run 的 accepted checkpoint 业务 truth 继续写入最终 Run result / task detail result,Git tag / commit trailer 承担 crash recovery evidence。Timeline 默认从 `tasks`、`run_results` 与历史主群聊 `refs.worklist_feedback` 投影任务级审计节点,当前 task terminal Chat feedback 写入 `refs.task_result` 消息;`project_timeline_events` 只保留缺少稳定 record 的轻量可观测性事件和历史 reconcile 兼容记录。project workspace、working diff 与 ignored runtime state 都不进入 SQLite truth。`provider_usage_events` 只保存 token 计数、调用来源、模型名、记录时间和可空 anchor,不保存 provider secret、prompt 或 raw response。store 基础设施本身已经可以创建并迁移 `tutti.sqlite`。
39
42
 
@@ -1,7 +1,7 @@
1
1
  import { type HostConnectionRef, type IdempotencyKey, type ProjectId, type RelayProjectRef, type RelayUploadRef } from "@tutti/shared/ids";
2
2
  import type { ProjectSurfaceProfile } from "@tutti/shared/domain";
3
3
  import type { RelayUploadPurpose, Sha256Digest } from "@tutti/shared/schemas/api";
4
- import { type FeishuSetupProjection, type PlatformOutboundHandoffResponse, type PlatformOutboundTextIntent } from "@tutti/shared/schemas/internal";
4
+ import { type FeishuSetupProjection, type PlatformOutboundHandoffResponse, type PlatformOutboundIntent } from "@tutti/shared/schemas/internal";
5
5
  export type RelayHostControlFetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
6
6
  export type RelayProjectProjection = {
7
7
  relay_project_ref: RelayProjectRef;
@@ -44,7 +44,10 @@ export type RegisterRelayHostConnectionPayload = {
44
44
  browser_secret_write: false;
45
45
  repo_viewer: boolean;
46
46
  integration_source_ingestion_v1?: boolean;
47
+ integration_attachment_ingestion_v1?: boolean;
48
+ integration_managed_reference_ingestion_v1?: boolean;
47
49
  integration_outbound_v1?: boolean;
50
+ integration_approval_decision_v1?: boolean;
48
51
  };
49
52
  };
50
53
  join_token?: {
@@ -139,7 +142,7 @@ export type DeliverRelayPlatformOutboundOptions = {
139
142
  relayProjectRef: RelayProjectRef;
140
143
  hostConnectionRef: HostConnectionRef;
141
144
  hostRegistrationSecret: string;
142
- intent: PlatformOutboundTextIntent;
145
+ intent: PlatformOutboundIntent;
143
146
  fetch?: RelayHostControlFetch;
144
147
  timeoutMs?: number;
145
148
  signal?: AbortSignal;
@@ -57,7 +57,10 @@ function createRegisterPayload(options) {
57
57
  browser_secret_write: false,
58
58
  repo_viewer: capabilities.repo_viewer ?? false,
59
59
  integration_source_ingestion_v1: capabilities.integration_source_ingestion_v1 ?? false,
60
+ integration_attachment_ingestion_v1: capabilities.integration_attachment_ingestion_v1 ?? false,
61
+ integration_managed_reference_ingestion_v1: capabilities.integration_managed_reference_ingestion_v1 ?? false,
60
62
  integration_outbound_v1: capabilities.integration_outbound_v1 ?? false,
63
+ integration_approval_decision_v1: capabilities.integration_approval_decision_v1 ?? false,
61
64
  },
62
65
  },
63
66
  };
@@ -5,8 +5,8 @@ export { CompleteDesktopEntryContinuationBodySchema, CompleteDesktopEntryContinu
5
5
  export type { CompleteDesktopEntryContinuationBody, CreateDesktopEntryContinuationResponse, GetDesktopEntryContinuationResponse, SealedDesktopEntryPayload, } from "./desktop-entry-continuations.js";
6
6
  export { LOCAL_CONSOLE_ACCOUNT_HANDOFF_TOKEN_MAX_LENGTH, LOCAL_CONSOLE_ACCOUNT_HANDOFF_TOKEN_MIN_LENGTH, RegisterLocalConsoleAccountHandoffBodySchema, RegisterLocalConsoleAccountHandoffResponseSchema, } from "./local-console-account-handoffs.js";
7
7
  export type { RegisterLocalConsoleAccountHandoffBody, RegisterLocalConsoleAccountHandoffResponse, } from "./local-console-account-handoffs.js";
8
- export { FEISHU_H5_AUTHORIZATION_CODE_MAX_LENGTH, FEISHU_H5_REQUIRED_USER_SCOPE, FEISHU_PLATFORM_STATE_LENGTH, FeishuPlatformSessionBootstrapBodySchema, FeishuPlatformSessionBootstrapResponseSchema, FeishuPlatformSessionExchangeBodySchema, FeishuPlatformSessionProjectionSchema, FeishuPlatformStateSchema, } from "./platform-sessions.js";
9
- export type { FeishuPlatformSessionBootstrapBody, FeishuPlatformSessionBootstrapResponse, FeishuPlatformSessionExchangeBody, FeishuPlatformSessionProjection, } from "./platform-sessions.js";
8
+ export { FEISHU_BROWSER_HANDOFF_TOKEN_LENGTH, FEISHU_DOCX_REQUIRED_USER_SCOPE, FEISHU_H5_AUTHORIZATION_CODE_MAX_LENGTH, FEISHU_H5_REQUIRED_USER_SCOPE, FEISHU_PLATFORM_STATE_LENGTH, FeishuPlatformSessionBootstrapBodySchema, FeishuPlatformSessionBootstrapResponseSchema, FeishuBrowserHandoffResponseSchema, FeishuBrowserHandoffTokenSchema, ConsumeFeishuBrowserHandoffBodySchema, FeishuDocumentAuthorizationBootstrapResponseSchema, FeishuDocumentAuthorizationExchangeBodySchema, FeishuDocumentAuthorizationProjectionSchema, FeishuPlatformSessionExchangeBodySchema, FeishuPlatformSessionProjectionSchema, FeishuPlatformStateSchema, } from "./platform-sessions.js";
9
+ export type { FeishuPlatformSessionBootstrapBody, FeishuPlatformSessionBootstrapResponse, FeishuBrowserHandoffResponse, ConsumeFeishuBrowserHandoffBody, FeishuDocumentAuthorizationBootstrapResponse, FeishuDocumentAuthorizationExchangeBody, FeishuDocumentAuthorizationProjection, FeishuPlatformSessionExchangeBody, FeishuPlatformSessionProjection, } from "./platform-sessions.js";
10
10
  export { ApiErrorCodeSchema, ApiErrorResponseSchema, CommandDispositionBaseSchema, CursorPageRequestSchema, DEFAULT_SSE_REPLAY_WINDOW_POLICY, InterruptedCommandDispositionSchema, QueryInvalidationHintSchema, RelayInvalidationHintSchema, RelaySseEventTypeSchema, SseReplayWindowPolicySchema, WorkspaceSseEventTypeSchema, commandEnvelopeSchema, commandResponseSchema, commandResponseWithResultSchema, cursorPageSchema, relaySseEventSchema, timelineWindowSchema, workspaceSseEventSchema, } from "./primitives.js";
11
11
  export { GetProviderModelsResponseSchema, MAX_PROVIDER_MODEL_NAME_LENGTH, ProviderConfigInvalidReasonCodeSchema, ProviderConfigProjectionSchema, ProviderModelDiscoveryUnavailableReasonSchema, ProviderModelNameSchema, ProviderModelValidationFailureReasonSchema, ProviderUnavailableReasonCodeSchema, ProjectProviderUnavailableReasonSchema, UpdateProviderDefaultModelBodySchema, UpdateProviderDefaultModelDispositionSchema, UpdateProviderDefaultModelPayloadSchema, UpdateProviderDefaultModelResponseSchema, } from "./provider-config.js";
12
12
  export { ProviderUsageBreakdownProjectionSchema, ProviderUsageCategorySchema, ProviderUsageModelSummaryProjectionSchema, ProviderUsageProjectionSchema, ProviderUsageSourceSummaryProjectionSchema, } from "./provider-usage.js";
@@ -2,7 +2,7 @@ export * from "./openapi.js";
2
2
  export { ARTIFACT_FEEDBACK_MAX_ANNOTATIONS, ARTIFACT_FEEDBACK_MAX_AUTHORED_TEXT_LENGTH, ARTIFACT_FEEDBACK_MAX_COMMENT_LENGTH, ARTIFACT_FEEDBACK_MAX_SERIALIZED_BYTES, ARTIFACT_FEEDBACK_MAX_SUMMARY_LENGTH, ArtifactElementAnchorSchema, ArtifactElementKindSchema, ArtifactElementTargetSchema, ArtifactFeedbackAnnotationSchema, ArtifactFeedbackCommandSchema, ArtifactFeedbackRefSchema, ArtifactSemanticContextSchema, ArtifactSemanticSnapshotSchema, ArtifactSemanticStateSchema, } from "./artifact-feedback.js";
3
3
  export { CompleteDesktopEntryContinuationBodySchema, CompleteDesktopEntryContinuationResponseSchema, CreateDesktopEntryContinuationResponseSchema, DESKTOP_ENTRY_COMPLETION_TOKEN_LENGTH, DESKTOP_ENTRY_PAYLOAD_KEY_LENGTH, DESKTOP_ENTRY_SEALED_IV_LENGTH, DesktopEntryCompletionTokenSchema, DesktopEntryContinuationPendingProjectionSchema, DesktopEntryContinuationReadyProjectionSchema, DesktopEntryPayloadKeySchema, GetDesktopEntryContinuationResponseSchema, MAX_DESKTOP_ENTRY_SEALED_CIPHERTEXT_LENGTH, SealedDesktopEntryPayloadSchema, } from "./desktop-entry-continuations.js";
4
4
  export { LOCAL_CONSOLE_ACCOUNT_HANDOFF_TOKEN_MAX_LENGTH, LOCAL_CONSOLE_ACCOUNT_HANDOFF_TOKEN_MIN_LENGTH, RegisterLocalConsoleAccountHandoffBodySchema, RegisterLocalConsoleAccountHandoffResponseSchema, } from "./local-console-account-handoffs.js";
5
- export { FEISHU_H5_AUTHORIZATION_CODE_MAX_LENGTH, FEISHU_H5_REQUIRED_USER_SCOPE, FEISHU_PLATFORM_STATE_LENGTH, FeishuPlatformSessionBootstrapBodySchema, FeishuPlatformSessionBootstrapResponseSchema, FeishuPlatformSessionExchangeBodySchema, FeishuPlatformSessionProjectionSchema, FeishuPlatformStateSchema, } from "./platform-sessions.js";
5
+ export { FEISHU_BROWSER_HANDOFF_TOKEN_LENGTH, FEISHU_DOCX_REQUIRED_USER_SCOPE, FEISHU_H5_AUTHORIZATION_CODE_MAX_LENGTH, FEISHU_H5_REQUIRED_USER_SCOPE, FEISHU_PLATFORM_STATE_LENGTH, FeishuPlatformSessionBootstrapBodySchema, FeishuPlatformSessionBootstrapResponseSchema, FeishuBrowserHandoffResponseSchema, FeishuBrowserHandoffTokenSchema, ConsumeFeishuBrowserHandoffBodySchema, FeishuDocumentAuthorizationBootstrapResponseSchema, FeishuDocumentAuthorizationExchangeBodySchema, FeishuDocumentAuthorizationProjectionSchema, FeishuPlatformSessionExchangeBodySchema, FeishuPlatformSessionProjectionSchema, FeishuPlatformStateSchema, } from "./platform-sessions.js";
6
6
  export { ApiErrorCodeSchema, ApiErrorResponseSchema, CommandDispositionBaseSchema, CursorPageRequestSchema, DEFAULT_SSE_REPLAY_WINDOW_POLICY, InterruptedCommandDispositionSchema, QueryInvalidationHintSchema, RelayInvalidationHintSchema, RelaySseEventTypeSchema, SseReplayWindowPolicySchema, WorkspaceSseEventTypeSchema, commandEnvelopeSchema, commandResponseSchema, commandResponseWithResultSchema, cursorPageSchema, relaySseEventSchema, timelineWindowSchema, workspaceSseEventSchema, } from "./primitives.js";
7
7
  export { GetProviderModelsResponseSchema, MAX_PROVIDER_MODEL_NAME_LENGTH, ProviderConfigInvalidReasonCodeSchema, ProviderConfigProjectionSchema, ProviderModelDiscoveryUnavailableReasonSchema, ProviderModelNameSchema, ProviderModelValidationFailureReasonSchema, ProviderUnavailableReasonCodeSchema, ProjectProviderUnavailableReasonSchema, UpdateProviderDefaultModelBodySchema, UpdateProviderDefaultModelDispositionSchema, UpdateProviderDefaultModelPayloadSchema, UpdateProviderDefaultModelResponseSchema, } from "./provider-config.js";
8
8
  export { ProviderUsageBreakdownProjectionSchema, ProviderUsageCategorySchema, ProviderUsageModelSummaryProjectionSchema, ProviderUsageProjectionSchema, ProviderUsageSourceSummaryProjectionSchema, } from "./provider-usage.js";
@@ -1,8 +1,11 @@
1
1
  import type { Static } from "@sinclair/typebox";
2
2
  export declare const FEISHU_H5_AUTHORIZATION_CODE_MAX_LENGTH = 2048;
3
3
  export declare const FEISHU_H5_REQUIRED_USER_SCOPE = "im:chat.members:read";
4
+ export declare const FEISHU_DOCX_REQUIRED_USER_SCOPE = "docx:document:readonly";
4
5
  export declare const FEISHU_PLATFORM_STATE_LENGTH = 43;
6
+ export declare const FEISHU_BROWSER_HANDOFF_TOKEN_LENGTH = 43;
5
7
  export declare const FeishuPlatformStateSchema: import("@sinclair/typebox").TString;
8
+ export declare const FeishuBrowserHandoffTokenSchema: import("@sinclair/typebox").TString;
6
9
  export declare const FeishuPlatformSessionBootstrapBodySchema: import("@sinclair/typebox").TObject<{
7
10
  relay_project_ref: import("@sinclair/typebox").TString;
8
11
  }>;
@@ -36,8 +39,39 @@ export declare const FeishuPlatformSessionProjectionSchema: import("@sinclair/ty
36
39
  transport: import("@sinclair/typebox").TLiteral<"http_only_cookie">;
37
40
  }>;
38
41
  }>;
42
+ export declare const FeishuDocumentAuthorizationBootstrapResponseSchema: import("@sinclair/typebox").TObject<{
43
+ platform: import("@sinclair/typebox").TLiteral<"feishu">;
44
+ app_id: import("@sinclair/typebox").TString;
45
+ state: import("@sinclair/typebox").TString;
46
+ authorization_scopes: import("@sinclair/typebox").TTuple<[import("@sinclair/typebox").TLiteral<"docx:document:readonly">]>;
47
+ expires_at: import("@sinclair/typebox").TString;
48
+ }>;
49
+ export declare const FeishuDocumentAuthorizationExchangeBodySchema: import("@sinclair/typebox").TObject<{
50
+ state: import("@sinclair/typebox").TString;
51
+ authorization_code: import("@sinclair/typebox").TString;
52
+ }>;
53
+ export declare const FeishuDocumentAuthorizationProjectionSchema: import("@sinclair/typebox").TObject<{
54
+ platform: import("@sinclair/typebox").TLiteral<"feishu">;
55
+ status: import("@sinclair/typebox").TLiteral<"authorized">;
56
+ authorized_at: import("@sinclair/typebox").TString;
57
+ }>;
58
+ export declare const FeishuBrowserHandoffResponseSchema: import("@sinclair/typebox").TObject<{
59
+ platform: import("@sinclair/typebox").TLiteral<"feishu">;
60
+ relay_project_ref: import("@sinclair/typebox").TString;
61
+ handoff_token: import("@sinclair/typebox").TString;
62
+ expires_at: import("@sinclair/typebox").TString;
63
+ }>;
64
+ export declare const ConsumeFeishuBrowserHandoffBodySchema: import("@sinclair/typebox").TObject<{
65
+ relay_project_ref: import("@sinclair/typebox").TString;
66
+ handoff_token: import("@sinclair/typebox").TString;
67
+ }>;
39
68
  export type FeishuPlatformSessionBootstrapBody = Static<typeof FeishuPlatformSessionBootstrapBodySchema>;
40
69
  export type FeishuPlatformSessionBootstrapResponse = Static<typeof FeishuPlatformSessionBootstrapResponseSchema>;
41
70
  export type FeishuPlatformSessionExchangeBody = Static<typeof FeishuPlatformSessionExchangeBodySchema>;
42
71
  export type FeishuPlatformSessionProjection = Static<typeof FeishuPlatformSessionProjectionSchema>;
72
+ export type FeishuDocumentAuthorizationBootstrapResponse = Static<typeof FeishuDocumentAuthorizationBootstrapResponseSchema>;
73
+ export type FeishuDocumentAuthorizationExchangeBody = Static<typeof FeishuDocumentAuthorizationExchangeBodySchema>;
74
+ export type FeishuDocumentAuthorizationProjection = Static<typeof FeishuDocumentAuthorizationProjectionSchema>;
75
+ export type FeishuBrowserHandoffResponse = Static<typeof FeishuBrowserHandoffResponseSchema>;
76
+ export type ConsumeFeishuBrowserHandoffBody = Static<typeof ConsumeFeishuBrowserHandoffBodySchema>;
43
77
  //# sourceMappingURL=platform-sessions.d.ts.map