@aifabrix/builder 2.55.0 → 2.56.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/host-approve.js +48 -6
- package/lib/agent-kit/init.js +2 -2
- package/lib/agent-kit/remote-prompts.js +46 -13
- package/lib/agent-kit/run.js +1 -1
- package/lib/agent-kit/start.js +310 -0
- package/lib/api/pipeline.api.js +32 -3
- package/lib/app/deploy.js +13 -9
- package/lib/app/offer-create-from-template.js +184 -0
- package/lib/cli/setup-app.js +15 -7
- package/lib/cli/setup-auth.js +11 -2
- 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 +74 -4
- package/lib/commands/agent-kit.js +83 -12
- package/lib/commands/auth-status-user.js +99 -0
- package/lib/commands/auth-status.js +14 -4
- package/lib/commands/datasource-load-export-cli.js +7 -2
- package/lib/commands/datasource-test-trust-cli.js +5 -1
- package/lib/commands/governance-command-action.js +5 -4
- package/lib/commands/identity-membership-role-cache.js +6 -1
- package/lib/commands/lifecycle-command-action.js +16 -15
- package/lib/commands/login-credentials.js +8 -3
- package/lib/commands/login-device.js +14 -5
- package/lib/commands/login.js +14 -1
- package/lib/commands/logout.js +50 -15
- package/lib/commands/repair-datasource-auto-rbac.js +4 -9
- package/lib/commands/role-assistant.js +24 -12
- 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/commands/verify-governance-command-action.js +9 -7
- package/lib/commands/verify-operations-command-action.js +9 -8
- package/lib/commands/verify-trust-command-action.js +6 -5
- package/lib/deployment/deploy-poll-ui.js +14 -10
- package/lib/deployment/deployer-status.js +4 -4
- package/lib/external-system/deploy.js +46 -51
- package/lib/external-system/download.js +1 -2
- package/lib/generator/helpers.js +14 -46
- package/lib/generator/index.js +0 -4
- package/lib/integration-definition/apply-static-enterprise.js +5 -2
- 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/knowledge-sync-settings-push.js +172 -0
- package/lib/role-assistant/knowledge-sync.js +9 -126
- package/lib/role-assistant/test-cases-evaluate.js +12 -1
- package/lib/role-assistant/test-cases-evidence.js +44 -5
- package/lib/role-assistant/test-cases-lifecycle.js +9 -3
- package/lib/role-assistant/test-runner.js +3 -0
- package/lib/schema/infra-parameter.schema.json +51 -3
- package/lib/schema/infra.parameter.yaml +482 -47
- package/lib/schema/type/document-storage.json +1 -1
- package/lib/utils/api-required-permissions.js +271 -0
- package/lib/utils/api.js +16 -13
- package/lib/utils/cli-json-exit.js +41 -0
- package/lib/utils/cli-utils.js +26 -7
- package/lib/utils/controller-url.js +78 -4
- package/lib/utils/deployment-errors.js +15 -0
- package/lib/utils/deployment-validation-helpers.js +4 -1
- package/lib/utils/device-code.js +31 -10
- package/lib/utils/error-formatters/error-parser.js +16 -1
- package/lib/utils/error-formatters/permission-errors.js +19 -5
- package/lib/utils/keycloak-realm-ready.js +5 -2
- package/lib/utils/logger.js +1 -0
- package/lib/utils/paths.js +26 -5
- package/lib/utils/qualification-poll-ui.js +136 -0
- package/lib/utils/secrets-helpers.js +2 -2
- package/lib/utils/write-stream-and-wait.js +63 -0
- package/package.json +22 -7
- package/templates/agent-kit/agent-kit.yaml +1 -1
- package/templates/agent-kit/instructions/AGENTKIT.md +25 -4
- package/templates/agent-kit/instructions/root.AGENTS.md +1 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +2 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +1 -1
- package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +2 -1
- package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +1 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +1 -0
- package/templates/agent-kit/skills/shared/hosts.md +13 -26
- package/templates/agent-kit/skills/shared/login.md +16 -0
- package/templates/agent-kit/workspace/README.md +1 -1
- package/templates/applications/builder-api/env.template +4 -0
- package/templates/applications/dataplane/application.yaml +1 -2
- package/templates/applications/dataplane/env.template +5 -5
- 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 +21 -2
- package/templates/applications/miso-controller/env.template +97 -28
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/lib/generator/deploy-manifest-azure-kv.js +0 -81
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offer to materialize a missing app from shipped application templates.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Interactive create-from-template before deploy when the app is not on disk
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const logger = require('../utils/logger');
|
|
12
|
+
const { metadata } = require('../utils/cli-test-layout-chalk');
|
|
13
|
+
const { listAvailableTemplates } = require('../validation/template');
|
|
14
|
+
const { findExistingAppType } = require('../utils/paths');
|
|
15
|
+
const { ensureAppFromTemplate } = require('../commands/up-common');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {Object} [options]
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
function assumeYesCreate(options = {}) {
|
|
22
|
+
return options.yes === true || options.assumeYes === true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {Object} [deps]
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
*/
|
|
29
|
+
function isInteractiveCreate(deps = {}) {
|
|
30
|
+
if (process.env.CI === 'true' || process.env.CI === '1') {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (typeof deps.isTty === 'function') {
|
|
34
|
+
return Boolean(deps.isTty());
|
|
35
|
+
}
|
|
36
|
+
return Boolean(process.stdin && process.stdin.isTTY);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {string[]} templates
|
|
41
|
+
* @returns {string}
|
|
42
|
+
*/
|
|
43
|
+
function formatTemplateNames(templates) {
|
|
44
|
+
return templates.join(', ');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {string} appName
|
|
49
|
+
* @param {string[]} templates
|
|
50
|
+
* @returns {Error}
|
|
51
|
+
*/
|
|
52
|
+
function buildMissingAppError(appName, templates) {
|
|
53
|
+
const listed = templates.length > 0
|
|
54
|
+
? `Shipped templates: ${formatTemplateNames(templates)}.`
|
|
55
|
+
: 'No shipped application templates were found.';
|
|
56
|
+
const hint = templates.includes(appName)
|
|
57
|
+
? `Create it with: aifabrix deploy ${appName} --yes`
|
|
58
|
+
: 'Pass a matching template name, or create the app first.';
|
|
59
|
+
return new Error(
|
|
60
|
+
`App '${appName}' was not found under integration/ or builder/. ${listed} ${hint}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {string} appName
|
|
66
|
+
* @param {Function} promptFn
|
|
67
|
+
* @returns {Promise<boolean>}
|
|
68
|
+
*/
|
|
69
|
+
async function confirmCreateMatchingTemplate(appName, promptFn) {
|
|
70
|
+
const ask = promptFn || ((qs) => require('inquirer').prompt(qs));
|
|
71
|
+
const { create } = await ask([{
|
|
72
|
+
type: 'confirm',
|
|
73
|
+
name: 'create',
|
|
74
|
+
message: `App '${appName}' is not available. Create it from the shipped '${appName}' template?`,
|
|
75
|
+
default: true
|
|
76
|
+
}]);
|
|
77
|
+
return Boolean(create);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {string[]} templates
|
|
82
|
+
* @param {Function} promptFn
|
|
83
|
+
* @returns {Promise<string|null>}
|
|
84
|
+
*/
|
|
85
|
+
async function pickShippedTemplate(templates, promptFn) {
|
|
86
|
+
const ask = promptFn || ((qs) => require('inquirer').prompt(qs));
|
|
87
|
+
const { template } = await ask([{
|
|
88
|
+
type: 'list',
|
|
89
|
+
name: 'template',
|
|
90
|
+
message: 'App was not found. Create from which shipped application template?',
|
|
91
|
+
choices: [
|
|
92
|
+
...templates.map((name) => ({ name, value: name })),
|
|
93
|
+
{ name: 'Cancel', value: null }
|
|
94
|
+
]
|
|
95
|
+
}]);
|
|
96
|
+
return template || null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @param {string} appName
|
|
101
|
+
* @param {Object} [deps]
|
|
102
|
+
* @returns {Promise<string>}
|
|
103
|
+
*/
|
|
104
|
+
async function materializeShippedTemplate(appName, deps = {}) {
|
|
105
|
+
const copy = deps.ensureAppFromTemplate || ensureAppFromTemplate;
|
|
106
|
+
await copy(appName);
|
|
107
|
+
return appName;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {string} appName
|
|
112
|
+
* @param {string[]} templates
|
|
113
|
+
* @param {Object} options
|
|
114
|
+
* @param {Object} deps
|
|
115
|
+
* @returns {Promise<string>}
|
|
116
|
+
*/
|
|
117
|
+
async function createMatchingTemplateApp(appName, templates, options, deps) {
|
|
118
|
+
if (assumeYesCreate(options)) {
|
|
119
|
+
return materializeShippedTemplate(appName, deps);
|
|
120
|
+
}
|
|
121
|
+
if (!isInteractiveCreate(deps)) {
|
|
122
|
+
throw buildMissingAppError(appName, templates);
|
|
123
|
+
}
|
|
124
|
+
const ok = await confirmCreateMatchingTemplate(appName, deps.prompt);
|
|
125
|
+
if (!ok) {
|
|
126
|
+
throw buildMissingAppError(appName, templates);
|
|
127
|
+
}
|
|
128
|
+
return materializeShippedTemplate(appName, deps);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {string} appName
|
|
133
|
+
* @param {string[]} templates
|
|
134
|
+
* @param {Object} options
|
|
135
|
+
* @param {Object} deps
|
|
136
|
+
* @returns {Promise<string>}
|
|
137
|
+
*/
|
|
138
|
+
async function createPickedTemplateApp(appName, templates, options, deps) {
|
|
139
|
+
if (assumeYesCreate(options) || !isInteractiveCreate(deps) || templates.length === 0) {
|
|
140
|
+
throw buildMissingAppError(appName, templates);
|
|
141
|
+
}
|
|
142
|
+
const chosen = await pickShippedTemplate(templates, deps.prompt);
|
|
143
|
+
if (!chosen) {
|
|
144
|
+
throw buildMissingAppError(appName, templates);
|
|
145
|
+
}
|
|
146
|
+
if (chosen !== appName) {
|
|
147
|
+
logger.log(metadata(
|
|
148
|
+
`Creating '${chosen}' from shipped template (requested '${appName}' was not found).`
|
|
149
|
+
));
|
|
150
|
+
}
|
|
151
|
+
await materializeShippedTemplate(chosen, deps);
|
|
152
|
+
return chosen;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* If the app is missing locally, offer to create it from shipped templates.
|
|
157
|
+
*
|
|
158
|
+
* @async
|
|
159
|
+
* @function offerCreateFromTemplateIfMissing
|
|
160
|
+
* @param {string} appName - Requested app or system key
|
|
161
|
+
* @param {Object} [options] - CLI options (`yes` skips the confirm when the name matches a template)
|
|
162
|
+
* @param {Object} [deps] - Test seams (prompt, isTty, listTemplates, findExisting, ensureAppFromTemplate)
|
|
163
|
+
* @returns {Promise<string>} App key to continue with (may differ if the user picked another template)
|
|
164
|
+
* @throws {Error} When the app is missing and the user declines or cannot be prompted
|
|
165
|
+
*/
|
|
166
|
+
async function offerCreateFromTemplateIfMissing(appName, options = {}, deps = {}) {
|
|
167
|
+
const findExisting = deps.findExisting || findExistingAppType;
|
|
168
|
+
if (findExisting(appName, options)) {
|
|
169
|
+
return appName;
|
|
170
|
+
}
|
|
171
|
+
const listTemplates = deps.listTemplates || listAvailableTemplates;
|
|
172
|
+
const templates = await listTemplates();
|
|
173
|
+
if (templates.includes(appName)) {
|
|
174
|
+
return createMatchingTemplateApp(appName, templates, options, deps);
|
|
175
|
+
}
|
|
176
|
+
return createPickedTemplateApp(appName, templates, options, deps);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
module.exports = {
|
|
180
|
+
offerCreateFromTemplateIfMissing,
|
|
181
|
+
buildMissingAppError,
|
|
182
|
+
assumeYesCreate,
|
|
183
|
+
isInteractiveCreate
|
|
184
|
+
};
|
package/lib/cli/setup-app.js
CHANGED
|
@@ -39,6 +39,10 @@ Examples:
|
|
|
39
39
|
$ aifabrix deploy myapp
|
|
40
40
|
$ aifabrix deploy myapp --local
|
|
41
41
|
|
|
42
|
+
# Missing local app that matches a shipped template (TTY asks to create)
|
|
43
|
+
$ aifabrix deploy dataplane
|
|
44
|
+
$ aifabrix deploy dataplane --yes
|
|
45
|
+
|
|
42
46
|
# Local — external system (integration/<systemKey>/); manifest regenerated on deploy
|
|
43
47
|
$ aifabrix deploy hubspot-demo
|
|
44
48
|
$ aifabrix deploy hubspot-demo --local
|
|
@@ -52,23 +56,25 @@ Examples:
|
|
|
52
56
|
--client-id "$DEV_MISO_CLIENTID" \\
|
|
53
57
|
--client-secret "$DEV_MISO_CLIENTSECRET"
|
|
54
58
|
|
|
55
|
-
# CI/CD — external integration (
|
|
59
|
+
# CI/CD — external integration (qualify once via upload, then fast promote via deploy)
|
|
56
60
|
$ aifabrix validate hubspot-demo
|
|
57
61
|
$ aifabrix upload hubspot-demo --probe
|
|
58
62
|
$ aifabrix deploy hubspot-demo --probe -v
|
|
59
|
-
# Prove pillars in tst/CI, then promote (plain deploy seals cert on published Deploy)
|
|
60
|
-
$ aifabrix deploy ek-sales --gate full --subject-email ops@example.com
|
|
61
63
|
$ aifabrix deploy ek-sales
|
|
62
64
|
|
|
63
65
|
Notes:
|
|
64
66
|
- Login or set MISO_CONTROLLER_URL + environment (aifabrix login / aifabrix auth).
|
|
65
67
|
- CI: register once (aifabrix app register <appKey>), store DEV_MISO_CLIENTID and DEV_MISO_CLIENTSECRET in pipeline secrets.
|
|
66
|
-
-
|
|
67
|
-
|
|
68
|
-
|
|
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.
|
|
69
74
|
- Default output is a compact status card; use -v for expanded preflight and readiness detail.
|
|
70
75
|
- Controller deploy always polls to a terminal status (no --poll / --no-poll on this command).
|
|
71
76
|
- --repository-url overrides repo URL for pipeline validate (default: application.yaml repository.repositoryUrl).
|
|
77
|
+
- If the app is missing locally and the name matches a shipped template, TTY asks to create it (use --yes in scripts).
|
|
72
78
|
`;
|
|
73
79
|
|
|
74
80
|
const PUSH_HELP_AFTER = `
|
|
@@ -367,6 +373,7 @@ function setupDeployCommand(program) {
|
|
|
367
373
|
'--subject-email <emails>',
|
|
368
374
|
'Subject email(s) for governance gate (comma-separated; used with --gate governance|full)'
|
|
369
375
|
)
|
|
376
|
+
.option('-y, --yes', 'Create a missing app from a matching shipped template without prompting')
|
|
370
377
|
.action(async(appName, options) => {
|
|
371
378
|
try {
|
|
372
379
|
const probeTimeout =
|
|
@@ -381,8 +388,9 @@ function setupDeployCommand(program) {
|
|
|
381
388
|
};
|
|
382
389
|
const outcome = await app.deployApp(appName, opts);
|
|
383
390
|
if (opts.local && outcome) {
|
|
391
|
+
const targetApp = outcome.appKey || appName;
|
|
384
392
|
if (outcome.usedExternalDeploy) await app.restartApp('dataplane');
|
|
385
|
-
else await app.runApp(
|
|
393
|
+
else await app.runApp(targetApp, opts);
|
|
386
394
|
}
|
|
387
395
|
} catch (error) {
|
|
388
396
|
handleCommandError(error, 'deploy');
|
package/lib/cli/setup-auth.js
CHANGED
|
@@ -17,7 +17,12 @@ const { handleAuthConfig } = require('../commands/auth-config');
|
|
|
17
17
|
const LOGIN_HELP_AFTER = `
|
|
18
18
|
Examples:
|
|
19
19
|
$ aifabrix login
|
|
20
|
+
$ aifabrix login -c https://controller.example.com
|
|
20
21
|
$ aifabrix login -m credentials -a myapp -e dev
|
|
22
|
+
|
|
23
|
+
Notes:
|
|
24
|
+
- Public controller URLs are stored as origin + /miso (extra path segments are ignored).
|
|
25
|
+
- Localhost URLs keep the origin unless the path is already /miso.
|
|
21
26
|
`;
|
|
22
27
|
|
|
23
28
|
const AUTH_HELP_AFTER = `
|
|
@@ -34,12 +39,15 @@ Subcommand: auth status [--validate] for CI/scripts (exit codes 0/1/3).
|
|
|
34
39
|
const LOGOUT_HELP_AFTER = `
|
|
35
40
|
Examples:
|
|
36
41
|
$ aifabrix logout
|
|
42
|
+
$ aifabrix logout --type client
|
|
43
|
+
$ aifabrix logout --type device
|
|
37
44
|
$ aifabrix logout -c http://localhost:3600
|
|
38
45
|
$ aifabrix logout -e dev
|
|
39
46
|
$ aifabrix logout -e dev -a hubspot-e2e
|
|
40
47
|
|
|
41
48
|
Notes:
|
|
42
49
|
- With no flags: clears all device tokens and all client tokens in config.yaml.
|
|
50
|
+
- Use --type client or --type device to clear only that token type.
|
|
43
51
|
- Device tokens are keyed by controller URL (-c).
|
|
44
52
|
- Client tokens are per environment and app (-e and optional -a).
|
|
45
53
|
- Run aifabrix auth status to list stored app tokens and copy-paste logout commands.
|
|
@@ -164,7 +172,7 @@ function setupLoginCommand(program) {
|
|
|
164
172
|
program.command('login')
|
|
165
173
|
.description('Sign in to Miso Controller (device or credentials flow)')
|
|
166
174
|
.addHelpText('after', LOGIN_HELP_AFTER)
|
|
167
|
-
.option('-c, --controller <url>', 'Controller URL (default:
|
|
175
|
+
.option('-c, --controller <url>', 'Controller URL (public hosts use origin + /miso; default: config or localhost by developer ID)')
|
|
168
176
|
.option('-m, --method <method>', 'Authentication method (device|credentials)', 'device')
|
|
169
177
|
.option('-a, --app <app>', 'Application name (required for credentials method, reads from secrets.local.yaml)')
|
|
170
178
|
.option('--client-id <id>', 'Client ID (for credentials method, overrides secrets.local.yaml)')
|
|
@@ -188,7 +196,8 @@ function setupLoginCommand(program) {
|
|
|
188
196
|
|
|
189
197
|
function setupLogoutCommand(program) {
|
|
190
198
|
program.command('logout')
|
|
191
|
-
.description('Clear stored tokens (optional filter by controller/env/app)')
|
|
199
|
+
.description('Clear stored tokens (optional filter by type/controller/env/app)')
|
|
200
|
+
.option('-t, --type <type>', 'Clear only one token type (device|client)')
|
|
192
201
|
.option('-c, --controller <url>', 'Clear device tokens for specific controller')
|
|
193
202
|
.option('-e, --environment <env>', 'Clear client tokens for specific environment')
|
|
194
203
|
.option('-a, --app <app>', 'Clear client tokens for specific app (requires --environment)')
|
|
@@ -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 };
|
|
@@ -5,24 +5,46 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
+
const HOST_OPTION_HELP =
|
|
9
|
+
'Coding hosts to activate: all, cursor, claude, or codex (one name = that host only)';
|
|
10
|
+
|
|
11
|
+
const APPROVE_ALL_OPTION_HELP =
|
|
12
|
+
'Auto-approve tools for all, claude, or codex (omit value = every selected host)';
|
|
13
|
+
|
|
8
14
|
const GROUP_HELP = `
|
|
15
|
+
Coding hosts (--host) are Cursor, Claude Code, and/or Codex in this workspace.
|
|
16
|
+
GitHub remotes are a separate command (agent-kit remote create).
|
|
17
|
+
|
|
9
18
|
Examples:
|
|
10
19
|
$ aifabrix agent-kit init cust-demo --host all --approve-all --yes
|
|
11
|
-
$ aifabrix agent-kit install --host
|
|
20
|
+
$ aifabrix agent-kit install --host claude --approve-all --yes
|
|
21
|
+
$ aifabrix agent-kit install --host all --approve-all claude --yes
|
|
12
22
|
$ aifabrix agent-kit update --host all --approve-all --yes
|
|
23
|
+
$ aifabrix agent-kit remote create --org my-org --yes
|
|
24
|
+
$ aifabrix agent-kit start claude --remote-control --approve-all --yes
|
|
25
|
+
$ aifabrix agent-kit start claude --name aifabrix-docs --remote-control --approve-all --yes
|
|
26
|
+
$ aifabrix agent-kit start codex --approve-all --yes
|
|
13
27
|
$ aifabrix agent-kit status
|
|
14
28
|
$ aifabrix agent-kit validate
|
|
15
29
|
`;
|
|
16
30
|
|
|
17
31
|
const INSTALL_HELP = `
|
|
32
|
+
--host chooses which coding apps this repo supports (default all).
|
|
33
|
+
Use one name to activate only that host. --approve-all [claude|codex] writes
|
|
34
|
+
auto-approve configs for that host's tools only.
|
|
35
|
+
|
|
18
36
|
Examples:
|
|
19
37
|
$ aifabrix agent-kit install
|
|
20
38
|
$ aifabrix agent-kit install --host all --approve-all --yes
|
|
21
39
|
$ aifabrix agent-kit install --host claude --approve-all --yes
|
|
40
|
+
$ aifabrix agent-kit install --host codex --approve-all --yes
|
|
41
|
+
$ aifabrix agent-kit install --host all --approve-all claude --yes
|
|
22
42
|
$ aifabrix agent-kit install --skip-approve-all
|
|
23
43
|
$ aifabrix agent-kit install --dry-run
|
|
24
44
|
|
|
25
|
-
TTY asks
|
|
45
|
+
TTY asks which hosts to support (omit --host) and which tools to auto-approve.
|
|
46
|
+
Silent: --host <name> --approve-all [claude|codex] --yes. Skip: --skip-approve-all.
|
|
47
|
+
Start without installing skills: aifabrix agent-kit start claude
|
|
26
48
|
`;
|
|
27
49
|
|
|
28
50
|
const STATUS_HELP = `
|
|
@@ -36,9 +58,12 @@ Examples:
|
|
|
36
58
|
$ aifabrix agent-kit update
|
|
37
59
|
$ aifabrix agent-kit update --host all --approve-all --yes
|
|
38
60
|
$ aifabrix agent-kit update --host claude --force
|
|
61
|
+
$ aifabrix agent-kit update --host all --approve-all claude --yes
|
|
39
62
|
$ aifabrix agent-kit update --dry-run
|
|
40
63
|
|
|
41
|
-
Omit --host to keep the coding hosts already recorded. Pass --host
|
|
64
|
+
Omit --host to keep the coding hosts already recorded. Pass --host claude or
|
|
65
|
+
--host codex to activate only that host. --approve-all claude writes Claude
|
|
66
|
+
Code tool auto-approve only.
|
|
42
67
|
`;
|
|
43
68
|
|
|
44
69
|
const VALIDATE_HELP = `
|
|
@@ -48,18 +73,39 @@ Examples:
|
|
|
48
73
|
`;
|
|
49
74
|
|
|
50
75
|
const INIT_HELP = `
|
|
76
|
+
--host chooses Cursor, Claude Code, and/or Codex for the new workspace.
|
|
77
|
+
GitHub (origin + push) is --remote / agent-kit remote create — not --host.
|
|
78
|
+
|
|
51
79
|
Examples:
|
|
52
80
|
$ aifabrix agent-kit init cust-demo
|
|
53
81
|
$ aifabrix agent-kit init cust-demo --host all --approve-all --yes
|
|
82
|
+
$ aifabrix agent-kit init cust-demo --host claude --approve-all --yes
|
|
83
|
+
$ aifabrix agent-kit init cust-demo --host all --approve-all claude --yes
|
|
54
84
|
$ aifabrix agent-kit init cust-demo --host all --remote --org my-org --yes
|
|
55
85
|
$ aifabrix agent-kit init ./path/to/cust-demo --dry-run --json
|
|
56
86
|
|
|
57
87
|
Interactive (TTY): omit --host / --yes to be prompted.
|
|
58
88
|
Silent local: --host all --approve-all --yes
|
|
89
|
+
Silent one host: --host claude --approve-all --yes
|
|
59
90
|
Silent remote: --host all --remote --org <owner> --yes
|
|
60
91
|
`;
|
|
61
92
|
|
|
93
|
+
const REMOTE_GROUP_HELP = `
|
|
94
|
+
This is GitHub only: create origin and push this workspace.
|
|
95
|
+
It does not choose Cursor, Claude Code, or Codex.
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
$ aifabrix agent-kit remote create
|
|
99
|
+
$ aifabrix agent-kit remote create --org my-org --yes
|
|
100
|
+
$ aifabrix agent-kit install --host claude --approve-all --yes
|
|
101
|
+
$ aifabrix agent-kit install --host codex --approve-all --yes
|
|
102
|
+
$ aifabrix agent-kit install --host all --approve-all claude --yes
|
|
103
|
+
`;
|
|
104
|
+
|
|
62
105
|
const REMOTE_HELP = `
|
|
106
|
+
Creates a GitHub repository (origin) and pushes this workspace.
|
|
107
|
+
Not coding-host selection — use --host on install/update for Claude or Codex.
|
|
108
|
+
|
|
63
109
|
Examples:
|
|
64
110
|
$ cd cust-demo && aifabrix agent-kit remote create
|
|
65
111
|
$ aifabrix agent-kit remote create --org my-org --yes
|
|
@@ -68,12 +114,36 @@ Examples:
|
|
|
68
114
|
Interactive (TTY): omit flags to be prompted. Silent: --org <owner> --yes
|
|
69
115
|
`;
|
|
70
116
|
|
|
117
|
+
const START_HELP = `
|
|
118
|
+
Does not install Agent Kit skills. Starts claude or codex in tmux in this git
|
|
119
|
+
workspace so closing the terminal does not kill the session. Detach: Ctrl-b then
|
|
120
|
+
d. --approve-all writes that app's local permission config only. --name is the
|
|
121
|
+
tmux session (default: last folder, e.g. aifabrix-docs). Claude also gets
|
|
122
|
+
--name and --remote-control hostname-user-folder, e.g.
|
|
123
|
+
builder01-dev03-aifabrix-docs. Claude --tmux is for worktrees, not this wrapper.
|
|
124
|
+
That is not Claude --cloud (a separate cloud VM). Codex has no phone/web attach.
|
|
125
|
+
|
|
126
|
+
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
|
+
$ aifabrix agent-kit start claude
|
|
132
|
+
$ aifabrix agent-kit start claude --approve-all --yes
|
|
133
|
+
$ aifabrix agent-kit start codex --approve-all --yes
|
|
134
|
+
$ aifabrix agent-kit start claude --dry-run --json
|
|
135
|
+
`;
|
|
136
|
+
|
|
71
137
|
module.exports = {
|
|
138
|
+
HOST_OPTION_HELP,
|
|
139
|
+
APPROVE_ALL_OPTION_HELP,
|
|
72
140
|
GROUP_HELP,
|
|
73
141
|
INSTALL_HELP,
|
|
74
142
|
STATUS_HELP,
|
|
75
143
|
UPDATE_HELP,
|
|
76
144
|
VALIDATE_HELP,
|
|
77
145
|
INIT_HELP,
|
|
78
|
-
|
|
146
|
+
REMOTE_GROUP_HELP,
|
|
147
|
+
REMOTE_HELP,
|
|
148
|
+
START_HELP
|
|
79
149
|
};
|