@noodleseed/one 0.136.0 → 0.138.0

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 (124) hide show
  1. package/dist/commands/assistant-ops.d.ts.map +1 -1
  2. package/dist/commands/assistant-ops.js +30 -1
  3. package/dist/commands/assistant-ops.js.map +1 -1
  4. package/dist/commands/deploy-first-flow.d.ts +2 -0
  5. package/dist/commands/deploy-first-flow.d.ts.map +1 -1
  6. package/dist/commands/deploy-first-flow.js +46 -14
  7. package/dist/commands/deploy-first-flow.js.map +1 -1
  8. package/dist/commands/deploy-ops.d.ts.map +1 -1
  9. package/dist/commands/deploy-ops.js +27 -1
  10. package/dist/commands/deploy-ops.js.map +1 -1
  11. package/dist/commands/deploy-preflight.d.ts +1 -0
  12. package/dist/commands/deploy-preflight.d.ts.map +1 -1
  13. package/dist/commands/deploy-preflight.js +1 -0
  14. package/dist/commands/deploy-preflight.js.map +1 -1
  15. package/dist/commands/deploy-status-ops.d.ts +1 -0
  16. package/dist/commands/deploy-status-ops.d.ts.map +1 -1
  17. package/dist/commands/deploy-status-ops.js +59 -4
  18. package/dist/commands/deploy-status-ops.js.map +1 -1
  19. package/dist/commands/deployments-ops.d.ts.map +1 -1
  20. package/dist/commands/deployments-ops.js +2 -0
  21. package/dist/commands/deployments-ops.js.map +1 -1
  22. package/dist/commands/diagnostics-ops.d.ts +1 -0
  23. package/dist/commands/diagnostics-ops.d.ts.map +1 -1
  24. package/dist/commands/diagnostics-ops.js +3 -0
  25. package/dist/commands/diagnostics-ops.js.map +1 -1
  26. package/dist/deploy.d.ts +3 -0
  27. package/dist/deploy.d.ts.map +1 -1
  28. package/dist/deploy.js +4 -0
  29. package/dist/deploy.js.map +1 -1
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +1 -1
  33. package/dist/index.js.map +1 -1
  34. package/node_modules/@noodle-borg/admission-limits/dist/envelope.js +1 -1
  35. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +4 -4
  36. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +1 -0
  37. package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +22 -13
  38. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  39. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.d.ts +6 -2
  40. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.js +5 -2
  41. package/node_modules/@noodle-borg/assistant-gateway/dist/model-request.js +37 -0
  42. package/node_modules/@noodle-borg/assistant-gateway/dist/model-runtime.js +4 -0
  43. package/node_modules/@noodle-borg/{service/dist/assistant-model-stream.js → assistant-gateway/dist/model-stream.js} +34 -2
  44. package/node_modules/@noodle-borg/assistant-gateway/dist/public-session.d.ts +3 -0
  45. package/node_modules/@noodle-borg/assistant-gateway/dist/public-session.js +2 -1
  46. package/node_modules/@noodle-borg/assistant-gateway/dist/public-turn.d.ts +4 -1
  47. package/node_modules/@noodle-borg/assistant-gateway/dist/public-turn.js +2 -1
  48. package/node_modules/@noodle-borg/assistant-gateway/dist/surface-budget.d.ts +6 -1
  49. package/node_modules/@noodle-borg/assistant-gateway/dist/surface-budget.js +11 -5
  50. package/node_modules/@noodle-borg/assistant-gateway/package.json +5 -1
  51. package/node_modules/@noodle-borg/authoring/dist/assistant.d.ts +10 -2
  52. package/node_modules/@noodle-borg/authoring/dist/assistant.js +4 -0
  53. package/node_modules/@noodle-borg/authoring/dist/index.d.ts +1 -1
  54. package/node_modules/@noodle-borg/authoring/dist/index.js +1 -1
  55. package/node_modules/@noodle-borg/authoring/dist/load-authored.js +1 -1
  56. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-assistant.js +17 -0
  57. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-hosted-deployment.js +14 -0
  58. package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +1 -7
  59. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +20 -8
  60. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +12 -8
  61. package/node_modules/@noodle-borg/control-plane/dist/portable.d.ts +2 -0
  62. package/node_modules/@noodle-borg/control-plane/dist/portable.js +1 -0
  63. package/node_modules/@noodle-borg/control-plane/dist/rollback-deployment.d.ts +61 -0
  64. package/node_modules/@noodle-borg/{service/dist/operations → control-plane/dist}/rollback-deployment.js +3 -2
  65. package/node_modules/@noodle-borg/control-plane/dist/rollback-result.d.ts +19 -0
  66. package/node_modules/@noodle-borg/control-plane/package.json +3 -1
  67. package/node_modules/@noodle-borg/developer-mcp/dist/contracts.js +4 -0
  68. package/node_modules/@noodle-borg/developer-mcp/dist/widgets/app-overview.js +1 -1
  69. package/node_modules/@noodle-borg/developer-mcp/dist/widgets/deployment-detail.js +1 -1
  70. package/node_modules/@noodle-borg/module/dist/contract.d.ts +1 -0
  71. package/node_modules/@noodle-borg/module/dist/deployment-automation.d.ts +1 -1
  72. package/node_modules/@noodle-borg/module/dist/endpoint-url.d.ts +11 -0
  73. package/node_modules/@noodle-borg/module/dist/endpoint-url.js +20 -0
  74. package/node_modules/@noodle-borg/module/dist/index.d.ts +1 -0
  75. package/node_modules/@noodle-borg/module/dist/index.js +1 -0
  76. package/node_modules/@noodle-borg/observability/dist/assistant-usage.js +217 -0
  77. package/node_modules/@noodle-borg/observability/dist/index.js +2 -0
  78. package/node_modules/@noodle-borg/{service → observability}/dist/request-event-metrics.js +5 -2
  79. package/node_modules/@noodle-borg/observability/dist/request-events-postgres.js +6 -0
  80. package/node_modules/@noodle-borg/observability/dist/request-events.js +2 -0
  81. package/node_modules/@noodle-borg/service/dist/assistant-bindings.js +3 -1
  82. package/node_modules/@noodle-borg/service/dist/developer-mcp/control-plane-adapter.js +3 -3
  83. package/node_modules/@noodle-borg/service/dist/developer-mcp/inspection.js +2 -1
  84. package/node_modules/@noodle-borg/service/dist/registry-access.js +73 -24
  85. package/node_modules/@noodle-borg/service/dist/registry-deploy-transaction.js +5 -2
  86. package/node_modules/@noodle-borg/service/dist/registry-helpers.d.ts +5 -9
  87. package/node_modules/@noodle-borg/service/dist/registry-helpers.js +4 -18
  88. package/node_modules/@noodle-borg/service/dist/registry-rollback.js +3 -1
  89. package/node_modules/@noodle-borg/service/dist/registry-status.js +4 -1
  90. package/node_modules/@noodle-borg/service/dist/registry-targets.js +4 -4
  91. package/node_modules/@noodle-borg/service/dist/registry-types.d.ts +11 -16
  92. package/node_modules/@noodle-borg/service/dist/registry.d.ts +8 -5
  93. package/node_modules/@noodle-borg/service/dist/registry.js +8 -5
  94. package/node_modules/@noodle-borg/service/dist/routes/access.js +19 -1
  95. package/node_modules/@noodle-borg/service/dist/routes/analytics-dispatch.js +17 -1
  96. package/node_modules/@noodle-borg/service/dist/routes/analytics.js +1 -1
  97. package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js +73 -59
  98. package/node_modules/@noodle-borg/service/dist/routes/assistant-doctor.js +1 -1
  99. package/node_modules/@noodle-borg/service/dist/routes/assistant-model-binding.js +28 -0
  100. package/node_modules/@noodle-borg/service/dist/routes/assistant-public-session.js +18 -0
  101. package/node_modules/@noodle-borg/service/dist/routes/assistant-public-turn.js +6 -0
  102. package/node_modules/@noodle-borg/service/dist/routes/assistant-usage.js +42 -0
  103. package/node_modules/@noodle-borg/service/dist/routes/assistant.js +20 -3
  104. package/node_modules/@noodle-borg/service/dist/routes/auth-doctor-live.js +1 -2
  105. package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +49 -4
  106. package/node_modules/@noodle-borg/service/dist/routes/deploy-preflight.js +11 -1
  107. package/node_modules/@noodle-borg/service/dist/routes/endpoint-enrichment.js +2 -1
  108. package/node_modules/@noodle-borg/service/dist/routes/paths.js +4 -0
  109. package/node_modules/@noodle-borg/service/dist/routes/rollback.js +1 -1
  110. package/node_modules/@noodle-borg/service/dist/service.js +6 -0
  111. package/node_modules/@noodle-borg/service/dist/store/in-memory.d.ts +2 -5
  112. package/node_modules/@noodle-borg/service/dist/store/in-memory.js +9 -21
  113. package/node_modules/@noodle-borg/service/dist/store/json-file.d.ts +2 -5
  114. package/node_modules/@noodle-borg/service/dist/store/json-file.js +8 -20
  115. package/node_modules/@noodle-borg/service/dist/store/records.js +39 -0
  116. package/node_modules/@noodle-borg/service/dist/store.d.ts +21 -10
  117. package/node_modules/@noodle-borg/service/package.json +5 -1
  118. package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.d.ts +120 -0
  119. package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.js +123 -1
  120. package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +4 -0
  121. package/node_modules/@noodle-borg/wire-contracts/dist/index.js +15 -1
  122. package/node_modules/@noodleseed/assistant/README.md +43 -8
  123. package/node_modules/@noodleseed/assistant/package.json +16 -2
  124. package/package.json +2 -2
@@ -1,5 +1,7 @@
1
1
  /** Strict service-output contracts for control-plane reads and mutations (ADR 0128). */
2
2
  import { z } from 'zod';
3
+ /** Exact OAuth subject bound by an operator to an owner-only deployment. */
4
+ export declare const deploymentOwnerSubjectSchema: z.ZodString;
3
5
  export declare const accessUpdateRequestSchema: z.ZodObject<{
4
6
  accessMode: z.ZodEnum<{
5
7
  "owner-only": "owner-only";
@@ -9,8 +11,118 @@ export declare const accessUpdateRequestSchema: z.ZodObject<{
9
11
  mixed: "mixed";
10
12
  customers: "customers";
11
13
  }>;
14
+ ownerSubject: z.ZodOptional<z.ZodString>;
12
15
  serverVersion: z.ZodOptional<z.ZodString>;
13
16
  }, z.core.$strict>;
17
+ export declare const accessUpdateResponseSchema: z.ZodObject<{
18
+ ok: z.ZodLiteral<true>;
19
+ target: z.ZodObject<{
20
+ org: z.ZodString;
21
+ app: z.ZodString;
22
+ env: z.ZodString;
23
+ }, z.core.$strict>;
24
+ deployment: z.ZodObject<{
25
+ deploymentId: z.ZodString;
26
+ serverVersion: z.ZodOptional<z.ZodString>;
27
+ accessMode: z.ZodEnum<{
28
+ "owner-only": "owner-only";
29
+ "org-members": "org-members";
30
+ authenticated: "authenticated";
31
+ public: "public";
32
+ mixed: "mixed";
33
+ customers: "customers";
34
+ }>;
35
+ ownerSubject: z.ZodOptional<z.ZodString>;
36
+ }, z.core.$strict>;
37
+ previousAccessMode: z.ZodEnum<{
38
+ "owner-only": "owner-only";
39
+ "org-members": "org-members";
40
+ authenticated: "authenticated";
41
+ public: "public";
42
+ mixed: "mixed";
43
+ customers: "customers";
44
+ }>;
45
+ previousOwnerSubject: z.ZodOptional<z.ZodString>;
46
+ accessChanged: z.ZodBoolean;
47
+ ownerChanged: z.ZodBoolean;
48
+ changed: z.ZodBoolean;
49
+ }, z.core.$strict>;
50
+ export type AccessUpdateResponse = z.output<typeof accessUpdateResponseSchema>;
51
+ /**
52
+ * Additive client reader for the access mutation response. Older services emitted only the aggregate
53
+ * `changed` bit, so the mode component is derived from the authoritative previous/current modes while an
54
+ * unobservable owner component remains omitted. Modern component bits retain the strict cross-field check.
55
+ */
56
+ export declare const accessUpdateClientResponseSchema: z.ZodPipe<z.ZodObject<{
57
+ ok: z.ZodLiteral<true>;
58
+ target: z.ZodObject<{
59
+ org: z.ZodString;
60
+ app: z.ZodString;
61
+ env: z.ZodString;
62
+ }, z.core.$strip>;
63
+ deployment: z.ZodObject<{
64
+ deploymentId: z.ZodString;
65
+ serverVersion: z.ZodOptional<z.ZodString>;
66
+ accessMode: z.ZodEnum<{
67
+ "owner-only": "owner-only";
68
+ "org-members": "org-members";
69
+ authenticated: "authenticated";
70
+ public: "public";
71
+ mixed: "mixed";
72
+ customers: "customers";
73
+ }>;
74
+ ownerSubject: z.ZodOptional<z.ZodString>;
75
+ }, z.core.$strip>;
76
+ previousAccessMode: z.ZodEnum<{
77
+ "owner-only": "owner-only";
78
+ "org-members": "org-members";
79
+ authenticated: "authenticated";
80
+ public: "public";
81
+ mixed: "mixed";
82
+ customers: "customers";
83
+ }>;
84
+ previousOwnerSubject: z.ZodOptional<z.ZodString>;
85
+ accessChanged: z.ZodOptional<z.ZodBoolean>;
86
+ ownerChanged: z.ZodOptional<z.ZodBoolean>;
87
+ changed: z.ZodBoolean;
88
+ }, z.core.$strip>, z.ZodTransform<{
89
+ accessChanged: boolean;
90
+ ok: true;
91
+ target: {
92
+ org: string;
93
+ app: string;
94
+ env: string;
95
+ };
96
+ deployment: {
97
+ deploymentId: string;
98
+ accessMode: "owner-only" | "org-members" | "authenticated" | "public" | "mixed" | "customers";
99
+ serverVersion?: string | undefined;
100
+ ownerSubject?: string | undefined;
101
+ };
102
+ previousAccessMode: "owner-only" | "org-members" | "authenticated" | "public" | "mixed" | "customers";
103
+ changed: boolean;
104
+ previousOwnerSubject?: string | undefined;
105
+ ownerChanged?: boolean | undefined;
106
+ }, {
107
+ ok: true;
108
+ target: {
109
+ org: string;
110
+ app: string;
111
+ env: string;
112
+ };
113
+ deployment: {
114
+ deploymentId: string;
115
+ accessMode: "owner-only" | "org-members" | "authenticated" | "public" | "mixed" | "customers";
116
+ serverVersion?: string | undefined;
117
+ ownerSubject?: string | undefined;
118
+ };
119
+ previousAccessMode: "owner-only" | "org-members" | "authenticated" | "public" | "mixed" | "customers";
120
+ changed: boolean;
121
+ previousOwnerSubject?: string | undefined;
122
+ accessChanged?: boolean | undefined;
123
+ ownerChanged?: boolean | undefined;
124
+ }>>;
125
+ export type AccessUpdateClientResponse = z.output<typeof accessUpdateClientResponseSchema>;
14
126
  export declare const deploymentLockRequestSchema: z.ZodObject<{
15
127
  serverVersion: z.ZodString;
16
128
  expectedDeploymentId: z.ZodString;
@@ -27,6 +139,7 @@ export declare const DeploymentSummarySchema: z.ZodObject<{
27
139
  serverName: z.ZodString;
28
140
  createdAt: z.ZodString;
29
141
  createdByEmail: z.ZodOptional<z.ZodString>;
142
+ ownerSubject: z.ZodOptional<z.ZodString>;
30
143
  deploymentSource: z.ZodOptional<z.ZodString>;
31
144
  accessMode: z.ZodEnum<{
32
145
  "owner-only": "owner-only";
@@ -66,6 +179,7 @@ export declare const AppSummarySchema: z.ZodObject<{
66
179
  serverName: z.ZodString;
67
180
  createdAt: z.ZodString;
68
181
  createdByEmail: z.ZodOptional<z.ZodString>;
182
+ ownerSubject: z.ZodOptional<z.ZodString>;
69
183
  deploymentSource: z.ZodOptional<z.ZodString>;
70
184
  accessMode: z.ZodEnum<{
71
185
  "owner-only": "owner-only";
@@ -107,6 +221,7 @@ export declare const AppsListResponseSchema: z.ZodObject<{
107
221
  serverName: z.ZodString;
108
222
  createdAt: z.ZodString;
109
223
  createdByEmail: z.ZodOptional<z.ZodString>;
224
+ ownerSubject: z.ZodOptional<z.ZodString>;
110
225
  deploymentSource: z.ZodOptional<z.ZodString>;
111
226
  accessMode: z.ZodEnum<{
112
227
  "owner-only": "owner-only";
@@ -150,6 +265,7 @@ export declare const AppResponseSchema: z.ZodObject<{
150
265
  serverName: z.ZodString;
151
266
  createdAt: z.ZodString;
152
267
  createdByEmail: z.ZodOptional<z.ZodString>;
268
+ ownerSubject: z.ZodOptional<z.ZodString>;
153
269
  deploymentSource: z.ZodOptional<z.ZodString>;
154
270
  accessMode: z.ZodEnum<{
155
271
  "owner-only": "owner-only";
@@ -190,6 +306,7 @@ export declare const EnvSummarySchema: z.ZodObject<{
190
306
  serverName: z.ZodString;
191
307
  createdAt: z.ZodString;
192
308
  createdByEmail: z.ZodOptional<z.ZodString>;
309
+ ownerSubject: z.ZodOptional<z.ZodString>;
193
310
  deploymentSource: z.ZodOptional<z.ZodString>;
194
311
  accessMode: z.ZodEnum<{
195
312
  "owner-only": "owner-only";
@@ -233,6 +350,7 @@ export declare const EnvsListResponseSchema: z.ZodObject<{
233
350
  serverName: z.ZodString;
234
351
  createdAt: z.ZodString;
235
352
  createdByEmail: z.ZodOptional<z.ZodString>;
353
+ ownerSubject: z.ZodOptional<z.ZodString>;
236
354
  deploymentSource: z.ZodOptional<z.ZodString>;
237
355
  accessMode: z.ZodEnum<{
238
356
  "owner-only": "owner-only";
@@ -277,6 +395,7 @@ export declare const EnvResponseSchema: z.ZodObject<{
277
395
  serverName: z.ZodString;
278
396
  createdAt: z.ZodString;
279
397
  createdByEmail: z.ZodOptional<z.ZodString>;
398
+ ownerSubject: z.ZodOptional<z.ZodString>;
280
399
  deploymentSource: z.ZodOptional<z.ZodString>;
281
400
  accessMode: z.ZodEnum<{
282
401
  "owner-only": "owner-only";
@@ -358,6 +477,7 @@ export declare const DeploymentResponseSchema: z.ZodObject<{
358
477
  serverName: z.ZodString;
359
478
  createdAt: z.ZodString;
360
479
  createdByEmail: z.ZodOptional<z.ZodString>;
480
+ ownerSubject: z.ZodOptional<z.ZodString>;
361
481
  deploymentSource: z.ZodOptional<z.ZodString>;
362
482
  accessMode: z.ZodEnum<{
363
483
  "owner-only": "owner-only";
@@ -1,12 +1,133 @@
1
1
  /** Strict service-output contracts for control-plane reads and mutations (ADR 0128). */
2
2
  import { z } from 'zod';
3
3
  import { accessModeSchema } from './access-mode.js';
4
+ function containsC0OrDel(value) {
5
+ for (let index = 0; index < value.length; index += 1) {
6
+ const codeUnit = value.charCodeAt(index);
7
+ if (codeUnit <= 0x1f || codeUnit === 0x7f)
8
+ return true;
9
+ }
10
+ return false;
11
+ }
12
+ /** Exact OAuth subject bound by an operator to an owner-only deployment. */
13
+ export const deploymentOwnerSubjectSchema = z
14
+ .string()
15
+ .min(1)
16
+ .max(512)
17
+ .refine((value) => value.trim() === value && !containsC0OrDel(value), 'owner subject must not contain outer whitespace or C0/DEL control characters');
4
18
  export const accessUpdateRequestSchema = z
5
19
  .object({
6
20
  accessMode: accessModeSchema,
21
+ ownerSubject: deploymentOwnerSubjectSchema.optional(),
7
22
  serverVersion: z.string().min(1).optional(),
8
23
  })
9
- .strict();
24
+ .strict()
25
+ .superRefine((value, context) => {
26
+ if (value.ownerSubject !== undefined && value.accessMode !== 'owner-only') {
27
+ context.addIssue({
28
+ code: 'custom',
29
+ path: ['ownerSubject'],
30
+ message: 'ownerSubject is valid only with owner-only access',
31
+ });
32
+ }
33
+ });
34
+ export const accessUpdateResponseSchema = z
35
+ .object({
36
+ ok: z.literal(true),
37
+ target: z
38
+ .object({
39
+ org: z.string().min(1),
40
+ app: z.string().min(1),
41
+ env: z.string().min(1),
42
+ })
43
+ .strict(),
44
+ deployment: z
45
+ .object({
46
+ deploymentId: z.string().min(1),
47
+ serverVersion: z.string().min(1).optional(),
48
+ accessMode: accessModeSchema,
49
+ ownerSubject: deploymentOwnerSubjectSchema.optional(),
50
+ })
51
+ .strict(),
52
+ previousAccessMode: accessModeSchema,
53
+ previousOwnerSubject: deploymentOwnerSubjectSchema.optional(),
54
+ accessChanged: z.boolean(),
55
+ ownerChanged: z.boolean(),
56
+ changed: z.boolean(),
57
+ })
58
+ .strict()
59
+ .superRefine((value, context) => {
60
+ if (value.deployment.accessMode === 'owner-only' &&
61
+ value.deployment.ownerSubject === undefined) {
62
+ context.addIssue({
63
+ code: 'custom',
64
+ path: ['deployment', 'ownerSubject'],
65
+ message: 'owner-only access requires a current owner subject',
66
+ });
67
+ }
68
+ if (value.changed !== (value.accessChanged || value.ownerChanged)) {
69
+ context.addIssue({
70
+ code: 'custom',
71
+ path: ['changed'],
72
+ message: 'changed must equal accessChanged || ownerChanged',
73
+ });
74
+ }
75
+ });
76
+ /**
77
+ * Additive client reader for the access mutation response. Older services emitted only the aggregate
78
+ * `changed` bit, so the mode component is derived from the authoritative previous/current modes while an
79
+ * unobservable owner component remains omitted. Modern component bits retain the strict cross-field check.
80
+ */
81
+ export const accessUpdateClientResponseSchema = z
82
+ .object({
83
+ ok: z.literal(true),
84
+ target: z.object({
85
+ org: z.string().min(1),
86
+ app: z.string().min(1),
87
+ env: z.string().min(1),
88
+ }),
89
+ deployment: z.object({
90
+ deploymentId: z.string().min(1),
91
+ serverVersion: z.string().min(1).optional(),
92
+ accessMode: accessModeSchema,
93
+ ownerSubject: deploymentOwnerSubjectSchema.optional(),
94
+ }),
95
+ previousAccessMode: accessModeSchema,
96
+ previousOwnerSubject: deploymentOwnerSubjectSchema.optional(),
97
+ accessChanged: z.boolean().optional(),
98
+ ownerChanged: z.boolean().optional(),
99
+ changed: z.boolean(),
100
+ })
101
+ .superRefine((value, context) => {
102
+ const modernComponents = value.accessChanged !== undefined && value.ownerChanged !== undefined;
103
+ if ((value.accessChanged === undefined) !== (value.ownerChanged === undefined)) {
104
+ context.addIssue({
105
+ code: 'custom',
106
+ path: ['accessChanged'],
107
+ message: 'accessChanged and ownerChanged must be present together',
108
+ });
109
+ }
110
+ if (modernComponents &&
111
+ value.deployment.accessMode === 'owner-only' &&
112
+ value.deployment.ownerSubject === undefined) {
113
+ context.addIssue({
114
+ code: 'custom',
115
+ path: ['deployment', 'ownerSubject'],
116
+ message: 'owner-only access requires a current owner subject',
117
+ });
118
+ }
119
+ if (modernComponents && value.changed !== (value.accessChanged || value.ownerChanged)) {
120
+ context.addIssue({
121
+ code: 'custom',
122
+ path: ['changed'],
123
+ message: 'changed must equal accessChanged || ownerChanged',
124
+ });
125
+ }
126
+ })
127
+ .transform((value) => ({
128
+ ...value,
129
+ accessChanged: value.accessChanged ?? value.previousAccessMode !== value.deployment.accessMode,
130
+ }));
10
131
  export const deploymentLockRequestSchema = z
11
132
  .object({
12
133
  serverVersion: z.string().min(1),
@@ -32,6 +153,7 @@ export const DeploymentSummarySchema = z
32
153
  serverName: z.string(),
33
154
  createdAt: z.string(),
34
155
  createdByEmail: z.string().optional(),
156
+ ownerSubject: deploymentOwnerSubjectSchema.optional(),
35
157
  deploymentSource: z.string().optional(),
36
158
  accessMode: accessModeSchema,
37
159
  deploymentLock: DeploymentLockMetadataSchema.optional(),
@@ -80,6 +80,7 @@ export declare const deployRequestSchema: z.ZodObject<{
80
80
  mixed: "mixed";
81
81
  customers: "customers";
82
82
  }>>;
83
+ ownerSubject: z.ZodOptional<z.ZodString>;
83
84
  orgMembershipSources: z.ZodOptional<z.ZodArray<z.ZodEnum<{
84
85
  explicit: "explicit";
85
86
  domain: "domain";
@@ -115,6 +116,7 @@ export declare const deploySuccessResponseSchema: z.ZodObject<{
115
116
  mixed: "mixed";
116
117
  customers: "customers";
117
118
  }>;
119
+ ownerSubject: z.ZodOptional<z.ZodString>;
118
120
  url: z.ZodString;
119
121
  defaultUrl: z.ZodString;
120
122
  embedId: z.ZodOptional<z.ZodString>;
@@ -158,6 +160,7 @@ export declare const deployPreflightRequestSchema: z.ZodObject<{
158
160
  mixed: "mixed";
159
161
  customers: "customers";
160
162
  }>>;
163
+ ownerSubject: z.ZodOptional<z.ZodString>;
161
164
  orgMembershipSources: z.ZodOptional<z.ZodArray<z.ZodEnum<{
162
165
  explicit: "explicit";
163
166
  domain: "domain";
@@ -183,6 +186,7 @@ export type DeployTargetState = z.infer<typeof deployTargetStateSchema>;
183
186
  export declare const deployPreflightResponseSchema: z.ZodObject<{
184
187
  ok: z.ZodLiteral<true>;
185
188
  ready: z.ZodBoolean;
189
+ ownerSubject: z.ZodOptional<z.ZodString>;
186
190
  target: z.ZodObject<{
187
191
  org: z.ZodString;
188
192
  app: z.ZodString;
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { z } from 'zod';
11
11
  import { accessModeSchema } from './access-mode.js';
12
+ import { deploymentOwnerSubjectSchema } from './control-plane.js';
12
13
  export * from './access-mode.js';
13
14
  export * from './assistant.js';
14
15
  export * from './billing-operations.js';
@@ -50,14 +51,25 @@ export const hostedAssetSchema = z.object({
50
51
  */
51
52
  export const ORG_MEMBERSHIP_SOURCES = ['explicit', 'domain'];
52
53
  export const orgMembershipSourceSchema = z.enum(ORG_MEMBERSHIP_SOURCES);
53
- export const deployRequestSchema = z.object({
54
+ export const deployRequestSchema = z
55
+ .object({
54
56
  manifest: z.string().min(1),
55
57
  connectors: z.string().min(1).optional(),
56
58
  hostedAssets: z.array(hostedAssetSchema).optional(),
57
59
  accessMode: accessModeSchema.optional(),
60
+ ownerSubject: deploymentOwnerSubjectSchema.optional(),
58
61
  orgMembershipSources: z.array(orgMembershipSourceSchema).min(1).optional(),
59
62
  serverVersion: z.string().min(1).optional(),
60
63
  deploymentSource: deploymentSourceSchema.optional(),
64
+ })
65
+ .superRefine((value, context) => {
66
+ if (value.ownerSubject !== undefined && (value.accessMode ?? 'owner-only') !== 'owner-only') {
67
+ context.addIssue({
68
+ code: 'custom',
69
+ path: ['ownerSubject'],
70
+ message: 'ownerSubject is valid only with owner-only access',
71
+ });
72
+ }
61
73
  });
62
74
  /** Exact bytes both sides bind when deriving a retry-safe deploy key. */
63
75
  export function deployIdempotencyMaterial(target, requestBody) {
@@ -72,6 +84,7 @@ export const deploySuccessResponseSchema = z.object({
72
84
  deploymentId: z.string().min(1),
73
85
  serverVersion: z.string().min(1),
74
86
  accessMode: accessModeSchema,
87
+ ownerSubject: deploymentOwnerSubjectSchema.optional(),
75
88
  url: z.string().min(1),
76
89
  defaultUrl: z.string().min(1),
77
90
  /**
@@ -111,6 +124,7 @@ const deployPreflightErrorSchema = z.object({
111
124
  export const deployPreflightResponseSchema = z.object({
112
125
  ok: z.literal(true),
113
126
  ready: z.boolean(),
127
+ ownerSubject: deploymentOwnerSubjectSchema.optional(),
114
128
  target: z.object({
115
129
  org: z.string().min(1),
116
130
  app: z.string().min(1),
@@ -2,8 +2,9 @@
2
2
 
3
3
  Customer-branded embedded assistant surfaces for Noodle Seed deployments.
4
4
 
5
- The package exports the canonical `<noodle-assistant>` Web Component, a managed React wrapper and secure
6
- `NoodleAppView` MCP App renderer from `@noodleseed/assistant/react`, a renderer-free React hook from
5
+ The package exports the canonical `<noodle-assistant>` managed Web Component, the framework-neutral
6
+ `<noodle-app-view>` MCP App host from `@noodleseed/assistant/app-view`, a managed React wrapper and
7
+ `NoodleAppView` adapter from `@noodleseed/assistant/react`, a renderer-free React hook from
7
8
  `@noodleseed/assistant/react/client`, a DOM-free client from `@noodleseed/assistant/client`, and the
8
9
  backend-only `createAssistantSession` helper from `@noodleseed/assistant/server`. Light, dark, and automatic
9
10
  themes work without configuration; the component inherits the deployed MCP server's brand kit while slots,
@@ -376,20 +377,54 @@ if (part.type === "data-view") {
376
377
  }
377
378
  ```
378
379
 
379
- `NoodleAppView` owns the double iframe and AppBridge. Its lifecycle identity is the supplied client plus
380
+ `<noodle-app-view>` owns the double iframe and AppBridge; `NoodleAppView` delegates to it. Its lifecycle identity is the supplied client plus
380
381
  `view.id` plus `view.resourceUri`: ordinary parent rerenders and fresh view/callback objects retain the
381
382
  iframe, while a semantic view replacement or unmount requests standard App teardown and closes the bridge.
382
383
  Do not also key an ancestor by the whole view object or a callback. Pass the embedding application's
383
384
  resolved `"light"` or `"dark"` theme; later changes are published through MCP Apps host context without
384
385
  replacing the iframe.
385
386
 
387
+ App views stay inline by default. The host advertises only inline presentation and rejects an untrusted
388
+ App's fullscreen request, so stale or third-party widget code cannot take over the embedding application's
389
+ viewport. If fullscreen is an intentional part of the customer-owned experience, opt in explicitly with
390
+ `allowFullscreen` on `NoodleAppView` or `allow-fullscreen` on `<noodle-app-view>`; do not enable it merely
391
+ because a widget requests it. After an accepted fullscreen request, the host displays an accessible exit
392
+ control in the top-right corner. It returns the same mounted App to inline mode without resetting its state.
393
+
394
+ Vue, Angular, and plain DOM renderers use the same host without installing React. Import its dedicated entry
395
+ once, then assign the complex values as element properties. In Vue, the explicit `.prop` modifier makes that
396
+ boundary unambiguous:
397
+
398
+ ```vue
399
+ <script setup lang="ts">
400
+ import "@noodleseed/assistant/app-view";
401
+ </script>
402
+
403
+ <template>
404
+ <noodle-app-view
405
+ :client.prop="assistant"
406
+ :view.prop="part.data"
407
+ :theme="resolvedTheme"
408
+ @assistant-error="reportAssistantError"
409
+ />
410
+ </template>
411
+ ```
412
+
413
+ Configure Vue's `isCustomElement` for `noodle-app-view`. Angular uses the same element with `[client]`,
414
+ `[view]`, and `[theme]` property bindings. Do not serialize `client` or `view` into attributes.
415
+
416
+ `<noodle-app-view>` is the canonical host; `NoodleAppView` delegates to it. Both use the
417
+ service-advertised sandbox URL, route App calls through the supplied client, publish theme changes without
418
+ replacing the iframe, and request standard teardown on semantic replacement, disconnect, or an App teardown
419
+ request.
420
+
386
421
  The App document owns its action intent: it calls standard `tools/call` after connecting and never relies on
387
422
  native form navigation. If that call needs input or confirmation, the same `client` publishes the normal
388
423
  pending interaction part for either managed or customer-owned rendering. The original App call stays pending
389
424
  and receives its MCP result after `client.respond(...)`; applications must not retry or translate the click.
390
425
 
391
- Outside React, subscribe to the DOM-free AI SDK `UIMessage` state without registering a custom element or
392
- touching browser storage:
426
+ Outside React, subscribe to the DOM-free AI SDK `UIMessage` state without touching browser storage. The
427
+ client itself registers no element; import `/app-view` only when the transcript renders linked MCP Apps:
393
428
 
394
429
  ```ts
395
430
  import { createAssistantClient } from "@noodleseed/assistant/client";
@@ -491,8 +526,8 @@ flow collects all elicited input before its first connector operation.
491
526
 
492
527
  A completed widget-linked tool emits typed `view_available` data with its call/interaction id, tool,
493
528
  `ui://` resource identity, optional title, bounded/redacted public result, and—on current services—the
494
- self-contained App document. This is an availability signal, not proof of rendering. A customer-owned React
495
- renderer either mounts the actual App with `NoodleAppView` or deliberately substitutes a component already
529
+ self-contained App document. This is an availability signal, not proof of rendering. A customer-owned
530
+ renderer either mounts the actual App with `<noodle-app-view>` (or its React `NoodleAppView` adapter) or deliberately substitutes a component already
496
531
  trusted by the application and selected by `resourceUri`/tool. The JSON `result` is data for a native
497
532
  component; serializing it is not a rendering of the linked App. Never fetch the `ui://` URI, inject
498
533
  `part.data.html`, or assign it to `srcdoc` yourself. The standard element also forwards the same detail as a
@@ -615,7 +650,7 @@ shadow-DOM selectors and classes are not public API.
615
650
 
616
651
  `theme="auto"` follows the browser's operating-system color preference. When the embedding application has
617
652
  its own theme toggle, pass its resolved `"light"` or `"dark"` value to `NoodleAssistant` and every
618
- `NoodleAppView`. Updates change the assistant in place and notify mounted MCP Apps through standard host
653
+ `<noodle-app-view>`/`NoodleAppView`. Updates change the assistant in place and notify mounted MCP Apps through standard host
619
654
  context.
620
655
 
621
656
  Server branding controls customer name, themed logo/mark/avatar assets, semantic light/dark colors, density,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@noodleseed/assistant",
3
- "version": "1.22.0",
4
- "description": "Embed the Noodle Seed customer-branded assistant in your web app with a Web Component, managed or custom React UI, DOM-free client, and backend session helper. Authoring and deploying the server is @noodleseed/one.",
3
+ "version": "1.23.0",
4
+ "description": "Embed the Noodle Seed customer-branded assistant in your web app with managed or framework-owned UI, a framework-neutral MCP App host, a DOM-free client, and a backend session helper. Authoring and deploying the server is @noodleseed/one.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -26,6 +26,17 @@
26
26
  },
27
27
  "default": "./dist/index.js"
28
28
  },
29
+ "./app-view": {
30
+ "import": {
31
+ "types": "./dist/app-view.d.ts",
32
+ "default": "./dist/app-view.js"
33
+ },
34
+ "require": {
35
+ "types": "./dist/app-view.d.cts",
36
+ "default": "./dist/app-view.cjs"
37
+ },
38
+ "default": "./dist/app-view.js"
39
+ },
29
40
  "./client": {
30
41
  "import": {
31
42
  "types": "./dist/client.d.ts",
@@ -103,6 +114,9 @@
103
114
  "module": "./dist/index.js",
104
115
  "typesVersions": {
105
116
  "*": {
117
+ "app-view": [
118
+ "./dist/app-view.d.ts"
119
+ ],
106
120
  "react": [
107
121
  "./dist/react.d.ts"
108
122
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/one",
3
- "version": "0.136.0",
3
+ "version": "0.138.0",
4
4
  "private": false,
5
5
  "description": "Noodle CLI by Noodle Seed — author, run, and deploy declarative MCP servers. Embedding the assistant in your own web app is @noodleseed/assistant.",
6
6
  "license": "Apache-2.0",
@@ -236,7 +236,7 @@
236
236
  "@modelcontextprotocol/client": "2.0.0",
237
237
  "@modelcontextprotocol/server": "2.0.0",
238
238
  "@noodle-borg/admission-limits": "0.0.0",
239
- "@noodle-borg/agent-kit": "0.81.0",
239
+ "@noodle-borg/agent-kit": "0.82.0",
240
240
  "@noodle-borg/app-audit": "0.0.0",
241
241
  "@noodle-borg/app-package": "0.0.0",
242
242
  "@noodle-borg/assistant-gateway": "0.0.0",