@aifabrix/builder 2.44.6 → 2.45.5
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 +7 -3
- package/.cursor/rules/docs-rules.mdc +3 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
- package/jest.projects.js +100 -1
- package/lib/api/agent-metadata-validation.api.js +93 -0
- package/lib/api/audit-api-helpers.js +68 -0
- package/lib/api/audit.api.js +119 -0
- package/lib/api/auth-cache.api.js +44 -0
- package/lib/api/certificates.api.js +4 -4
- package/lib/api/credential.api.js +2 -2
- package/lib/api/dataplane-health.api.js +137 -0
- package/lib/api/dataplane-sync.api.js +27 -0
- package/lib/api/datasources-core.api.js +21 -18
- package/lib/api/datasources-extended.api.js +22 -22
- package/lib/api/dimensions.api.js +3 -0
- package/lib/api/external-systems.api.js +13 -13
- package/lib/api/governance-scenarios.api.js +39 -0
- package/lib/api/groups.api.js +79 -0
- package/lib/api/index.js +45 -2
- package/lib/api/pipeline.api.js +4 -4
- package/lib/api/protection.api.js +157 -0
- package/lib/api/records-bulk.api.js +30 -0
- package/lib/api/records-search-parse.js +49 -0
- package/lib/api/records-search.api.js +29 -0
- package/lib/api/types/agent-metadata-validation.types.js +67 -0
- package/lib/api/types/audit.types.js +72 -0
- package/lib/api/types/dataplane-health.types.js +27 -0
- package/lib/api/types/dimensions.types.js +2 -0
- package/lib/api/types/governance-scenarios.types.js +39 -0
- package/lib/api/types/protection.types.js +69 -0
- package/lib/api/types/records-bulk.types.js +35 -0
- package/lib/api/types/records-search.types.js +28 -0
- package/lib/api/user-groups.api.js +50 -0
- package/lib/api/users.api.js +95 -0
- package/lib/api/validation-run.api.js +3 -3
- package/lib/api/validation-runner.js +3 -3
- package/lib/api/wizard-platform.api.js +3 -3
- package/lib/api/wizard.api.js +21 -21
- package/lib/app/deploy.js +34 -19
- package/lib/app/helpers.js +3 -3
- package/lib/app/index.js +3 -3
- package/lib/app/register.js +7 -6
- package/lib/app/restart-display.js +52 -21
- package/lib/app/rotate-secret.js +7 -6
- package/lib/app/run-helpers.js +15 -8
- package/lib/app/run.js +57 -9
- package/lib/app/show-display.js +7 -0
- package/lib/app/show.js +87 -5
- package/lib/build/index.js +9 -5
- package/lib/cli/index.js +4 -2
- package/lib/cli/infra-guided.js +62 -28
- package/lib/cli/installation-log-command.js +73 -0
- package/lib/cli/setup-app.help.js +50 -2
- package/lib/cli/setup-app.js +44 -25
- package/lib/cli/setup-app.test-commands.js +80 -21
- package/lib/cli/setup-auth.js +124 -52
- package/lib/cli/setup-external-system.js +37 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +111 -0
- package/lib/cli/setup-infra-up-platform-action.js +131 -0
- package/lib/cli/setup-infra.js +60 -119
- package/lib/cli/setup-platform.js +1 -1
- package/lib/cli/setup-utility-help-after.js +45 -0
- package/lib/cli/setup-utility-resolve.js +132 -0
- package/lib/cli/setup-utility.js +148 -116
- package/lib/commands/app-logs.js +81 -33
- package/lib/commands/auth-config.js +116 -18
- package/lib/commands/auth-status-dataplane-version.js +231 -0
- package/lib/commands/auth-status-display.js +94 -0
- package/lib/commands/auth-status.js +70 -6
- package/lib/commands/credential-push.js +10 -5
- package/lib/commands/datasource-load-export-cli.js +178 -0
- package/lib/commands/datasource-test-trust-cli.js +114 -0
- package/lib/commands/datasource-unified-test-cli.js +25 -17
- package/lib/commands/datasource-unified-test-cli.options.js +18 -3
- package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
- package/lib/commands/datasource-verify-audit-cli.js +96 -0
- package/lib/commands/datasource.js +68 -1
- package/lib/commands/dimension-value.js +43 -13
- package/lib/commands/dimension.js +38 -7
- package/lib/commands/identity-apply-sync.js +131 -0
- package/lib/commands/identity-group-cli.js +146 -0
- package/lib/commands/identity-membership-role-cache.js +175 -0
- package/lib/commands/identity-shared.js +94 -0
- package/lib/commands/identity-user-cli.js +158 -0
- package/lib/commands/identity.js +43 -0
- package/lib/commands/login.js +46 -16
- package/lib/commands/protection-cli-leaves.js +286 -0
- package/lib/commands/protection.js +50 -0
- package/lib/commands/repair.js +13 -3
- package/lib/commands/setup-modes.js +19 -6
- package/lib/commands/setup-prompts.js +41 -8
- package/lib/commands/setup.js +114 -9
- package/lib/commands/teardown.js +54 -5
- package/lib/commands/test-e2e-external.js +40 -9
- package/lib/commands/test-governance-cli-options.js +47 -0
- package/lib/commands/test-governance-command-action.js +55 -0
- package/lib/commands/test-governance-external.js +88 -0
- package/lib/commands/test-trust-cli-options.js +32 -0
- package/lib/commands/test-trust-command-action.js +118 -0
- package/lib/commands/test-trust-external.js +127 -0
- package/lib/commands/up-common.js +48 -14
- package/lib/commands/up-dataplane.js +21 -18
- package/lib/commands/up-miso.js +12 -8
- package/lib/commands/upload.js +38 -15
- package/lib/commands/wizard-core.js +3 -0
- package/lib/core/audit-logger.js +1 -34
- package/lib/core/config-admin-email.js +56 -0
- package/lib/core/config-device-dataplane.js +185 -0
- package/lib/core/config-normalize.js +60 -0
- package/lib/core/config-registered-controller-urls.js +54 -0
- package/lib/core/config.js +33 -50
- package/lib/core/secrets-ensure-infra.js +1 -1
- package/lib/core/secrets-env-content.js +86 -90
- package/lib/core/secrets-env-declarative-expand.js +170 -0
- package/lib/core/secrets-env-write.js +2 -0
- package/lib/core/secrets-load.js +106 -102
- package/lib/datasource/agent-trust-debug-log.js +45 -0
- package/lib/datasource/agent-trust-fetch.js +115 -0
- package/lib/datasource/agent-trust-map.js +101 -0
- package/lib/datasource/agent-trust-mock.js +44 -0
- package/lib/datasource/agent-trust-run.js +93 -0
- package/lib/datasource/agent-trust-timeout.js +25 -0
- package/lib/datasource/audit-evidence-display.js +80 -0
- package/lib/datasource/audit-evidence-extract-debug.js +103 -0
- package/lib/datasource/audit-evidence-extract.js +177 -0
- package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
- package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
- package/lib/datasource/audit-evidence-poll.js +109 -0
- package/lib/datasource/audit-evidence-run.js +177 -0
- package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
- package/lib/datasource/audit-evidence-verify-matrix.js +177 -0
- package/lib/datasource/audit-evidence-verify.js +108 -0
- package/lib/datasource/bulk-loader-run-batches.js +88 -0
- package/lib/datasource/bulk-loader-service-retry.js +52 -0
- package/lib/datasource/bulk-loader-service.js +127 -0
- package/lib/datasource/capability/run-capability-dimension.js +2 -1
- package/lib/datasource/datasource-exporter-resolve.js +82 -0
- package/lib/datasource/datasource-exporter-service.js +144 -0
- package/lib/datasource/datasource-identifier.js +148 -0
- package/lib/datasource/datasource-load-export-context.js +92 -0
- package/lib/datasource/integration-context.js +6 -4
- package/lib/datasource/local-data-paths.js +145 -0
- package/lib/datasource/log-cleaner.js +241 -0
- package/lib/datasource/log-viewer.js +111 -6
- package/lib/datasource/record-file-parser.js +85 -0
- package/lib/datasource/record-mapper.js +129 -0
- package/lib/datasource/resolve-app.js +74 -55
- package/lib/datasource/test-e2e.js +26 -2
- package/lib/datasource/unified-validation-run-resolve.js +45 -12
- package/lib/datasource/unified-validation-run.js +43 -17
- package/lib/datasource/validate.js +37 -20
- package/lib/external-system/deploy.js +5 -1
- package/lib/external-system/test-system-level.js +25 -4
- package/lib/external-system/test.js +3 -1
- package/lib/governance/governance-pack-loader.js +70 -0
- package/lib/governance/governance-run-display.js +119 -0
- package/lib/identity/identity-apply-core.js +108 -0
- package/lib/identity/identity-apply-phases.js +244 -0
- package/lib/identity/identity-apply-service.js +77 -0
- package/lib/identity/identity-csv-parser.js +114 -0
- package/lib/internal/fs-real-sync.js +29 -1
- package/lib/internal/node-fs.js +2 -0
- package/lib/protection/auth-context.js +45 -0
- package/lib/protection/convert-batch.js +90 -0
- package/lib/protection/load.js +41 -0
- package/lib/protection/paths.js +158 -0
- package/lib/protection/preflight-datasource-ready.js +46 -0
- package/lib/protection/protection-create-probe-lines.js +142 -0
- package/lib/protection/protection-create-probes.js +95 -0
- package/lib/protection/protection-create-scaffold.js +281 -0
- package/lib/protection/protection-display-helpers.js +445 -0
- package/lib/protection/protection-display.js +215 -0
- package/lib/protection/protection-preset-registry.js +97 -0
- package/lib/protection/report-exit.js +62 -0
- package/lib/protection/resolve.js +202 -0
- package/lib/protection/run-commands-validate.js +130 -0
- package/lib/protection/run-commands.js +216 -0
- package/lib/protection/run-protection-create-helpers.js +134 -0
- package/lib/protection/run-protection-create-probes-flow.js +43 -0
- package/lib/protection/run-protection-create.js +191 -0
- package/lib/protection/scope.js +22 -0
- package/lib/protection/sync-after-upload.js +64 -0
- package/lib/protection/upload-batch.js +127 -0
- package/lib/protection/validate-batch.js +113 -0
- package/lib/protection/validate-local.js +65 -0
- package/lib/resolvers/dimension-file.js +29 -4
- package/lib/schema/application-schema.json +4 -0
- package/lib/schema/external-datasource.schema.json +47 -13
- package/lib/schema/flag-map-validation-run.json +2 -2
- package/lib/schema/infra.parameter.yaml +10 -0
- package/lib/schema/protection.schema.json +374 -0
- package/lib/schema/type/credential-field-registry.json +636 -0
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/agent-trust-run-display.js +231 -0
- package/lib/utils/agent-trust-run-exit.js +59 -0
- package/lib/utils/agent-trust-wait-ui.js +94 -0
- package/lib/utils/app-config-resolver.js +24 -1
- package/lib/utils/applications-config-defaults.js +206 -0
- package/lib/utils/auth-config-validator.js +2 -12
- package/lib/utils/bash-secret-env.js +1 -1
- package/lib/utils/cli-exit-codes.js +30 -0
- package/lib/utils/cli-sync-options.js +33 -0
- package/lib/utils/compose-generate-docker-compose.js +111 -6
- package/lib/utils/compose-generator.js +17 -8
- package/lib/utils/controller-url.js +50 -7
- package/lib/utils/credential-push-ui.js +90 -0
- package/lib/utils/dataplane-cli-version-gate.js +202 -0
- package/lib/utils/dataplane-cli-version-help.js +74 -0
- package/lib/utils/datasource-export-display.js +137 -0
- package/lib/utils/datasource-load-display.js +174 -0
- package/lib/utils/datasource-load-export-ui.js +120 -0
- package/lib/utils/datasource-test-run-capability-scope.js +3 -3
- package/lib/utils/datasource-test-run-display.js +3 -3
- package/lib/utils/datasource-test-run-tty-log.js +5 -1
- package/lib/utils/env-copy.js +99 -14
- package/lib/utils/env-template.js +5 -1
- package/lib/utils/health-check-url.js +18 -15
- package/lib/utils/health-check.js +7 -5
- package/lib/utils/help-builder.js +30 -24
- package/lib/utils/infra-optional-service-flags.js +69 -0
- package/lib/utils/installation-log-core.js +282 -0
- package/lib/utils/installation-log-record.js +237 -0
- package/lib/utils/installation-log.js +123 -0
- package/lib/utils/log-redaction.js +105 -0
- package/lib/utils/manifest-location.js +164 -0
- package/lib/utils/manifest-source-emit.js +184 -0
- package/lib/utils/paths.js +238 -89
- package/lib/utils/remote-secrets-loader.js +7 -1
- package/lib/utils/run-cli-flags.js +29 -0
- package/lib/utils/secrets-canonical.js +10 -3
- package/lib/utils/secrets-path.js +3 -4
- package/lib/utils/secrets-utils.js +20 -10
- package/lib/utils/semver-compare.js +127 -0
- package/lib/utils/system-builder-root.js +10 -2
- package/lib/utils/upload-pipeline-ui.js +91 -0
- package/lib/utils/url-declarative-public-base.js +80 -12
- package/lib/utils/url-declarative-resolve-build-urls.js +238 -0
- package/lib/utils/url-declarative-resolve-build.js +24 -393
- package/lib/utils/url-declarative-resolve-expand-token.js +189 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +12 -3
- package/lib/utils/url-declarative-resolve-surface-state.js +102 -0
- package/lib/utils/url-declarative-resolve.js +47 -7
- package/lib/utils/url-declarative-runtime-base-path.js +21 -1
- package/lib/utils/urls-local-registry-scan.js +103 -0
- package/lib/utils/urls-local-registry.js +161 -90
- package/lib/utils/validation-poll-ui.js +14 -7
- package/lib/validation/wizard-config-validator.js +58 -19
- package/package.json +3 -1
- package/templates/applications/dataplane/application.yaml +4 -0
- package/templates/applications/dataplane/env.template +13 -1
- package/templates/applications/dataplane/rbac.yaml +4 -0
- package/templates/applications/miso-controller/application.yaml +2 -0
- package/templates/applications/miso-controller/env.template +27 -29
- package/templates/external-system/README.md.hbs +56 -8
- package/.npmrc.token +0 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared "Next actions" + blocking error formatter for the Builder CLI ↔
|
|
3
|
+
* dataplane version gate (plan 142.0). Used by `auth status` display and by
|
|
4
|
+
* the gate thrown from dataplane API entrypoints so users see the same bullets
|
|
5
|
+
* wherever the incompatibility surfaces.
|
|
6
|
+
*
|
|
7
|
+
* @fileoverview Shared CLI version-gate UX helpers (next actions + blocking)
|
|
8
|
+
* @author AI Fabrix Team
|
|
9
|
+
* @version 2.0.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
formatBlockingError,
|
|
16
|
+
formatNextActions
|
|
17
|
+
} = require('./cli-test-layout-chalk');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Build the canonical Next actions bullets for a CLI ↔ dataplane mismatch.
|
|
21
|
+
*
|
|
22
|
+
* @param {string} required - Minimum Builder CLI semver advertised by dataplane
|
|
23
|
+
* @param {string} installed - Current Builder CLI semver (from package.json)
|
|
24
|
+
* @returns {string[]} Bullet lines (no prefix)
|
|
25
|
+
*/
|
|
26
|
+
function buildCliVersionUpgradeNextActions(required, installed) {
|
|
27
|
+
const req = (required || '').trim() || 'the dataplane minimum';
|
|
28
|
+
const inst = (installed || '').trim() || 'this CLI';
|
|
29
|
+
return [
|
|
30
|
+
`Upgrade Builder CLI: npm install -g @aifabrix/builder@${req} (or @latest)`,
|
|
31
|
+
'Confirm after upgrade: aifabrix auth status',
|
|
32
|
+
'CI / scripts: aifabrix auth status --validate (exit 3 until upgraded)',
|
|
33
|
+
`Local work (validate, run, up-infra) still works on ${inst}`
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Build the blocking line shown before the Next actions block when the CLI is
|
|
39
|
+
* older than the dataplane minimum.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} required - Required minimum semver
|
|
42
|
+
* @param {string} installed - Currently installed semver
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
function buildCliVersionBlockingLine(required, installed) {
|
|
46
|
+
const req = (required || '').trim() || '(unknown)';
|
|
47
|
+
const inst = (installed || '').trim() || '(unknown)';
|
|
48
|
+
return formatBlockingError(
|
|
49
|
+
`Builder CLI ${inst} is below the dataplane minimum (${req}). Upgrade before running dataplane commands.`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Format the full version-gate error block (blocking line + Next actions).
|
|
55
|
+
* Suitable for `handleCommandError` output and the `auth status` incompatible
|
|
56
|
+
* branch.
|
|
57
|
+
*
|
|
58
|
+
* @param {string} required - Required minimum semver
|
|
59
|
+
* @param {string} installed - Currently installed semver
|
|
60
|
+
* @returns {string} Multi-line, chalk-colored block
|
|
61
|
+
*/
|
|
62
|
+
function formatCliVersionGateError(required, installed) {
|
|
63
|
+
return [
|
|
64
|
+
buildCliVersionBlockingLine(required, installed),
|
|
65
|
+
'',
|
|
66
|
+
formatNextActions(buildCliVersionUpgradeNextActions(required, installed))
|
|
67
|
+
].join('\n');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
buildCliVersionUpgradeNextActions,
|
|
72
|
+
buildCliVersionBlockingLine,
|
|
73
|
+
formatCliVersionGateError
|
|
74
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview TTY display for `datasource export` (plan 144)
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const logger = require('./logger');
|
|
11
|
+
const {
|
|
12
|
+
sectionTitle,
|
|
13
|
+
headerKeyValue,
|
|
14
|
+
metadata: metaGray,
|
|
15
|
+
formatSuccessLine,
|
|
16
|
+
formatWarningLine
|
|
17
|
+
} = require('./cli-test-layout-chalk');
|
|
18
|
+
const { emitManifestSourceMetadata } = require('./manifest-source-emit');
|
|
19
|
+
const { integrationManifestLabel } = require('../datasource/datasource-load-export-context');
|
|
20
|
+
const { formatElapsedMs } = require('./datasource-load-export-ui');
|
|
21
|
+
|
|
22
|
+
const SEP = '────────────────────────────────────────────────────────';
|
|
23
|
+
|
|
24
|
+
function logExportHeader(ctx, envLabel) {
|
|
25
|
+
logger.log(SEP);
|
|
26
|
+
logger.log(sectionTitle(`Export records — ${ctx.datasourceKey}`));
|
|
27
|
+
logger.log(headerKeyValue('Environment:', envLabel || '—'));
|
|
28
|
+
logger.log(headerKeyValue('System:', ctx.systemKey));
|
|
29
|
+
logger.log(SEP);
|
|
30
|
+
logger.log(metaGray(' Layer: governed records search (ABAC applied)'));
|
|
31
|
+
logger.log(metaGray(' Not used: direct database access'));
|
|
32
|
+
logger.log('');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function logExportVerboseStats(result) {
|
|
36
|
+
const excluded = result.meta?.excluded || {};
|
|
37
|
+
const abac = excluded.abac !== undefined && excluded.abac !== null ? excluded.abac : 0;
|
|
38
|
+
const filterEx =
|
|
39
|
+
excluded.filter !== undefined && excluded.filter !== null ? excluded.filter : 0;
|
|
40
|
+
logger.log(
|
|
41
|
+
metaGray(
|
|
42
|
+
` Fetched: ${result.recordCount} records · excluded abac ${abac} · filter ${filterEx}`
|
|
43
|
+
)
|
|
44
|
+
);
|
|
45
|
+
const stat = fs.statSync(result.outputFile);
|
|
46
|
+
const mb = (stat.size / (1024 * 1024)).toFixed(2);
|
|
47
|
+
logger.log(
|
|
48
|
+
metaGray(` Wrote: ${result.recordCount} line(s) (${result.format}) · ${mb} MB`)
|
|
49
|
+
);
|
|
50
|
+
logger.log('');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {Object} result
|
|
55
|
+
*/
|
|
56
|
+
function displayExportAbacZeroRowsWarning(result) {
|
|
57
|
+
const excludedAbac = Number(result.excludedAbac ?? result.meta?.excluded?.abac) || 0;
|
|
58
|
+
if (result.recordCount !== 0 || excludedAbac <= 0) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
logger.log(
|
|
62
|
+
formatWarningLine(
|
|
63
|
+
`Governed search returned 0 rows; ABAC excluded ${excludedAbac} record(s) for your principal.`
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
logger.log(
|
|
67
|
+
metaGray(
|
|
68
|
+
' The physical table may still hold data — export only includes rows your token may read.'
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
logger.log(
|
|
72
|
+
metaGray(
|
|
73
|
+
' Fix: upload a protection manifest (aifabrix protection upload <datasourceKey>) with dimension grants for your user, then retry.'
|
|
74
|
+
)
|
|
75
|
+
);
|
|
76
|
+
logger.log('');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {Object} result
|
|
81
|
+
*/
|
|
82
|
+
function displayExportLimitCapWarning(result) {
|
|
83
|
+
if (!result.hitLimitCap) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
logger.log(
|
|
87
|
+
formatWarningLine(`Fetched ${result.recordCount} records (limit cap). More rows may exist.`)
|
|
88
|
+
);
|
|
89
|
+
logger.log(metaGray(' Re-run with --filter or wait for dataplane search pagination.'));
|
|
90
|
+
logger.log('');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {Object} result
|
|
95
|
+
*/
|
|
96
|
+
function logExportDurationFooter(result) {
|
|
97
|
+
if (result.durationMs === undefined || result.durationMs === null) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
logger.log(metaGray(` Completed in ${formatElapsedMs(result.durationMs)}`));
|
|
101
|
+
logger.log('');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {Object} result
|
|
106
|
+
* @param {Object} opts
|
|
107
|
+
*/
|
|
108
|
+
function displayDatasourceExportTTY(result, opts = {}) {
|
|
109
|
+
const ctx = result.context || {};
|
|
110
|
+
logExportHeader(ctx, opts.environment);
|
|
111
|
+
|
|
112
|
+
const filterLabel = result.filters ? 'filters (set)' : 'filters (none)';
|
|
113
|
+
logger.log(
|
|
114
|
+
metaGray(` Search: intent ${result.intent} · limit ${result.limit} · ${filterLabel}`)
|
|
115
|
+
);
|
|
116
|
+
emitManifestSourceMetadata({
|
|
117
|
+
tier: 'int',
|
|
118
|
+
configPath: ctx.manifestPath,
|
|
119
|
+
labelPrefix: integrationManifestLabel(ctx.appKey)
|
|
120
|
+
});
|
|
121
|
+
logger.log(metaGray(` Output: ${result.outputFile}`));
|
|
122
|
+
logger.log('');
|
|
123
|
+
|
|
124
|
+
if (opts.verbose) {
|
|
125
|
+
logExportVerboseStats(result);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
displayExportAbacZeroRowsWarning(result);
|
|
129
|
+
displayExportLimitCapWarning(result);
|
|
130
|
+
logger.log(formatSuccessLine('Export complete'));
|
|
131
|
+
logExportDurationFooter(result);
|
|
132
|
+
logger.log(SEP);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = {
|
|
136
|
+
displayDatasourceExportTTY
|
|
137
|
+
};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview TTY display for `datasource load` (plan 144)
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('./logger');
|
|
11
|
+
const {
|
|
12
|
+
sectionTitle,
|
|
13
|
+
headerKeyValue,
|
|
14
|
+
metadata: metaGray,
|
|
15
|
+
formatSuccessLine,
|
|
16
|
+
formatBlockingError,
|
|
17
|
+
successGlyph,
|
|
18
|
+
failureGlyph
|
|
19
|
+
} = require('./cli-test-layout-chalk');
|
|
20
|
+
const { emitManifestSourceMetadata } = require('./manifest-source-emit');
|
|
21
|
+
const { integrationManifestLabel } = require('../datasource/datasource-load-export-context');
|
|
22
|
+
const { formatElapsedMs } = require('./datasource-load-export-ui');
|
|
23
|
+
|
|
24
|
+
const SEP = '────────────────────────────────────────────────────────';
|
|
25
|
+
|
|
26
|
+
function logLoadHeader(ctx, envLabel) {
|
|
27
|
+
logger.log(SEP);
|
|
28
|
+
logger.log(sectionTitle(`Load records — ${ctx.datasourceKey}`));
|
|
29
|
+
logger.log(headerKeyValue('Environment:', envLabel || '—'));
|
|
30
|
+
logger.log(headerKeyValue('System:', ctx.systemKey));
|
|
31
|
+
logger.log(SEP);
|
|
32
|
+
logger.log(metaGray(' Layer: dataplane bulk sync'));
|
|
33
|
+
emitManifestSourceMetadata({
|
|
34
|
+
tier: 'int',
|
|
35
|
+
configPath: ctx.manifestPath,
|
|
36
|
+
labelPrefix: integrationManifestLabel(ctx.appKey)
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function displayLoadDryRun(result) {
|
|
41
|
+
logger.log(chalk.cyan(' Mode: dry-run (no upload)'));
|
|
42
|
+
logger.log('');
|
|
43
|
+
const mb = (result.estimatedPayloadBytes / (1024 * 1024)).toFixed(2);
|
|
44
|
+
const batchCount = Math.ceil(result.recordCount / result.batchSize) || 0;
|
|
45
|
+
logger.log(
|
|
46
|
+
metaGray(
|
|
47
|
+
` Parsed: ${result.recordCount} records · format ${result.format} · est. payload ~${mb} MB`
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
logger.log(
|
|
51
|
+
metaGray(` Would upload: ${batchCount} batch(es) · syncType ${result.syncType}`)
|
|
52
|
+
);
|
|
53
|
+
logger.log('');
|
|
54
|
+
logger.log(formatSuccessLine('Dry-run passed'));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function displayLoadBatchesVerbose(batches) {
|
|
58
|
+
batches.forEach(batch => {
|
|
59
|
+
if (batch.error) {
|
|
60
|
+
logger.log(
|
|
61
|
+
` Batch ${batch.index}/${batch.total} ${failureGlyph()} failed (${batch.error})`
|
|
62
|
+
);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const failed = Array.isArray(batch.failed) ? batch.failed.length : 0;
|
|
66
|
+
if (failed > 0) {
|
|
67
|
+
logger.log(
|
|
68
|
+
` Batch ${batch.index}/${batch.total} ${failureGlyph()} failed ${failed} of ${batch.recordCount || '?'}`
|
|
69
|
+
);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
logger.log(
|
|
73
|
+
` Batch ${batch.index}/${batch.total} ${successGlyph()} inserted ${batch.insertedCount || 0} · updated ${batch.updatedCount || 0} · failed 0`
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const MAX_FAILURE_LINES = 5;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {Object[]} batches
|
|
82
|
+
*/
|
|
83
|
+
function displayLoadFailureSamples(batches) {
|
|
84
|
+
const samples = [];
|
|
85
|
+
(batches || []).forEach(batch => {
|
|
86
|
+
if (!Array.isArray(batch.failed)) return;
|
|
87
|
+
batch.failed.forEach(item => {
|
|
88
|
+
if (samples.length >= MAX_FAILURE_LINES) return;
|
|
89
|
+
const key = item.key ? String(item.key) : '—';
|
|
90
|
+
const message = item.message || batch.error || 'failed';
|
|
91
|
+
samples.push({ key, message });
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
if (samples.length === 0) return;
|
|
95
|
+
logger.log('');
|
|
96
|
+
logger.log(chalk.white(` Failures (first ${MAX_FAILURE_LINES})`));
|
|
97
|
+
samples.forEach(({ key, message }) => {
|
|
98
|
+
logger.log(` • ${key} — ${message}`);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function displayLoadVerdict(result) {
|
|
103
|
+
const failed = result.totals.failedCount || 0;
|
|
104
|
+
const ok = result.recordCount - failed;
|
|
105
|
+
if (failed > 0) {
|
|
106
|
+
if (result.batches && result.batches.length > 0) {
|
|
107
|
+
displayLoadFailureSamples(result.batches);
|
|
108
|
+
logger.log('');
|
|
109
|
+
}
|
|
110
|
+
logger.log(formatBlockingError(`${ok} ok · ${failed} failed`));
|
|
111
|
+
} else {
|
|
112
|
+
logger.log(
|
|
113
|
+
formatSuccessLine(
|
|
114
|
+
`${result.recordCount} processed · ${result.totals.insertedCount} inserted · ${result.totals.updatedCount} updated · 0 failed`
|
|
115
|
+
)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @param {Object} result
|
|
122
|
+
*/
|
|
123
|
+
function logLoadDurationFooter(result) {
|
|
124
|
+
if (result.durationMs === undefined || result.durationMs === null) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
logger.log(metaGray(` Completed in ${formatElapsedMs(result.durationMs)}`));
|
|
128
|
+
logger.log('');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {Object} result
|
|
133
|
+
* @param {Object} opts
|
|
134
|
+
*/
|
|
135
|
+
function displayLoadUploadSummary(result, opts) {
|
|
136
|
+
const batchCount = Math.ceil(result.recordCount / result.batchSize) || 0;
|
|
137
|
+
logger.log(
|
|
138
|
+
metaGray(
|
|
139
|
+
` Parsed: ${result.recordCount} records · format ${result.format} · est. ${batchCount} batch(es) @ ${result.batchSize}`
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
logger.log('');
|
|
143
|
+
if (opts.verbose) {
|
|
144
|
+
displayLoadBatchesVerbose(result.batches);
|
|
145
|
+
logger.log('');
|
|
146
|
+
}
|
|
147
|
+
displayLoadVerdict(result);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param {Object} result
|
|
152
|
+
* @param {Object} opts
|
|
153
|
+
*/
|
|
154
|
+
function displayDatasourceLoadTTY(result, opts = {}) {
|
|
155
|
+
const ctx = result.context || {};
|
|
156
|
+
logLoadHeader(ctx, opts.environment);
|
|
157
|
+
logger.log(metaGray(` Data file: ${result.file}`));
|
|
158
|
+
logger.log('');
|
|
159
|
+
|
|
160
|
+
if (result.dryRun) {
|
|
161
|
+
displayLoadDryRun(result);
|
|
162
|
+
logLoadDurationFooter(result);
|
|
163
|
+
logger.log(SEP);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
displayLoadUploadSummary(result, opts);
|
|
168
|
+
logLoadDurationFooter(result);
|
|
169
|
+
logger.log(SEP);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = {
|
|
173
|
+
displayDatasourceLoadTTY
|
|
174
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Spinner + elapsed time for datasource load/export (plan 144)
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('./logger');
|
|
11
|
+
const { formatProgress } = require('./cli-test-layout-chalk');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {number} ms
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
function formatElapsedMs(ms) {
|
|
18
|
+
const n = Math.max(0, Math.round(Number(ms) || 0));
|
|
19
|
+
if (n < 1000) {
|
|
20
|
+
return `${n} ms`;
|
|
21
|
+
}
|
|
22
|
+
if (n < 60000) {
|
|
23
|
+
const sec = n / 1000;
|
|
24
|
+
return sec >= 10 ? `${Math.round(sec)} s` : `${sec.toFixed(1)} s`;
|
|
25
|
+
}
|
|
26
|
+
const min = Math.floor(n / 60000);
|
|
27
|
+
const sec = Math.round((n % 60000) / 1000);
|
|
28
|
+
return sec > 0 ? `${min} m ${sec} s` : `${min} m`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {Object} [options]
|
|
33
|
+
* @param {boolean} [options.json]
|
|
34
|
+
* @returns {boolean}
|
|
35
|
+
*/
|
|
36
|
+
function shouldShowDatasourceLoadExportProgress(options = {}) {
|
|
37
|
+
return options.json !== true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {Object} [options]
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
function shouldUseDatasourceLoadExportSpinner(options = {}) {
|
|
45
|
+
if (!shouldShowDatasourceLoadExportProgress(options)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return Boolean(process && process.stdout && process.stdout.isTTY);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {string} operation
|
|
53
|
+
* @param {string} datasourceKey
|
|
54
|
+
* @returns {string}
|
|
55
|
+
*/
|
|
56
|
+
function buildDatasourceLoadExportSpinnerLabel(operation, datasourceKey) {
|
|
57
|
+
const key =
|
|
58
|
+
datasourceKey && String(datasourceKey).trim() ? String(datasourceKey).trim() : 'datasource';
|
|
59
|
+
if (operation === 'export') {
|
|
60
|
+
return `Exporting records for ${key}…`;
|
|
61
|
+
}
|
|
62
|
+
if (operation === 'load-dry-run') {
|
|
63
|
+
return `Parsing records for ${key}…`;
|
|
64
|
+
}
|
|
65
|
+
return `Loading records for ${key} into dataplane…`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @param {string} operation
|
|
70
|
+
* @param {string} datasourceKey
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
function buildDatasourceLoadExportProgressText(operation, datasourceKey) {
|
|
74
|
+
return formatProgress(buildDatasourceLoadExportSpinnerLabel(operation, datasourceKey));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @async
|
|
79
|
+
* @param {Function} work
|
|
80
|
+
* @param {Object} [opts]
|
|
81
|
+
* @param {'load'|'load-dry-run'|'export'} [opts.operation]
|
|
82
|
+
* @param {string} [opts.datasourceKey]
|
|
83
|
+
* @param {boolean} [opts.json]
|
|
84
|
+
* @returns {Promise<*>}
|
|
85
|
+
*/
|
|
86
|
+
async function runWithDatasourceLoadExportSpinner(work, opts = {}) {
|
|
87
|
+
if (!shouldShowDatasourceLoadExportProgress(opts)) {
|
|
88
|
+
return work();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const operation = opts.operation || 'load';
|
|
92
|
+
const datasourceKey = opts.datasourceKey || '';
|
|
93
|
+
|
|
94
|
+
if (!shouldUseDatasourceLoadExportSpinner(opts)) {
|
|
95
|
+
logger.log(buildDatasourceLoadExportProgressText(operation, datasourceKey));
|
|
96
|
+
return work();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const ora = require('ora');
|
|
100
|
+
const label = buildDatasourceLoadExportSpinnerLabel(operation, datasourceKey);
|
|
101
|
+
const spinner = ora({
|
|
102
|
+
text: chalk.white(label),
|
|
103
|
+
spinner: 'dots'
|
|
104
|
+
}).start();
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
return await work();
|
|
108
|
+
} finally {
|
|
109
|
+
spinner.stop();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
formatElapsedMs,
|
|
115
|
+
shouldShowDatasourceLoadExportProgress,
|
|
116
|
+
shouldUseDatasourceLoadExportSpinner,
|
|
117
|
+
buildDatasourceLoadExportSpinnerLabel,
|
|
118
|
+
buildDatasourceLoadExportProgressText,
|
|
119
|
+
runWithDatasourceLoadExportSpinner
|
|
120
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Single-capability CLI contract when
|
|
2
|
+
* @fileoverview Single-capability CLI contract when positional [capabilityKey] is set.
|
|
3
3
|
* @author AI Fabrix Team
|
|
4
4
|
* @version 2.0.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @param {Object|null|undefined} envelope - DatasourceTestRun-like
|
|
9
|
-
* @param {string|undefined|null} requestedCapabilityKey - From
|
|
9
|
+
* @param {string|undefined|null} requestedCapabilityKey - From positional [capabilityKey]
|
|
10
10
|
* @returns {{ violated: boolean, message?: string, count?: number }}
|
|
11
11
|
*/
|
|
12
12
|
function analyzeCapabilityScope(envelope, requestedCapabilityKey) {
|
|
@@ -34,7 +34,7 @@ function analyzeCapabilityScope(envelope, requestedCapabilityKey) {
|
|
|
34
34
|
return {
|
|
35
35
|
violated: true,
|
|
36
36
|
count: caps.length,
|
|
37
|
-
message: `Capabilities scope: with
|
|
37
|
+
message: `Capabilities scope: with capabilityKey "${key}", expected a single row in capabilities[]; server returned ${caps.length} (${preview}${suffix}).`
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -98,7 +98,7 @@ function colorStepLine(ok, body) {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
* Normalize
|
|
101
|
+
* Normalize positional [capabilityKey] for matching envelope.capabilities[].key
|
|
102
102
|
* @param {*} focusCapabilityKey
|
|
103
103
|
* @returns {string} trimmed or ''
|
|
104
104
|
*/
|
|
@@ -354,7 +354,7 @@ function pickExecutiveVerdictLine(envelope) {
|
|
|
354
354
|
}
|
|
355
355
|
|
|
356
356
|
/**
|
|
357
|
-
* Plan §3.9: explicit line when E2E has no capability rows (skipped when
|
|
357
|
+
* Plan §3.9: explicit line when E2E has no capability rows (skipped when capability drill-down is active).
|
|
358
358
|
* @param {string[]} lines
|
|
359
359
|
* @param {Object} envelope
|
|
360
360
|
* @param {{ focusCapabilityKey?: string }} [options]
|
|
@@ -428,7 +428,7 @@ function formatDatasourceTestRunSummary(envelope, options = {}) {
|
|
|
428
428
|
* focusCapabilityKey?: string,
|
|
429
429
|
* includeRefs?: boolean,
|
|
430
430
|
* includeDebugExecutionSummary?: boolean
|
|
431
|
-
* }} [options] - When focusCapabilityKey set (
|
|
431
|
+
* }} [options] - When focusCapabilityKey set (positional [capabilityKey]), append single-cap block (plan §2.3).
|
|
432
432
|
* includeDebugExecutionSummary: show dataplane `debug.executionSummary` in header (TTY debug appendix uses CLI `--debug`).
|
|
433
433
|
* @returns {string}
|
|
434
434
|
*/
|
|
@@ -49,7 +49,11 @@ function printDatasourceTestRunForTTY(envelope, options = {}) {
|
|
|
49
49
|
includeDebugExecutionSummary: Boolean(mode)
|
|
50
50
|
};
|
|
51
51
|
if (options.json) {
|
|
52
|
-
|
|
52
|
+
const payload =
|
|
53
|
+
options.auditEvidenceVerification && typeof options.auditEvidenceVerification === 'object'
|
|
54
|
+
? { ...envelope, auditEvidenceVerification: options.auditEvidenceVerification }
|
|
55
|
+
: envelope;
|
|
56
|
+
logger.log(JSON.stringify(payload));
|
|
53
57
|
return;
|
|
54
58
|
}
|
|
55
59
|
if (options.summary) {
|