@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
@@ -0,0 +1,106 @@
1
+ import { type Static } from "@sinclair/typebox";
2
+ export declare const ModelSessionOwnerSchema: import("@sinclair/typebox").TObject<{
3
+ kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"chat">, import("@sinclair/typebox").TLiteral<"workflow">, import("@sinclair/typebox").TLiteral<"task">]>;
4
+ ref: import("@sinclair/typebox").TString;
5
+ }>;
6
+ export type ModelSessionOwner = Static<typeof ModelSessionOwnerSchema>;
7
+ declare const SessionSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
8
+ state: import("@sinclair/typebox").TLiteral<"ready">;
9
+ version: import("@sinclair/typebox").TLiteral<2>;
10
+ project_id: import("@sinclair/typebox").TString;
11
+ delegation_ref: import("@sinclair/typebox").TString;
12
+ grant_ref: import("@sinclair/typebox").TString;
13
+ installation_ref: import("@sinclair/typebox").TString;
14
+ owner: import("@sinclair/typebox").TObject<{
15
+ kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"chat">, import("@sinclair/typebox").TLiteral<"workflow">, import("@sinclair/typebox").TLiteral<"task">]>;
16
+ ref: import("@sinclair/typebox").TString;
17
+ }>;
18
+ session_ref: import("@sinclair/typebox").TString;
19
+ route_ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
20
+ provider_identity: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
21
+ model: import("@sinclair/typebox").TString;
22
+ base_url: import("@sinclair/typebox").TString;
23
+ }>>;
24
+ }>, import("@sinclair/typebox").TObject<{
25
+ state: import("@sinclair/typebox").TLiteral<"issuing">;
26
+ request_ref: import("@sinclair/typebox").TString;
27
+ version: import("@sinclair/typebox").TLiteral<2>;
28
+ project_id: import("@sinclair/typebox").TString;
29
+ delegation_ref: import("@sinclair/typebox").TString;
30
+ grant_ref: import("@sinclair/typebox").TString;
31
+ installation_ref: import("@sinclair/typebox").TString;
32
+ owner: import("@sinclair/typebox").TObject<{
33
+ kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"chat">, import("@sinclair/typebox").TLiteral<"workflow">, import("@sinclair/typebox").TLiteral<"task">]>;
34
+ ref: import("@sinclair/typebox").TString;
35
+ }>;
36
+ session_ref: import("@sinclair/typebox").TString;
37
+ route_ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
38
+ provider_identity: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
39
+ model: import("@sinclair/typebox").TString;
40
+ base_url: import("@sinclair/typebox").TString;
41
+ }>>;
42
+ }>, import("@sinclair/typebox").TObject<{
43
+ state: import("@sinclair/typebox").TLiteral<"active">;
44
+ request_ref: import("@sinclair/typebox").TString;
45
+ credential: import("@sinclair/typebox").TObject<{
46
+ credential_ref: import("@sinclair/typebox").TString;
47
+ session_ref: import("@sinclair/typebox").TString;
48
+ device_ref: import("@sinclair/typebox").TString;
49
+ state: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"creating">, import("@sinclair/typebox").TLiteral<"active">, import("@sinclair/typebox").TLiteral<"expired">, import("@sinclair/typebox").TLiteral<"revoking">, import("@sinclair/typebox").TLiteral<"revoked">]>;
50
+ expires_at: import("@sinclair/typebox").TInteger;
51
+ quota_cap: import("@sinclair/typebox").TInteger;
52
+ }>;
53
+ provider: import("@sinclair/typebox").TObject<{
54
+ base_url: import("@sinclair/typebox").TString;
55
+ model: import("@sinclair/typebox").TString;
56
+ api_key: import("@sinclair/typebox").TString;
57
+ }>;
58
+ version: import("@sinclair/typebox").TLiteral<2>;
59
+ project_id: import("@sinclair/typebox").TString;
60
+ delegation_ref: import("@sinclair/typebox").TString;
61
+ grant_ref: import("@sinclair/typebox").TString;
62
+ installation_ref: import("@sinclair/typebox").TString;
63
+ owner: import("@sinclair/typebox").TObject<{
64
+ kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"chat">, import("@sinclair/typebox").TLiteral<"workflow">, import("@sinclair/typebox").TLiteral<"task">]>;
65
+ ref: import("@sinclair/typebox").TString;
66
+ }>;
67
+ session_ref: import("@sinclair/typebox").TString;
68
+ route_ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
69
+ provider_identity: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
70
+ model: import("@sinclair/typebox").TString;
71
+ base_url: import("@sinclair/typebox").TString;
72
+ }>>;
73
+ }>, import("@sinclair/typebox").TObject<{
74
+ state: import("@sinclair/typebox").TLiteral<"revoking">;
75
+ request_ref: import("@sinclair/typebox").TString;
76
+ credential: import("@sinclair/typebox").TObject<{
77
+ credential_ref: import("@sinclair/typebox").TString;
78
+ session_ref: import("@sinclair/typebox").TString;
79
+ device_ref: import("@sinclair/typebox").TString;
80
+ state: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"creating">, import("@sinclair/typebox").TLiteral<"active">, import("@sinclair/typebox").TLiteral<"expired">, import("@sinclair/typebox").TLiteral<"revoking">, import("@sinclair/typebox").TLiteral<"revoked">]>;
81
+ expires_at: import("@sinclair/typebox").TInteger;
82
+ quota_cap: import("@sinclair/typebox").TInteger;
83
+ }>;
84
+ version: import("@sinclair/typebox").TLiteral<2>;
85
+ project_id: import("@sinclair/typebox").TString;
86
+ delegation_ref: import("@sinclair/typebox").TString;
87
+ grant_ref: import("@sinclair/typebox").TString;
88
+ installation_ref: import("@sinclair/typebox").TString;
89
+ owner: import("@sinclair/typebox").TObject<{
90
+ kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"chat">, import("@sinclair/typebox").TLiteral<"workflow">, import("@sinclair/typebox").TLiteral<"task">]>;
91
+ ref: import("@sinclair/typebox").TString;
92
+ }>;
93
+ session_ref: import("@sinclair/typebox").TString;
94
+ route_ref: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
95
+ provider_identity: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
96
+ model: import("@sinclair/typebox").TString;
97
+ base_url: import("@sinclair/typebox").TString;
98
+ }>>;
99
+ }>]>;
100
+ export type NativeModelSession = Static<typeof SessionSchema>;
101
+ export declare function parseNativeModelSession(value: unknown): NativeModelSession;
102
+ export declare function readyModelSession(row: NativeModelSession): NativeModelSession & {
103
+ state: "ready";
104
+ };
105
+ export {};
106
+ //# sourceMappingURL=runtime-records.d.ts.map
@@ -0,0 +1,65 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { Value } from "@sinclair/typebox/value";
3
+ import { ProjectIdSchema, IdempotencyKeySchema } from "@tutti/shared/schemas/domain";
4
+ import { HostDelegationRefSchema, HostInstallationRefSchema, ProjectModelGrantRefSchema, ManagedRuntimeSessionRefSchema, ManagedRouteRefSchema, ManagedCredentialProjectionSchema, ManagedProviderCredentialSchema, } from "@tutti/shared/schemas/internal";
5
+ import { ManagedLocalStateError } from "./private-store.js";
6
+ import { upgradeTieredPrivateRecord } from "./legacy-records.js";
7
+ export const ModelSessionOwnerSchema = Type.Object({
8
+ kind: Type.Union([Type.Literal("chat"), Type.Literal("workflow"), Type.Literal("task")]),
9
+ ref: Type.String({ pattern: "^[A-Za-z0-9_-]{1,150}$" }),
10
+ }, { additionalProperties: false });
11
+ const Common = {
12
+ version: Type.Literal(2),
13
+ project_id: ProjectIdSchema,
14
+ delegation_ref: HostDelegationRefSchema,
15
+ grant_ref: ProjectModelGrantRefSchema,
16
+ installation_ref: HostInstallationRefSchema,
17
+ owner: ModelSessionOwnerSchema,
18
+ session_ref: ManagedRuntimeSessionRefSchema,
19
+ route_ref: Type.Optional(ManagedRouteRefSchema),
20
+ provider_identity: Type.Optional(Type.Object({
21
+ model: Type.String({ minLength: 1, maxLength: 100 }),
22
+ base_url: Type.String({ minLength: 1, maxLength: 500 }),
23
+ }, { additionalProperties: false })),
24
+ };
25
+ const SessionSchema = Type.Union([
26
+ Type.Object({ ...Common, state: Type.Literal("ready") }, { additionalProperties: false }),
27
+ Type.Object({ ...Common, state: Type.Literal("issuing"), request_ref: IdempotencyKeySchema }, { additionalProperties: false }),
28
+ Type.Object({
29
+ ...Common,
30
+ state: Type.Literal("active"),
31
+ request_ref: IdempotencyKeySchema,
32
+ credential: ManagedCredentialProjectionSchema,
33
+ provider: ManagedProviderCredentialSchema,
34
+ }, { additionalProperties: false }),
35
+ Type.Object({
36
+ ...Common,
37
+ state: Type.Literal("revoking"),
38
+ request_ref: IdempotencyKeySchema,
39
+ credential: ManagedCredentialProjectionSchema,
40
+ }, { additionalProperties: false }),
41
+ ]);
42
+ export function parseNativeModelSession(value) {
43
+ value = upgradeTieredPrivateRecord(value);
44
+ if (!Value.Check(SessionSchema, value))
45
+ throw new ManagedLocalStateError("managed_model_session_invalid");
46
+ if ((value.state === "active" || value.state === "revoking") &&
47
+ value.credential.session_ref !== value.session_ref)
48
+ throw new ManagedLocalStateError("managed_model_session_invalid");
49
+ return value;
50
+ }
51
+ export function readyModelSession(row) {
52
+ return {
53
+ version: row.version,
54
+ project_id: row.project_id,
55
+ delegation_ref: row.delegation_ref,
56
+ grant_ref: row.grant_ref,
57
+ installation_ref: row.installation_ref,
58
+ owner: row.owner,
59
+ session_ref: row.session_ref,
60
+ state: "ready",
61
+ ...(row.route_ref === undefined ? {} : { route_ref: row.route_ref }),
62
+ ...(row.provider_identity === undefined ? {} : { provider_identity: row.provider_identity }),
63
+ };
64
+ }
65
+ //# sourceMappingURL=runtime-records.js.map
@@ -0,0 +1,48 @@
1
+ import type { ManagedProviderCredential } from "@tutti/shared/schemas/internal";
2
+ import { type ModelSessionOwner } from "./runtime-records.js";
3
+ export type ManagedRuntimeObservation = {
4
+ stage: "credential_ready" | "credential_revoked" | "credential_revoke_pending" | "managed_selection_failed" | "managed_invocation_failed";
5
+ session_ref?: string;
6
+ credential_ref?: string;
7
+ reason_code?: string;
8
+ request_id?: string;
9
+ };
10
+ export type ManagedInvocationAccess = {
11
+ provider: ManagedProviderCredential;
12
+ route_ref: string;
13
+ session_ref: string;
14
+ delegation_ref: string;
15
+ credential_ref: string;
16
+ };
17
+ export declare class NativeManagedRuntime {
18
+ private readonly options;
19
+ private readonly files;
20
+ private readonly state;
21
+ private readonly client;
22
+ private readonly now;
23
+ constructor(options: {
24
+ tuttiHome: string;
25
+ relayUrl: string;
26
+ projectId: string;
27
+ fetchImpl?: typeof fetch;
28
+ now?: () => Date;
29
+ observe?: (event: ManagedRuntimeObservation) => void;
30
+ });
31
+ private observe;
32
+ private name;
33
+ private readOrCreate;
34
+ private save;
35
+ private pin;
36
+ private providerEndpoint;
37
+ selection(owner: ModelSessionOwner): Promise<{
38
+ session_ref: string;
39
+ route_ref: string;
40
+ provider: {
41
+ model: string;
42
+ base_url: string;
43
+ };
44
+ }>;
45
+ private retire;
46
+ run<T>(owner: ModelSessionOwner, maxDurationSeconds: number, action: (access: ManagedInvocationAccess) => Promise<T>): Promise<T>;
47
+ }
48
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1,300 @@
1
+ import { createHash } from "node:crypto";
2
+ import { Value } from "@sinclair/typebox/value";
3
+ import { authorizeNativeModelRuntime, NativeAuthorityTransportError } from "@tutti/relay-client";
4
+ import { createIdempotencyKey, createPrefixedId, ID_PREFIXES } from "@tutti/shared/ids";
5
+ import { ensureManagedPrivateRoot, ManagedPrivateStore, ManagedLocalStateError, } from "./private-store.js";
6
+ import { NativeModelControlClient, ManagedControlError } from "./model-control-client.js";
7
+ import { ModelSessionOwnerSchema, parseNativeModelSession, readyModelSession, } from "./runtime-records.js";
8
+ import { NativeManagedState, managedRelayOrigin } from "./state.js";
9
+ export class NativeManagedRuntime {
10
+ options;
11
+ files;
12
+ state;
13
+ client;
14
+ now;
15
+ constructor(options) {
16
+ this.options = options;
17
+ this.state = new NativeManagedState(options);
18
+ this.files = new ManagedPrivateStore(ensureManagedPrivateRoot(options.tuttiHome, createHash("sha256").update(this.state.origin).digest("hex")));
19
+ this.now = options.now ?? (() => new Date());
20
+ this.client = new NativeModelControlClient({
21
+ authorize: async () => {
22
+ const journal = this.state.project(options.projectId);
23
+ if (journal.state !== "registered")
24
+ throw new ManagedLocalStateError("managed_project_not_registered");
25
+ const authority = await authorizeNativeModelRuntime({
26
+ relayUrl: this.state.origin,
27
+ body: {
28
+ project_id: journal.project_id,
29
+ relay_project_ref: journal.authority.relay_project_ref,
30
+ delegation_ref: journal.authority.delegation_ref,
31
+ installation_ref: journal.installation_ref,
32
+ installation_secret: this.state.installation().secret,
33
+ host_registration_secret: journal.host_registration_secret,
34
+ },
35
+ ...(options.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
36
+ });
37
+ if (authority.delegation_ref !== journal.authority.delegation_ref ||
38
+ authority.expires_at <= Math.floor(this.now().getTime() / 1000))
39
+ throw new ManagedLocalStateError("managed_runtime_authority_mismatch");
40
+ return authority;
41
+ },
42
+ ...(options.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
43
+ });
44
+ }
45
+ observe(event) {
46
+ try {
47
+ this.options.observe?.(event);
48
+ }
49
+ catch {
50
+ /* Diagnostics cannot replay a model call. */
51
+ }
52
+ }
53
+ name(owner) {
54
+ if (!Value.Check(ModelSessionOwnerSchema, owner))
55
+ throw new ManagedLocalStateError("managed_session_owner_invalid");
56
+ return `model-${createHash("sha256")
57
+ .update(JSON.stringify([this.options.projectId, owner.kind, owner.ref]))
58
+ .digest("hex")}`;
59
+ }
60
+ readOrCreate(name, owner, authority, reauthorized) {
61
+ return this.files.transaction(() => {
62
+ const saved = this.files.read(`${name}.json`);
63
+ if (saved !== null) {
64
+ const row = parseNativeModelSession(saved);
65
+ if (row.project_id !== this.options.projectId ||
66
+ row.owner.kind !== owner.kind ||
67
+ row.owner.ref !== owner.ref ||
68
+ row.installation_ref !== authority.installation_ref)
69
+ throw new ManagedLocalStateError("managed_model_session_scope_changed");
70
+ if (row.delegation_ref !== authority.delegation_ref ||
71
+ row.grant_ref !== authority.grant_ref) {
72
+ // An explicitly reauthorized native journal is the only entry to a new
73
+ // scope. Relay admits it only after prior installation keys are confirmed
74
+ // revoked. Keep the exact route/provider and durable Task Thread; the old
75
+ // credential and service session are never reused across delegations.
76
+ if (!reauthorized)
77
+ throw new ManagedLocalStateError("managed_model_session_scope_changed");
78
+ const renewed = {
79
+ ...readyModelSession(row),
80
+ delegation_ref: authority.delegation_ref,
81
+ grant_ref: authority.grant_ref,
82
+ session_ref: createPrefixedId(ID_PREFIXES.managedSession),
83
+ };
84
+ this.files.write(`${name}.json`, renewed);
85
+ return renewed;
86
+ }
87
+ if (typeof saved === "object" && "version" in saved && saved.version === 1)
88
+ this.files.write(`${name}.json`, row);
89
+ return row;
90
+ }
91
+ const row = {
92
+ version: 2,
93
+ project_id: this.options.projectId,
94
+ delegation_ref: authority.delegation_ref,
95
+ grant_ref: authority.grant_ref,
96
+ installation_ref: authority.installation_ref,
97
+ owner,
98
+ session_ref: createPrefixedId(ID_PREFIXES.managedSession),
99
+ state: "ready",
100
+ };
101
+ this.files.write(`${name}.json`, row, true);
102
+ return row;
103
+ });
104
+ }
105
+ save(name, row) {
106
+ this.files.transaction(() => {
107
+ this.files.write(`${name}.json`, parseNativeModelSession(row));
108
+ });
109
+ return row;
110
+ }
111
+ async pin(name, row) {
112
+ const pin = await this.client.pin(row.session_ref, row.route_ref);
113
+ if (pin.session_ref !== row.session_ref ||
114
+ (row.route_ref !== undefined && pin.route_ref !== row.route_ref) ||
115
+ (row.provider_identity !== undefined &&
116
+ (row.provider_identity.model !== pin.provider.model ||
117
+ row.provider_identity.base_url !== pin.provider.base_url)))
118
+ throw new ManagedLocalStateError("managed_route_changed");
119
+ this.providerEndpoint(pin.provider.base_url);
120
+ return this.save(name, { ...row, route_ref: pin.route_ref, provider_identity: pin.provider });
121
+ }
122
+ providerEndpoint(value) {
123
+ try {
124
+ const endpoint = new URL(value);
125
+ managedRelayOrigin(endpoint.origin);
126
+ if (endpoint.username ||
127
+ endpoint.password ||
128
+ endpoint.search ||
129
+ endpoint.hash ||
130
+ !/^\/v1\/?$/.test(endpoint.pathname))
131
+ throw new Error();
132
+ }
133
+ catch {
134
+ throw new ManagedLocalStateError("managed_provider_endpoint_invalid");
135
+ }
136
+ }
137
+ // Resolve the immutable route before opening a durable Codex Thread. No key is
138
+ // issued by selection; each later turn obtains its own bounded credential lease.
139
+ async selection(owner) {
140
+ try {
141
+ const journal = this.state.project(this.options.projectId);
142
+ if (journal.state !== "registered")
143
+ throw new ManagedLocalStateError("managed_project_not_registered");
144
+ const name = this.name(owner), unlock = this.files.acquireExecutionLease(name);
145
+ try {
146
+ const row = await this.pin(name, this.readOrCreate(name, owner, journal.authority, journal.previous_request_ref !== undefined));
147
+ return {
148
+ session_ref: row.session_ref,
149
+ route_ref: row.route_ref,
150
+ provider: row.provider_identity,
151
+ };
152
+ }
153
+ finally {
154
+ unlock();
155
+ }
156
+ }
157
+ catch (error) {
158
+ this.observe({
159
+ stage: "managed_selection_failed",
160
+ reason_code: error instanceof ManagedLocalStateError ||
161
+ error instanceof ManagedControlError ||
162
+ error instanceof NativeAuthorityTransportError
163
+ ? error.code
164
+ : "managed_selection_unavailable",
165
+ ...((error instanceof ManagedControlError ||
166
+ error instanceof NativeAuthorityTransportError) &&
167
+ error.requestId !== undefined
168
+ ? { request_id: error.requestId }
169
+ : {}),
170
+ });
171
+ throw error;
172
+ }
173
+ }
174
+ async retire(name, row) {
175
+ if (row.state !== "active" && row.state !== "revoking")
176
+ return row;
177
+ const pending = {
178
+ ...readyModelSession(row),
179
+ state: "revoking",
180
+ request_ref: row.request_ref,
181
+ credential: row.credential,
182
+ };
183
+ this.save(name, pending); // Drop the local key before any revoke I/O.
184
+ const response = await this.client.revoke(row.credential.credential_ref);
185
+ if (response.credential.credential_ref !== row.credential.credential_ref ||
186
+ response.credential.session_ref !== row.session_ref ||
187
+ response.credential.state !== "revoked")
188
+ throw new ManagedLocalStateError("managed_revocation_unconfirmed");
189
+ this.observe({
190
+ stage: "credential_revoked",
191
+ session_ref: row.session_ref,
192
+ credential_ref: row.credential.credential_ref,
193
+ });
194
+ return this.save(name, readyModelSession(row));
195
+ }
196
+ // One finite credential lease per bounded provider invocation. Fresh credentials
197
+ // renew automatically on the same pinned session; the model callback is never retried.
198
+ async run(owner, maxDurationSeconds, action) {
199
+ if (!Number.isSafeInteger(maxDurationSeconds) ||
200
+ maxDurationSeconds < 1 ||
201
+ maxDurationSeconds > 82_800)
202
+ throw new ManagedLocalStateError("managed_invocation_duration_invalid");
203
+ const journal = this.state.project(this.options.projectId);
204
+ if (journal.state !== "registered")
205
+ throw new ManagedLocalStateError("managed_project_not_registered");
206
+ const name = this.name(owner), unlock = this.files.acquireExecutionLease(name);
207
+ let row;
208
+ try {
209
+ row = this.readOrCreate(name, owner, journal.authority, journal.previous_request_ref !== undefined);
210
+ row = await this.retire(name, row);
211
+ row = await this.pin(name, row);
212
+ for (let attempt = 0; attempt < 2; attempt++) {
213
+ if (row.state === "ready")
214
+ row = this.save(name, { ...row, state: "issuing", request_ref: createIdempotencyKey() });
215
+ if (row.state !== "issuing")
216
+ throw new ManagedLocalStateError("managed_model_session_invalid");
217
+ const requestRef = row.request_ref;
218
+ const result = await this.client.issue(row.session_ref, requestRef);
219
+ if (result.credential.session_ref !== row.session_ref ||
220
+ result.credential.device_ref !==
221
+ row.installation_ref.replace(/^host_installation_/, "managed_device_"))
222
+ throw new ManagedLocalStateError("managed_credential_scope_mismatch");
223
+ // Store enough metadata to revoke even when delivery or policy checks fail.
224
+ row = this.save(name, {
225
+ ...readyModelSession(row),
226
+ state: "revoking",
227
+ request_ref: row.request_ref,
228
+ credential: result.credential,
229
+ });
230
+ if (result.disposition === "already_issued") {
231
+ row = await this.retire(name, row);
232
+ continue;
233
+ }
234
+ if (result.route_ref !== row.route_ref ||
235
+ result.credential.state !== "active" ||
236
+ result.credential.expires_at <=
237
+ Math.floor(this.now().getTime() / 1000) + maxDurationSeconds + 60)
238
+ throw new ManagedLocalStateError("managed_credential_policy_invalid");
239
+ this.providerEndpoint(result.provider.base_url);
240
+ if (row.provider_identity &&
241
+ (row.provider_identity.model !== result.provider.model ||
242
+ row.provider_identity.base_url !== result.provider.base_url))
243
+ throw new ManagedLocalStateError("managed_route_changed");
244
+ row = this.save(name, {
245
+ ...readyModelSession(row),
246
+ state: "active",
247
+ request_ref: requestRef,
248
+ credential: result.credential,
249
+ provider: result.provider,
250
+ provider_identity: { model: result.provider.model, base_url: result.provider.base_url },
251
+ });
252
+ this.observe({
253
+ stage: "credential_ready",
254
+ session_ref: row.session_ref,
255
+ credential_ref: result.credential.credential_ref,
256
+ });
257
+ return await action({
258
+ provider: result.provider,
259
+ route_ref: result.route_ref,
260
+ session_ref: row.session_ref,
261
+ delegation_ref: row.delegation_ref,
262
+ credential_ref: result.credential.credential_ref,
263
+ });
264
+ }
265
+ throw new ManagedLocalStateError("managed_credential_delivery_unconfirmed");
266
+ }
267
+ catch (error) {
268
+ if (row)
269
+ this.observe({
270
+ stage: "managed_invocation_failed",
271
+ session_ref: row.session_ref,
272
+ reason_code: error instanceof ManagedLocalStateError ? error.code : "managed_invocation_unavailable",
273
+ ...(error instanceof ManagedControlError && error.requestId !== undefined
274
+ ? { request_id: error.requestId }
275
+ : {}),
276
+ });
277
+ throw error;
278
+ }
279
+ finally {
280
+ try {
281
+ if (row)
282
+ await this.retire(name, row);
283
+ }
284
+ catch (error) {
285
+ if (row)
286
+ this.observe({
287
+ stage: "credential_revoke_pending",
288
+ session_ref: row.session_ref,
289
+ reason_code: error instanceof ManagedLocalStateError
290
+ ? error.code
291
+ : "managed_revocation_unconfirmed",
292
+ });
293
+ }
294
+ finally {
295
+ unlock();
296
+ }
297
+ }
298
+ }
299
+ }
300
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1,53 @@
1
+ import { type HostDelegationProjection, type PrepareProjectAuthority, type ManagedProjectBootstrap, type NativeCreationProof } from "@tutti/shared/schemas/internal";
2
+ import { type CreationJournal, type Installation } from "./records.js";
3
+ export declare function managedRelayOrigin(input: string): string;
4
+ export declare function findNativeManagedProject(options: {
5
+ tuttiHome: string;
6
+ relayUrl: string;
7
+ projectId: string;
8
+ }): {
9
+ state: NativeManagedState;
10
+ journal: CreationJournal;
11
+ } | null;
12
+ export declare class NativeManagedState {
13
+ readonly origin: string;
14
+ private readonly files;
15
+ constructor(options: {
16
+ tuttiHome: string;
17
+ relayUrl: string;
18
+ });
19
+ installation(now?: Date): Installation;
20
+ createDraft(options: {
21
+ workspaceRoot: string;
22
+ displayName: string;
23
+ description?: string;
24
+ surface: "standalone" | "feishu";
25
+ requestRef?: string;
26
+ projectId?: string;
27
+ existing?: {
28
+ relayProjectRef: string;
29
+ hostSecret: string;
30
+ previousRequestRef?: string;
31
+ };
32
+ now?: Date;
33
+ }): CreationJournal;
34
+ read(requestRef: string): CreationJournal;
35
+ private readJournal;
36
+ attachProject(requestRef: string, now?: Date): CreationJournal;
37
+ project(projectId: string): CreationJournal;
38
+ preparationBody(requestRef: string): PrepareProjectAuthority;
39
+ proof(requestRef: string): NativeCreationProof;
40
+ prepared(requestRef: string, receipt: {
41
+ creation_ref: string;
42
+ project_id: string;
43
+ installation_ref: string;
44
+ surface: string;
45
+ expires_at: string;
46
+ }, now?: Date): CreationJournal;
47
+ validation(requestRef: string, outcome: "validated" | "validation_unknown" | "validation_failed"): CreationJournal;
48
+ bootstrap(requestRef: string, now?: Date): ManagedProjectBootstrap;
49
+ registered(requestRef: string, authority: HostDelegationProjection): CreationJournal;
50
+ private update;
51
+ private journalName;
52
+ }
53
+ //# sourceMappingURL=state.d.ts.map