@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.
- package/dist/approvals/decision-command.d.ts +2 -2
- package/dist/collaboration-state/clarification-snapshot.d.ts +9 -9
- package/dist/collaboration-state/task-compile-context.d.ts +1 -1
- package/dist/control-plane/workflows/openai.d.ts +3 -4
- package/dist/control-plane/workflows/openai.js +3 -2
- package/dist/providers/openai/app-server/invocation-coordinator.d.ts +1 -0
- package/dist/providers/openai/app-server/invocation-coordinator.js +4 -1
- package/dist/providers/openai/app-server/invocation-deadline.d.ts +3 -0
- package/dist/providers/openai/app-server/invocation-deadline.js +15 -0
- package/dist/providers/openai/app-server/read-only-procedure.d.ts +4 -2
- package/dist/providers/openai/app-server/read-only-procedure.js +16 -0
- package/dist/providers/openai/app-server/workspace-write-run.d.ts +4 -2
- package/dist/providers/openai/app-server/workspace-write-run.js +16 -0
- package/dist/providers/openai/chat-assistant.d.ts +3 -4
- package/dist/providers/openai/chat-assistant.js +2 -1
- package/dist/providers/openai/execution-access.d.ts +17 -0
- package/dist/providers/openai/execution-access.js +13 -0
- package/dist/providers/openai/sdk-procedure-runner.d.ts +2 -2
- package/dist/providers/openai/sdk-procedure-runner.js +17 -0
- package/dist/run-pipeline/artifact-applicability.d.ts +3 -4
- package/dist/run-pipeline/artifact-applicability.js +2 -1
- package/dist/run-pipeline/openai.d.ts +3 -4
- package/dist/run-pipeline/openai.js +3 -2
- package/dist/run-pipeline/task-run-invocation.js +6 -12
- package/dist/server-shell/cli/cli.js +3 -0
- package/dist/server-shell/cli/host-lifecycle.js +1 -0
- package/dist/server-shell/cli/host-server-runtime.d.ts +1 -0
- package/dist/server-shell/cli/host-server-runtime.js +83 -34
- package/dist/server-shell/cli/launch-command.js +1 -1
- package/dist/server-shell/cli/launch.d.ts +7 -3
- package/dist/server-shell/cli/launch.js +23 -4
- package/dist/server-shell/cli/machine-local.d.ts +9 -0
- package/dist/server-shell/cli/machine-local.js +60 -6
- package/dist/server-shell/cli/project-resolver.d.ts +2 -2
- package/dist/server-shell/cli/project-resolver.js +6 -3
- package/dist/server-shell/cli/relay-registration.js +38 -1
- package/dist/server-shell/http/routes/local-control.d.ts +1 -1
- package/dist/server-shell/http/routes/local-control.js +2 -46
- package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +45 -137
- package/dist/server-shell/http/routes/project-api/openapi.d.ts +45 -137
- package/dist/server-shell/http/routes/project-api/schemas.d.ts +24 -136
- package/dist/server-shell/http/routes/project-api/schemas.js +4 -58
- package/dist/server-shell/http/routes/project-api/types.d.ts +3 -0
- package/dist/server-shell/local-console/managed-project-routes.d.ts +9 -0
- package/dist/server-shell/local-console/managed-project-routes.js +120 -0
- package/dist/server-shell/local-console/managed-project-service.d.ts +141 -0
- package/dist/server-shell/local-console/managed-project-service.js +158 -0
- package/dist/server-shell/local-console/operation-coordinator.d.ts +1 -1
- package/dist/server-shell/local-console/package-update-hosts.js +2 -1
- package/dist/server-shell/local-console/project-service.d.ts +4 -1
- package/dist/server-shell/local-console/project-service.js +62 -14
- package/dist/server-shell/local-console/server.js +22 -2
- package/dist/server-shell/managed-access/execution-binding.d.ts +9 -0
- package/dist/server-shell/managed-access/execution-binding.js +22 -0
- package/dist/server-shell/managed-access/existing-project.d.ts +15 -0
- package/dist/server-shell/managed-access/existing-project.js +41 -0
- package/dist/server-shell/managed-access/legacy-records.d.ts +2 -0
- package/dist/server-shell/managed-access/legacy-records.js +24 -0
- package/dist/server-shell/managed-access/model-control-client.d.ts +65 -0
- package/dist/server-shell/managed-access/model-control-client.js +112 -0
- package/dist/server-shell/managed-access/private-store.d.ts +19 -0
- package/dist/server-shell/managed-access/private-store.js +275 -0
- package/dist/server-shell/managed-access/project-provider.d.ts +18 -0
- package/dist/server-shell/managed-access/project-provider.js +30 -0
- package/dist/server-shell/managed-access/records.d.ts +103 -0
- package/dist/server-shell/managed-access/records.js +74 -0
- package/dist/server-shell/managed-access/runners.d.ts +11 -0
- package/dist/server-shell/managed-access/runners.js +103 -0
- package/dist/server-shell/managed-access/runtime-records.d.ts +106 -0
- package/dist/server-shell/managed-access/runtime-records.js +65 -0
- package/dist/server-shell/managed-access/runtime.d.ts +48 -0
- package/dist/server-shell/managed-access/runtime.js +300 -0
- package/dist/server-shell/managed-access/state.d.ts +53 -0
- package/dist/server-shell/managed-access/state.js +292 -0
- package/dist/server-shell/managed-access/transport.d.ts +45 -0
- package/dist/server-shell/managed-access/transport.js +39 -0
- package/dist/server-shell/managed-access/workspace.d.ts +10 -0
- package/dist/server-shell/managed-access/workspace.js +69 -0
- package/dist/server-shell/smoke/e2e-client.d.ts +8 -3
- package/dist/server-shell/smoke/e2e-client.js +11 -11
- package/node_modules/@tutti/relay-client/dist/host-control.d.ts +4 -1
- package/node_modules/@tutti/relay-client/dist/host-control.js +26 -3
- package/node_modules/@tutti/relay-client/dist/index.d.ts +1 -0
- package/node_modules/@tutti/relay-client/dist/index.js +1 -0
- package/node_modules/@tutti/relay-client/dist/project-authority.d.ts +70 -0
- package/node_modules/@tutti/relay-client/dist/project-authority.js +139 -0
- package/node_modules/@tutti/shared/dist/ids/index.d.ts +7 -0
- package/node_modules/@tutti/shared/dist/ids/index.js +7 -0
- package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/index.js +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/managed-account.d.ts +34 -0
- package/node_modules/@tutti/shared/dist/schemas/api/managed-account.js +40 -0
- package/node_modules/@tutti/shared/dist/schemas/api/provider-config.d.ts +7 -4
- package/node_modules/@tutti/shared/dist/schemas/api/provider-config.js +5 -0
- package/node_modules/@tutti/shared/dist/schemas/api/runtime-events.d.ts +3 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/creation-validation.d.ts +26 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/creation-validation.js +40 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/index.d.ts +5 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/index.js +5 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/managed-account.d.ts +12 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/managed-account.js +13 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/managed-models.d.ts +17 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/managed-models.js +17 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/managed-runtime.d.ts +113 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/managed-runtime.js +84 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/project-authority.d.ts +114 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/project-authority.js +102 -0
- package/package.json +1 -1
- package/web/assets/{homepage-motion-scene-B6lCCHBq.js → homepage-motion-scene-WfLyzcCG.js} +1 -1
- package/web/assets/{index-DsYi7AhN.css → index-ATsYiBZs.css} +1 -1
- package/web/assets/index-o9YCtzEd.js +70 -0
- package/web/index.html +2 -2
- 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
|
-
|
|
31
|
-
|
|
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
|
|
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: "
|
|
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;
|