@aifabrix/builder 2.44.5 → 2.44.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/cli-layout.mdc +1 -1
- package/.cursor/rules/project-rules.mdc +1 -1
- package/.npmrc.token +1 -1
- package/README.md +15 -23
- package/integration/hubspot-test/README.md +2 -0
- package/integration/hubspot-test/test.js +5 -3
- package/jest.projects.js +48 -2
- package/lib/api/controller-health.api.js +49 -0
- package/lib/api/dimension-values.api.js +82 -0
- package/lib/api/dimensions.api.js +114 -0
- package/lib/api/external-systems.api.js +1 -0
- package/lib/api/integration-clients.api.js +168 -0
- package/lib/api/types/dimension-values.types.js +28 -0
- package/lib/api/types/dimensions.types.js +31 -0
- package/lib/api/types/integration-clients.types.js +45 -0
- package/lib/api/validation-runner.js +46 -25
- package/lib/app/deploy-config.js +11 -1
- package/lib/app/deploy-status-display.js +3 -3
- package/lib/app/deploy.js +36 -14
- package/lib/app/display.js +15 -11
- package/lib/app/push.js +46 -23
- package/lib/app/register.js +1 -1
- package/lib/app/restart-display.js +95 -0
- package/lib/app/rotate-secret.js +1 -1
- package/lib/app/run-container-start.js +12 -6
- package/lib/app/run-env-compose.js +30 -1
- package/lib/app/run-helpers.js +44 -12
- package/lib/app/run-reload-sync.js +148 -0
- package/lib/app/run-resolve-image.js +51 -1
- package/lib/app/run.js +99 -73
- package/lib/build/index.js +75 -45
- package/lib/cli/doctor-check.js +117 -0
- package/lib/cli/index.js +8 -2
- package/lib/cli/infra-guided.js +445 -0
- package/lib/cli/setup-app.js +20 -2
- package/lib/cli/setup-auth.js +26 -0
- package/lib/cli/setup-dev-path-commands.js +50 -3
- package/lib/cli/setup-infra.js +134 -61
- package/lib/cli/setup-integration-client.js +182 -0
- package/lib/cli/setup-parameters.js +21 -2
- package/lib/cli/setup-platform.js +102 -0
- package/lib/cli/setup-secrets.js +18 -6
- package/lib/cli/setup-utility.js +78 -33
- package/lib/commands/datasource-capability-dimension-cli.js +128 -0
- package/lib/commands/datasource-capability-output.js +29 -0
- package/lib/commands/datasource-capability-relate-cli.js +140 -0
- package/lib/commands/datasource-capability.js +411 -0
- package/lib/commands/datasource-unified-test-cli.options.js +1 -1
- package/lib/commands/datasource.js +53 -13
- package/lib/commands/dev-down.js +3 -3
- package/lib/commands/dev-infra-gate.js +32 -0
- package/lib/commands/dev-init.js +13 -7
- package/lib/commands/dimension-value.js +179 -0
- package/lib/commands/dimension.js +330 -0
- package/lib/commands/integration-client.js +430 -0
- package/lib/commands/login-device.js +65 -30
- package/lib/commands/login.js +21 -10
- package/lib/commands/parameters-validate.js +78 -13
- package/lib/commands/repair-datasource-auto-rbac.js +166 -0
- package/lib/commands/repair-datasource-keys.js +10 -5
- package/lib/commands/repair-datasource.js +19 -7
- package/lib/commands/repair-env-template.js +4 -1
- package/lib/commands/repair-openapi-sync.js +172 -0
- package/lib/commands/repair-persist.js +102 -0
- package/lib/commands/repair-rbac-extract.js +27 -0
- package/lib/commands/repair-rbac-migrate.js +186 -0
- package/lib/commands/repair-rbac.js +214 -31
- package/lib/commands/repair-system-alignment.js +246 -0
- package/lib/commands/repair-system-permissions.js +168 -0
- package/lib/commands/repair.js +120 -338
- package/lib/commands/secure.js +1 -1
- package/lib/commands/setup-modes.js +455 -0
- package/lib/commands/setup-prompts.js +388 -0
- package/lib/commands/setup.js +149 -0
- package/lib/commands/teardown.js +228 -0
- package/lib/commands/up-common.js +79 -19
- package/lib/commands/up-dataplane.js +33 -11
- package/lib/commands/up-miso.js +7 -11
- package/lib/commands/upload.js +109 -23
- package/lib/commands/wizard-core-helpers.js +14 -11
- package/lib/commands/wizard-core.js +6 -5
- package/lib/commands/wizard-dataplane.js +2 -2
- package/lib/commands/wizard-entity-selection.js +4 -3
- package/lib/commands/wizard-headless.js +2 -1
- package/lib/commands/wizard.js +2 -1
- package/lib/constants/infra-compose-service-names.js +40 -0
- package/lib/core/env-reader.js +16 -3
- package/lib/core/secrets-admin-env.js +101 -0
- package/lib/core/secrets-ensure-infra.js +34 -1
- package/lib/core/secrets-ensure.js +88 -66
- package/lib/core/secrets-env-content.js +432 -0
- package/lib/core/secrets-env-write.js +27 -1
- package/lib/core/secrets-load.js +248 -0
- package/lib/core/secrets-names.js +32 -0
- package/lib/core/secrets.js +17 -757
- package/lib/datasource/capability/basic-exposure.js +76 -0
- package/lib/datasource/capability/capability-diff-slice.js +41 -0
- package/lib/datasource/capability/capability-key.js +34 -0
- package/lib/datasource/capability/capability-resolve.js +172 -0
- package/lib/datasource/capability/capability-storage-keys.js +22 -0
- package/lib/datasource/capability/copy-operations.js +348 -0
- package/lib/datasource/capability/copy-test-payload.js +139 -0
- package/lib/datasource/capability/create-operations.js +235 -0
- package/lib/datasource/capability/dimension-operations.js +151 -0
- package/lib/datasource/capability/dimension-validate.js +219 -0
- package/lib/datasource/capability/json-pointer.js +31 -0
- package/lib/datasource/capability/reference-rewrite.js +51 -0
- package/lib/datasource/capability/relate-operations.js +325 -0
- package/lib/datasource/capability/relate-validate.js +219 -0
- package/lib/datasource/capability/remove-operations.js +275 -0
- package/lib/datasource/capability/run-capability-copy.js +152 -0
- package/lib/datasource/capability/run-capability-diff.js +135 -0
- package/lib/datasource/capability/run-capability-dimension.js +291 -0
- package/lib/datasource/capability/run-capability-edit.js +377 -0
- package/lib/datasource/capability/run-capability-relate.js +193 -0
- package/lib/datasource/capability/run-capability-remove.js +105 -0
- package/lib/datasource/capability/templates/minimal-fetch.json +18 -0
- package/lib/datasource/capability/validate-capability-slice.js +35 -0
- package/lib/datasource/list.js +136 -23
- package/lib/datasource/log-viewer.js +2 -4
- package/lib/datasource/unified-validation-run.js +51 -16
- package/lib/datasource/validate.js +53 -1
- package/lib/deployment/deploy-poll-ui.js +60 -0
- package/lib/deployment/deployer-status.js +29 -3
- package/lib/deployment/deployer.js +48 -30
- package/lib/deployment/environment.js +7 -2
- package/lib/deployment/poll-interval.js +72 -0
- package/lib/deployment/push.js +11 -9
- package/lib/external-system/deploy.js +4 -1
- package/lib/external-system/download.js +61 -32
- package/lib/external-system/sync-deploy-manifest.js +33 -0
- package/lib/infrastructure/index.js +49 -19
- package/lib/infrastructure/orphan-infra-docker-teardown.js +177 -0
- package/lib/parameters/infra-kv-discovery.js +29 -4
- package/lib/parameters/infra-parameter-catalog.js +6 -3
- package/lib/parameters/infra-parameter-validate.js +67 -19
- package/lib/resolvers/datasource-resolver.js +53 -0
- package/lib/resolvers/dimension-file.js +52 -0
- package/lib/resolvers/manifest-resolver.js +133 -0
- package/lib/schema/external-datasource.schema.json +183 -53
- package/lib/schema/external-system.schema.json +23 -10
- package/lib/schema/infra.parameter.yaml +26 -11
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/aifabrix-config-dir-walk.js +40 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +26 -3
- package/lib/utils/app-run-containers.js +2 -2
- package/lib/utils/bash-secret-env.js +59 -0
- package/lib/utils/cli-secrets-error-format.js +78 -0
- package/lib/utils/cli-test-layout-chalk.js +31 -9
- package/lib/utils/cli-utils.js +4 -36
- package/lib/utils/datasource-test-run-display.js +8 -0
- package/lib/utils/dev-hosts-helper.js +3 -2
- package/lib/utils/dev-init-ssh-merge.js +2 -1
- package/lib/utils/docker-build.js +17 -9
- package/lib/utils/docker-reload-mount.js +127 -0
- package/lib/utils/external-readme.js +71 -2
- package/lib/utils/external-system-local-test-tty.js +3 -2
- package/lib/utils/external-system-readiness-core.js +45 -12
- package/lib/utils/external-system-readiness-deploy-display.js +3 -3
- package/lib/utils/external-system-readiness-display-internals.js +33 -3
- package/lib/utils/external-system-readiness-display.js +10 -1
- package/lib/utils/file-upload.js +40 -3
- package/lib/utils/health-check-db-init.js +107 -0
- package/lib/utils/health-check-public-warn.js +69 -0
- package/lib/utils/health-check-url.js +19 -4
- package/lib/utils/health-check.js +135 -105
- package/lib/utils/help-builder.js +5 -1
- package/lib/utils/image-name.js +34 -7
- package/lib/utils/integration-file-backup.js +74 -0
- package/lib/utils/mutagen-install.js +30 -3
- package/lib/utils/paths.js +108 -25
- package/lib/utils/postgres-wipe.js +212 -0
- package/lib/utils/register-aifabrix-shell-env.js +15 -0
- package/lib/utils/remote-dev-auth.js +21 -5
- package/lib/utils/remote-docker-env.js +9 -1
- package/lib/utils/remote-secrets-loader.js +42 -3
- package/lib/utils/resolve-docker-image-ref.js +9 -3
- package/lib/utils/secrets-ancestor-paths.js +47 -0
- package/lib/utils/secrets-helpers.js +17 -10
- package/lib/utils/secrets-kv-refs.js +42 -0
- package/lib/utils/secrets-kv-scope.js +19 -2
- package/lib/utils/secrets-materialize-local.js +134 -0
- package/lib/utils/secrets-path.js +24 -10
- package/lib/utils/secrets-utils.js +2 -2
- package/lib/utils/system-builder-root.js +34 -0
- package/lib/utils/url-declarative-resolve-build.js +6 -1
- package/lib/utils/url-declarative-runtime-base-path.js +32 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +2 -1
- package/lib/utils/urls-local-registry.js +23 -12
- package/lib/utils/validation-poll-ui.js +81 -0
- package/lib/utils/validation-run-poll.js +29 -5
- package/lib/utils/with-muted-logger.js +53 -0
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +1 -1
- package/templates/applications/dataplane/rbac.yaml +10 -10
- package/templates/applications/keycloak/env.template +8 -6
- package/templates/applications/miso-controller/application.yaml +7 -0
- package/templates/applications/miso-controller/env.template +1 -1
- package/templates/applications/miso-controller/rbac.yaml +9 -9
- package/templates/external-system/README.md.hbs +83 -123
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/lib/api/service-users.api.js +0 -150
- package/lib/api/types/service-users.types.js +0 -65
- package/lib/cli/setup-service-user.js +0 -187
- package/lib/commands/service-user.js +0 -429
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
"$schema":"https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id":"aifabrix://schema/external-datasource.schema.json",
|
|
4
4
|
"title":"External Data Source",
|
|
5
|
-
"description":"Configuration for AI Fabrix ExternalDataSource entities. Includes metadata schema, data dimensions, transformation mappings, OpenAPI/MCP exposure, execution logic, and sync behavior.",
|
|
5
|
+
"description":"Configuration for AI Fabrix ExternalDataSource entities. Includes metadata schema, data dimensions, transformation mappings, OpenAPI/MCP exposure, execution logic, and sync behavior. Root externalSpec is the datasource-level authoritative reference for where to obtain the vendor or tooling API specification used for import and validation; external-system.schema.json openapi/mcp are system-level connectivity hints only.",
|
|
6
6
|
"metadata":{
|
|
7
7
|
"key":"external-datasource-schema",
|
|
8
8
|
"name":"External Data Source Configuration Schema",
|
|
9
9
|
"description":"JSON schema for validating ExternalDataSource configuration files",
|
|
10
|
-
"version":"2.4.
|
|
10
|
+
"version":"2.4.8",
|
|
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-
|
|
15
|
+
"updatedAt":"2026-05-10T00:00:00Z",
|
|
16
16
|
"compatibility":{
|
|
17
17
|
"minVersion":"1.0.0",
|
|
18
18
|
"maxVersion":"3.0.0",
|
|
@@ -183,6 +183,27 @@
|
|
|
183
183
|
"Added optional fetch.httpResponseNormalization for manifest-driven GET response shaping (302 Location follow, JSON redirect envelopes, nested JSON string URL follow-up)."
|
|
184
184
|
],
|
|
185
185
|
"breaking":false
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"version":"2.4.8",
|
|
189
|
+
"date":"2026-05-10T00:00:00Z",
|
|
190
|
+
"changes":[
|
|
191
|
+
"Documented roles: root externalSpec is the datasource-level authoritative vendor/API specification provenance (fetch, import, validation); config.openapi is the runtime connector (operations, documentKey) and is the behavioral source of truth; external-system openapi/mcp remain connectivity/bootstrap only.",
|
|
192
|
+
"Clarified externalSpec and openapi property descriptions to distinguish vendor spec location from generated or persisted AI-facing OpenAPI material managed by dataplane."
|
|
193
|
+
],
|
|
194
|
+
"breaking":false
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"version":"2.4.7",
|
|
198
|
+
"date":"2026-05-08T00:00:00Z",
|
|
199
|
+
"changes":[
|
|
200
|
+
"externalSpec: optional root object with required type (openapi | mcp) plus documentKey, url, relativePath for vendor or tooling provenance (wizard/import).",
|
|
201
|
+
"fieldMappings.attributes.<name>: added optional writePath (provider-payload target dot-path), direction (read|write|readwrite), and passthrough (boolean) to support bidirectional mapping authoring; compiler auto-derives writePath from invertible '{{raw.<dot.path>}}' expressions.",
|
|
202
|
+
"fieldMappings.attributes.<name>: short-form sugar accepted - a string equal to a {{...}} expression is normalized to { expression: '<value>' } at compile time.",
|
|
203
|
+
"Rejected body and rawBody as aliases for writePath (engine-neutral writePath is the only write-target identifier).",
|
|
204
|
+
"validate_raw_path: replaced provider-aware traversal with one generic JSON-Schema rule (descend via properties.<seg>; accept remaining path under additionalProperties: true; otherwise emit one actionable error)."
|
|
205
|
+
],
|
|
206
|
+
"breaking":false
|
|
186
207
|
}
|
|
187
208
|
]
|
|
188
209
|
},
|
|
@@ -283,69 +304,131 @@
|
|
|
283
304
|
"properties":{
|
|
284
305
|
"attributes":{
|
|
285
306
|
"type":"object",
|
|
286
|
-
"description":"Key = normalized attribute name. Value = transformation configuration.",
|
|
307
|
+
"description":"Key = normalized attribute name. Value = transformation configuration. Short-form: a string equal to a {{...}} expression is normalized to { expression: '...' } by the compiler.",
|
|
287
308
|
"propertyNames":{
|
|
288
309
|
"pattern":"^[a-z][a-zA-Z0-9]*$"
|
|
289
310
|
},
|
|
290
311
|
"additionalProperties":{
|
|
291
|
-
"
|
|
292
|
-
|
|
293
|
-
"expression":{
|
|
312
|
+
"oneOf":[
|
|
313
|
+
{
|
|
294
314
|
"type":"string",
|
|
295
|
-
"description":"
|
|
315
|
+
"description":"Short-form sugar: an expression string is normalized by the compiler to { expression: '<value>' }.",
|
|
296
316
|
"maxLength":512,
|
|
297
317
|
"pattern":"^\\s*\\{\\{(raw\\.[a-zA-Z0-9_.]+|fk\\.[a-z][a-zA-Z0-9]*\\.metadata\\.[a-z][a-zA-Z0-9]*|fk\\.[a-z][a-zA-Z0-9]*\\.dimension\\.[a-zA-Z0-9_]+(\\.label)?|dimension\\.[a-zA-Z0-9_]+(\\.label)?)\\}\\}(\\s*\\|\\s*[a-zA-Z0-9_]+(\\([^)]*\\))?)*\\s*$"
|
|
298
318
|
},
|
|
299
|
-
|
|
300
|
-
"type":"string",
|
|
301
|
-
"description":"Technical description of the normalized field."
|
|
302
|
-
},
|
|
303
|
-
"semantic":{
|
|
319
|
+
{
|
|
304
320
|
"type":"object",
|
|
305
|
-
"description":"Semantic metadata for AI agents and schema generation.",
|
|
306
321
|
"properties":{
|
|
307
|
-
"
|
|
322
|
+
"expression":{
|
|
308
323
|
"type":"string",
|
|
309
|
-
"description":"
|
|
324
|
+
"description":"Pipe-based DSL expression. Allowed roots: raw.<path>, fk.<fk>.metadata.<field>, fk.<fk>.dimension.<dimension>[.label], dimension.<dimension>[.label]. FK traversal in DSL is one-hop only.",
|
|
325
|
+
"maxLength":512,
|
|
326
|
+
"pattern":"^\\s*\\{\\{(raw\\.[a-zA-Z0-9_.]+|fk\\.[a-z][a-zA-Z0-9]*\\.metadata\\.[a-z][a-zA-Z0-9]*|fk\\.[a-z][a-zA-Z0-9]*\\.dimension\\.[a-zA-Z0-9_]+(\\.label)?|dimension\\.[a-zA-Z0-9_]+(\\.label)?)\\}\\}(\\s*\\|\\s*[a-zA-Z0-9_]+(\\([^)]*\\))?)*\\s*$"
|
|
310
327
|
},
|
|
311
328
|
"description":{
|
|
312
329
|
"type":"string",
|
|
313
|
-
"description":"
|
|
330
|
+
"description":"Technical description of the normalized field."
|
|
314
331
|
},
|
|
315
|
-
"
|
|
316
|
-
"
|
|
317
|
-
"
|
|
332
|
+
"writePath":{
|
|
333
|
+
"type":"string",
|
|
334
|
+
"description":"Optional. Provider-payload target path for write operations. Dot-separated identifiers (e.g. 'properties.name'). When omitted and the expression is a single, function-free '{{raw.<dot.path>}}', the compiler derives writePath from raw.<dot.path>. When the expression is non-invertible (function chain, fk., dimension., literal, multiple references), writePath is null unless explicitly set.",
|
|
335
|
+
"pattern":"^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)*$",
|
|
336
|
+
"maxLength":256
|
|
318
337
|
},
|
|
319
|
-
"
|
|
320
|
-
"type":"
|
|
321
|
-
"description":"
|
|
322
|
-
"
|
|
323
|
-
"type":"string"
|
|
324
|
-
}
|
|
338
|
+
"direction":{
|
|
339
|
+
"type":"string",
|
|
340
|
+
"description":"Optional. Mapping direction. 'readwrite' (default for invertible mappings, including those with explicit writePath), 'read' (default for non-invertible expressions or fields listed in exposed.readonly), 'write' (write-only).",
|
|
341
|
+
"enum":["read","write","readwrite"]
|
|
325
342
|
},
|
|
326
|
-
"
|
|
327
|
-
"type":"
|
|
328
|
-
"description":"Optional
|
|
329
|
-
"
|
|
330
|
-
|
|
331
|
-
|
|
343
|
+
"passthrough":{
|
|
344
|
+
"type":"boolean",
|
|
345
|
+
"description":"Optional. When true, declares an explicit dynamic-keys passthrough into the provider payload. The mapper writes the exposed value verbatim at writePath. Requires writePath. There is no implicit deep-merge of unknown keys; passthrough is the only mechanism for forwarding arbitrary provider-bag keys.",
|
|
346
|
+
"default":false
|
|
347
|
+
},
|
|
348
|
+
"semantic":{
|
|
349
|
+
"type":"object",
|
|
350
|
+
"description":"Semantic metadata for AI agents and schema generation.",
|
|
351
|
+
"properties":{
|
|
352
|
+
"title":{
|
|
353
|
+
"type":"string",
|
|
354
|
+
"description":"Human-friendly label for this field."
|
|
355
|
+
},
|
|
356
|
+
"description":{
|
|
357
|
+
"type":"string",
|
|
358
|
+
"description":"Business-level description of the field and how it is used."
|
|
359
|
+
},
|
|
360
|
+
"example":{
|
|
361
|
+
"description":"Example value for this field.",
|
|
362
|
+
"type":["string","number","boolean","object","array","null"]
|
|
363
|
+
},
|
|
364
|
+
"categories":{
|
|
365
|
+
"type":"array",
|
|
366
|
+
"description":"Logical categories/tags (e.g. ['sales', 'revenue']).",
|
|
367
|
+
"items":{
|
|
368
|
+
"type":"string"
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
"synonyms":{
|
|
372
|
+
"type":"array",
|
|
373
|
+
"description":"Optional list of synonyms used in natural language (e.g. 'opportunity', 'sales-case').",
|
|
374
|
+
"items":{
|
|
375
|
+
"type":"string"
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
"additionalProperties":false
|
|
380
|
+
},
|
|
381
|
+
"lineage":{
|
|
382
|
+
"$ref":"#/$defs/fieldMappingLineage"
|
|
332
383
|
}
|
|
333
384
|
},
|
|
385
|
+
"required":[
|
|
386
|
+
"expression"
|
|
387
|
+
],
|
|
388
|
+
"not":{
|
|
389
|
+
"anyOf":[
|
|
390
|
+
{"required":["body"]},
|
|
391
|
+
{"required":["rawBody"]}
|
|
392
|
+
]
|
|
393
|
+
},
|
|
334
394
|
"additionalProperties":false
|
|
335
|
-
},
|
|
336
|
-
"lineage":{
|
|
337
|
-
"$ref":"#/$defs/fieldMappingLineage"
|
|
338
395
|
}
|
|
339
|
-
|
|
340
|
-
"required":[
|
|
341
|
-
"expression"
|
|
342
|
-
],
|
|
343
|
-
"additionalProperties":false
|
|
396
|
+
]
|
|
344
397
|
}
|
|
345
398
|
}
|
|
346
399
|
},
|
|
347
400
|
"additionalProperties":false
|
|
348
401
|
},
|
|
402
|
+
"externalSpec":{
|
|
403
|
+
"type":"object",
|
|
404
|
+
"description":"Optional datasource-level provenance for the authoritative vendor or tooling API specification: where to fetch or resolve the external OpenAPI document or MCP surface (type, url, relativePath, optional documentKey). Used for import paths and lightweight validation against declared operations—not system-level connectivity (see external-system openapi/mcp). The generated or materialized AI-facing OpenAPI derived from config.openapi.operations is a separate dataplane-managed artifact keyed by openapi.documentKey.",
|
|
405
|
+
"properties":{
|
|
406
|
+
"type":{
|
|
407
|
+
"type":"string",
|
|
408
|
+
"enum":[
|
|
409
|
+
"openapi",
|
|
410
|
+
"mcp"
|
|
411
|
+
],
|
|
412
|
+
"description":"Whether this provenance describes an OpenAPI document (openapi) or an MCP server/tooling surface (mcp)."
|
|
413
|
+
},
|
|
414
|
+
"documentKey":{
|
|
415
|
+
"type":"string",
|
|
416
|
+
"description":"Optional key when external source aligns with openapi.documentKey."
|
|
417
|
+
},
|
|
418
|
+
"url":{
|
|
419
|
+
"type":"string",
|
|
420
|
+
"description":"Optional absolute URL of the external OpenAPI document or MCP descriptor, depending on type."
|
|
421
|
+
},
|
|
422
|
+
"relativePath":{
|
|
423
|
+
"type":"string",
|
|
424
|
+
"description":"Optional path relative to the integration bundle root for an external OpenAPI JSON file or MCP artifact, depending on type."
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
"required":[
|
|
428
|
+
"type"
|
|
429
|
+
],
|
|
430
|
+
"additionalProperties":false
|
|
431
|
+
},
|
|
349
432
|
"exposed":{
|
|
350
433
|
"type":"object",
|
|
351
434
|
"description":"Defines public API exposure contract. v2.4.0 freeze requires exposed.schema as canonical response shape.",
|
|
@@ -500,7 +583,7 @@
|
|
|
500
583
|
},
|
|
501
584
|
"openapi":{
|
|
502
585
|
"type":"object",
|
|
503
|
-
"description":"OpenAPI-driven connector configuration.
|
|
586
|
+
"description":"OpenAPI-driven connector configuration: authoritative runtime operation bindings and AI-facing documentKey. Operations are selected during wizard onboarding; dataplane may generate or refresh the persisted OpenAPI artifact for that documentKey from these operations when needed. Where the vendor OpenAPI file is obtained from is described by root externalSpec, not this block.",
|
|
504
587
|
"properties":{
|
|
505
588
|
"enabled":{
|
|
506
589
|
"type":"boolean",
|
|
@@ -551,8 +634,13 @@
|
|
|
551
634
|
"type":"boolean",
|
|
552
635
|
"default":false,
|
|
553
636
|
"description":"When true and no explicit operation security scopes are configured, the runtime resolves required RBAC permission as '<resourceType>:<operation>' for each operation (resourceType from the datasource config, default document), matching builder repair RBAC permission names. Explicit operation-level scopes (openapi.operations.*.security/permissions) take precedence and disable autoRbac for that operation."
|
|
637
|
+
},
|
|
638
|
+
"operationRef":{
|
|
639
|
+
"type":"string",
|
|
640
|
+
"description":"Optional OpenAPI JSON Pointer to the primary operation (e.g. list) used by wizard-generated configs for document resolution."
|
|
554
641
|
}
|
|
555
|
-
}
|
|
642
|
+
},
|
|
643
|
+
"additionalProperties":false
|
|
556
644
|
},
|
|
557
645
|
"validation":{
|
|
558
646
|
"type":"object",
|
|
@@ -694,12 +782,17 @@
|
|
|
694
782
|
},
|
|
695
783
|
"primaryKey":{
|
|
696
784
|
"type":"object",
|
|
697
|
-
"description":"
|
|
785
|
+
"description":"Concrete primary-key field values for list/get/mutations, keyed by the same names as the datasource manifest primaryKey array. Authors may supply a subset of PK fields. Optional primaryKey.search (string legacy filter or JSON filter object) resolves a row via list when implemented for the engine.",
|
|
698
786
|
"additionalProperties":true
|
|
699
787
|
},
|
|
788
|
+
"useCopyForMutations":{
|
|
789
|
+
"type":"boolean",
|
|
790
|
+
"default":true,
|
|
791
|
+
"description":"When true (default if scenarios include create), after create the executor merges returned identifiers into the effective primary key for later get/update/delete in that run. When false, mutations use the static manifest primaryKey (destructive on shared fixtures). Ignored when no create scenario exists."
|
|
792
|
+
},
|
|
700
793
|
"scenarios":{
|
|
701
794
|
"type":"array",
|
|
702
|
-
"description":"
|
|
795
|
+
"description":"Ordered scenario steps for capacity E2E; execution order is array order (optional order field is a diagnostics hint only).",
|
|
703
796
|
"items":{
|
|
704
797
|
"type":"object",
|
|
705
798
|
"required":[
|
|
@@ -710,6 +803,11 @@
|
|
|
710
803
|
"type":"string",
|
|
711
804
|
"pattern":"^[a-z][a-zA-Z0-9]*$"
|
|
712
805
|
},
|
|
806
|
+
"enabled":{
|
|
807
|
+
"type":"boolean",
|
|
808
|
+
"default":true,
|
|
809
|
+
"description":"When false, the executor skips this scenario and records an explicit skip (scenario_disabled) in evidence."
|
|
810
|
+
},
|
|
713
811
|
"input":{
|
|
714
812
|
"type":"object",
|
|
715
813
|
"additionalProperties":true
|
|
@@ -756,15 +854,15 @@
|
|
|
756
854
|
},
|
|
757
855
|
"additionalProperties":false
|
|
758
856
|
},
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
857
|
+
"capabilities":{
|
|
858
|
+
"description":"Supported operations list.",
|
|
859
|
+
"type":"array",
|
|
860
|
+
"items":{
|
|
861
|
+
"type":"string",
|
|
862
|
+
"pattern":"^[a-z][a-zA-Z0-9_]*$"
|
|
863
|
+
},
|
|
864
|
+
"uniqueItems":true
|
|
865
|
+
},
|
|
768
866
|
"execution":{
|
|
769
867
|
"type":"object",
|
|
770
868
|
"description":"Execution engine configuration for this datasource (CIP, Python, or datasource-chaining). CIP is the native declarative mode.",
|
|
@@ -1524,6 +1622,29 @@
|
|
|
1524
1622
|
}
|
|
1525
1623
|
]
|
|
1526
1624
|
},
|
|
1625
|
+
"restRuntime":{
|
|
1626
|
+
"type":"object",
|
|
1627
|
+
"description":"Canonical REST path shape for manifest-defined (non-core) operations. Core CRUD keys ignore this block.",
|
|
1628
|
+
"additionalProperties":false,
|
|
1629
|
+
"properties":{
|
|
1630
|
+
"pathKind":{
|
|
1631
|
+
"type":"string",
|
|
1632
|
+
"enum":[
|
|
1633
|
+
"collection",
|
|
1634
|
+
"collectionSubresource",
|
|
1635
|
+
"item",
|
|
1636
|
+
"itemSubresource"
|
|
1637
|
+
]
|
|
1638
|
+
},
|
|
1639
|
+
"subpathSegments":{
|
|
1640
|
+
"type":"array",
|
|
1641
|
+
"items":{
|
|
1642
|
+
"type":"string"
|
|
1643
|
+
},
|
|
1644
|
+
"description":"Trailing path segments after the resource segment or record identifier (e.g. basic → /{resource}/basic)."
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
},
|
|
1527
1648
|
"security":{
|
|
1528
1649
|
"description":"OpenAPI security requirements. Supports object/list/string forms consumed by RBAC coverage validation.",
|
|
1529
1650
|
"oneOf":[
|
|
@@ -1755,6 +1876,15 @@
|
|
|
1755
1876
|
"identity":{
|
|
1756
1877
|
"$ref":"#/$defs/identitySpec"
|
|
1757
1878
|
},
|
|
1879
|
+
"shape":{
|
|
1880
|
+
"type":"string",
|
|
1881
|
+
"enum":[
|
|
1882
|
+
"create",
|
|
1883
|
+
"update",
|
|
1884
|
+
"delete"
|
|
1885
|
+
],
|
|
1886
|
+
"description":"Optional semantic classification for this operation when automatic inference from fetch steps (method/path) is insufficient."
|
|
1887
|
+
},
|
|
1758
1888
|
"steps":{
|
|
1759
1889
|
"type":"array",
|
|
1760
1890
|
"minItems":1,
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
"$schema":"http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"$id":"aifabrix://schema/external-system.schema.json",
|
|
4
4
|
"title":"AI Fabrix External System Configuration Schema",
|
|
5
|
-
"description":"Schema for configuring an external system connected to the AI Fabrix Dataplane. This defines authentication, OpenAPI/MCP
|
|
5
|
+
"description":"Schema for configuring an external system connected to the AI Fabrix Dataplane. This defines authentication, system-level OpenAPI/MCP connectivity hints (not the datasource-grade vendor contract; see external-datasource.schema.json root externalSpec), field mappings defaults, metadata handling and portal inputs.",
|
|
6
6
|
"metadata":{
|
|
7
7
|
"key":"external-system-schema",
|
|
8
8
|
"name":"External System Configuration Schema",
|
|
9
9
|
"description":"JSON schema for validating ExternalSystem configuration files",
|
|
10
|
-
|
|
10
|
+
"version":"1.6.3",
|
|
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-
|
|
15
|
+
"updatedAt":"2026-05-10T00:00:00Z",
|
|
16
16
|
"compatibility":{
|
|
17
17
|
"minVersion":"1.4.0",
|
|
18
18
|
"maxVersion":"2.0.0",
|
|
@@ -29,6 +29,15 @@
|
|
|
29
29
|
|
|
30
30
|
],
|
|
31
31
|
"changelog":[
|
|
32
|
+
{
|
|
33
|
+
"version":"1.6.3",
|
|
34
|
+
"date":"2026-05-10T00:00:00Z",
|
|
35
|
+
"changes":[
|
|
36
|
+
"Documented split: system openapi/mcp objects are connectivity and bootstrap hints (specUrl, serverUrl, documentKey); datasource-level vendor/API provenance belongs in external-datasource externalSpec.",
|
|
37
|
+
"Declared optional openapi.autoDiscoverEntities (wizard/tooling); tightened openapi and mcp to additionalProperties: false."
|
|
38
|
+
],
|
|
39
|
+
"breaking":false
|
|
40
|
+
},
|
|
32
41
|
{
|
|
33
42
|
"version":"1.6.2",
|
|
34
43
|
"date":"2026-04-23T00:00:00Z",
|
|
@@ -154,7 +163,7 @@
|
|
|
154
163
|
"mcp",
|
|
155
164
|
"custom"
|
|
156
165
|
],
|
|
157
|
-
"description":"Integration type:
|
|
166
|
+
"description":"Integration type: openapi and mcp indicate how the system is wired at a high level; per-datasource vendor specifications and import provenance are authored on each ExternalDataSource (external-datasource.schema.json externalSpec), not duplicated as the full contract here."
|
|
158
167
|
},
|
|
159
168
|
"enabled":{
|
|
160
169
|
"type":"boolean",
|
|
@@ -235,23 +244,27 @@
|
|
|
235
244
|
},
|
|
236
245
|
"openapi":{
|
|
237
246
|
"type":"object",
|
|
238
|
-
"description":"OpenAPI
|
|
247
|
+
"description":"System-level connectivity and bootstrap hints for OpenAPI-backed systems (e.g. default specUrl for discovery, documentKey alignment with shared registry entries). Not the authoritative per-datasource vendor OpenAPI contract; that is declared on the datasource via externalSpec and validated against imported material.",
|
|
239
248
|
"properties":{
|
|
240
249
|
"documentKey":{
|
|
241
250
|
"type":"string",
|
|
242
|
-
"description":"
|
|
251
|
+
"description":"Optional registry-oriented key associated with this system's default OpenAPI document (wizard/bootstrap)."
|
|
243
252
|
},
|
|
244
253
|
"specUrl":{
|
|
245
254
|
"type":"string",
|
|
246
|
-
"description":"URL to
|
|
255
|
+
"description":"Optional absolute URL to a representative OpenAPI specification for onboarding or tooling (not a substitute for datasource externalSpec).",
|
|
247
256
|
"pattern":"^(http|https)://.*$"
|
|
257
|
+
},
|
|
258
|
+
"autoDiscoverEntities":{
|
|
259
|
+
"type":"boolean",
|
|
260
|
+
"description":"Optional wizard or tooling hint to discover entities from the system default spec. Not part of the per-datasource vendor contract (see external-datasource externalSpec)."
|
|
248
261
|
}
|
|
249
262
|
},
|
|
250
|
-
"additionalProperties":
|
|
263
|
+
"additionalProperties":false
|
|
251
264
|
},
|
|
252
265
|
"mcp":{
|
|
253
266
|
"type":"object",
|
|
254
|
-
"description":"
|
|
267
|
+
"description":"System-level MCP connectivity hints (server URL, tool prefix). Not the datasource-level MCP security or operation contract; those live on ExternalDataSource configuration.",
|
|
255
268
|
"properties":{
|
|
256
269
|
"serverUrl":{
|
|
257
270
|
"type":"string",
|
|
@@ -264,7 +277,7 @@
|
|
|
264
277
|
"pattern":"^[a-zA-Z0-9_-]+$"
|
|
265
278
|
}
|
|
266
279
|
},
|
|
267
|
-
"additionalProperties":
|
|
280
|
+
"additionalProperties":false
|
|
268
281
|
},
|
|
269
282
|
"dataSources":{
|
|
270
283
|
"type":"array",
|
|
@@ -11,6 +11,10 @@ defaults:
|
|
|
11
11
|
userPassword: user123
|
|
12
12
|
# Always ensured on up-infra even when no workspace env.template references these kv:// keys (bootstrap defaults).
|
|
13
13
|
standardUpInfraEnsureKeys:
|
|
14
|
+
# Docker Postgres admin + Redis — required for admin-secrets / infra compose; not guaranteed in every app env.template
|
|
15
|
+
- postgres-passwordKeyVault
|
|
16
|
+
- redis-url
|
|
17
|
+
- redis-passwordKeyVault
|
|
14
18
|
- databases-miso-controller-0-urlKeyVault
|
|
15
19
|
- databases-miso-controller-0-passwordKeyVault
|
|
16
20
|
- databases-miso-controller-1-urlKeyVault
|
|
@@ -113,6 +117,17 @@ parameters:
|
|
|
113
117
|
vaultSecretName: keycloak-client-secretKeyVault
|
|
114
118
|
notes: Per-app OAuth client secret from Keycloak registration; generated on first ensure.
|
|
115
119
|
|
|
120
|
+
# Keycloak events: webhook signature secret used by miso-controller (KEYCLOAK_EVENTS_SECRET).
|
|
121
|
+
# This must exist on first boot because up-platform runs containers from templates (no prior resolve).
|
|
122
|
+
- key: keycloak-events-secretKeyVault
|
|
123
|
+
scope: shared-service
|
|
124
|
+
generator:
|
|
125
|
+
type: randomBytes32
|
|
126
|
+
ensureOn: [upInfra, resolveApp]
|
|
127
|
+
azure:
|
|
128
|
+
notes: >-
|
|
129
|
+
Shared secret for Keycloak event signature verification. Generated on first ensure for local bootstrap.
|
|
130
|
+
|
|
116
131
|
- key: keycloak-default-passwordKeyVault
|
|
117
132
|
scope: shared-service
|
|
118
133
|
generator:
|
|
@@ -236,6 +251,16 @@ parameters:
|
|
|
236
251
|
notes: >-
|
|
237
252
|
Per-app OAuth client id from controller registration; literal default matches local Keycloak client naming.
|
|
238
253
|
|
|
254
|
+
- key: miso-controller-client-secretKeyVault
|
|
255
|
+
scope: app
|
|
256
|
+
generator:
|
|
257
|
+
type: randomBytes32
|
|
258
|
+
ensureOn: [upInfra, resolveApp]
|
|
259
|
+
azure:
|
|
260
|
+
notes: >-
|
|
261
|
+
Per-app OAuth client secret used by miso-controller for service-to-service auth (MISO_CLIENTSECRET).
|
|
262
|
+
Generated on first ensure for local bootstrap.
|
|
263
|
+
|
|
239
264
|
# Dataplane ↔ controller OAuth (builder/dataplane env.template MISO_CLIENTID / MISO_CLIENTSECRET).
|
|
240
265
|
- key: dataplane-client-idKeyVault
|
|
241
266
|
scope: app
|
|
@@ -317,22 +342,12 @@ parameters:
|
|
|
317
342
|
azure:
|
|
318
343
|
notes: Empty until set; user-supplied Azure OpenAI API key (not auto-generated).
|
|
319
344
|
|
|
320
|
-
# Legacy unprefixed name (scaffold / old env.template); prefer *KeyVault suffix or {appKey}-secrets-apiKeyVault (keyvault.md).
|
|
321
|
-
- key: api-key
|
|
322
|
-
scope: app
|
|
323
|
-
generator:
|
|
324
|
-
type: randomBytes32
|
|
325
|
-
ensureOn: [resolveApp]
|
|
326
|
-
azure:
|
|
327
|
-
notes: >-
|
|
328
|
-
Legacy kv://api-key; new apps should use kv://api-keyKeyVault or {appKey}-secrets-apiKeyVault.
|
|
329
|
-
|
|
330
345
|
# Legacy unprefixed name; prefer kv://{appKey}-secrets-apiKeyVault in env.template (keyvault.md secrets.apiKeyVault).
|
|
331
346
|
- key: miso-controller-secrets-apiKeyVault
|
|
332
347
|
scope: app
|
|
333
348
|
generator:
|
|
334
349
|
type: randomBytes32
|
|
335
|
-
ensureOn: [resolveApp]
|
|
350
|
+
ensureOn: [upInfra, resolveApp]
|
|
336
351
|
azure:
|
|
337
352
|
notes: >-
|
|
338
353
|
Prefer {appKey}-secrets-apiKeyVault locally; dataplane shares miso-controller's entry for pipeline Bearer bypass.
|
|
@@ -214,7 +214,7 @@
|
|
|
214
214
|
},
|
|
215
215
|
"debug": {
|
|
216
216
|
"type": "boolean",
|
|
217
|
-
"description": "When true, capture detailed generation steps and save to debug.log (dataplane returns debugLog)",
|
|
217
|
+
"description": "When true, capture detailed generation steps and save to integration/<app>/logs/debug.log (dataplane returns debugLog)",
|
|
218
218
|
"default": false
|
|
219
219
|
}
|
|
220
220
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walk ancestors of `startDir` for `<dir>/.aifabrix/config.yaml`.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Config directory discovery from cwd
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} startDir
|
|
15
|
+
* @param {(p: string) => boolean} existsSyncFn
|
|
16
|
+
* @returns {string|null} Absolute path to `.aifabrix` directory containing `config.yaml`
|
|
17
|
+
*/
|
|
18
|
+
function findAifabrixConfigDirFromAncestors(startDir, existsSyncFn) {
|
|
19
|
+
if (!startDir || typeof startDir !== 'string') {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
let dir = path.resolve(startDir);
|
|
23
|
+
const maxSteps = 64;
|
|
24
|
+
for (let i = 0; i < maxSteps; i += 1) {
|
|
25
|
+
const candidate = path.join(dir, '.aifabrix', 'config.yaml');
|
|
26
|
+
if (existsSyncFn(candidate)) {
|
|
27
|
+
return path.join(dir, '.aifabrix');
|
|
28
|
+
}
|
|
29
|
+
const parent = path.dirname(dir);
|
|
30
|
+
if (parent === dir) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
dir = parent;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = {
|
|
39
|
+
findAifabrixConfigDirFromAncestors
|
|
40
|
+
};
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Shared by `paths.getConfigDirForPaths` and `config.getConfigDir` (no circular imports).
|
|
4
4
|
*
|
|
5
5
|
* When `AIFABRIX_HOME` is set to the POSIX home (builder-server pattern) but the real
|
|
6
|
-
* config file is under `~/.aifabrix/config.yaml`, use that nested directory
|
|
7
|
-
*
|
|
6
|
+
* config file is under `~/.aifabrix/config.yaml`, use that nested directory.
|
|
7
|
+
* With no env override, walks up from cwd for `<ancestor>/.aifabrix/config.yaml`, else `~/.aifabrix`.
|
|
8
8
|
*
|
|
9
9
|
* Relative `AIFABRIX_HOME` / `AIFABRIX_CONFIG` values are anchored to the user home
|
|
10
10
|
* directory (not `process.cwd()`), so a mistaken `aifabrix-training` does not become
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
const { existsSync } = require('../internal/fs-real-sync');
|
|
22
22
|
const path = require('path');
|
|
23
23
|
const os = require('os');
|
|
24
|
+
const { findAifabrixConfigDirFromAncestors } = require('./aifabrix-config-dir-walk');
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* @returns {string}
|
|
@@ -102,6 +103,23 @@ function resolveAifabrixConfigEnvPath(raw) {
|
|
|
102
103
|
return resolveAifabrixHomeLikePath(raw);
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
/**
|
|
107
|
+
* When neither `AIFABRIX_CONFIG` nor `AIFABRIX_HOME` is set, look for `<ancestor>/.aifabrix/config.yaml`
|
|
108
|
+
* walking up from `process.cwd()`. Skipped under Jest so suites do not pick up the workspace config.
|
|
109
|
+
*
|
|
110
|
+
* @returns {string|null} Directory containing `config.yaml`, or null
|
|
111
|
+
*/
|
|
112
|
+
function findAifabrixConfigDirWalkingUpFromCwd() {
|
|
113
|
+
if (process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
return findAifabrixConfigDirFromAncestors(process.cwd(), existsSync);
|
|
118
|
+
} catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
105
123
|
/**
|
|
106
124
|
* @returns {string} Absolute directory containing `config.yaml`
|
|
107
125
|
*/
|
|
@@ -122,11 +140,16 @@ function getAifabrixRuntimeConfigDir() {
|
|
|
122
140
|
}
|
|
123
141
|
return homeDir;
|
|
124
142
|
}
|
|
143
|
+
const fromCwd = findAifabrixConfigDirWalkingUpFromCwd();
|
|
144
|
+
if (fromCwd) {
|
|
145
|
+
return fromCwd;
|
|
146
|
+
}
|
|
125
147
|
return path.join(safeHomedir(), '.aifabrix');
|
|
126
148
|
}
|
|
127
149
|
|
|
128
150
|
module.exports = {
|
|
129
151
|
getAifabrixRuntimeConfigDir,
|
|
130
152
|
resolveAifabrixHomeLikePath,
|
|
131
|
-
resolveAifabrixConfigEnvPath
|
|
153
|
+
resolveAifabrixConfigEnvPath,
|
|
154
|
+
findAifabrixConfigDirWalkingUpFromCwd
|
|
132
155
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { formatSuccessLine } = require('./cli-test-layout-chalk');
|
|
1
|
+
const { formatSuccessLine, formatProgress } = require('./cli-test-layout-chalk');
|
|
2
2
|
/**
|
|
3
3
|
* AI Fabrix Builder - App Run Container Helpers
|
|
4
4
|
*
|
|
@@ -118,7 +118,7 @@ async function checkContainerRunning(appName, developerId, debug = false, scopeO
|
|
|
118
118
|
async function stopAndRemoveContainer(appName, developerId, debug = false, scopeOpts = null) {
|
|
119
119
|
try {
|
|
120
120
|
const containerName = getContainerName(appName, developerId, scopeOpts);
|
|
121
|
-
logger.log(
|
|
121
|
+
logger.log(formatProgress(`Stopping container ${containerName}…`));
|
|
122
122
|
const stopCmd = `docker stop ${containerName}`;
|
|
123
123
|
if (debug) {
|
|
124
124
|
logger.log(chalk.gray(`[DEBUG] Executing: ${stopCmd}`));
|