@xfey/tutti 0.1.119 → 0.1.121

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 (113) hide show
  1. package/dist/approvals/decision-command.d.ts +2 -2
  2. package/dist/collaboration-state/clarification-snapshot.d.ts +9 -9
  3. package/dist/collaboration-state/task-compile-context.d.ts +1 -1
  4. package/dist/control-plane/workflows/openai.d.ts +3 -4
  5. package/dist/control-plane/workflows/openai.js +3 -2
  6. package/dist/providers/openai/app-server/invocation-coordinator.d.ts +1 -0
  7. package/dist/providers/openai/app-server/invocation-coordinator.js +4 -1
  8. package/dist/providers/openai/app-server/invocation-deadline.d.ts +3 -0
  9. package/dist/providers/openai/app-server/invocation-deadline.js +15 -0
  10. package/dist/providers/openai/app-server/read-only-procedure.d.ts +4 -2
  11. package/dist/providers/openai/app-server/read-only-procedure.js +16 -0
  12. package/dist/providers/openai/app-server/workspace-write-run.d.ts +4 -2
  13. package/dist/providers/openai/app-server/workspace-write-run.js +16 -0
  14. package/dist/providers/openai/chat-assistant.d.ts +3 -4
  15. package/dist/providers/openai/chat-assistant.js +2 -1
  16. package/dist/providers/openai/execution-access.d.ts +17 -0
  17. package/dist/providers/openai/execution-access.js +13 -0
  18. package/dist/providers/openai/sdk-procedure-runner.d.ts +2 -2
  19. package/dist/providers/openai/sdk-procedure-runner.js +17 -0
  20. package/dist/run-pipeline/artifact-applicability.d.ts +3 -4
  21. package/dist/run-pipeline/artifact-applicability.js +2 -1
  22. package/dist/run-pipeline/openai.d.ts +3 -4
  23. package/dist/run-pipeline/openai.js +3 -2
  24. package/dist/run-pipeline/task-run-invocation.js +6 -12
  25. package/dist/server-shell/cli/cli.js +3 -0
  26. package/dist/server-shell/cli/host-lifecycle.js +1 -0
  27. package/dist/server-shell/cli/host-server-runtime.d.ts +1 -0
  28. package/dist/server-shell/cli/host-server-runtime.js +83 -34
  29. package/dist/server-shell/cli/launch-command.js +1 -1
  30. package/dist/server-shell/cli/launch.d.ts +7 -3
  31. package/dist/server-shell/cli/launch.js +23 -4
  32. package/dist/server-shell/cli/machine-local.d.ts +9 -0
  33. package/dist/server-shell/cli/machine-local.js +60 -6
  34. package/dist/server-shell/cli/project-resolver.d.ts +2 -2
  35. package/dist/server-shell/cli/project-resolver.js +6 -3
  36. package/dist/server-shell/cli/relay-registration.js +38 -1
  37. package/dist/server-shell/http/routes/local-control.d.ts +1 -1
  38. package/dist/server-shell/http/routes/local-control.js +2 -46
  39. package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +45 -137
  40. package/dist/server-shell/http/routes/project-api/openapi.d.ts +45 -137
  41. package/dist/server-shell/http/routes/project-api/schemas.d.ts +24 -136
  42. package/dist/server-shell/http/routes/project-api/schemas.js +4 -58
  43. package/dist/server-shell/http/routes/project-api/types.d.ts +3 -0
  44. package/dist/server-shell/local-console/managed-project-routes.d.ts +9 -0
  45. package/dist/server-shell/local-console/managed-project-routes.js +120 -0
  46. package/dist/server-shell/local-console/managed-project-service.d.ts +141 -0
  47. package/dist/server-shell/local-console/managed-project-service.js +158 -0
  48. package/dist/server-shell/local-console/operation-coordinator.d.ts +1 -1
  49. package/dist/server-shell/local-console/package-update-hosts.js +2 -1
  50. package/dist/server-shell/local-console/project-service.d.ts +4 -1
  51. package/dist/server-shell/local-console/project-service.js +62 -14
  52. package/dist/server-shell/local-console/server.js +22 -2
  53. package/dist/server-shell/managed-access/execution-binding.d.ts +9 -0
  54. package/dist/server-shell/managed-access/execution-binding.js +22 -0
  55. package/dist/server-shell/managed-access/existing-project.d.ts +15 -0
  56. package/dist/server-shell/managed-access/existing-project.js +41 -0
  57. package/dist/server-shell/managed-access/legacy-records.d.ts +2 -0
  58. package/dist/server-shell/managed-access/legacy-records.js +24 -0
  59. package/dist/server-shell/managed-access/model-control-client.d.ts +65 -0
  60. package/dist/server-shell/managed-access/model-control-client.js +112 -0
  61. package/dist/server-shell/managed-access/private-store.d.ts +19 -0
  62. package/dist/server-shell/managed-access/private-store.js +275 -0
  63. package/dist/server-shell/managed-access/project-provider.d.ts +18 -0
  64. package/dist/server-shell/managed-access/project-provider.js +30 -0
  65. package/dist/server-shell/managed-access/records.d.ts +103 -0
  66. package/dist/server-shell/managed-access/records.js +74 -0
  67. package/dist/server-shell/managed-access/runners.d.ts +11 -0
  68. package/dist/server-shell/managed-access/runners.js +103 -0
  69. package/dist/server-shell/managed-access/runtime-records.d.ts +106 -0
  70. package/dist/server-shell/managed-access/runtime-records.js +65 -0
  71. package/dist/server-shell/managed-access/runtime.d.ts +48 -0
  72. package/dist/server-shell/managed-access/runtime.js +300 -0
  73. package/dist/server-shell/managed-access/state.d.ts +53 -0
  74. package/dist/server-shell/managed-access/state.js +292 -0
  75. package/dist/server-shell/managed-access/transport.d.ts +45 -0
  76. package/dist/server-shell/managed-access/transport.js +39 -0
  77. package/dist/server-shell/managed-access/workspace.d.ts +10 -0
  78. package/dist/server-shell/managed-access/workspace.js +69 -0
  79. package/dist/server-shell/smoke/e2e-client.d.ts +8 -3
  80. package/dist/server-shell/smoke/e2e-client.js +11 -11
  81. package/node_modules/@tutti/relay-client/dist/host-control.d.ts +4 -1
  82. package/node_modules/@tutti/relay-client/dist/host-control.js +26 -3
  83. package/node_modules/@tutti/relay-client/dist/index.d.ts +1 -0
  84. package/node_modules/@tutti/relay-client/dist/index.js +1 -0
  85. package/node_modules/@tutti/relay-client/dist/project-authority.d.ts +70 -0
  86. package/node_modules/@tutti/relay-client/dist/project-authority.js +139 -0
  87. package/node_modules/@tutti/shared/dist/ids/index.d.ts +7 -0
  88. package/node_modules/@tutti/shared/dist/ids/index.js +7 -0
  89. package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -0
  90. package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -0
  91. package/node_modules/@tutti/shared/dist/schemas/api/managed-account.d.ts +34 -0
  92. package/node_modules/@tutti/shared/dist/schemas/api/managed-account.js +40 -0
  93. package/node_modules/@tutti/shared/dist/schemas/api/provider-config.d.ts +7 -4
  94. package/node_modules/@tutti/shared/dist/schemas/api/provider-config.js +5 -0
  95. package/node_modules/@tutti/shared/dist/schemas/api/runtime-events.d.ts +3 -0
  96. package/node_modules/@tutti/shared/dist/schemas/internal/creation-validation.d.ts +26 -0
  97. package/node_modules/@tutti/shared/dist/schemas/internal/creation-validation.js +40 -0
  98. package/node_modules/@tutti/shared/dist/schemas/internal/index.d.ts +5 -0
  99. package/node_modules/@tutti/shared/dist/schemas/internal/index.js +5 -0
  100. package/node_modules/@tutti/shared/dist/schemas/internal/managed-account.d.ts +12 -0
  101. package/node_modules/@tutti/shared/dist/schemas/internal/managed-account.js +13 -0
  102. package/node_modules/@tutti/shared/dist/schemas/internal/managed-models.d.ts +17 -0
  103. package/node_modules/@tutti/shared/dist/schemas/internal/managed-models.js +17 -0
  104. package/node_modules/@tutti/shared/dist/schemas/internal/managed-runtime.d.ts +113 -0
  105. package/node_modules/@tutti/shared/dist/schemas/internal/managed-runtime.js +84 -0
  106. package/node_modules/@tutti/shared/dist/schemas/internal/project-authority.d.ts +114 -0
  107. package/node_modules/@tutti/shared/dist/schemas/internal/project-authority.js +102 -0
  108. package/package.json +1 -1
  109. package/web/assets/{homepage-motion-scene-B6lCCHBq.js → homepage-motion-scene-WfLyzcCG.js} +1 -1
  110. package/web/assets/{index-DsYi7AhN.css → index-ATsYiBZs.css} +1 -1
  111. package/web/assets/index-o9YCtzEd.js +70 -0
  112. package/web/index.html +2 -2
  113. package/web/assets/index-DepsYMLl.js +0 -70
@@ -1,5 +1,5 @@
1
1
  import { ApprovalRequestIdSchema, ClarificationRoundRefSchema, ClarificationThreadRefSchema, IdempotencyKeySchema, IsoDateTimeStringSchema, ProjectIdSchema, RelayAccountRefSchema, RelayClientSessionIdSchema, RelayPlatformSessionRefSchema, RelayProjectRefSchema, RecoverySummaryIdSchema, TaskIdSchema, } from "@tutti/shared/schemas/domain";
2
- import { ActiveClarificationProjectionSchema, ActiveApprovalProjectionSchema, ExecutionStatusProjectionSchema, MessageWindowSchema, ProjectTimelineResponseSchema, ReadStateSummaryProjectionSchema, ScratchpadProjectionSchema, WorklistProjectionSchema, } from "@tutti/shared/schemas/api";
2
+ import { ActiveClarificationProjectionSchema, ActiveApprovalProjectionSchema, ExecutionStatusProjectionSchema, MessageWindowSchema, ProjectTimelineResponseSchema, ReadStateSummaryProjectionSchema, ScratchpadProjectionSchema, WorklistProjectionSchema, ProviderConfigProjectionSchema, } from "@tutti/shared/schemas/api";
3
3
  import { ACCOUNT_AVATAR_COLORS } from "@tutti/shared/domain";
4
4
  import { HOST_MAINLINE_BRANCH } from "./constants.js";
5
5
  export const AccountAvatarProjectionSchema = {
@@ -27,62 +27,8 @@ export const AccountAvatarProjectionSchema = {
27
27
  },
28
28
  ],
29
29
  };
30
- export const ProviderConfigProjectionSchema = {
31
- oneOf: [
32
- {
33
- type: "object",
34
- required: ["status"],
35
- additionalProperties: false,
36
- properties: {
37
- status: { type: "string", enum: ["not_configured"] },
38
- },
39
- },
40
- {
41
- type: "object",
42
- required: [
43
- "status",
44
- "provider",
45
- "auth_kind",
46
- "redacted_key",
47
- "default_model",
48
- "validated_at",
49
- ],
50
- additionalProperties: false,
51
- properties: {
52
- status: { type: "string", enum: ["configured"] },
53
- provider: { type: "string", enum: ["openai"] },
54
- auth_kind: { type: "string", enum: ["api_key"] },
55
- redacted_key: { type: "string" },
56
- default_model: { type: "string" },
57
- validated_at: IsoDateTimeStringSchema,
58
- },
59
- },
60
- {
61
- type: "object",
62
- required: ["status"],
63
- additionalProperties: false,
64
- properties: {
65
- status: { type: "string", enum: ["invalid"] },
66
- provider: { type: "string", enum: ["openai"] },
67
- auth_kind: { type: "string", enum: ["api_key"] },
68
- redacted_key: { type: "string" },
69
- default_model: { type: "string" },
70
- validated_at: IsoDateTimeStringSchema,
71
- invalid_reason_code: {
72
- type: "string",
73
- enum: [
74
- "provider_auth_invalid",
75
- "provider_quota_or_billing_required",
76
- "provider_rate_limited",
77
- "provider_model_unavailable",
78
- "provider_network_error",
79
- "unknown",
80
- ],
81
- },
82
- },
83
- },
84
- ],
85
- };
30
+ // Keep Fastify serialization and OpenAPI on the shared provider contract.
31
+ export { ProviderConfigProjectionSchema } from "@tutti/shared/schemas/api";
86
32
  const ProviderUsageBreakdownProjectionSchema = {
87
33
  type: "object",
88
34
  required: [
@@ -305,7 +251,7 @@ export const WorkspaceResponseSchema = {
305
251
  required: ["status"],
306
252
  additionalProperties: false,
307
253
  properties: {
308
- status: { type: "string", enum: ["not_configured", "configured", "invalid"] },
254
+ status: { type: "string", enum: ["not_configured", "configured", "managed", "invalid"] },
309
255
  provider: { type: "string", enum: ["openai"] },
310
256
  },
311
257
  },
@@ -23,6 +23,9 @@ export type ResolvedStagedUpload = {
23
23
  complete: (status: "completed" | "aborted") => Promise<void>;
24
24
  };
25
25
  export type HostProviderConfigProjection = {
26
+ status: "managed";
27
+ funding_kind: "trial";
28
+ } | {
26
29
  status: "not_configured";
27
30
  } | {
28
31
  status: "configured";
@@ -0,0 +1,9 @@
1
+ import type { FastifyInstance, FastifyRequest } from "fastify";
2
+ import { type LocalConsoleManagedProjectService } from "./managed-project-service.js";
3
+ import type { ReadLocalConsoleSession } from "./session.js";
4
+ export declare function registerLocalConsoleManagedProjectRoutes(app: FastifyInstance, options: {
5
+ service: LocalConsoleManagedProjectService;
6
+ tuttiHome: string;
7
+ requireSession: (request: FastifyRequest, csrf: boolean) => ReadLocalConsoleSession;
8
+ }): void;
9
+ //# sourceMappingURL=managed-project-routes.d.ts.map
@@ -0,0 +1,120 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { Value } from "@sinclair/typebox/value";
3
+ import { IdempotencyKeySchema } from "@tutti/shared/schemas/domain";
4
+ import { serializeRuntimeLogLine } from "@tutti/shared/utils";
5
+ import { NativeAuthorityTransportError } from "@tutti/relay-client";
6
+ import { appendHostLogLine, getHostLogFilePath } from "../cli/machine-local.js";
7
+ import { ManagedLocalStateError } from "../managed-access/private-store.js";
8
+ import { LocalConsoleProjectError } from "./project-service.js";
9
+ import { LocalConsoleOperationConflictError } from "./operation-coordinator.js";
10
+ import { LaunchError } from "../cli/errors.js";
11
+ import { ManagedDraftInputSchema, } from "./managed-project-service.js";
12
+ const ReadSchema = Type.Object({ request_ref: IdempotencyKeySchema }, { additionalProperties: false });
13
+ export function registerLocalConsoleManagedProjectRoutes(app, options) {
14
+ for (const operation of ["prepare", "read", "reconcile", "validate", "launch"]) {
15
+ app.post(`/local-console/v1/managed-projects/${operation}`, {
16
+ bodyLimit: 8192,
17
+ errorHandler: (error, request, reply) => {
18
+ if (error.code !== "FST_ERR_CTP_INVALID_JSON_BODY" &&
19
+ error.code !== "FST_ERR_CTP_BODY_TOO_LARGE")
20
+ throw error;
21
+ const status = error.code === "FST_ERR_CTP_BODY_TOO_LARGE" ? 413 : 400;
22
+ void reply
23
+ .code(status)
24
+ .header("cache-control", "no-store")
25
+ .header("x-tutti-request-id", request.id)
26
+ .send({
27
+ error: {
28
+ code: status === 413 ? "payload_too_large" : "managed_creation_input_invalid",
29
+ request_id: request.id,
30
+ retryable: false,
31
+ },
32
+ });
33
+ },
34
+ onError: (request, _reply, error, done) => {
35
+ // Parser, loopback, cookie and CSRF rejection precede the operation handler.
36
+ // Never record error.message: JSON parser errors may include request content.
37
+ observeManagedCreation(options.tuttiHome, request.id, operation, "rejected", error.statusCode === 401
38
+ ? "session_required"
39
+ : error.statusCode === 403
40
+ ? "request_origin_or_csrf_rejected"
41
+ : error.statusCode === 413
42
+ ? "payload_too_large"
43
+ : "managed_http_rejected");
44
+ done();
45
+ },
46
+ }, async (request, reply) => {
47
+ const diagnostic = request.id;
48
+ reply.header("x-tutti-request-id", diagnostic);
49
+ const session = options.requireSession(request, true);
50
+ if (!session.accountReady) {
51
+ observeManagedCreation(options.tuttiHome, diagnostic, operation, "rejected", "account_required");
52
+ return reply.code(401).send({
53
+ error: { code: "account_required", request_id: diagnostic, retryable: false },
54
+ });
55
+ }
56
+ const observe = (status, reason, upstreamRequestId) => {
57
+ observeManagedCreation(options.tuttiHome, diagnostic, operation, status, reason, upstreamRequestId);
58
+ };
59
+ try {
60
+ if (Object.keys(request.query).length)
61
+ throw new ManagedLocalStateError("managed_creation_input_invalid");
62
+ let result;
63
+ if (operation === "prepare") {
64
+ if (!Value.Check(ManagedDraftInputSchema, request.body))
65
+ throw new ManagedLocalStateError("managed_creation_input_invalid");
66
+ result = await options.service.prepare(request.body, session.context);
67
+ }
68
+ else {
69
+ if (!Value.Check(ReadSchema, request.body))
70
+ throw new ManagedLocalStateError("managed_creation_input_invalid");
71
+ result = await options.service[operation](request.body.request_ref, session.context);
72
+ }
73
+ observe("succeeded");
74
+ return result;
75
+ }
76
+ catch (error) {
77
+ const code = error instanceof ManagedLocalStateError ||
78
+ error instanceof LocalConsoleProjectError ||
79
+ error instanceof LocalConsoleOperationConflictError ||
80
+ error instanceof LaunchError ||
81
+ error instanceof NativeAuthorityTransportError
82
+ ? error.code
83
+ : "managed_creation_unavailable";
84
+ const status = error instanceof NativeAuthorityTransportError
85
+ ? (error.status ?? 503)
86
+ : error instanceof LocalConsoleProjectError
87
+ ? error.statusCode
88
+ : code === "managed_creation_input_invalid"
89
+ ? 400
90
+ : 409;
91
+ observe("rejected", code, error instanceof NativeAuthorityTransportError ? error.requestId : undefined);
92
+ return reply
93
+ .code(status)
94
+ .send({ error: { code, request_id: diagnostic, retryable: false } });
95
+ }
96
+ });
97
+ }
98
+ }
99
+ function observeManagedCreation(tuttiHome, diagnostic, stage, status, reason, upstreamRequestId) {
100
+ try {
101
+ appendHostLogLine(getHostLogFilePath(tuttiHome), serializeRuntimeLogLine({
102
+ service: "host",
103
+ component: "managed-creation",
104
+ level: status === "succeeded" ? "info" : "warn",
105
+ message: "Native managed creation operation",
106
+ fields: {
107
+ request_id: diagnostic,
108
+ stage,
109
+ status,
110
+ ...(reason === undefined ? {} : { reason_code: reason }),
111
+ ...(upstreamRequestId === undefined ? {} : { relay_request_id: upstreamRequestId }),
112
+ },
113
+ now: () => new Date(),
114
+ }));
115
+ }
116
+ catch {
117
+ /* Diagnostics cannot alter authorization or disclose private failures. */
118
+ }
119
+ }
120
+ //# sourceMappingURL=managed-project-routes.js.map
@@ -0,0 +1,141 @@
1
+ import { type Static } from "@sinclair/typebox";
2
+ import { type LocalConsoleInvocationContext } from "./invocation-context.js";
3
+ import type { LocalConsoleOperationCoordinator } from "./operation-coordinator.js";
4
+ import type { LocalConsoleProjectService } from "./project-service.js";
5
+ export declare const ManagedDraftInputSchema: import("@sinclair/typebox").TObject<{
6
+ request_ref: import("@sinclair/typebox").TString;
7
+ workspace_path: import("@sinclair/typebox").TString;
8
+ display_name: import("@sinclair/typebox").TString;
9
+ description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
10
+ surface: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"standalone">, import("@sinclair/typebox").TLiteral<"feishu">]>;
11
+ existing_project_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
12
+ }>;
13
+ export type ManagedDraftInput = Static<typeof ManagedDraftInputSchema>;
14
+ export declare class LocalConsoleManagedProjectService {
15
+ private readonly options;
16
+ constructor(options: {
17
+ tuttiHome: string;
18
+ operations: LocalConsoleOperationCoordinator;
19
+ serviceEnvironment?: NodeJS.ProcessEnv;
20
+ fetchImpl?: typeof fetch;
21
+ now?: () => Date;
22
+ projects?: Pick<LocalConsoleProjectService, "launchAuthorizedProject">;
23
+ });
24
+ private environment;
25
+ private state;
26
+ prepare(input: ManagedDraftInput, context: LocalConsoleInvocationContext): Promise<{
27
+ draft: {
28
+ state: "validation_failed" | "prepared" | "registered" | "validated" | "awaiting_authorization" | "validation_unknown";
29
+ expires_at: string;
30
+ existing_project_id?: `prj_${string}`;
31
+ surface: "standalone" | "feishu";
32
+ description?: string;
33
+ request_ref: string;
34
+ project_id: `prj_${string}`;
35
+ display_name: string;
36
+ workspace_path: string;
37
+ };
38
+ relay_origin: string;
39
+ preparation: {
40
+ existing_relay_project_ref?: string;
41
+ expires_before?: string;
42
+ installation_ref: string;
43
+ surface: "standalone" | "feishu";
44
+ request_ref: string;
45
+ project_id: string;
46
+ installation_secret_hash: string;
47
+ handoff_token_hash: string;
48
+ host_registration_secret_hash: string;
49
+ trial_consent: "trial-project-v1";
50
+ };
51
+ }>;
52
+ read(requestRef: string, context: LocalConsoleInvocationContext): {
53
+ draft: {
54
+ state: "validation_failed" | "prepared" | "registered" | "validated" | "awaiting_authorization" | "validation_unknown";
55
+ expires_at: string;
56
+ existing_project_id?: `prj_${string}`;
57
+ surface: "standalone" | "feishu";
58
+ description?: string;
59
+ request_ref: string;
60
+ project_id: `prj_${string}`;
61
+ display_name: string;
62
+ workspace_path: string;
63
+ };
64
+ relay_origin: string;
65
+ preparation: {
66
+ existing_relay_project_ref?: string;
67
+ expires_before?: string;
68
+ installation_ref: string;
69
+ surface: "standalone" | "feishu";
70
+ request_ref: string;
71
+ project_id: string;
72
+ installation_secret_hash: string;
73
+ handoff_token_hash: string;
74
+ host_registration_secret_hash: string;
75
+ trial_consent: "trial-project-v1";
76
+ };
77
+ };
78
+ reconcile(requestRef: string, context: LocalConsoleInvocationContext): Promise<{
79
+ draft: {
80
+ state: "validation_failed" | "prepared" | "registered" | "validated" | "awaiting_authorization" | "validation_unknown";
81
+ expires_at: string;
82
+ existing_project_id?: `prj_${string}`;
83
+ surface: "standalone" | "feishu";
84
+ description?: string;
85
+ request_ref: string;
86
+ project_id: `prj_${string}`;
87
+ display_name: string;
88
+ workspace_path: string;
89
+ };
90
+ relay_origin: string;
91
+ preparation: {
92
+ existing_relay_project_ref?: string;
93
+ expires_before?: string;
94
+ installation_ref: string;
95
+ surface: "standalone" | "feishu";
96
+ request_ref: string;
97
+ project_id: string;
98
+ installation_secret_hash: string;
99
+ handoff_token_hash: string;
100
+ host_registration_secret_hash: string;
101
+ trial_consent: "trial-project-v1";
102
+ };
103
+ }>;
104
+ validate(requestRef: string, context: LocalConsoleInvocationContext): Promise<{
105
+ validation: {
106
+ state: "failed" | "unknown" | "started" | "succeeded";
107
+ installation_ref: string;
108
+ reason_code: "validation_started" | "validation_succeeded" | "validation_route_unavailable" | "validation_http_rejected" | "validation_response_invalid" | "validation_transport_unknown" | "validation_interrupted";
109
+ project_id: string;
110
+ creation_ref: string;
111
+ route_ref: string;
112
+ http_status: number | null;
113
+ };
114
+ draft: {
115
+ state: "validation_failed" | "prepared" | "registered" | "validated" | "awaiting_authorization" | "validation_unknown";
116
+ expires_at: string;
117
+ existing_project_id?: `prj_${string}`;
118
+ surface: "standalone" | "feishu";
119
+ description?: string;
120
+ request_ref: string;
121
+ project_id: `prj_${string}`;
122
+ display_name: string;
123
+ workspace_path: string;
124
+ };
125
+ relay_origin: string;
126
+ preparation: {
127
+ existing_relay_project_ref?: string;
128
+ expires_before?: string;
129
+ installation_ref: string;
130
+ surface: "standalone" | "feishu";
131
+ request_ref: string;
132
+ project_id: string;
133
+ installation_secret_hash: string;
134
+ handoff_token_hash: string;
135
+ host_registration_secret_hash: string;
136
+ trial_consent: "trial-project-v1";
137
+ };
138
+ }>;
139
+ launch(requestRef: string, context: LocalConsoleInvocationContext): Promise<import("./project-service.js").LocalConsoleLaunchResult>;
140
+ }
141
+ //# sourceMappingURL=managed-project-service.d.ts.map
@@ -0,0 +1,158 @@
1
+ import { Value } from "@sinclair/typebox/value";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { IdempotencyKeySchema, ProjectIdSchema } from "@tutti/shared/schemas/domain";
4
+ import { resolveLaunchLocalContext } from "../cli/launch.js";
5
+ import { NativeManagedState } from "../managed-access/state.js";
6
+ import { findNativeManagedProject } from "../managed-access/state.js";
7
+ import { readExistingManagedTarget } from "../managed-access/existing-project.js";
8
+ import { ManagedLocalStateError } from "../managed-access/private-store.js";
9
+ import { reconcileNativePreparation, validateNativePreparation, } from "../managed-access/transport.js";
10
+ import { createLocalConsoleOperationEnvironment, } from "./invocation-context.js";
11
+ export const ManagedDraftInputSchema = Type.Object({
12
+ request_ref: IdempotencyKeySchema,
13
+ workspace_path: Type.String({ minLength: 1, maxLength: 4096 }),
14
+ display_name: Type.String({ minLength: 1, maxLength: 80 }),
15
+ description: Type.Optional(Type.String({ maxLength: 160 })),
16
+ surface: Type.Union([Type.Literal("standalone"), Type.Literal("feishu")]),
17
+ existing_project_id: Type.Optional(ProjectIdSchema),
18
+ }, { additionalProperties: false });
19
+ function projection(row) {
20
+ return {
21
+ request_ref: row.request_ref,
22
+ project_id: row.project_id,
23
+ display_name: row.display_name,
24
+ workspace_path: row.workspace_root,
25
+ ...(row.description === undefined ? {} : { description: row.description }),
26
+ surface: row.surface,
27
+ ...(row.existing_relay_project_ref === undefined
28
+ ? {}
29
+ : { existing_project_id: row.project_id }),
30
+ state: row.state,
31
+ expires_at: row.expires_at,
32
+ };
33
+ }
34
+ // Native orchestration only. No project SQLite, Git writes, model key or browser account authority.
35
+ export class LocalConsoleManagedProjectService {
36
+ options;
37
+ constructor(options) {
38
+ this.options = options;
39
+ }
40
+ environment(context) {
41
+ return createLocalConsoleOperationEnvironment({
42
+ serviceEnvironment: this.options.serviceEnvironment ?? process.env,
43
+ invocationEnvironment: context.environment,
44
+ tuttiHome: this.options.tuttiHome,
45
+ });
46
+ }
47
+ state(context) {
48
+ const env = this.environment(context);
49
+ return new NativeManagedState({
50
+ tuttiHome: this.options.tuttiHome,
51
+ relayUrl: env.TUTTI_RELAY_URL ?? "https://tutti.now",
52
+ });
53
+ }
54
+ prepare(input, context) {
55
+ return this.options.operations.runProjectOperation(() => {
56
+ if (!Value.Check(ManagedDraftInputSchema, input) || !input.display_name.trim())
57
+ throw new ManagedLocalStateError("managed_creation_input_invalid");
58
+ const local = resolveLaunchLocalContext({
59
+ workspacePath: input.workspace_path,
60
+ env: this.environment(context),
61
+ cwd: context.source === "terminal" ? context.currentDirectory : this.options.tuttiHome,
62
+ });
63
+ if (local.existing_identity.kind !== "missing" && input.existing_project_id === undefined)
64
+ throw new ManagedLocalStateError("managed_existing_project_requires_opt_in");
65
+ const state = this.state(context);
66
+ let existing;
67
+ if (input.existing_project_id !== undefined) {
68
+ const target = readExistingManagedTarget({
69
+ tuttiHome: this.options.tuttiHome,
70
+ relayOrigin: state.origin,
71
+ projectId: input.existing_project_id,
72
+ workspaceRoot: local.workspace_root,
73
+ surface: input.surface,
74
+ });
75
+ const previous = findNativeManagedProject({
76
+ tuttiHome: this.options.tuttiHome,
77
+ relayUrl: state.origin,
78
+ projectId: input.existing_project_id,
79
+ });
80
+ if (previous !== null && previous.journal.state !== "registered")
81
+ throw new ManagedLocalStateError("managed_reauthorization_conflict");
82
+ existing = {
83
+ ...target,
84
+ ...(previous === null ? {} : { previousRequestRef: previous.journal.request_ref }),
85
+ };
86
+ }
87
+ const row = state.createDraft({
88
+ requestRef: input.request_ref,
89
+ workspaceRoot: local.workspace_root,
90
+ displayName: input.display_name.trim(),
91
+ ...(input.description === undefined ? {} : { description: input.description.trim() }),
92
+ surface: input.surface,
93
+ ...(existing === undefined ? {} : { projectId: input.existing_project_id, existing }),
94
+ now: this.options.now?.() ?? new Date(),
95
+ });
96
+ return {
97
+ draft: projection(row),
98
+ relay_origin: state.origin,
99
+ preparation: state.preparationBody(row.request_ref),
100
+ };
101
+ });
102
+ }
103
+ read(requestRef, context) {
104
+ const state = this.state(context);
105
+ return {
106
+ draft: projection(state.read(requestRef)),
107
+ relay_origin: state.origin,
108
+ preparation: state.preparationBody(requestRef),
109
+ };
110
+ }
111
+ async reconcile(requestRef, context) {
112
+ return this.options.operations.runProjectOperation(async () => {
113
+ const state = this.state(context);
114
+ await reconcileNativePreparation({
115
+ state,
116
+ requestRef,
117
+ now: this.options.now?.() ?? new Date(),
118
+ ...(this.options.fetchImpl === undefined ? {} : { fetchImpl: this.options.fetchImpl }),
119
+ });
120
+ return this.read(requestRef, context);
121
+ });
122
+ }
123
+ async validate(requestRef, context) {
124
+ return this.options.operations.runProjectOperation(async () => {
125
+ const state = this.state(context);
126
+ await reconcileNativePreparation({
127
+ state,
128
+ requestRef,
129
+ now: this.options.now?.() ?? new Date(),
130
+ ...(this.options.fetchImpl === undefined ? {} : { fetchImpl: this.options.fetchImpl }),
131
+ });
132
+ const validation = await validateNativePreparation({
133
+ state,
134
+ requestRef,
135
+ ...(this.options.fetchImpl === undefined ? {} : { fetchImpl: this.options.fetchImpl }),
136
+ });
137
+ return { ...this.read(requestRef, context), validation };
138
+ });
139
+ }
140
+ async launch(requestRef, context) {
141
+ return this.options.operations.runProjectOperation(async () => {
142
+ const projects = this.options.projects;
143
+ if (projects === undefined)
144
+ throw new ManagedLocalStateError("managed_launch_unavailable");
145
+ const state = this.state(context);
146
+ // Re-check current Relay authority immediately before any workspace mutation.
147
+ await reconcileNativePreparation({
148
+ state,
149
+ requestRef,
150
+ now: this.options.now?.() ?? new Date(),
151
+ ...(this.options.fetchImpl === undefined ? {} : { fetchImpl: this.options.fetchImpl }),
152
+ });
153
+ state.bootstrap(requestRef, this.options.now?.() ?? new Date());
154
+ return projects.launchAuthorizedProject(state, requestRef, context);
155
+ });
156
+ }
157
+ }
158
+ //# sourceMappingURL=managed-project-service.js.map
@@ -10,7 +10,7 @@ export type LocalConsoleOperationState = "idle" | "project_busy" | "package_upda
10
10
  export declare class LocalConsoleOperationCoordinator {
11
11
  #private;
12
12
  state(): LocalConsoleOperationState;
13
- runProjectOperation<T>(operation: () => Promise<T>): Promise<T>;
13
+ runProjectOperation<T>(operation: () => T | Promise<T>): Promise<T>;
14
14
  tryBeginPackageUpdate(): LocalConsolePackageUpdateOperationLease | null;
15
15
  }
16
16
  //# sourceMappingURL=operation-coordinator.d.ts.map
@@ -3,6 +3,7 @@ import { readHostLocalPackageUpdateReadiness, requestHostLocalIdleShutdown, } fr
3
3
  import { createRuntimeEndpointProbe, waitForHostShutdown } from "../cli/host-runtime-endpoint.js";
4
4
  import { spawnDetachedHost, waitForManagedHostReady } from "../cli/managed-host.js";
5
5
  import { resolveManagedProjectContext } from "../cli/project-resolver.js";
6
+ import { hasProjectModelConfiguration } from "../managed-access/project-provider.js";
6
7
  const PACKAGE_UPDATE_HOST_SHUTDOWN_WAIT_MS = 5_000;
7
8
  export async function stopPackageUpdateHost(options) {
8
9
  const fetchImpl = options.fetchImpl ?? fetch;
@@ -65,7 +66,7 @@ export async function restorePackageUpdateHosts(options) {
65
66
  target: projectId,
66
67
  env: { ...options.env, TUTTI_HOME: options.tuttiHome },
67
68
  });
68
- if (!project.workspace_exists || project.provider_config.status !== "configured") {
69
+ if (!project.workspace_exists || !hasProjectModelConfiguration(project.provider_config)) {
69
70
  failed.push(projectId);
70
71
  continue;
71
72
  }
@@ -1,6 +1,8 @@
1
1
  import { type ProjectSurface, type ProjectSurfaceProfile } from "@tutti/shared/domain";
2
2
  import { type ProjectId, type RelayProjectRef } from "@tutti/shared/ids";
3
3
  import type { FeishuSetupProjection } from "@tutti/shared/schemas/internal";
4
+ import type { ProviderConfigProjection } from "@tutti/shared/schemas/api";
5
+ import type { NativeManagedState } from "../managed-access/state.js";
4
6
  import { type ConfigureProjectOpenAiProviderResult, type OpenAiProviderCredentialValidator } from "../../providers/openai/index.js";
5
7
  import { type FetchLike } from "../cli/host-runtime-endpoint.js";
6
8
  import type { HostLaunchRelaySummary } from "../cli/relay-registration.js";
@@ -13,7 +15,7 @@ export type LocalConsoleProject = {
13
15
  display_name: string;
14
16
  workspace_path: string;
15
17
  status: RuntimeProjectRow["status"];
16
- provider_status: "configured" | "not_configured" | "invalid";
18
+ provider_status: ProviderConfigProjection["status"];
17
19
  provider_model?: string;
18
20
  relay_project_ref?: RelayProjectRef;
19
21
  open_url?: string;
@@ -91,6 +93,7 @@ export declare class LocalConsoleProjectService {
91
93
  provider?: LocalConsoleProviderInput;
92
94
  surface?: ProjectSurface;
93
95
  }, context: LocalConsoleInvocationContext, accountHandoff?: LocalConsoleAccountHandoff): Promise<LocalConsoleLaunchResult>;
96
+ launchAuthorizedProject(state: NativeManagedState, requestRef: string, context: LocalConsoleInvocationContext): Promise<LocalConsoleLaunchResult>;
94
97
  openProject(projectId: string, context: LocalConsoleInvocationContext): Promise<LocalConsoleOpenResult>;
95
98
  refreshInvite(projectId: string, context: LocalConsoleInvocationContext): Promise<{
96
99
  join_url: string;