@aifabrix/builder 2.51.1 → 2.52.1

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 (187) hide show
  1. package/jest.isolated-projects.js +25 -2
  2. package/jest.projects.js +4 -1
  3. package/lib/api/datasources-extended.api.js +8 -8
  4. package/lib/api/keycloak.api.js +92 -0
  5. package/lib/api/token-providers.api.js +77 -0
  6. package/lib/api/types/keycloak.types.js +23 -0
  7. package/lib/api/types/token-providers.types.js +65 -0
  8. package/lib/app/down.js +16 -1
  9. package/lib/app/run-container-start.js +4 -0
  10. package/lib/app/run-deploy-job.js +135 -27
  11. package/lib/app/run-env-compose.js +32 -0
  12. package/lib/app/run-env-recovery.js +35 -0
  13. package/lib/app/run-helpers.js +5 -6
  14. package/lib/app/run.js +11 -3
  15. package/lib/channels/add-channel.js +126 -19
  16. package/lib/channels/approval-guides/chatgpt.js +12 -9
  17. package/lib/channels/approval-guides/microsoft-copilot.js +16 -12
  18. package/lib/channels/channel-add-ensure.js +128 -0
  19. package/lib/channels/channel-artifact-generator.js +11 -1
  20. package/lib/channels/channel-branding.js +94 -0
  21. package/lib/channels/channel-credential.js +8 -0
  22. package/lib/channels/channel-discovery.js +330 -0
  23. package/lib/channels/channel-external-system.js +1 -1
  24. package/lib/channels/channel-runtime-resolver.js +103 -14
  25. package/lib/channels/channel-status-display.js +7 -1
  26. package/lib/channels/channel-targets.js +18 -1
  27. package/lib/channels/chatgpt-runtime-contract.js +1 -1
  28. package/lib/channels/microsoft-copilot-channel-add.js +138 -0
  29. package/lib/channels/microsoft-copilot-entra-sso-form.js +180 -0
  30. package/lib/channels/microsoft-copilot-entra-sso.js +264 -0
  31. package/lib/channels/microsoft-copilot-icons.js +74 -0
  32. package/lib/channels/microsoft-copilot-limits.js +84 -0
  33. package/lib/channels/microsoft-copilot-package.js +130 -49
  34. package/lib/channels/microsoft-copilot-validate.js +197 -0
  35. package/lib/cli/index.js +2 -0
  36. package/lib/cli/infra-guided-footers.js +1 -1
  37. package/lib/cli/infra-guided-public-url-warn.js +55 -0
  38. package/lib/cli/infra-guided.js +78 -62
  39. package/lib/cli/setup-app.help.js +4 -0
  40. package/lib/cli/setup-app.test-commands.js +59 -28
  41. package/lib/cli/setup-external-system.js +50 -12
  42. package/lib/cli/setup-infra.js +31 -4
  43. package/lib/commands/channel-add-setup.js +35 -10
  44. package/lib/commands/channel.js +27 -12
  45. package/lib/commands/deploy-gate-orchestrator.js +3 -2
  46. package/lib/commands/governance-verify-external.js +2 -5
  47. package/lib/commands/integration-definition.js +158 -0
  48. package/lib/commands/lifecycle-external.js +14 -7
  49. package/lib/commands/repair-auth-apply.js +19 -5
  50. package/lib/commands/repair-datasource-sync-operations.js +4 -1
  51. package/lib/commands/role-assistant-test-output.js +200 -0
  52. package/lib/commands/role-assistant.js +131 -114
  53. package/lib/commands/test-governance-external.js +2 -5
  54. package/lib/commands/up-miso.js +61 -24
  55. package/lib/commands/upload-data-sync-finalize.js +20 -3
  56. package/lib/commands/verify-governance-external.js +2 -5
  57. package/lib/commands/verify-operations-external.js +2 -5
  58. package/lib/commands/verify-operations-step-plan.js +31 -0
  59. package/lib/commands/verify-trust-command-action.js +2 -5
  60. package/lib/datasource/capability/capability-resolve.js +15 -5
  61. package/lib/datasource/capability/copy-operations.js +14 -4
  62. package/lib/datasource/datasource-identifier.js +4 -3
  63. package/lib/datasource/integration-context.js +3 -3
  64. package/lib/datasource/resolve-app.js +90 -8
  65. package/lib/datasource/test-e2e.js +2 -2
  66. package/lib/datasource/unified-validation-run-body.js +15 -1
  67. package/lib/datasource/unified-validation-run-resolve.js +2 -2
  68. package/lib/external-system/deploy-helpers.js +9 -5
  69. package/lib/external-system/deploy.js +2 -1
  70. package/lib/external-system/test-system-level.js +21 -3
  71. package/lib/external-system/test.js +4 -4
  72. package/lib/generator/builders.js +9 -15
  73. package/lib/infrastructure/index.js +19 -4
  74. package/lib/integration-definition/apply.js +478 -0
  75. package/lib/integration-definition/canonical-json.js +51 -0
  76. package/lib/integration-definition/emit-suite-bid.js +94 -0
  77. package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
  78. package/lib/integration-definition/enrich-openapi-operations.js +434 -0
  79. package/lib/integration-definition/from-discovery.js +339 -0
  80. package/lib/integration-definition/hash.js +37 -0
  81. package/lib/integration-definition/index.js +37 -0
  82. package/lib/integration-definition/openapi-enrichment/hubspot-crm-companies.json +205 -0
  83. package/lib/integration-definition/resource-type-catalog.js +59 -0
  84. package/lib/integration-definition/system-kind-enum.js +40 -0
  85. package/lib/integration-definition/validate.js +148 -0
  86. package/lib/programmatic/builder-api-request.js +5 -1
  87. package/lib/programmatic/builder-help-governance.js +3 -2
  88. package/lib/programmatic/capability-registry.js +19 -0
  89. package/lib/programmatic/openapi-component-schemas.js +6 -1
  90. package/lib/programmatic/openapi-descriptions.js +40 -0
  91. package/lib/programmatic/openapi-envelope-examples.js +269 -0
  92. package/lib/programmatic/openapi-operation-bindings.js +45 -0
  93. package/lib/programmatic/openapi-request-schemas.js +14 -0
  94. package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
  95. package/lib/programmatic/openapi-result-schemas.js +46 -99
  96. package/lib/programmatic/openapi-schema-descriptions-core.js +7 -4
  97. package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
  98. package/lib/programmatic/openapi-schema-descriptions-operations.js +24 -0
  99. package/lib/programmatic/openapi-schema-helpers.js +9 -9
  100. package/lib/programmatic/openapi-spec.js +11 -1
  101. package/lib/programmatic/orchestration-openapi-meta.js +10 -0
  102. package/lib/programmatic/route-handler-map.js +29 -1
  103. package/lib/programmatic/run-channel-package.js +236 -0
  104. package/lib/programmatic/run-integration-definition.js +69 -0
  105. package/lib/role-assistant/knowledge-markdown-frontmatter.js +75 -0
  106. package/lib/role-assistant/knowledge-sync-logging.js +58 -0
  107. package/lib/role-assistant/knowledge-sync.js +104 -89
  108. package/lib/role-assistant/test-cases-bid.js +155 -0
  109. package/lib/role-assistant/test-cases-evaluate.js +9 -1
  110. package/lib/role-assistant/test-cases-honesty.js +24 -10
  111. package/lib/role-assistant/test-cases.js +28 -0
  112. package/lib/role-assistant/test-runner-bid-apply.js +122 -0
  113. package/lib/role-assistant/test-runner-bid-document.js +278 -0
  114. package/lib/role-assistant/test-runner-workhub-answers.js +289 -46
  115. package/lib/role-assistant/test-runner-workhub.js +121 -25
  116. package/lib/role-assistant/test-suite.js +119 -0
  117. package/lib/schema/application-schema.json +64 -32
  118. package/lib/schema/external-datasource.schema.json +103 -17
  119. package/lib/schema/external-system.schema.json +54 -3
  120. package/lib/schema/infra.parameter.yaml +0 -20
  121. package/lib/schema/integration-definition.schema.json +195 -0
  122. package/lib/utils/authentication-shape.js +6 -0
  123. package/lib/utils/certify-external-workspace.js +40 -0
  124. package/lib/utils/docker-build.js +3 -3
  125. package/lib/utils/docker-run-ephemeral.js +77 -17
  126. package/lib/utils/health-check-public-warn.js +31 -13
  127. package/lib/utils/health-check.js +11 -1
  128. package/lib/utils/help-builder.js +1 -0
  129. package/lib/utils/paths.js +13 -15
  130. package/lib/utils/promote-dev-docker-image.js +97 -18
  131. package/lib/utils/role-assistant-paths.js +76 -14
  132. package/lib/utils/transient-developer-id.js +28 -0
  133. package/lib/utils/upload-sync-options.js +7 -4
  134. package/lib/validation/reserved-system-key-prefixes.js +56 -0
  135. package/lib/validation/validate.js +54 -19
  136. package/package.json +1 -1
  137. package/scripts/pnpm/af.mjs +24 -9
  138. package/scripts/pnpm/help.mjs +1 -1
  139. package/templates/applications/builder-api/application.yaml +3 -3
  140. package/templates/applications/dataplane/application.yaml +5 -5
  141. package/templates/applications/dataplane/env.template +8 -7
  142. package/templates/applications/dataplane/rbac.yaml +10 -10
  143. package/templates/applications/keycloak/application.yaml +2 -2
  144. package/templates/applications/keycloak/env.template +5 -2
  145. package/templates/applications/miso-controller/application.yaml +25 -11
  146. package/templates/applications/miso-controller/env.template +24 -5
  147. package/templates/channels/README.md +11 -1
  148. package/templates/channels/brand/color-192.png +0 -0
  149. package/templates/channels/brand/dark/128.png +0 -0
  150. package/templates/channels/brand/dark/192.png +0 -0
  151. package/templates/channels/brand/dark/256.png +0 -0
  152. package/templates/channels/brand/dark/32.png +0 -0
  153. package/templates/channels/brand/dark/512.png +0 -0
  154. package/templates/channels/brand/dark/64.png +0 -0
  155. package/templates/channels/brand/light/128.png +0 -0
  156. package/templates/channels/brand/light/192.png +0 -0
  157. package/templates/channels/brand/light/256.png +0 -0
  158. package/templates/channels/brand/light/32.png +0 -0
  159. package/templates/channels/brand/light/512.png +0 -0
  160. package/templates/channels/brand/light/64.png +0 -0
  161. package/templates/channels/brand/mono-white/128.png +0 -0
  162. package/templates/channels/brand/mono-white/192.png +0 -0
  163. package/templates/channels/brand/mono-white/256.png +0 -0
  164. package/templates/channels/brand/mono-white/32.png +0 -0
  165. package/templates/channels/brand/mono-white/512.png +0 -0
  166. package/templates/channels/brand/mono-white/64.png +0 -0
  167. package/templates/channels/brand/outline-32.png +0 -0
  168. package/templates/channels/chatgpt/install.template.md.hbs +76 -36
  169. package/templates/channels/chatgpt/integration/README.md +4 -4
  170. package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
  171. package/templates/channels/chatgpt/manifest.template.json.hbs +3 -3
  172. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +10 -16
  173. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
  174. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +27 -0
  175. package/templates/channels/microsoft-copilot/install.template.md.hbs +39 -20
  176. package/templates/channels/microsoft-copilot/integration/README.md +2 -3
  177. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
  178. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +7 -7
  179. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +11 -0
  180. package/templates/channels/slack/install.template.md.hbs +6 -1
  181. package/templates/channels/slack/integration/README.md +2 -4
  182. package/templates/channels/teams-bot/install.template.md.hbs +4 -0
  183. package/templates/channels/teams-bot/integration/README.md +3 -5
  184. package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
  185. package/templates/python/docker-compose.hbs +10 -0
  186. package/templates/typescript/docker-compose.hbs +10 -0
  187. /package/.cursor/plans/{Done → Archive}/157.1-security-quality-violations-by-type.csv +0 -0
@@ -7,12 +7,12 @@
7
7
  "key": "external-system-schema",
8
8
  "name": "External System Configuration Schema",
9
9
  "description": "JSON schema for validating ExternalSystem configuration files",
10
- "version": "1.13.1",
10
+ "version": "1.14.0",
11
11
  "type": "schema",
12
12
  "category": "integration",
13
13
  "author": "AI Fabrix Team",
14
14
  "createdAt": "2024-01-01T00:00:00Z",
15
- "updatedAt": "2026-07-22T00:00:00Z",
15
+ "updatedAt": "2026-08-07T00:00:00Z",
16
16
  "compatibility": {
17
17
  "minVersion": "1.4.0",
18
18
  "maxVersion": "2.0.0",
@@ -27,6 +27,14 @@
27
27
  ],
28
28
  "dependencies": [],
29
29
  "changelog": [
30
+ {
31
+ "version": "1.14.0",
32
+ "date": "2026-08-07T00:00:00Z",
33
+ "changes": [
34
+ "Added authentication.authType system for platform-managed downstream auth (no credential/apiProvider; ownership only — not autonomous system actor)."
35
+ ],
36
+ "breaking": false
37
+ },
30
38
  {
31
39
  "version": "1.13.1",
32
40
  "date": "2026-07-22T00:00:00Z",
@@ -806,6 +814,7 @@
806
814
  "enum": [
807
815
  "credential",
808
816
  "apiProvider",
817
+ "system",
809
818
  "none"
810
819
  ]
811
820
  },
@@ -845,6 +854,36 @@
845
854
  "apiProvider"
846
855
  ]
847
856
  }
857
+ },
858
+ {
859
+ "if": {
860
+ "properties": {
861
+ "authType": {
862
+ "const": "system"
863
+ }
864
+ }
865
+ },
866
+ "then": {
867
+ "properties": {
868
+ "credential": false,
869
+ "apiProvider": false
870
+ }
871
+ }
872
+ },
873
+ {
874
+ "if": {
875
+ "properties": {
876
+ "authType": {
877
+ "const": "none"
878
+ }
879
+ }
880
+ },
881
+ "then": {
882
+ "properties": {
883
+ "credential": false,
884
+ "apiProvider": false
885
+ }
886
+ }
848
887
  }
849
888
  ]
850
889
  }
@@ -1039,7 +1078,7 @@
1039
1078
  "default": false
1040
1079
  },
1041
1080
  "authentication": {
1042
- "description": "Nested authentication: authType credential (local template), apiProvider (Miso delegated), or none. Deprecated — prefer authentications[] with usage.",
1081
+ "description": "Nested authentication: authType credential (local template), apiProvider (Miso delegated), system (platform-managed downstream auth ownership), or none (downstream anonymous). Deprecated — prefer authentications[] with usage.",
1043
1082
  "oneOf": [
1044
1083
  {
1045
1084
  "type": "object",
@@ -1073,6 +1112,18 @@
1073
1112
  },
1074
1113
  "additionalProperties": false
1075
1114
  },
1115
+ {
1116
+ "type": "object",
1117
+ "required": [
1118
+ "authType"
1119
+ ],
1120
+ "properties": {
1121
+ "authType": {
1122
+ "const": "system"
1123
+ }
1124
+ },
1125
+ "additionalProperties": false
1126
+ },
1076
1127
  {
1077
1128
  "type": "object",
1078
1129
  "required": [
@@ -340,26 +340,6 @@ parameters:
340
340
  vaultSecretName: dataplane-client-secretKeyVault
341
341
  notes: Per-app OAuth client secret for dataplane; generated on first ensure.
342
342
 
343
- - key: mori-controller-client-idKeyVault
344
- scope: app
345
- generator:
346
- type: literal
347
- value: 'miso-controller-dev-mori-controller'
348
- ensureOn: [upInfra, resolveApp]
349
- azure:
350
- notes: >-
351
- Per-app OAuth client id from controller registration; literal default matches
352
- {controllerId}-{environmentKey}-{applicationKey} (override per environment).
353
-
354
- - key: mori-controller-client-secretKeyVault
355
- scope: app
356
- generator:
357
- type: randomBytes32
358
- ensureOn: [upInfra, resolveApp]
359
- azure:
360
- vaultSecretName: mori-controller-client-secretKeyVault
361
- notes: Per-app OAuth client secret for mori-controller; generated on first ensure.
362
-
363
343
  # Mori / telemetry: optional locally (LICENSE_JWT via miso-controller-jwt-licenseKeyVault=DEVELOPMENT skips Mori).
364
344
  # MORI_AUTH_METHOD=kv://mori-controller-auth-methodKeyVault — local default apiKey.
365
345
  - key: mori-controller-auth-methodKeyVault
@@ -0,0 +1,195 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "aifabrix://schema/integration-definition.schema.json",
4
+ "title": "AI Fabrix Builder Integration Definition (BID)",
5
+ "description": "Canonical BT → Builder integration definition. Schema name aifabrix.builder.integrationDefinition v1.0.0.",
6
+ "metadata": {
7
+ "key": "integration-definition-schema",
8
+ "name": "Builder Integration Definition",
9
+ "version": "1.0.0",
10
+ "schemaName": "aifabrix.builder.integrationDefinition",
11
+ "type": "schema",
12
+ "category": "integration",
13
+ "author": "AI Fabrix Team",
14
+ "createdAt": "2026-08-04T00:00:00Z",
15
+ "updatedAt": "2026-08-04T00:00:00Z"
16
+ },
17
+ "type": "object",
18
+ "additionalProperties": false,
19
+ "required": [
20
+ "schemaName",
21
+ "schemaVersion",
22
+ "definitionId",
23
+ "definitionHash",
24
+ "meta",
25
+ "packageIdentity",
26
+ "system",
27
+ "datasources",
28
+ "relationships",
29
+ "sync",
30
+ "capabilities",
31
+ "authority",
32
+ "acceptance"
33
+ ],
34
+ "properties": {
35
+ "schemaName": {
36
+ "type": "string",
37
+ "const": "aifabrix.builder.integrationDefinition"
38
+ },
39
+ "schemaVersion": {
40
+ "type": "string",
41
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
42
+ "description": "BID schema semver; implementers must accept 1.0.0."
43
+ },
44
+ "definitionId": {
45
+ "type": "string",
46
+ "format": "uuid"
47
+ },
48
+ "definitionHash": {
49
+ "type": "string",
50
+ "pattern": "^sha256:[a-f0-9]{64}$",
51
+ "description": "SHA-256 of canonicalized BID body excluding this field."
52
+ },
53
+ "meta": {
54
+ "type": "object",
55
+ "additionalProperties": false,
56
+ "required": ["suiteRunId", "producedAt", "btAssistantKey"],
57
+ "properties": {
58
+ "suiteRunId": { "type": "string", "minLength": 1 },
59
+ "producedAt": { "type": "string", "format": "date-time" },
60
+ "btAssistantKey": { "type": "string", "minLength": 1 },
61
+ "answerFingerprint": { "type": "string" },
62
+ "knowledgePackRefs": {
63
+ "type": "array",
64
+ "items": { "type": "string", "minLength": 1 }
65
+ },
66
+ "humanAnswerRefs": {
67
+ "type": "array",
68
+ "items": { "type": "string", "minLength": 1 }
69
+ },
70
+ "replaceSystemKey": { "type": "boolean", "default": false }
71
+ }
72
+ },
73
+ "packageIdentity": {
74
+ "type": "object",
75
+ "additionalProperties": false,
76
+ "required": ["systemKey", "packageVersion", "displayName"],
77
+ "properties": {
78
+ "systemKey": { "type": "string", "pattern": "^[a-z0-9-]+$", "minLength": 3 },
79
+ "packageVersion": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
80
+ "displayName": { "type": "string", "minLength": 1 }
81
+ }
82
+ },
83
+ "system": {
84
+ "type": "object",
85
+ "additionalProperties": true,
86
+ "required": ["key", "systemKind", "connectionRefs"],
87
+ "properties": {
88
+ "key": { "type": "string", "pattern": "^[a-z0-9-]+$" },
89
+ "displayName": { "type": "string" },
90
+ "description": { "type": "string" },
91
+ "systemKind": { "type": "string", "minLength": 1 },
92
+ "type": { "type": "string", "enum": ["openapi", "mcp", "custom"] },
93
+ "connectionRefs": {
94
+ "type": "object",
95
+ "description": "kv:// or credential key refs only — no plaintext secrets.",
96
+ "additionalProperties": { "type": "string", "minLength": 1 }
97
+ },
98
+ "openapiSourceRef": { "type": "string" }
99
+ }
100
+ },
101
+ "datasources": {
102
+ "type": "array",
103
+ "minItems": 1,
104
+ "items": {
105
+ "type": "object",
106
+ "additionalProperties": true,
107
+ "required": ["key", "displayName", "entityType", "resourceType"],
108
+ "properties": {
109
+ "key": { "type": "string", "pattern": "^[a-z0-9-]+$", "minLength": 3 },
110
+ "displayName": { "type": "string", "minLength": 1 },
111
+ "entityType": {
112
+ "type": "string",
113
+ "enum": [
114
+ "documentStorage",
115
+ "vectorStore",
116
+ "recordStorage",
117
+ "messageService",
118
+ "serviceContract",
119
+ "none"
120
+ ]
121
+ },
122
+ "resourceType": { "type": "string", "pattern": "^[a-z0-9-]+$" },
123
+ "capabilityKeys": {
124
+ "type": "array",
125
+ "items": { "type": "string", "pattern": "^[a-z][a-zA-Z0-9]*$" }
126
+ },
127
+ "propertyKeys": {
128
+ "type": "array",
129
+ "description": "Vendor property names to sync/index (CRM objects → CIP query.properties + fieldMappings).",
130
+ "items": { "type": "string", "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", "minLength": 1 }
131
+ },
132
+ "openapiSourceRef": { "type": "string" }
133
+ }
134
+ }
135
+ },
136
+ "relationships": {
137
+ "type": "array",
138
+ "items": {
139
+ "type": "object",
140
+ "additionalProperties": true,
141
+ "required": ["from", "to", "kind"],
142
+ "properties": {
143
+ "from": { "type": "string", "minLength": 1 },
144
+ "to": { "type": "string", "minLength": 1 },
145
+ "kind": { "type": "string", "minLength": 1 }
146
+ }
147
+ }
148
+ },
149
+ "sync": {
150
+ "type": "object",
151
+ "additionalProperties": true,
152
+ "required": ["mode"],
153
+ "properties": {
154
+ "mode": {
155
+ "type": "string",
156
+ "enum": ["incremental"],
157
+ "description": "Incremental sync is mandatory for CRM profile datasources."
158
+ },
159
+ "datasources": {
160
+ "type": "array",
161
+ "items": { "type": "string", "pattern": "^[a-z0-9-]+$" }
162
+ }
163
+ }
164
+ },
165
+ "capabilities": {
166
+ "type": "object",
167
+ "additionalProperties": {
168
+ "type": "array",
169
+ "items": { "type": "string", "pattern": "^[a-z][a-zA-Z0-9]*$" }
170
+ },
171
+ "description": "Map of datasource key → capability keys (must include named write for company DS)."
172
+ },
173
+ "authority": {
174
+ "type": "object",
175
+ "additionalProperties": true,
176
+ "required": ["writeRequiresUserAuthority"],
177
+ "properties": {
178
+ "writeRequiresUserAuthority": { "type": "boolean" },
179
+ "notes": { "type": "string" }
180
+ }
181
+ },
182
+ "acceptance": {
183
+ "type": "object",
184
+ "additionalProperties": true,
185
+ "required": ["gates"],
186
+ "properties": {
187
+ "gates": {
188
+ "type": "array",
189
+ "minItems": 1,
190
+ "items": { "type": "string", "minLength": 1 }
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
@@ -110,6 +110,9 @@ function buildAuthenticationFromMethod(systemKey, authType) {
110
110
  if (method === 'none') {
111
111
  return { authType: 'none' };
112
112
  }
113
+ if (method === 'system') {
114
+ return { authType: 'system' };
115
+ }
113
116
  const flat = buildFlatCredentialTemplate(systemKey, method);
114
117
  return {
115
118
  authType: 'credential',
@@ -174,6 +177,9 @@ function migrateAuthenticationToNestedSchema(authentication, systemKey) {
174
177
  if (authentication.authType === 'none') {
175
178
  return { authentication: { authType: 'none' }, changed: false };
176
179
  }
180
+ if (authentication.authType === 'system') {
181
+ return { authentication: { authType: 'system' }, changed: false };
182
+ }
177
183
  if (authentication.authType === 'apiProvider' && authentication.apiProvider) {
178
184
  return { authentication, changed: false };
179
185
  }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @fileoverview Workspace roots allowed for external certify / verify CLI commands.
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const CERTIFY_EXTERNAL_BASE_DIRS = new Set([
8
+ 'integration',
9
+ 'role-assistant',
10
+ 'enterprise-knowledge'
11
+ ]);
12
+
13
+ /**
14
+ * @param {string|null|undefined} baseDir
15
+ * @returns {boolean}
16
+ */
17
+ function isCertifyExternalWorkspace(baseDir) {
18
+ return CERTIFY_EXTERNAL_BASE_DIRS.has(baseDir);
19
+ }
20
+
21
+ /**
22
+ * @param {string|null|undefined} baseDir
23
+ * @param {string} commandLabel - e.g. verify-operations
24
+ * @returns {void}
25
+ * @throws {Error}
26
+ */
27
+ function assertCertifyExternalWorkspace(baseDir, commandLabel) {
28
+ if (!isCertifyExternalWorkspace(baseDir)) {
29
+ throw new Error(
30
+ `${commandLabel} applies to external authoring folders only ` +
31
+ '(integration/<systemKey>/, role-assistant/<roleKey>/, or enterprise-knowledge/<key>/).'
32
+ );
33
+ }
34
+ }
35
+
36
+ module.exports = {
37
+ CERTIFY_EXTERNAL_BASE_DIRS,
38
+ isCertifyExternalWorkspace,
39
+ assertCertifyExternalWorkspace
40
+ };
@@ -253,12 +253,12 @@ async function executeBuild(imageName, dockerfilePath, contextPath, tag, options
253
253
  );
254
254
  await executeDockerBuild(imageName, dockerfilePath, contextPath, tag, buildArgs, noCache);
255
255
 
256
- // Tag image if additional tag provided
257
- if (options && options.tag && options.tag !== 'latest') {
256
+ // Also apply floating `main` when building a version tag (matches dev-promote dual tags).
257
+ if (options && options.tag && options.tag !== 'latest' && options.tag !== 'main') {
258
258
  const { execFileWithDockerEnv } = require('./docker-exec');
259
259
  const { getDockerExecEnv } = require('./remote-docker-env');
260
260
  const env = await getDockerExecEnv();
261
- await execFileWithDockerEnv('docker', ['tag', `${imageName}:${tag}`, `${imageName}:latest`], { env });
261
+ await execFileWithDockerEnv('docker', ['tag', `${imageName}:${tag}`, `${imageName}:main`], { env });
262
262
  }
263
263
  }
264
264
 
@@ -16,8 +16,12 @@ const { getDockerExecEnv } = require('./remote-docker-env');
16
16
  * @param {string} fullImage - Image:tag
17
17
  * @param {string} cmd - Shell command (passed to sh -c)
18
18
  * @param {string|null} [envFilePath] - Path for docker run --env-file
19
- * @param {{ network?: string|null, volumeMounts?: Array<{ host: string, container: string }> }} [options]
20
- * @returns {Promise<number>} Exit code
19
+ * @param {{
20
+ * network?: string|null,
21
+ * volumeMounts?: Array<{ host: string, container: string }>,
22
+ * quiet?: boolean
23
+ * }} [options] - quiet=true pipes stdio (installer-friendly; dump on failure)
24
+ * @returns {Promise<number|{ code: number, output: string }>} Exit code, or code+output when quiet
21
25
  */
22
26
  async function runDockerRunEphemeral(fullImage, cmd, envFilePath = null, options = {}) {
23
27
  const dockerEnv = await getDockerExecEnv();
@@ -26,22 +30,48 @@ async function runDockerRunEphemeral(fullImage, cmd, envFilePath = null, options
26
30
  ? options.network.trim()
27
31
  : null;
28
32
  const volumeMounts = Array.isArray(options?.volumeMounts) ? options.volumeMounts : [];
29
- return new Promise((resolve) => {
30
- const args = ['run', '--rm'];
31
- if (network) {
32
- args.push('--network', network);
33
- }
34
- if (envFilePath) {
35
- args.push('--env-file', envFilePath);
36
- }
37
- for (const mount of volumeMounts) {
38
- const host = typeof mount?.host === 'string' ? mount.host.trim() : '';
39
- const container = typeof mount?.container === 'string' ? mount.container.trim() : '';
40
- if (host && container) {
41
- args.push('-v', `${host}:${container}`);
42
- }
33
+ const quiet = options?.quiet === true;
34
+ const args = _buildDockerRunArgs(fullImage, cmd, envFilePath, network, volumeMounts);
35
+ if (quiet) {
36
+ return _spawnDockerQuiet(args, dockerEnv);
37
+ }
38
+ return _spawnDockerInherit(args, dockerEnv);
39
+ }
40
+
41
+ /**
42
+ * @param {string} fullImage
43
+ * @param {string} cmd
44
+ * @param {string|null} envFilePath
45
+ * @param {string|null} network
46
+ * @param {Array<{ host: string, container: string }>} volumeMounts
47
+ * @returns {string[]}
48
+ */
49
+ function _buildDockerRunArgs(fullImage, cmd, envFilePath, network, volumeMounts) {
50
+ const args = ['run', '--rm'];
51
+ if (network) {
52
+ args.push('--network', network);
53
+ }
54
+ if (envFilePath) {
55
+ args.push('--env-file', envFilePath);
56
+ }
57
+ for (const mount of volumeMounts) {
58
+ const host = typeof mount?.host === 'string' ? mount.host.trim() : '';
59
+ const container = typeof mount?.container === 'string' ? mount.container.trim() : '';
60
+ if (host && container) {
61
+ args.push('-v', `${host}:${container}`);
43
62
  }
44
- args.push(fullImage, 'sh', '-c', cmd);
63
+ }
64
+ args.push(fullImage, 'sh', '-c', cmd);
65
+ return args;
66
+ }
67
+
68
+ /**
69
+ * @param {string[]} args
70
+ * @param {NodeJS.ProcessEnv} dockerEnv
71
+ * @returns {Promise<number>}
72
+ */
73
+ function _spawnDockerInherit(args, dockerEnv) {
74
+ return new Promise((resolve) => {
45
75
  const proc = spawn('docker', args, {
46
76
  stdio: 'inherit',
47
77
  shell: false,
@@ -52,4 +82,34 @@ async function runDockerRunEphemeral(fullImage, cmd, envFilePath = null, options
52
82
  });
53
83
  }
54
84
 
85
+ /**
86
+ * @param {string[]} args
87
+ * @param {NodeJS.ProcessEnv} dockerEnv
88
+ * @returns {Promise<{ code: number, output: string }>}
89
+ */
90
+ function _spawnDockerQuiet(args, dockerEnv) {
91
+ return new Promise((resolve) => {
92
+ const proc = spawn('docker', args, {
93
+ stdio: ['ignore', 'pipe', 'pipe'],
94
+ shell: false,
95
+ env: dockerEnv
96
+ });
97
+ const chunks = [];
98
+ const push = (buf) => {
99
+ if (buf && buf.length) {
100
+ chunks.push(buf);
101
+ }
102
+ };
103
+ proc.stdout.on('data', push);
104
+ proc.stderr.on('data', push);
105
+ proc.on('close', (code) => {
106
+ resolve({
107
+ code: code !== null ? code : 1,
108
+ output: Buffer.concat(chunks).toString('utf8')
109
+ });
110
+ });
111
+ proc.on('error', () => resolve({ code: 1, output: '' }));
112
+ });
113
+ }
114
+
55
115
  module.exports = { runDockerRunEphemeral };
@@ -38,32 +38,50 @@ async function filterTraefikUrlByDns(traefikUrl, debug, isHostnameResolvableFn)
38
38
  * @param {string} [p.skippedPublicHealthUrl]
39
39
  * @param {string[]} [p.urlsToTry]
40
40
  * @param {number} p.resolvedIndex
41
+ * @returns {string|null} Warning message without leading glyph, or null
41
42
  */
42
- function logPublicHealthUrlWarningIfNeeded(p) {
43
+ function buildPublicHealthUrlWarningMessage(p) {
43
44
  const { skippedPublicHealthUrl, urlsToTry, resolvedIndex } = p;
44
- if (typeof resolvedIndex !== 'number' || resolvedIndex < 0) return;
45
+ if (typeof resolvedIndex !== 'number' || resolvedIndex < 0) return null;
45
46
 
46
47
  if (skippedPublicHealthUrl) {
47
- logger.log(
48
- chalk.yellow(
49
- `⚠ Public URL was not verified (DNS): ${skippedPublicHealthUrl}. ` +
50
- 'The application reported healthy via localhost only. Validate DNS names and Traefik routing for this host.'
51
- )
48
+ return (
49
+ `Public URL was not verified (DNS): ${skippedPublicHealthUrl}. ` +
50
+ 'The application reported healthy via localhost only. Validate DNS names and Traefik routing for this host.'
52
51
  );
53
- return;
54
52
  }
55
53
  if (Array.isArray(urlsToTry) && urlsToTry.length > 1 && resolvedIndex > 0) {
56
54
  const pub = urlsToTry[0];
57
- logger.log(
58
- chalk.yellow(
59
- `⚠ Public URL was not verified: ${pub}. ` +
60
- 'Health checks succeeded via localhost only. Validate Traefik routing, TLS, and DNS.'
61
- )
55
+ return (
56
+ `Public URL was not verified: ${pub}. ` +
57
+ 'Health checks succeeded via localhost only. Validate Traefik routing, TLS, and DNS.'
62
58
  );
63
59
  }
60
+ return null;
61
+ }
62
+
63
+ /**
64
+ * @param {Object} p
65
+ * @param {string} [p.skippedPublicHealthUrl]
66
+ * @param {string[]} [p.urlsToTry]
67
+ * @param {number} p.resolvedIndex
68
+ * @param {boolean} [p.defer]
69
+ * @param {(message: string) => void} [p.onDeferred]
70
+ */
71
+ function logPublicHealthUrlWarningIfNeeded(p) {
72
+ const message = buildPublicHealthUrlWarningMessage(p);
73
+ if (!message) return;
74
+ if (p && p.defer === true) {
75
+ if (typeof p.onDeferred === 'function') {
76
+ p.onDeferred(message);
77
+ }
78
+ return;
79
+ }
80
+ logger.log(chalk.yellow(`⚠ ${message}`));
64
81
  }
65
82
 
66
83
  module.exports = {
67
84
  filterTraefikUrlByDns,
85
+ buildPublicHealthUrlWarningMessage,
68
86
  logPublicHealthUrlWarningIfNeeded
69
87
  };
@@ -339,6 +339,14 @@ function resolveHealthCheckPollOptions(runOptions = {}) {
339
339
  if (typeof runOptions.onPollText === 'function') {
340
340
  pollOptions.onPollText = runOptions.onPollText;
341
341
  }
342
+ const defer =
343
+ runOptions.deferPublicUrlWarning === true || typeof runOptions.onPollText === 'function';
344
+ if (defer) {
345
+ pollOptions.deferPublicUrlWarning = true;
346
+ if (typeof runOptions.onDeferredPublicUrlWarning === 'function') {
347
+ pollOptions.onDeferredPublicUrlWarning = runOptions.onDeferredPublicUrlWarning;
348
+ }
349
+ }
342
350
  return pollOptions;
343
351
  }
344
352
 
@@ -367,7 +375,9 @@ async function pollUntilHealthCheckPasses({
367
375
  logPublicHealthUrlWarningIfNeeded({
368
376
  skippedPublicHealthUrl,
369
377
  urlsToTry,
370
- resolvedIndex: attemptResult.resolvedIndex
378
+ resolvedIndex: attemptResult.resolvedIndex,
379
+ defer: pollOptions.deferPublicUrlWarning === true,
380
+ onDeferred: pollOptions.onDeferredPublicUrlWarning
371
381
  });
372
382
  return;
373
383
  }
@@ -111,6 +111,7 @@ const CATEGORIES = [
111
111
  { name: 'delete', term: 'delete <systemKey>' },
112
112
  { name: 'repair', term: 'repair <systemKey>' },
113
113
  { name: 'manifest', term: 'manifest get-section <systemKey> <sectionKey>' },
114
+ { name: 'integration-definition', term: 'integration-definition apply <file>' },
114
115
  { name: 'channel', term: 'channel scaffold <channelTarget>' },
115
116
  { name: 'datasource' },
116
117
  { name: 'datasource load', term: 'datasource load <datasourceKey>' },
@@ -1022,23 +1022,17 @@ async function getResolveAppPath(appName, options = {}) {
1022
1022
  return { appPath: result.appPath, envOnly: false };
1023
1023
  }
1024
1024
 
1025
- /**
1026
- * @param {string} walkDir - Candidate workspace root (walk upward from cwd)
1027
- * @param {string} cwd - Resolved process.cwd()
1028
- * @param {ReturnType<typeof nodeFs>} disk
1029
- * @returns {string|null}
1030
- */
1031
- function tryIntegrationAppKeyAtWalkStep(walkDir, cwd, disk) {
1032
- const integrationDir = path.join(walkDir, 'integration');
1025
+ function tryAuthoringAppKeyAtWalkStep(walkDir, cwd, disk, folderName) {
1026
+ const authoringDir = path.join(walkDir, folderName);
1033
1027
  try {
1034
- if (!disk.existsSync(integrationDir)) {
1028
+ if (!disk.existsSync(authoringDir)) {
1035
1029
  return null;
1036
1030
  }
1037
- const intNorm = path.resolve(integrationDir);
1038
- if (cwd !== intNorm && !cwd.startsWith(intNorm + path.sep)) {
1031
+ const rootNorm = path.resolve(authoringDir);
1032
+ if (cwd !== rootNorm && !cwd.startsWith(rootNorm + path.sep)) {
1039
1033
  return null;
1040
1034
  }
1041
- const rel = path.relative(intNorm, cwd);
1035
+ const rel = path.relative(rootNorm, cwd);
1042
1036
  if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) {
1043
1037
  return null;
1044
1038
  }
@@ -1049,16 +1043,20 @@ function tryIntegrationAppKeyAtWalkStep(walkDir, cwd, disk) {
1049
1043
  }
1050
1044
 
1051
1045
  /**
1052
- * Resolve app folder name when cwd is under some ancestor's `integration/<systemKey>/`.
1046
+ * Resolve app folder name when cwd is under integration/, role-assistant/, or
1047
+ * enterprise-knowledge/<systemKey>/.
1053
1048
  * Walks up from cwd (does not use {@link getIntegrationBuilderBaseDir}) so detection still works
1054
- * when the canonical base is config/home but the shell is inside a checkout's integration tree.
1049
+ * when the canonical base is config/home but the shell is inside a checkout's tree.
1055
1050
  */
1056
1051
  function resolveIntegrationAppKeyFromCwd() {
1057
1052
  const cwd = path.resolve(process.cwd());
1058
1053
  const disk = nodeFs();
1059
1054
  let p = cwd;
1060
1055
  for (let i = 0; i < 64; i += 1) {
1061
- const key = tryIntegrationAppKeyAtWalkStep(p, cwd, disk);
1056
+ const key =
1057
+ tryAuthoringAppKeyAtWalkStep(p, cwd, disk, 'integration') ||
1058
+ tryAuthoringAppKeyAtWalkStep(p, cwd, disk, 'role-assistant') ||
1059
+ tryAuthoringAppKeyAtWalkStep(p, cwd, disk, 'enterprise-knowledge');
1062
1060
  if (key) {
1063
1061
  return key;
1064
1062
  }