@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.
Files changed (101) hide show
  1. package/lib/agent-kit/host-approve.js +48 -6
  2. package/lib/agent-kit/init.js +2 -2
  3. package/lib/agent-kit/remote-prompts.js +46 -13
  4. package/lib/agent-kit/run.js +1 -1
  5. package/lib/agent-kit/start.js +310 -0
  6. package/lib/api/pipeline.api.js +32 -3
  7. package/lib/app/deploy.js +13 -9
  8. package/lib/app/offer-create-from-template.js +184 -0
  9. package/lib/cli/setup-app.js +15 -7
  10. package/lib/cli/setup-auth.js +11 -2
  11. package/lib/cli/setup-external-system-help.js +15 -3
  12. package/lib/cli/setup-external-system.js +21 -3
  13. package/lib/commands/agent-kit-help.js +74 -4
  14. package/lib/commands/agent-kit.js +83 -12
  15. package/lib/commands/auth-status-user.js +99 -0
  16. package/lib/commands/auth-status.js +14 -4
  17. package/lib/commands/datasource-load-export-cli.js +7 -2
  18. package/lib/commands/datasource-test-trust-cli.js +5 -1
  19. package/lib/commands/governance-command-action.js +5 -4
  20. package/lib/commands/identity-membership-role-cache.js +6 -1
  21. package/lib/commands/lifecycle-command-action.js +16 -15
  22. package/lib/commands/login-credentials.js +8 -3
  23. package/lib/commands/login-device.js +14 -5
  24. package/lib/commands/login.js +14 -1
  25. package/lib/commands/logout.js +50 -15
  26. package/lib/commands/repair-datasource-auto-rbac.js +4 -9
  27. package/lib/commands/role-assistant.js +24 -12
  28. package/lib/commands/upload-openapi-sync-followup.js +59 -0
  29. package/lib/commands/upload-qualification-client.js +131 -0
  30. package/lib/commands/upload-qualification-followups.js +104 -0
  31. package/lib/commands/upload-qualification-poll.js +143 -0
  32. package/lib/commands/upload.js +37 -156
  33. package/lib/commands/verify-governance-command-action.js +9 -7
  34. package/lib/commands/verify-operations-command-action.js +9 -8
  35. package/lib/commands/verify-trust-command-action.js +6 -5
  36. package/lib/deployment/deploy-poll-ui.js +14 -10
  37. package/lib/deployment/deployer-status.js +4 -4
  38. package/lib/external-system/deploy.js +46 -51
  39. package/lib/external-system/download.js +1 -2
  40. package/lib/generator/helpers.js +14 -46
  41. package/lib/generator/index.js +0 -4
  42. package/lib/integration-definition/apply-static-enterprise.js +5 -2
  43. package/lib/programmatic/builder-api-request.js +8 -4
  44. package/lib/programmatic/capability-registry.js +2 -0
  45. package/lib/programmatic/get-deploy-status.js +45 -0
  46. package/lib/programmatic/get-upload-status.js +45 -0
  47. package/lib/programmatic/http-accepted-response.js +31 -0
  48. package/lib/programmatic/openapi-descriptions.js +14 -4
  49. package/lib/programmatic/request-timeout.js +21 -15
  50. package/lib/programmatic/route-handler-map.js +6 -0
  51. package/lib/programmatic/run-deploy.js +7 -3
  52. package/lib/programmatic/run-upload.js +11 -7
  53. package/lib/role-assistant/knowledge-sync-settings-push.js +172 -0
  54. package/lib/role-assistant/knowledge-sync.js +9 -126
  55. package/lib/role-assistant/test-cases-evaluate.js +12 -1
  56. package/lib/role-assistant/test-cases-evidence.js +44 -5
  57. package/lib/role-assistant/test-cases-lifecycle.js +9 -3
  58. package/lib/role-assistant/test-runner.js +3 -0
  59. package/lib/schema/infra-parameter.schema.json +51 -3
  60. package/lib/schema/infra.parameter.yaml +482 -47
  61. package/lib/schema/type/document-storage.json +1 -1
  62. package/lib/utils/api-required-permissions.js +271 -0
  63. package/lib/utils/api.js +16 -13
  64. package/lib/utils/cli-json-exit.js +41 -0
  65. package/lib/utils/cli-utils.js +26 -7
  66. package/lib/utils/controller-url.js +78 -4
  67. package/lib/utils/deployment-errors.js +15 -0
  68. package/lib/utils/deployment-validation-helpers.js +4 -1
  69. package/lib/utils/device-code.js +31 -10
  70. package/lib/utils/error-formatters/error-parser.js +16 -1
  71. package/lib/utils/error-formatters/permission-errors.js +19 -5
  72. package/lib/utils/keycloak-realm-ready.js +5 -2
  73. package/lib/utils/logger.js +1 -0
  74. package/lib/utils/paths.js +26 -5
  75. package/lib/utils/qualification-poll-ui.js +136 -0
  76. package/lib/utils/secrets-helpers.js +2 -2
  77. package/lib/utils/write-stream-and-wait.js +63 -0
  78. package/package.json +22 -7
  79. package/templates/agent-kit/agent-kit.yaml +1 -1
  80. package/templates/agent-kit/instructions/AGENTKIT.md +25 -4
  81. package/templates/agent-kit/instructions/root.AGENTS.md +1 -1
  82. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +2 -1
  83. package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +1 -1
  84. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +2 -1
  85. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +1 -0
  86. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +1 -0
  87. package/templates/agent-kit/skills/shared/hosts.md +13 -26
  88. package/templates/agent-kit/skills/shared/login.md +16 -0
  89. package/templates/agent-kit/workspace/README.md +1 -1
  90. package/templates/applications/builder-api/env.template +4 -0
  91. package/templates/applications/dataplane/application.yaml +1 -2
  92. package/templates/applications/dataplane/env.template +5 -5
  93. package/templates/applications/keycloak/Dockerfile +12 -5
  94. package/templates/applications/keycloak/application.yaml +2 -2
  95. package/templates/applications/keycloak/cimd-lenient-parse/AbstractClientIdMetadataDocumentExecutor.java +3 -3
  96. package/templates/applications/keycloak/cimd-lenient-parse/SOURCE.md +6 -6
  97. package/templates/applications/keycloak/env.template +13 -1
  98. package/templates/applications/miso-controller/application.yaml +21 -2
  99. package/templates/applications/miso-controller/env.template +97 -28
  100. package/templates/applications/miso-controller/rbac.yaml +5 -0
  101. 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
+ };
@@ -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 (after upload/tests; promote to controller)
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
- - upload = dataplane publish for dev iteration; deploy = controller validate + deploy (Azure or local Docker).
67
- - Prove (tst/CI): use --gate full (optional --subject-email) before promote; plain deploy promotes without live E2E gates.
68
- - After a successful published Deploy, the platform seals the integration certificate (no separate certificates issue step).
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(appName, opts);
393
+ else await app.runApp(targetApp, opts);
386
394
  }
387
395
  } catch (error) {
388
396
  handleCommandError(error, 'deploy');
@@ -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: from config or developer ID, e.g. http://localhost:3000)')
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
- # Publish integration/<systemKey>/ to the dataplane (typical lab flow after validate + resolve)
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 --timeout 600000
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 sets publish budget in ms (HTTP client and dataplane); default 300000.
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
- const timeoutMs = resolvePipelineUploadTimeoutMs(options.timeout);
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
- 'Publish timeout in ms for HTTP and dataplane budget (default: 300000; min 5000, max 2700000)'
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 all --approve-all --yes
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 to auto-approve Claude Code and Codex permissions (default yes). Silent: --approve-all --yes. Skip: --skip-approve-all.
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 when you add or switch Cursor, Claude Code, or Codex.
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
- REMOTE_HELP
146
+ REMOTE_GROUP_HELP,
147
+ REMOTE_HELP,
148
+ START_HELP
79
149
  };