@aifabrix/builder 2.55.2 → 2.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/agent-kit/session-report.js +76 -0
- package/lib/agent-kit/start.js +124 -57
- package/lib/agent-kit/tmux-sessions.js +163 -0
- package/lib/api/environments.api.js +38 -0
- package/lib/api/marketplace-bootstrap.api.js +31 -0
- package/lib/api/pipeline.api.js +32 -3
- package/lib/app/deploy.js +6 -5
- package/lib/cli/setup-app.js +7 -6
- package/lib/cli/setup-environment.js +76 -19
- package/lib/cli/setup-external-system-help.js +15 -3
- package/lib/cli/setup-external-system.js +21 -3
- package/lib/commands/agent-kit-help.js +32 -15
- package/lib/commands/agent-kit.js +90 -8
- package/lib/commands/repair-datasource-auto-rbac.js +4 -9
- package/lib/commands/upload-openapi-sync-followup.js +59 -0
- package/lib/commands/upload-qualification-client.js +131 -0
- package/lib/commands/upload-qualification-followups.js +104 -0
- package/lib/commands/upload-qualification-poll.js +143 -0
- package/lib/commands/upload.js +37 -156
- package/lib/deployment/deploy-poll-ui.js +14 -10
- package/lib/deployment/deployer-status.js +4 -4
- package/lib/deployment/installation/azure-infra-stage.js +160 -0
- package/lib/deployment/installation/azure-preflight.js +102 -0
- package/lib/deployment/installation/azure-readiness.js +71 -0
- package/lib/deployment/installation/docker-register.js +112 -0
- package/lib/deployment/installation/environment-auth.js +76 -0
- package/lib/deployment/installation/environment-manifest.js +165 -0
- package/lib/deployment/installation/environment-stage.js +191 -0
- package/lib/deployment/installation/index.js +39 -0
- package/lib/deployment/installation/infra-catalog.js +165 -0
- package/lib/deployment/installation/infra-manifest.js +161 -0
- package/lib/deployment/installation/infra-projection.js +86 -0
- package/lib/deployment/installation/public-ip.js +65 -0
- package/lib/deployment/installation/stage-input.js +169 -0
- package/lib/deployment/installation/stage-output.js +53 -0
- package/lib/deployment/installation/workspace-env.js +76 -0
- package/lib/deployment/installation/workspace-files.js +178 -0
- package/lib/deployment/installation/workspace-schema.js +40 -0
- package/lib/deployment/installation/workspace-secrets.js +66 -0
- package/lib/deployment/installation/workspace.js +128 -0
- package/lib/deployment/marketplace-environment.js +305 -0
- package/lib/external-system/deploy.js +46 -51
- package/lib/generator/builders.js +4 -0
- package/lib/generator/helpers.js +55 -99
- package/lib/generator/index.js +0 -4
- package/lib/generator/split-variables.js +11 -5
- package/lib/internal/fs-real-sync.js +29 -0
- package/lib/programmatic/builder-api-request.js +8 -4
- package/lib/programmatic/capability-registry.js +2 -0
- package/lib/programmatic/get-deploy-status.js +45 -0
- package/lib/programmatic/get-upload-status.js +45 -0
- package/lib/programmatic/http-accepted-response.js +31 -0
- package/lib/programmatic/openapi-descriptions.js +14 -4
- package/lib/programmatic/request-timeout.js +21 -15
- package/lib/programmatic/route-handler-map.js +6 -0
- package/lib/programmatic/run-deploy.js +7 -3
- package/lib/programmatic/run-upload.js +11 -7
- package/lib/role-assistant/package-validate.js +4 -0
- package/lib/role-assistant/test-runner-clarification-resubmit.js +149 -0
- package/lib/role-assistant/test-runner.js +14 -17
- package/lib/schema/application-schema.json +20 -2
- package/lib/schema/infra-parameter.schema.json +7 -0
- package/lib/schema/infra.parameter.yaml +32 -43
- package/lib/schema/infrastructure-schema.json +1480 -399
- package/lib/schema/installation-environment.schema.json +601 -0
- package/lib/utils/cli-utils.js +3 -2
- package/lib/utils/qualification-poll-ui.js +136 -0
- package/lib/utils/variable-transformer.js +3 -0
- package/lib/validation/required-variables.js +41 -0
- package/lib/validation/validator.js +8 -5
- package/package.json +7 -2
- package/templates/README.md +4 -0
- package/templates/agent-kit/instructions/AGENTKIT.md +6 -6
- package/templates/agent-kit/skills/shared/hosts.md +10 -10
- package/templates/applications/builder-api/env.template +4 -0
- package/templates/applications/dataplane/application.yaml +1 -1
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/keycloak/Dockerfile +12 -5
- package/templates/applications/keycloak/application.yaml +2 -2
- package/templates/applications/keycloak/cimd-lenient-parse/AbstractClientIdMetadataDocumentExecutor.java +3 -3
- package/templates/applications/keycloak/cimd-lenient-parse/SOURCE.md +6 -6
- package/templates/applications/keycloak/env.template +13 -1
- package/templates/applications/miso-controller/application.yaml +3 -2
- package/templates/applications/miso-controller/env.template +28 -22
- package/templates/marketplace/createUiDefinition.json +77 -0
- package/templates/marketplace/install.parameters.example.json +9 -0
- package/templates/marketplace/main.json +4087 -0
- package/lib/generator/deploy-manifest-azure-kv.js +0 -81
package/lib/cli/setup-app.js
CHANGED
|
@@ -56,20 +56,21 @@ Examples:
|
|
|
56
56
|
--client-id "$DEV_MISO_CLIENTID" \\
|
|
57
57
|
--client-secret "$DEV_MISO_CLIENTSECRET"
|
|
58
58
|
|
|
59
|
-
# CI/CD — external integration (
|
|
59
|
+
# CI/CD — external integration (qualify once via upload, then fast promote via deploy)
|
|
60
60
|
$ aifabrix validate hubspot-demo
|
|
61
61
|
$ aifabrix upload hubspot-demo --probe
|
|
62
62
|
$ aifabrix deploy hubspot-demo --probe -v
|
|
63
|
-
# Prove pillars in tst/CI, then promote (plain deploy seals cert on published Deploy)
|
|
64
|
-
$ aifabrix deploy ek-sales --gate full --subject-email ops@example.com
|
|
65
63
|
$ aifabrix deploy ek-sales
|
|
66
64
|
|
|
67
65
|
Notes:
|
|
68
66
|
- Login or set MISO_CONTROLLER_URL + environment (aifabrix login / aifabrix auth).
|
|
69
67
|
- CI: register once (aifabrix app register <appKey>), store DEV_MISO_CLIENTID and DEV_MISO_CLIENTSECRET in pipeline secrets.
|
|
70
|
-
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
- For Connected Systems, upload validates, publishes, and finalizes the system; optional
|
|
69
|
+
checks run only with upload --gate. Deploy promotes the completed upload — the
|
|
70
|
+
server decides this automatically, no flag needed. A system that has never been uploaded
|
|
71
|
+
falls back to the full legacy ladder at deploy time instead.
|
|
72
|
+
- --gate is a no-op on deploy (kept for compatibility; prints a notice) — gates now run once
|
|
73
|
+
during "aifabrix upload", not at deploy time.
|
|
73
74
|
- Default output is a compact status card; use -v for expanded preflight and readiness detail.
|
|
74
75
|
- Controller deploy always polls to a terminal status (no --poll / --no-poll on this command).
|
|
75
76
|
- --repository-url overrides repo URL for pipeline validate (default: application.yaml repository.repositoryUrl).
|
|
@@ -7,39 +7,95 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
+
const { formatWarningLine } = require('../utils/cli-test-layout-chalk');
|
|
11
|
+
const { isWorkspaceMode, isLegacyMarketplaceMode } = require('../deployment/installation/stage-input');
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
|
-
*
|
|
13
|
-
* @param {Command}
|
|
14
|
+
* Adds installation workspace and deprecated explicit Marketplace options.
|
|
15
|
+
* @param {Command} command - Commander command
|
|
16
|
+
* @returns {Command} The command
|
|
14
17
|
*/
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
function addMarketplaceOptions(command) {
|
|
19
|
+
return command
|
|
20
|
+
.option('--stage <stage>', 'Installation workspace stage: register, infra, dev, tst or pro (<env> is then the resource group)')
|
|
21
|
+
.option('--vendor <vendor>', 'Installation vendor: AZURE (default) or DOCKER (register only)')
|
|
22
|
+
.option('--allow-my-ip', 'Allow the caller public IPv4 /32 to reach PostgreSQL, Key Vault and Storage (infra only; default off)')
|
|
23
|
+
.option('--license-edition <edition>', 'License requested at activation: COMMUNITY, STANDARD, ENTERPRISE or a Marketplace subscription ID (infra only; saved in the workspace)')
|
|
24
|
+
.option('--miso-api-key-env <name>', 'Environment variable holding a temporary Miso API key (dev, tst, pro)')
|
|
25
|
+
.option('--controller-url <url>', 'Controller URL override for dev, tst or pro (deprecated platform stage also uses it)')
|
|
26
|
+
.option('--marketplace-json <file>', 'Deprecated explicit mode: ARM Marketplace infrastructure template')
|
|
27
|
+
.option('--parameters <file>', 'Deprecated explicit mode: secure ARM deploymentParameters JSON file')
|
|
28
|
+
.option('--subscription <id>', 'Deprecated explicit mode: Azure subscription ID')
|
|
29
|
+
.option('--resource-group <name>', 'Deprecated explicit mode: new isolated Azure resource group')
|
|
30
|
+
.option('--install-id <id>', 'Deprecated explicit mode: installation ID and resume-journal key')
|
|
31
|
+
.option('--location <region>', 'Deprecated explicit mode: Azure region when not set in the parameter file');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function runLegacyMarketplace(envKey, options) {
|
|
35
|
+
process.stderr.write(`${formatWarningLine('Explicit Marketplace flags are deprecated; use af env deploy <resource-group> --stage infra')}\n`);
|
|
36
|
+
const installer = require('../deployment/marketplace-environment');
|
|
37
|
+
const result = await installer.deployMarketplaceEnvironment(envKey, options);
|
|
38
|
+
if (result.platformComplete) {
|
|
39
|
+
process.stdout.write(`Platform ready: ${result.publicControllerUrl}\n`);
|
|
40
|
+
} else {
|
|
41
|
+
process.stdout.write(`Infrastructure deployed: ${result.outputs.webAppUrl} (deployment ${result.deploymentId})\n`);
|
|
42
|
+
process.stdout.write(`Resume after controller login and wizard activation: af env deploy ${envKey} --install-id ${result.installId} --controller-url https://<ready-public-host>/miso --stage platform\n`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function runInstallationStage(resourceGroup, options) {
|
|
47
|
+
const { deployInstallationStage } = require('../deployment/installation');
|
|
48
|
+
const { formatStageResult } = require('../deployment/installation/stage-output');
|
|
49
|
+
const result = await deployInstallationStage(resourceGroup, options);
|
|
50
|
+
process.stdout.write(formatStageResult(result, resourceGroup));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function deployEnvHandler(envKey, options) {
|
|
54
|
+
try {
|
|
55
|
+
if (isWorkspaceMode(options)) {
|
|
56
|
+
await runInstallationStage(envKey, options);
|
|
57
|
+
} else if (isLegacyMarketplaceMode(options)) {
|
|
58
|
+
await runLegacyMarketplace(envKey, options);
|
|
59
|
+
} else {
|
|
18
60
|
const environmentDeploy = require('../deployment/environment');
|
|
19
61
|
await environmentDeploy.deployEnvironment(envKey, options);
|
|
20
|
-
} catch (error) {
|
|
21
|
-
handleCommandError(error, 'env deploy');
|
|
22
|
-
process.exit(1);
|
|
23
62
|
}
|
|
24
|
-
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
handleCommandError(error, 'env deploy');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
25
68
|
|
|
26
|
-
|
|
69
|
+
const DEPLOY_EXAMPLES = `
|
|
27
70
|
Examples:
|
|
28
71
|
$ aifabrix env deploy dev
|
|
29
72
|
$ aifabrix env deploy tst
|
|
30
73
|
$ aifabrix env deploy pro --preset m
|
|
31
|
-
$ aifabrix env deploy dev --preset xl
|
|
32
74
|
$ aifabrix env deploy dev --config ./env-config.json
|
|
33
75
|
$ aifabrix env deploy dev --no-poll
|
|
34
76
|
|
|
35
|
-
|
|
77
|
+
Installation workspace (<env> is the resource group; files under infrastructure/<resource-group>/):
|
|
78
|
+
$ af env deploy <resource-group> --stage infra
|
|
79
|
+
$ af env deploy <resource-group> --stage infra --allow-my-ip
|
|
80
|
+
$ af env deploy <resource-group> --stage infra --license-edition ENTERPRISE
|
|
81
|
+
$ af env deploy <resource-group> --stage dev
|
|
82
|
+
$ af env deploy <resource-group> --stage pro --preset m
|
|
83
|
+
$ af env deploy <resource-group> --stage register --vendor DOCKER
|
|
84
|
+
|
|
85
|
+
Vendor/stage matrix:
|
|
86
|
+
AZURE infra, dev, tst, pro (Mori bootstrap runs inside the Marketplace template)
|
|
87
|
+
DOCKER register only (deploy with aifabrix setup)
|
|
88
|
+
|
|
89
|
+
Prerequisites: aifabrix login (controller permission controller:deploy); infra also needs az login.
|
|
36
90
|
Environment keys: miso, dev, tst, pro. Default size preset: s (use --preset s|m|l|xl).
|
|
91
|
+
Tenant activation after infra is a manual step in the Miso web application.
|
|
37
92
|
Run this before aifabrix deploy <app> — the environment must exist first.`;
|
|
38
93
|
|
|
39
|
-
|
|
94
|
+
const ENV_GROUP_HELP_AFTER = `
|
|
40
95
|
Examples:
|
|
41
96
|
$ aifabrix env deploy dev
|
|
42
97
|
$ aifabrix env deploy dev --preset m
|
|
98
|
+
$ af env deploy <resource-group> --stage infra
|
|
43
99
|
$ aifabrix env deploy dev --help
|
|
44
100
|
|
|
45
101
|
Typical workflow:
|
|
@@ -51,21 +107,22 @@ Subcommands:
|
|
|
51
107
|
deploy <env> Provision/update environment in Miso Controller (see env deploy --help)
|
|
52
108
|
`;
|
|
53
109
|
|
|
110
|
+
function setupEnvironmentCommands(program) {
|
|
54
111
|
const env = program
|
|
55
112
|
.command('env')
|
|
56
113
|
.description('Miso Controller environments (primary: env deploy <env>)')
|
|
57
114
|
.addHelpText('after', ENV_GROUP_HELP_AFTER);
|
|
58
115
|
|
|
59
|
-
env
|
|
116
|
+
addMarketplaceOptions(env
|
|
60
117
|
.command('deploy <env>')
|
|
61
|
-
.description('Deploy environment infrastructure in Miso Controller
|
|
118
|
+
.description('Deploy environment infrastructure in Miso Controller, or an installation workspace stage with --stage')
|
|
62
119
|
.option('--config <file>', 'Environment configuration file (optional if --preset is used)')
|
|
63
|
-
.option('--preset <size>', 'Environment size preset: s, m, l, xl (default: s
|
|
120
|
+
.option('--preset <size>', 'Environment size preset: s, m, l, xl (default: s, or the workspace file value)')
|
|
64
121
|
.option('--skip-validation', 'Skip environment validation')
|
|
65
122
|
.option('--poll', 'Poll for deployment status', true)
|
|
66
|
-
.option('--no-poll', 'Do not poll for status')
|
|
67
|
-
.addHelpText('after',
|
|
123
|
+
.option('--no-poll', 'Do not poll for status'))
|
|
124
|
+
.addHelpText('after', DEPLOY_EXAMPLES)
|
|
68
125
|
.action(deployEnvHandler);
|
|
69
126
|
}
|
|
70
127
|
|
|
71
|
-
module.exports = { setupEnvironmentCommands };
|
|
128
|
+
module.exports = { setupEnvironmentCommands, deployEnvHandler, addMarketplaceOptions };
|
|
@@ -6,11 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
const UPLOAD_HELP_AFTER = `
|
|
8
8
|
Examples:
|
|
9
|
-
#
|
|
9
|
+
# Upload and wait for completion
|
|
10
10
|
$ aifabrix upload hubspot-demo
|
|
11
11
|
$ aifabrix upload hubspot-demo -v
|
|
12
12
|
$ aifabrix upload hubspot-demo --probe
|
|
13
|
-
$ aifabrix upload hubspot-demo --
|
|
13
|
+
$ aifabrix upload hubspot-demo --gate operations,trust
|
|
14
|
+
$ aifabrix upload hubspot-demo --gate full --subject-email user@example.com
|
|
15
|
+
|
|
16
|
+
# Queue the upload and return immediately (script/CI-friendly)
|
|
17
|
+
$ aifabrix upload hubspot-demo --no-wait
|
|
18
|
+
|
|
19
|
+
# Resume watching an existing upload job (e.g. after Ctrl-C or a closed terminal)
|
|
20
|
+
$ aifabrix upload hubspot-demo --resume <jobId>
|
|
14
21
|
|
|
15
22
|
# Build and validate payload only (no API calls)
|
|
16
23
|
$ aifabrix upload hubspot-demo --dry-run
|
|
@@ -25,9 +32,14 @@ Examples:
|
|
|
25
32
|
Notes:
|
|
26
33
|
- Requires login (aifabrix auth status).
|
|
27
34
|
- Reads files under integration/<systemKey>/ or role-assistant/<roleKey>/ for digital workers.
|
|
35
|
+
- Upload validates, publishes, and finalizes the system. Operations, trust, and governance
|
|
36
|
+
checks are optional and run only when selected with --gate. The upload keeps running on
|
|
37
|
+
Dataplane even if this CLI process is interrupted, closed, or times out — --resume re-attaches
|
|
38
|
+
to it later, it is never re-submitted or lost.
|
|
28
39
|
- Default output is a compact readiness summary; use -v for expanded detail and server-side validate warnings.
|
|
29
40
|
- --probe runs dataplane runtime checks after publish (slower).
|
|
30
|
-
- --timeout
|
|
41
|
+
- --timeout bounds only how long this CLI waits before printing a resume hint
|
|
42
|
+
(default 1800000ms/30min); it does not stop the upload job.
|
|
31
43
|
- --env selects role-assistant.yaml section (dev|tst|pro) for digital workers; default dev.
|
|
32
44
|
- Role Assistant packages under role-assistant/ do not use application.yaml; upload applies settings and Evidence only.
|
|
33
45
|
- test-e2e and test-integration publish local files first by default; use --no-publish on those commands to skip.
|
|
@@ -50,7 +50,11 @@ async function handleUploadCommandAction(systemKey, options) {
|
|
|
50
50
|
options.probeTimeout === undefined || options.probeTimeout === null
|
|
51
51
|
? 120000
|
|
52
52
|
: Number(options.probeTimeout);
|
|
53
|
-
|
|
53
|
+
// Only resolve --timeout when the caller explicitly set it; leaving it undefined otherwise
|
|
54
|
+
// lets the qualification poll fall back to its own default (30min) instead of the legacy
|
|
55
|
+
// 300000ms HTTP/dataplane-publish budget default, which no longer applies to the async path.
|
|
56
|
+
const timeoutMs =
|
|
57
|
+
options.timeout !== undefined ? resolvePipelineUploadTimeoutMs(options.timeout) : undefined;
|
|
54
58
|
await upload.uploadExternalSystem(systemKey, {
|
|
55
59
|
...options,
|
|
56
60
|
probeTimeout: Number.isFinite(probeTimeout) ? probeTimeout : 120000,
|
|
@@ -101,9 +105,17 @@ function setupUploadCommand(program) {
|
|
|
101
105
|
.option('-v, --verbose', 'Expanded upload summary and server-side pipeline validate warnings before publish')
|
|
102
106
|
.option('--probe', 'After publish, run dataplane runtime checks (validation/run); slower')
|
|
103
107
|
.option('--probe-timeout <ms>', 'Timeout for --probe (default: 120000)', '120000')
|
|
108
|
+
.option(
|
|
109
|
+
'--gate <gates>',
|
|
110
|
+
'Optional upload checks (comma-separated): operations, trust, governance, full'
|
|
111
|
+
)
|
|
112
|
+
.option(
|
|
113
|
+
'--subject-email <emails>',
|
|
114
|
+
'Subject email(s) for governance checks (comma-separated; used with --gate governance|full)'
|
|
115
|
+
)
|
|
104
116
|
.option(
|
|
105
117
|
'--timeout <ms>',
|
|
106
|
-
'
|
|
118
|
+
'How long this CLI waits for the upload job before printing a resume hint (default: 1800000/30min; min 5000, max 2700000). The job keeps running regardless.'
|
|
107
119
|
)
|
|
108
120
|
.option(
|
|
109
121
|
'--force',
|
|
@@ -114,6 +126,12 @@ function setupUploadCommand(program) {
|
|
|
114
126
|
'Role Assistant settings environment section: dev, tst, or pro (default: dev)',
|
|
115
127
|
'dev'
|
|
116
128
|
)
|
|
129
|
+
.option('--wait', 'Wait for the upload job to complete (default)', true)
|
|
130
|
+
.option('--no-wait', 'Return the upload job id immediately without waiting')
|
|
131
|
+
.option(
|
|
132
|
+
'--resume <jobId>',
|
|
133
|
+
'Wait for an existing upload job instead of submitting again'
|
|
134
|
+
)
|
|
117
135
|
.action(async(systemKey, options) => {
|
|
118
136
|
try {
|
|
119
137
|
await handleUploadCommandAction(systemKey, options);
|
|
@@ -341,4 +359,4 @@ function setupExternalSystemCommands(program) {
|
|
|
341
359
|
setupExternalSystemTestCommands(program);
|
|
342
360
|
}
|
|
343
361
|
|
|
344
|
-
module.exports = { setupExternalSystemCommands };
|
|
362
|
+
module.exports = { setupExternalSystemCommands, handleUploadCommandAction };
|
|
@@ -21,9 +21,10 @@ Examples:
|
|
|
21
21
|
$ aifabrix agent-kit install --host all --approve-all claude --yes
|
|
22
22
|
$ aifabrix agent-kit update --host all --approve-all --yes
|
|
23
23
|
$ aifabrix agent-kit remote create --org my-org --yes
|
|
24
|
-
$ aifabrix agent-kit start claude
|
|
25
|
-
$ aifabrix agent-kit start
|
|
26
|
-
$ aifabrix agent-kit
|
|
24
|
+
$ aifabrix agent-kit start claude
|
|
25
|
+
$ aifabrix agent-kit start codex
|
|
26
|
+
$ aifabrix agent-kit list
|
|
27
|
+
$ aifabrix agent-kit kill aifabrix-docs
|
|
27
28
|
$ aifabrix agent-kit status
|
|
28
29
|
$ aifabrix agent-kit validate
|
|
29
30
|
`;
|
|
@@ -117,23 +118,37 @@ Interactive (TTY): omit flags to be prompted. Silent: --org <owner> --yes
|
|
|
117
118
|
const START_HELP = `
|
|
118
119
|
Does not install Agent Kit skills. Starts claude or codex in tmux in this git
|
|
119
120
|
workspace so closing the terminal does not kill the session. Detach: Ctrl-b then
|
|
120
|
-
d.
|
|
121
|
-
tmux session (default: last folder, e.g. aifabrix-docs).
|
|
122
|
-
--name and
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
d. The defaults enable that app's Remote Control and workspace auto-approval.
|
|
122
|
+
--name is the tmux session (default: last git-root folder, e.g. aifabrix-docs).
|
|
123
|
+
Claude gets --name and hostname-user-folder Remote Control. Codex uses its native
|
|
124
|
+
remote-control daemon. Use --no-remote-control and/or --skip-approve-all to opt
|
|
125
|
+
out. Claude --tmux is for worktrees, not this wrapper.
|
|
125
126
|
|
|
126
127
|
Examples:
|
|
127
|
-
$ aifabrix agent-kit start claude --remote-control --approve-all --yes
|
|
128
|
-
$ aifabrix agent-kit start claude --name aifabrix-docs --remote-control --approve-all --yes
|
|
129
|
-
$ aifabrix agent-kit start claude --name aifabrix-miso --remote-control --approve-all --yes
|
|
130
|
-
$ aifabrix agent-kit start claude --remote-control --detach
|
|
131
128
|
$ aifabrix agent-kit start claude
|
|
132
|
-
$ aifabrix agent-kit start
|
|
133
|
-
$ aifabrix agent-kit start
|
|
129
|
+
$ aifabrix agent-kit start codex
|
|
130
|
+
$ aifabrix agent-kit start claude --name aifabrix-miso
|
|
131
|
+
$ aifabrix agent-kit start codex --no-remote-control --skip-approve-all
|
|
132
|
+
$ aifabrix agent-kit start claude --detach
|
|
134
133
|
$ aifabrix agent-kit start claude --dry-run --json
|
|
135
134
|
`;
|
|
136
135
|
|
|
136
|
+
const LIST_HELP = `
|
|
137
|
+
Lists every active tmux session visible to the current Unix user.
|
|
138
|
+
|
|
139
|
+
Examples:
|
|
140
|
+
$ aifabrix agent-kit list
|
|
141
|
+
$ aifabrix agent-kit list --json
|
|
142
|
+
`;
|
|
143
|
+
|
|
144
|
+
const KILL_HELP = `
|
|
145
|
+
Stops exactly one tmux session. Use agent-kit list to find its name.
|
|
146
|
+
|
|
147
|
+
Examples:
|
|
148
|
+
$ aifabrix agent-kit kill aifabrix-miso
|
|
149
|
+
$ aifabrix agent-kit kill aifabrix-miso --json
|
|
150
|
+
`;
|
|
151
|
+
|
|
137
152
|
module.exports = {
|
|
138
153
|
HOST_OPTION_HELP,
|
|
139
154
|
APPROVE_ALL_OPTION_HELP,
|
|
@@ -145,5 +160,7 @@ module.exports = {
|
|
|
145
160
|
INIT_HELP,
|
|
146
161
|
REMOTE_GROUP_HELP,
|
|
147
162
|
REMOTE_HELP,
|
|
148
|
-
START_HELP
|
|
163
|
+
START_HELP,
|
|
164
|
+
LIST_HELP,
|
|
165
|
+
KILL_HELP
|
|
149
166
|
};
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `aifabrix agent-kit` command group.
|
|
3
|
-
* @fileoverview Install, init, status, update, validate, remote create, start
|
|
4
|
-
*/
|
|
1
|
+
/** `aifabrix agent-kit` command group. */
|
|
5
2
|
|
|
6
3
|
'use strict';
|
|
7
4
|
|
|
8
5
|
const logger = require('../utils/logger');
|
|
9
6
|
const { handleCommandError } = require('../utils/cli-utils');
|
|
10
|
-
const {
|
|
7
|
+
const {
|
|
8
|
+
formatSuccessLine,
|
|
9
|
+
formatBlockingError,
|
|
10
|
+
formatWarningLine
|
|
11
|
+
} = require('../utils/cli-layout-chalk');
|
|
11
12
|
const { runInstall, runUpdate } = require('../agent-kit/run');
|
|
12
13
|
const { runStart } = require('../agent-kit/start');
|
|
14
|
+
const { runList, runKill } = require('../agent-kit/tmux-sessions');
|
|
15
|
+
const { formatSessionList, formatMissingKillName } = require('../agent-kit/session-report');
|
|
13
16
|
const path = require('path');
|
|
14
17
|
const { runInit, runRemoteCreate } = require('../agent-kit/init');
|
|
15
18
|
const { enrichInitHostOptions, enrichInitRemoteOptions, enrichRemoteOptions, enrichApproveAllOptions } = require('../agent-kit/remote-prompts');
|
|
@@ -30,6 +33,8 @@ const {
|
|
|
30
33
|
REMOTE_GROUP_HELP,
|
|
31
34
|
REMOTE_HELP,
|
|
32
35
|
START_HELP,
|
|
36
|
+
LIST_HELP,
|
|
37
|
+
KILL_HELP,
|
|
33
38
|
HOST_OPTION_HELP,
|
|
34
39
|
APPROVE_ALL_OPTION_HELP
|
|
35
40
|
} = require('./agent-kit-help');
|
|
@@ -110,6 +115,8 @@ function emitStartReport(json, asJson) {
|
|
|
110
115
|
logger.log(`Session ${json.session}`);
|
|
111
116
|
if (json.remoteControlName) {
|
|
112
117
|
logger.log(`Remote ${json.remoteControlName}`);
|
|
118
|
+
} else if (json.remoteControl) {
|
|
119
|
+
logger.log('Remote Codex Remote Control');
|
|
113
120
|
}
|
|
114
121
|
logger.log(`Path ${json.path}`);
|
|
115
122
|
logger.log(`Launch ${json.launch.join(' ')}`);
|
|
@@ -124,6 +131,32 @@ function emitStartReport(json, asJson) {
|
|
|
124
131
|
logger.log(formatSuccessLine(json.dryRun ? 'Dry-run complete' : 'Ready'));
|
|
125
132
|
}
|
|
126
133
|
|
|
134
|
+
/**
|
|
135
|
+
* @param {object} json
|
|
136
|
+
* @param {boolean} asJson
|
|
137
|
+
* @returns {void}
|
|
138
|
+
*/
|
|
139
|
+
function emitListReport(json, asJson) {
|
|
140
|
+
if (asJson) {
|
|
141
|
+
logger.log(JSON.stringify(json, null, 2));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
logger.log(formatSessionList(json));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* @param {object} json
|
|
149
|
+
* @param {boolean} asJson
|
|
150
|
+
* @returns {void}
|
|
151
|
+
*/
|
|
152
|
+
function emitKillReport(json, asJson) {
|
|
153
|
+
if (asJson) {
|
|
154
|
+
logger.log(JSON.stringify(json, null, 2));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
logger.log(formatSuccessLine(`Stopped tmux session ${json.session}`));
|
|
158
|
+
}
|
|
159
|
+
|
|
127
160
|
/**
|
|
128
161
|
* @param {Function} runner
|
|
129
162
|
* @param {object} options
|
|
@@ -159,6 +192,8 @@ function setupAgentKitCommands(program) {
|
|
|
159
192
|
addValidateCommand(group);
|
|
160
193
|
addRemoteCommand(group);
|
|
161
194
|
addStartCommand(group);
|
|
195
|
+
addListCommand(group);
|
|
196
|
+
addKillCommand(group);
|
|
162
197
|
}
|
|
163
198
|
|
|
164
199
|
/**
|
|
@@ -387,8 +422,8 @@ async function runValidateLeaf(options) {
|
|
|
387
422
|
function addStartCommand(group) {
|
|
388
423
|
group
|
|
389
424
|
.command('start <app>')
|
|
390
|
-
.description('Start Claude Code or Codex
|
|
391
|
-
.option('--approve-all', 'Write auto-approve config for
|
|
425
|
+
.description('Start Claude Code or Codex with Remote Control in named tmux')
|
|
426
|
+
.option('--approve-all', 'Write auto-approve config (default for start)')
|
|
392
427
|
.option('--skip-approve-all', 'Do not write auto-approve configs')
|
|
393
428
|
.option('--yes', 'Same as --approve-all')
|
|
394
429
|
.option('--detach', 'Create the tmux session in the background (no attach)')
|
|
@@ -398,8 +433,10 @@ function addStartCommand(group) {
|
|
|
398
433
|
)
|
|
399
434
|
.option(
|
|
400
435
|
'--remote-control',
|
|
401
|
-
'
|
|
436
|
+
'Enable native Remote Control for Claude or Codex (default)',
|
|
437
|
+
true
|
|
402
438
|
)
|
|
439
|
+
.option('--no-remote-control', 'Start a local tmux-only session')
|
|
403
440
|
.option('--dry-run', 'Print the launch command without starting it')
|
|
404
441
|
.option('--json', 'Machine-readable output')
|
|
405
442
|
.addHelpText('after', START_HELP)
|
|
@@ -414,4 +451,49 @@ function addStartCommand(group) {
|
|
|
414
451
|
});
|
|
415
452
|
}
|
|
416
453
|
|
|
454
|
+
/**
|
|
455
|
+
* @param {import('commander').Command} group
|
|
456
|
+
*/
|
|
457
|
+
function addListCommand(group) {
|
|
458
|
+
group
|
|
459
|
+
.command('list')
|
|
460
|
+
.description('List active tmux sessions for the current user')
|
|
461
|
+
.option('--json', 'Machine-readable output')
|
|
462
|
+
.addHelpText('after', LIST_HELP)
|
|
463
|
+
.action(async(options) => {
|
|
464
|
+
try {
|
|
465
|
+
emitListReport(runList(options), Boolean(options.json));
|
|
466
|
+
} catch (error) {
|
|
467
|
+
handleCommandError(error, 'agent-kit list');
|
|
468
|
+
process.exitCode = 1;
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* @param {import('commander').Command} group
|
|
475
|
+
*/
|
|
476
|
+
function addKillCommand(group) {
|
|
477
|
+
group
|
|
478
|
+
.command('kill [name]')
|
|
479
|
+
.description('Stop one tmux session by exact name')
|
|
480
|
+
.option('--json', 'Machine-readable output')
|
|
481
|
+
.addHelpText('after', KILL_HELP)
|
|
482
|
+
.action(async(name, options) => {
|
|
483
|
+
if (!name) {
|
|
484
|
+
const report = formatMissingKillName(Boolean(options.json));
|
|
485
|
+
logger.error(report.stderr);
|
|
486
|
+
if (report.stdout) logger.log(report.stdout);
|
|
487
|
+
process.exitCode = 1;
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
try {
|
|
491
|
+
emitKillReport(runKill({ ...options, name }), Boolean(options.json));
|
|
492
|
+
} catch (error) {
|
|
493
|
+
handleCommandError(error, 'agent-kit kill');
|
|
494
|
+
process.exitCode = 1;
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
417
499
|
module.exports = { setupAgentKitCommands };
|
|
@@ -34,18 +34,14 @@ function buildRenameMap(operationMap) {
|
|
|
34
34
|
if (!operationMap || typeof operationMap !== 'object' || Array.isArray(operationMap)) return {};
|
|
35
35
|
const renameMap = {};
|
|
36
36
|
for (const k of Object.keys(operationMap)) {
|
|
37
|
-
//
|
|
38
|
-
//
|
|
37
|
+
// Operation keys use the capability naming contract, which allows camelCase.
|
|
38
|
+
// RBAC permission names are normalized separately when permissions are generated.
|
|
39
39
|
if (/^[a-z][a-zA-Z0-9]*$/.test(k)) {
|
|
40
|
-
if (/[A-Z]/.test(k)) {
|
|
41
|
-
renameMap[k] = k.toLowerCase();
|
|
42
|
-
}
|
|
43
40
|
continue;
|
|
44
41
|
}
|
|
45
42
|
const camel = toCamelCaseKey(k);
|
|
46
43
|
if (!camel || camel === k) continue;
|
|
47
|
-
|
|
48
|
-
renameMap[k] = camel.toLowerCase();
|
|
44
|
+
renameMap[k] = camel;
|
|
49
45
|
}
|
|
50
46
|
return renameMap;
|
|
51
47
|
}
|
|
@@ -212,7 +208,7 @@ function normalizeAutoRbacOperationKeys(parsed, changes) {
|
|
|
212
208
|
if (updated && Array.isArray(changes)) {
|
|
213
209
|
const pairs = keysToRename.map((k) => `${k}→${renameMap[k]}`).join(', ');
|
|
214
210
|
changes.push(
|
|
215
|
-
`Normalized autoRbac operation keys (permission names
|
|
211
|
+
`Normalized schema-invalid autoRbac operation aliases to camelCase keys (RBAC permission names remain lowercase): ${pairs}`
|
|
216
212
|
);
|
|
217
213
|
}
|
|
218
214
|
|
|
@@ -224,4 +220,3 @@ module.exports = {
|
|
|
224
220
|
toCamelCaseKey,
|
|
225
221
|
toKebabAliasKey
|
|
226
222
|
};
|
|
227
|
-
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Post-publish local OpenAPI sync follow-up, shared by the synchronous and
|
|
3
|
+
* qualification-async upload paths (extracted from upload.js per plan 191.0 file-size gate).
|
|
4
|
+
* @author AI Fabrix Team
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const logger = require('../utils/logger');
|
|
11
|
+
const { formatSuccessLine, formatWarningLine } = require('../utils/cli-test-layout-chalk');
|
|
12
|
+
const { resolveExternalSystemPath } = require('../utils/app-path-resolve');
|
|
13
|
+
const { maybeSyncOpenApiFilesForMcp } = require('./repair-openapi-sync');
|
|
14
|
+
const { exportProgrammaticOpenApiForRepair } = require('./repair-openapi-export');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Upload local `integration/<systemKey>/openapi/*.json` specs when present so dataplane can store
|
|
18
|
+
* vendor OpenAPI keyed by each datasource `openapi.documentKey` (same behavior as repair --api OpenAPI sync).
|
|
19
|
+
* Call this **after** the external system row exists (successful publish or completed qualification):
|
|
20
|
+
* list/upload endpoints require it. First publish still succeeds because pipeline materializes
|
|
21
|
+
* internal specs from `openapi.operations` when needed.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} systemKey
|
|
24
|
+
* @param {Object} manifest
|
|
25
|
+
* @param {Object} [uploadContext]
|
|
26
|
+
* @returns {Promise<void>}
|
|
27
|
+
*/
|
|
28
|
+
async function logAndSyncLocalOpenApiForUpload(systemKey, manifest, uploadContext = {}) {
|
|
29
|
+
const pathOptions = uploadContext.pathOptions || {};
|
|
30
|
+
const appPath = resolveExternalSystemPath(systemKey, pathOptions);
|
|
31
|
+
const ei = manifest && manifest.externalIntegration;
|
|
32
|
+
const datasourceFiles = ei && Array.isArray(ei.dataSources) ? ei.dataSources : [];
|
|
33
|
+
await exportProgrammaticOpenApiForRepair({
|
|
34
|
+
appPath,
|
|
35
|
+
systemKey,
|
|
36
|
+
datasourceFiles,
|
|
37
|
+
dryRun: false,
|
|
38
|
+
backupCtx: { dryRun: false, changedFiles: [] }
|
|
39
|
+
});
|
|
40
|
+
const openapiSyncLines = await maybeSyncOpenApiFilesForMcp({
|
|
41
|
+
enabled: true,
|
|
42
|
+
dryRun: false,
|
|
43
|
+
appPath,
|
|
44
|
+
systemKey,
|
|
45
|
+
datasourceFiles,
|
|
46
|
+
dataplaneUrl: uploadContext.dataplaneUrl,
|
|
47
|
+
authConfig: uploadContext.authConfig,
|
|
48
|
+
// Always replace SpecFile rows keyed by openapi.documentKey so vendor/full
|
|
49
|
+
// specs are not left missing while only thin internal:* slices remain.
|
|
50
|
+
force: true
|
|
51
|
+
});
|
|
52
|
+
if (!uploadContext.quiet) {
|
|
53
|
+
for (const line of openapiSyncLines) {
|
|
54
|
+
logger.log(line.startsWith('Skipped') ? formatWarningLine(line) : formatSuccessLine(line));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = { logAndSyncLocalOpenApiForUpload };
|