@aifabrix/builder 2.58.0 → 2.60.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/codex-app-server.js +44 -0
- package/lib/agent-kit/git-identity.js +180 -0
- package/lib/agent-kit/init.js +4 -17
- package/lib/agent-kit/session-report.js +15 -10
- package/lib/agent-kit/setup-auth.js +131 -0
- package/lib/agent-kit/setup-context.js +118 -0
- package/lib/agent-kit/setup-github.js +70 -0
- package/lib/agent-kit/setup-managed.js +79 -0
- package/lib/agent-kit/setup-process.js +42 -0
- package/lib/agent-kit/setup-session.js +53 -0
- package/lib/agent-kit/setup-state.js +52 -0
- package/lib/agent-kit/setup-workspace.js +113 -0
- package/lib/agent-kit/setup.js +87 -0
- package/lib/agent-kit/start.js +48 -3
- package/lib/agent-kit/tmux-sessions.js +20 -3
- package/lib/api/dev.api.js +1 -1
- package/lib/api/miso-health.api.js +26 -0
- package/lib/api/role-assistant-test-job.api.js +60 -0
- package/lib/api/types/dev.types.js +3 -3
- package/lib/api/work-search.api.js +13 -6
- package/lib/app/deploy.js +8 -103
- package/lib/app/show-display.js +1 -0
- package/lib/app/show-online.js +15 -0
- package/lib/build/standard-docker-build.js +4 -1
- package/lib/cli/index.js +4 -0
- package/lib/cli/setup-app.js +14 -1
- package/lib/cli/setup-dev-path-commands.js +4 -0
- package/lib/cli/setup-dev.js +7 -4
- package/lib/cli/setup-help.js +86 -0
- package/lib/cli/setup-onboarding.js +37 -0
- package/lib/cli/setup-utility-repair.js +7 -5
- package/lib/cli/setup-utility.js +24 -1
- package/lib/commands/agent-kit-help.js +21 -7
- package/lib/commands/agent-kit-sessions.js +126 -0
- package/lib/commands/agent-kit-setup.js +44 -0
- package/lib/commands/agent-kit.js +5 -79
- package/lib/commands/dev-init.js +21 -23
- package/lib/commands/dev-refresh.js +2 -2
- package/lib/commands/governance-verify-external.js +12 -5
- package/lib/commands/repair-datasource.js +9 -9
- package/lib/commands/repair.js +45 -8
- package/lib/commands/role-assistant.js +7 -0
- package/lib/commands/upload-qualification-client.js +56 -11
- package/lib/commands/upload-qualification-poll.js +51 -22
- package/lib/commands/wizard-dataplane.js +16 -52
- package/lib/core/env-platform-expand.js +93 -0
- package/lib/core/secrets-env-content.js +37 -3
- package/lib/datasource/datasource-validate-summary.js +8 -5
- package/lib/datasource/sync-defaults.js +53 -0
- package/lib/deployment/installation/azure-infra-stage.js +13 -1
- package/lib/deployment/installation/azure-preflight.js +13 -2
- package/lib/deployment/installation/azure-readiness.js +24 -2
- package/lib/deployment/installation/environment-auth.js +60 -20
- package/lib/deployment/installation/environment-stage.js +9 -5
- package/lib/deployment/installation/infra-catalog.js +10 -7
- package/lib/deployment/installation/infra-manifest.js +5 -0
- package/lib/deployment/installation/registry-auth-mode.js +33 -10
- package/lib/deployment/marketplace-environment.js +26 -1
- package/lib/generator/builders.js +17 -0
- package/lib/generator/helpers.js +23 -2
- package/lib/generator/index.js +33 -18
- package/lib/integration-definition/apply.js +2 -2
- package/lib/internal/fs-real-sync.js +4 -1
- package/lib/programmatic/bearer-auth.js +3 -62
- package/lib/programmatic/builder-api-startup.js +51 -0
- package/lib/programmatic/builder-miso-runtime.js +167 -0
- package/lib/programmatic/openapi-descriptions.js +3 -3
- package/lib/programmatic/openapi-schema-descriptions-core.js +3 -3
- package/lib/programmatic/openapi-spec.js +2 -1
- package/lib/programmatic/route-handler-map.js +3 -2
- package/lib/role-assistant/test-cases-search.js +3 -0
- package/lib/role-assistant/test-job-runner.js +125 -0
- package/lib/role-assistant/test-runner-search.js +44 -2
- package/lib/schema/application-schema.json +193 -2
- package/lib/schema/environment-deploy-request.schema.json +1 -1
- package/lib/schema/external-datasource.schema.json +20 -5
- package/lib/schema/infra-parameter.schema.json +140 -34
- package/lib/schema/infra.parameter.yaml +30 -29
- package/lib/schema/infrastructure-schema.json +133 -14
- package/lib/schema/installation-environment.schema.json +1 -1
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/compose-generate-docker-compose.js +12 -0
- package/lib/utils/config-paths.js +24 -29
- package/lib/utils/config-registry-preference.js +13 -6
- package/lib/utils/dev-init-ssh-merge.js +5 -4
- package/lib/utils/dev-user-groups.js +2 -1
- package/lib/utils/docker-build.js +29 -8
- package/lib/utils/docker-daemon-tls-ca.js +2 -2
- package/lib/utils/docker-manifest-public-port.js +36 -0
- package/lib/utils/error-formatters/validation-errors.js +25 -5
- package/lib/utils/help-builder.js +4 -3
- package/lib/utils/platform-resolution.js +226 -0
- package/lib/utils/resolve-docker-image-ref.js +8 -3
- package/lib/utils/token-manager.js +29 -36
- package/package.json +4 -3
- package/templates/README.md +2 -1
- package/templates/agent-kit/agent-kit.yaml +4 -1
- package/templates/agent-kit/instructions/AGENTKIT.md +40 -3
- package/templates/agent-kit/instructions/root.AGENTS.md +42 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +33 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/scripts/delivery-verdict.js +176 -0
- package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +3 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +10 -3
- package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +22 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +21 -0
- package/templates/agent-kit/skills/shared/feedback.md +31 -0
- package/templates/agent-kit/skills/shared/hosts.md +35 -7
- package/templates/agent-kit/skills/shared/status.md +85 -0
- package/templates/agent-kit/workspace/BUILDER_IMPROVEMENT_FINDINGS.md +27 -0
- package/templates/agent-kit/workspace/README.md +14 -1
- package/templates/applications/builder-api/application.yaml +1 -1
- package/templates/applications/dataplane/application.yaml +30 -2
- package/templates/applications/dataplane/env.template +37 -4
- package/templates/applications/miso-controller/application.yaml +24 -1
- package/templates/applications/miso-controller/env.template +22 -35
- package/templates/external-system/external-datasource.yaml.hbs +7 -6
- package/templates/marketplace/main.json +281 -75
- package/templates/python/Dockerfile.hbs +2 -0
- package/templates/typescript/Dockerfile.hbs +2 -0
- package/templates/typescript/docker-compose.hbs +12 -0
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* @property {string} aifabrix-secrets - Local filesystem path or https URL for shared secrets (file vs remote API)
|
|
31
31
|
* @property {string} aifabrix-env-config - Env config path
|
|
32
32
|
* @property {string} remote-server - Builder-server base URL
|
|
33
|
-
* @property {string} docker-endpoint - Docker API endpoint
|
|
33
|
+
* @property {string} [docker-endpoint] - Docker API endpoint; omit for SSH-only/integrator users
|
|
34
34
|
* @property {string} [developer-root-domain] - App hostname root (e.g. aifabrix.dev → dev01.aifabrix.dev)
|
|
35
35
|
* @property {boolean} [docker-tls-skip-verify] - When true, Docker uses DOCKER_TLS_VERIFY=0 even if ca.pem exists (client mTLS unchanged)
|
|
36
36
|
* @property {string} sync-ssh-user - SSH user for Mutagen
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
* @property {string} createdAt - ISO 8601
|
|
47
47
|
* @property {boolean} certificateIssued - Whether cert was issued
|
|
48
48
|
* @property {string} [certificateValidNotAfter] - Cert validity end (optional)
|
|
49
|
-
* @property {string[]} groups - Access groups (admin, secret-manager, secret-reader, developer, docker)
|
|
49
|
+
* @property {string[]} groups - Access groups (admin, secret-manager, secret-reader, developer, docker, integrator)
|
|
50
50
|
*/
|
|
51
51
|
|
|
52
52
|
/**
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
* @property {string} developerId - Unique developer ID (numeric string)
|
|
56
56
|
* @property {string} name - Display name
|
|
57
57
|
* @property {string} email - Email
|
|
58
|
-
* @property {string[]} [groups] - Default [developer]; tokens: admin, secret-manager, secret-reader, developer, docker
|
|
58
|
+
* @property {string[]} [groups] - Default [developer]; tokens: admin, secret-manager, secret-reader, developer, docker, integrator
|
|
59
59
|
*/
|
|
60
60
|
|
|
61
61
|
/**
|
|
@@ -121,16 +121,23 @@ async function getWorkRoles(dataplaneUrl, authConfig) {
|
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
123
|
* GET-equivalent work.skills for one roleRef.
|
|
124
|
-
*
|
|
125
|
-
*
|
|
124
|
+
* Defaults to detail=full so search.resourceTypes (executable grammar) is present.
|
|
125
|
+
* A caller may request progressive resource/operation detail for skills-only checks.
|
|
126
126
|
* @requiresPermission {Dataplane} Authenticated (oauth2: [])
|
|
127
127
|
* @async
|
|
128
128
|
*/
|
|
129
|
-
async function getWorkSkills(dataplaneUrl, authConfig, roleRef) {
|
|
130
|
-
|
|
129
|
+
async function getWorkSkills(dataplaneUrl, authConfig, roleRef, options = {}) {
|
|
130
|
+
const args = {
|
|
131
131
|
roleRef: String(roleRef || '').trim(),
|
|
132
|
-
detail: 'full'
|
|
133
|
-
}
|
|
132
|
+
detail: String(options.detail || 'full').trim()
|
|
133
|
+
};
|
|
134
|
+
if (typeof options.resourceType === 'string' && options.resourceType.trim()) {
|
|
135
|
+
args.resourceType = options.resourceType.trim();
|
|
136
|
+
}
|
|
137
|
+
if (typeof options.operation === 'string' && options.operation.trim()) {
|
|
138
|
+
args.operation = options.operation.trim();
|
|
139
|
+
}
|
|
140
|
+
return executeLayerBTool(dataplaneUrl, authConfig, LAYER_B_TOOLS.skills, args);
|
|
134
141
|
}
|
|
135
142
|
|
|
136
143
|
/**
|
package/lib/app/deploy.js
CHANGED
|
@@ -18,7 +18,6 @@ const {
|
|
|
18
18
|
|
|
19
19
|
const fs = require('fs').promises;
|
|
20
20
|
const chalk = require('chalk');
|
|
21
|
-
const pushUtils = require('../deployment/push');
|
|
22
21
|
|
|
23
22
|
const SEP = chalk.gray('────────────────────────────────────────');
|
|
24
23
|
const logger = require('../utils/logger');
|
|
@@ -56,106 +55,6 @@ function validateAppName(appName) {
|
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
/**
|
|
60
|
-
* Validates push prerequisites
|
|
61
|
-
* @async
|
|
62
|
-
* @function validatePushPrerequisites
|
|
63
|
-
* @param {string} appName - Application name
|
|
64
|
-
* @param {string} registry - Registry URL
|
|
65
|
-
* @throws {Error} If prerequisites are not met
|
|
66
|
-
*/
|
|
67
|
-
async function validatePushPrerequisites(appName, registry) {
|
|
68
|
-
if (!pushUtils.validateRegistryURL(registry)) {
|
|
69
|
-
throw new Error(`Invalid registry URL format: ${registry}. Expected format: *.azurecr.io`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (!await pushUtils.checkLocalImageExists(appName, 'latest')) {
|
|
73
|
-
throw new Error(`Docker image ${appName}:latest not found locally.\nRun 'aifabrix build ${appName}' first`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (!await pushUtils.checkAzureCLIInstalled()) {
|
|
77
|
-
throw new Error('Azure CLI is not installed. Install from: https://docs.microsoft.com/cli/azure/install-azure-cli');
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Executes push operations
|
|
83
|
-
* @async
|
|
84
|
-
* @function executePush
|
|
85
|
-
* @param {string} appName - Application name
|
|
86
|
-
* @param {string} registry - Registry URL
|
|
87
|
-
* @param {string[]} tags - Tags to push
|
|
88
|
-
* @throws {Error} If push fails
|
|
89
|
-
*/
|
|
90
|
-
async function executePush(appName, registry, tags) {
|
|
91
|
-
if (await pushUtils.checkACRAuthentication(registry)) {
|
|
92
|
-
logger.log(formatSuccessLine(`Already authenticated with ${registry}`));
|
|
93
|
-
} else {
|
|
94
|
-
await pushUtils.authenticateACR(registry);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
await Promise.all(tags.map(async(tag) => {
|
|
98
|
-
await pushUtils.tagImage(`${appName}:latest`, `${registry}/${appName}:${tag}`);
|
|
99
|
-
await pushUtils.pushImage(`${registry}/${appName}:${tag}`, registry);
|
|
100
|
-
}));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Verifies push result
|
|
105
|
-
* @function verifyPushResult
|
|
106
|
-
* @param {string[]} tags - Tags that were pushed
|
|
107
|
-
* @param {string} registry - Registry URL
|
|
108
|
-
* @param {string} appName - Application name
|
|
109
|
-
*/
|
|
110
|
-
function verifyPushResult(tags, registry, appName) {
|
|
111
|
-
logger.log(formatSuccessParagraph(`Successfully pushed ${tags.length} tag(s) to ${registry}`));
|
|
112
|
-
logger.log(chalk.gray(`Image: ${registry}/${appName}:*`));
|
|
113
|
-
logger.log(chalk.gray(`Tags: ${tags.join(', ')}`));
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Pushes application image to Azure Container Registry
|
|
118
|
-
* @async
|
|
119
|
-
* @function pushApp
|
|
120
|
-
* @param {string} appName - Name of the application
|
|
121
|
-
* @param {Object} options - Push options (registry, tag)
|
|
122
|
-
* @returns {Promise<void>} Resolves when push is complete
|
|
123
|
-
*/
|
|
124
|
-
async function pushApp(appName, options = {}) {
|
|
125
|
-
try {
|
|
126
|
-
validateAppName(appName);
|
|
127
|
-
|
|
128
|
-
const { getBuilderPath, resolveApplicationConfigPath } = require('../utils/paths');
|
|
129
|
-
const { loadConfigFile } = require('../utils/config-format');
|
|
130
|
-
const builderPath = getBuilderPath(appName);
|
|
131
|
-
let config;
|
|
132
|
-
try {
|
|
133
|
-
const configPath = resolveApplicationConfigPath(builderPath);
|
|
134
|
-
config = loadConfigFile(configPath);
|
|
135
|
-
} catch (error) {
|
|
136
|
-
throw new Error(`Failed to load configuration: ${error.message}\nRun 'aifabrix create ${appName}' first`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const registry = options.registry || config.image?.registry;
|
|
140
|
-
if (!registry) {
|
|
141
|
-
throw new Error('Registry URL is required. Provide via --registry flag or configure in application.yaml under image.registry');
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (!/^[^.]+\.azurecr\.io$/.test(registry)) {
|
|
145
|
-
throw new Error(`Invalid ACR URL format: ${registry}. Expected format: *.azurecr.io`);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const tags = options.tag ? options.tag.split(',').map(t => t.trim()) : ['latest'];
|
|
149
|
-
|
|
150
|
-
await validatePushPrerequisites(appName, registry);
|
|
151
|
-
await executePush(appName, registry, tags);
|
|
152
|
-
verifyPushResult(tags, registry, appName);
|
|
153
|
-
|
|
154
|
-
} catch (error) {
|
|
155
|
-
throw new Error(`Failed to push application: ${error.message}`);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
58
|
/**
|
|
160
59
|
* Generates and validates deployment manifest
|
|
161
60
|
* @async
|
|
@@ -369,7 +268,14 @@ async function executeStandardDeployment(appName, options) {
|
|
|
369
268
|
const controllerUrl = config.controllerUrl || 'unknown';
|
|
370
269
|
const appExists = await checkApplicationExists(appName, controllerUrl, config.envKey, config.auth);
|
|
371
270
|
|
|
372
|
-
|
|
271
|
+
// A controller deployment ships tokens plus the platforms/environments sections, so the
|
|
272
|
+
// Controller resolves them per installation and can promote dev -> tst without regenerating.
|
|
273
|
+
// Local runs and an explicit --resource-group resolve here instead.
|
|
274
|
+
const resolveHere = Boolean(options.local || options.resourceGroup);
|
|
275
|
+
const { manifest, manifestPath } = await generateAndValidateManifest(appName, {
|
|
276
|
+
...options,
|
|
277
|
+
...(resolveHere ? { target: { environment: config.envKey, resourceGroup: options.resourceGroup } } : {})
|
|
278
|
+
});
|
|
373
279
|
applyManifestOverrides(manifest, options);
|
|
374
280
|
validateImageIsPullable(manifest.image, appName);
|
|
375
281
|
displayDeploymentInfo(manifest, manifestPath);
|
|
@@ -492,7 +398,6 @@ async function deployApp(appName, options = {}) {
|
|
|
492
398
|
}
|
|
493
399
|
|
|
494
400
|
module.exports = {
|
|
495
|
-
pushApp,
|
|
496
401
|
deployApp,
|
|
497
402
|
validateAppName,
|
|
498
403
|
validateImageIsPullable
|
package/lib/app/show-display.js
CHANGED
|
@@ -234,6 +234,7 @@ function logExternalSystemMain(ext) {
|
|
|
234
234
|
logger.log(` Version: ${ext.version ?? '—'}`);
|
|
235
235
|
logger.log(` Credential: ${formatCredentialShowLine(ext)}`);
|
|
236
236
|
logger.log(` Status: ${formatDataplaneStatusDisplay(ext.status)}`);
|
|
237
|
+
logger.log(` System link: ${ext.systemUrl ?? '—'}`);
|
|
237
238
|
logger.log(` API docs: ${ext.openApiDocsPageUrl ?? ext.apiDocumentUrl ?? '—'}`);
|
|
238
239
|
logger.log(` MCP server: ${ext.mcpServerUrl ?? '—'}`);
|
|
239
240
|
logger.log(` OpenAPI spec: ${ext.apiDocumentUrl ?? '—'}`);
|
package/lib/app/show-online.js
CHANGED
|
@@ -89,6 +89,7 @@ function buildOnlineSummaryFromDataplane(appKey, controllerUrl, dataplaneUrl, ex
|
|
|
89
89
|
|
|
90
90
|
async function finishOnlineShow(summary, appKey, json, permissionsOnly, verifyCert, authBundle) {
|
|
91
91
|
await enrichExternalShowSummary(summary, appKey, verifyCert, authBundle);
|
|
92
|
+
attachSystemUrl(summary);
|
|
92
93
|
attachRunDefaultsFromUserConfig(summary, appKey, await getConfig());
|
|
93
94
|
await attachDeclarativeUrlsToShowApplication(summary, appKey);
|
|
94
95
|
if (json) {
|
|
@@ -100,6 +101,20 @@ async function finishOnlineShow(summary, appKey, json, permissionsOnly, verifyCe
|
|
|
100
101
|
displayShow(summary, { permissionsOnly: !!permissionsOnly });
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Expose the Dataplane system browser route for humans and agents.
|
|
106
|
+
* Preserve the deployment base path (for example /data).
|
|
107
|
+
* @param {Object} summary - Online application summary
|
|
108
|
+
*/
|
|
109
|
+
function attachSystemUrl(summary) {
|
|
110
|
+
const ext = summary.externalSystem;
|
|
111
|
+
if (!summary.isExternal || !ext || ext.error || !ext.dataplaneUrl) return;
|
|
112
|
+
const baseUrl = ext.dataplaneUrl.replace(/\/+$/, '');
|
|
113
|
+
const systemKey = ext.systemKey || summary.appKey;
|
|
114
|
+
const section = /^(ra-|ek-)/.test(systemKey) ? 'enterprise-knowledge' : 'connected-systems';
|
|
115
|
+
ext.systemUrl = `${baseUrl}/${section}/${encodeURIComponent(systemKey)}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
async function runOnlineFromDataplane(appKey, json, permissionsOnly, verifyCert, authConfig, authResult) {
|
|
104
119
|
const environment = await resolveEnvironment();
|
|
105
120
|
const dataplaneUrl = await resolveDataplaneUrl(authResult.actualControllerUrl, environment, authConfig);
|
|
@@ -81,13 +81,16 @@ async function executeDockerImageBuild(appName, options, buildConfig) {
|
|
|
81
81
|
await ensureRunSecretsForApp(appName);
|
|
82
82
|
const buildArgs = await resolveDockerBuildArgsForApp(appName, contextPath);
|
|
83
83
|
const { primary, aliases, tags } = options.tagPlan;
|
|
84
|
+
// `build.target` selects a stage of a multi-stage Dockerfile, so one source tree can
|
|
85
|
+
// produce more than one image. Absent, Docker builds the last stage as before.
|
|
86
|
+
const target = buildConfig && buildConfig.target;
|
|
84
87
|
await dockerBuild.executeDockerBuildWithTag(
|
|
85
88
|
effectiveImageName,
|
|
86
89
|
imageName,
|
|
87
90
|
dockerfilePath,
|
|
88
91
|
contextPath,
|
|
89
92
|
primary,
|
|
90
|
-
{ ...options, buildArgs, tagAliases: aliases }
|
|
93
|
+
{ ...options, buildArgs, tagAliases: aliases, target }
|
|
91
94
|
);
|
|
92
95
|
await postBuildTasks(appName, buildConfig);
|
|
93
96
|
logger.log(formatSuccessParagraph('Build completed successfully!'));
|
package/lib/cli/index.js
CHANGED
|
@@ -41,6 +41,8 @@ const { setupChannelCommands } = require('../commands/channel');
|
|
|
41
41
|
const { setupManifestCommands } = require('../commands/manifest');
|
|
42
42
|
const { setupNpmCommands } = require('./setup-npm');
|
|
43
43
|
const { setupListCommand } = require('./setup-list');
|
|
44
|
+
const { setupHelpCommand } = require('./setup-help');
|
|
45
|
+
const { setupOnboardingCommand } = require('./setup-onboarding');
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
48
|
* Dev, secrets, parameters, and platform commands (keeps setupCommands under statement limit).
|
|
@@ -101,6 +103,8 @@ function setupExtendedCliCommands(program) {
|
|
|
101
103
|
* @param {Command} program - Commander program instance
|
|
102
104
|
*/
|
|
103
105
|
function setupCommands(program) {
|
|
106
|
+
setupHelpCommand(program);
|
|
107
|
+
setupOnboardingCommand(program);
|
|
104
108
|
setupCoreCliCommands(program);
|
|
105
109
|
setupExtendedCliCommands(program);
|
|
106
110
|
setupDevAndPlatformCommands(program);
|
package/lib/cli/setup-app.js
CHANGED
|
@@ -362,7 +362,7 @@ function setupDockerfileGenerateCommand(program) {
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
function setupDeployCommand(program) {
|
|
365
|
-
program.command('deploy <appKey|systemKey>')
|
|
365
|
+
addDeployTargetOptions(program.command('deploy <appKey|systemKey>'))
|
|
366
366
|
.description('Deploy builder app or external system via Miso Controller (Azure or --local)')
|
|
367
367
|
.addHelpText('after', DEPLOY_HELP_AFTER)
|
|
368
368
|
.option('--local', 'Send manifest to controller then run app locally (app: same as aifabrix run <app>; external: restart dataplane)')
|
|
@@ -410,6 +410,19 @@ function setupDeployCommand(program) {
|
|
|
410
410
|
});
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
+
/**
|
|
414
|
+
* Deployment-target options. A controller deployment normally ships {NAME} tokens plus the
|
|
415
|
+
* platforms/environments sections; these flags force local resolution instead.
|
|
416
|
+
* @param {Command} command - Commander command
|
|
417
|
+
* @returns {Command} The command
|
|
418
|
+
*/
|
|
419
|
+
function addDeployTargetOptions(command) {
|
|
420
|
+
return command.option(
|
|
421
|
+
'-g, --resource-group <name>',
|
|
422
|
+
'Target Azure resource group; resolves platforms values in the generated manifest instead of shipping tokens'
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
|
|
413
426
|
function setupPushDeployDockerfileCommands(program) {
|
|
414
427
|
program.command('push <appKey>')
|
|
415
428
|
.description('Push builder appKey image to Azure Container Registry')
|
package/lib/cli/setup-dev.js
CHANGED
|
@@ -44,8 +44,11 @@ const DEV_ADD_HELP_AFTER = `
|
|
|
44
44
|
Examples:
|
|
45
45
|
$ aifabrix dev add --developer-id 02 --name "Jane Doe" --email jane@example.com
|
|
46
46
|
$ aifabrix dev add --developer-id 03 --name "Build admin" --email admin@example.com --groups admin,developer
|
|
47
|
-
$ aifabrix dev add --developer-id 04 --name "
|
|
48
|
-
$ aifabrix dev add --developer-id 05 --name "Integrator" --email integrator@example.com --groups
|
|
47
|
+
$ aifabrix dev add --developer-id 04 --name "Docker developer" --email docker-dev@example.com --groups developer,docker
|
|
48
|
+
$ aifabrix dev add --developer-id 05 --name "Integrator" --email integrator@example.com --groups integrator
|
|
49
|
+
|
|
50
|
+
Groups: integrator is for SSH onboarding without Docker. Use developer,docker for host Docker access (root-equivalent; grant sparingly).
|
|
51
|
+
When --groups is supplied, it replaces the default developer group; developer is not added automatically.
|
|
49
52
|
|
|
50
53
|
Requires a configured remote Builder Server and an admin client certificate (same machine setup as dev list / dev pin). After add, run dev pin <id> once to create a PIN for aifabrix dev init.
|
|
51
54
|
`;
|
|
@@ -318,7 +321,7 @@ function setupDevListAddCommands(dev) {
|
|
|
318
321
|
.requiredOption('--developer-id <id>', 'Unique id, digits only (e.g. 02); used with dev init --developer-id')
|
|
319
322
|
.requiredOption('--name <name>', 'Display name')
|
|
320
323
|
.requiredOption('--email <email>', 'Email address')
|
|
321
|
-
.option('--groups <items>', 'Comma-separated roles: admin, secret-manager, secret-reader, developer, docker', 'developer')
|
|
324
|
+
.option('--groups <items>', 'Comma-separated roles: admin, secret-manager, secret-reader, developer, docker, integrator', 'developer')
|
|
322
325
|
.option('--no-provision', 'Create user in database only (skip host provision job)')
|
|
323
326
|
.option('--builder-version <ver>', 'Builder CLI version for provision job')
|
|
324
327
|
.option('--admin-email <email>', 'Platform admin email for provision job')
|
|
@@ -373,7 +376,7 @@ function setupDevUpdatePinDeleteCommands(dev) {
|
|
|
373
376
|
.option('--developer-id <id>', 'Developer ID (same as dev add)')
|
|
374
377
|
.option('--name <name>', 'Display name')
|
|
375
378
|
.option('--email <email>', 'Email address')
|
|
376
|
-
.option('--groups <items>', 'Comma-separated groups (admin, secret-manager, secret-reader, developer, docker)')
|
|
379
|
+
.option('--groups <items>', 'Comma-separated groups (admin, secret-manager, secret-reader, developer, docker, integrator)')
|
|
377
380
|
.addHelpText('after', DEV_UPDATE_HELP_AFTER)
|
|
378
381
|
.action(async(developerId, options) => {
|
|
379
382
|
try {
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** Read-only onboarding guide; command reference remains available through --help. */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const ONBOARDING_GUIDE = `Welcome to AI Fabrix
|
|
5
|
+
|
|
6
|
+
On a managed workspace host with provisioned config, run:
|
|
7
|
+
|
|
8
|
+
af onboarding
|
|
9
|
+
af onboarding --coding claude
|
|
10
|
+
af onboarding --coding codex
|
|
11
|
+
af onboarding --coding cursor
|
|
12
|
+
af onboarding --coding claude --name sales-workspace
|
|
13
|
+
af onboarding --coding claude --name finance-workspace
|
|
14
|
+
af onboarding --repo example-org/example-workspace
|
|
15
|
+
af onboarding --repo my-org/new-repo
|
|
16
|
+
|
|
17
|
+
This prepares the coding platform selected by your organisation, or the one
|
|
18
|
+
you pass for this run. Claude starts in a detached tmux session; Codex and
|
|
19
|
+
Cursor use their own SSH clients. It does not install the local AI Fabrix platform.
|
|
20
|
+
Use --name <folder> for separate workspaces; each Claude workspace has its own
|
|
21
|
+
tmux session. Use --repo owner/name to clone an accessible GitHub repository
|
|
22
|
+
or create a new private one. agent-kit remote create creates a new GitHub
|
|
23
|
+
repository for the current local workspace; --name sets that remote name.
|
|
24
|
+
|
|
25
|
+
Start your integration workspace with Codex:
|
|
26
|
+
|
|
27
|
+
aifabrix agent-kit setup <controller-url>
|
|
28
|
+
|
|
29
|
+
Ask your administrator for the Controller URL.
|
|
30
|
+
Setup guides you through sign-in, installs the Agent Kit,
|
|
31
|
+
and starts your coding agent.
|
|
32
|
+
|
|
33
|
+
Run setup in a Linux/macOS terminal with Builder, Git and tmux installed.
|
|
34
|
+
On Windows, connect to your organisation's Builder Server first.
|
|
35
|
+
Your files stay under the AI Fabrix work directory on the machine running setup.
|
|
36
|
+
No GitHub account or Docker is required for the default local workspace.
|
|
37
|
+
|
|
38
|
+
Optional:
|
|
39
|
+
Use GitHub (requires gh):
|
|
40
|
+
aifabrix agent-kit setup <controller-url> --repo owner/project
|
|
41
|
+
|
|
42
|
+
Use Claude:
|
|
43
|
+
aifabrix agent-kit setup <controller-url> --code claude
|
|
44
|
+
|
|
45
|
+
Already have a project?
|
|
46
|
+
Open its Git repository folder and install the Agent Kit:
|
|
47
|
+
aifabrix agent-kit install --host codex
|
|
48
|
+
|
|
49
|
+
Using your organisation's Builder Server?
|
|
50
|
+
On your own computer, use the onboarding command your administrator gives you:
|
|
51
|
+
aifabrix dev init --developer-id <id> --server <builder-server-url> --pin <pin>
|
|
52
|
+
|
|
53
|
+
Use the SSH command printed after successful onboarding to connect.
|
|
54
|
+
Once connected to a managed workspace, run af onboarding.
|
|
55
|
+
For a portable server without managed config, use agent-kit setup above.
|
|
56
|
+
Integrator accounts use the integrator group; Docker is not needed.
|
|
57
|
+
|
|
58
|
+
Controller URL: connects your workspace to AI Fabrix.
|
|
59
|
+
Builder Server URL: connects your computer to the remote workspace host.
|
|
60
|
+
These are different services; ask your administrator for the correct URLs.
|
|
61
|
+
|
|
62
|
+
Explore:
|
|
63
|
+
aifabrix --help
|
|
64
|
+
aifabrix agent-kit --help
|
|
65
|
+
aifabrix <command> --help
|
|
66
|
+
|
|
67
|
+
This guide does not sign you in, install software, or change configuration.
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
function setupHelpCommand(program) {
|
|
71
|
+
program.addHelpCommand(false);
|
|
72
|
+
program.command('help [command]')
|
|
73
|
+
.description('Show the onboarding guide, or help for a command')
|
|
74
|
+
.addHelpText('after', '\nExamples:\n $ aifabrix help\n $ aifabrix help agent-kit\n')
|
|
75
|
+
.action((name, options, command) => {
|
|
76
|
+
if (!name) {
|
|
77
|
+
command.configureOutput().writeOut(ONBOARDING_GUIDE);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const target = program.commands.find(item => item.name() === name || item.aliases().includes(name));
|
|
81
|
+
if (!target) command.error(`Unknown command '${name}'. Run aifabrix --help to list commands.`);
|
|
82
|
+
target.outputHelp();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = { setupHelpCommand, ONBOARDING_GUIDE };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Top-level managed Agent Kit onboarding command. */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const logger = require('../utils/logger');
|
|
5
|
+
const { formatBlockingError } = require('../utils/cli-layout-chalk');
|
|
6
|
+
const { maskSensitiveData } = require('../utils/log-redaction');
|
|
7
|
+
const { runManagedOnboarding } = require('../agent-kit/setup');
|
|
8
|
+
|
|
9
|
+
function setupOnboardingCommand(program) {
|
|
10
|
+
program.command('onboarding')
|
|
11
|
+
.description('Prepare your provisioned Agent Kit workspace for the selected coding platform')
|
|
12
|
+
.option('--coding <platform>', 'Use claude, codex, or cursor for this run')
|
|
13
|
+
.option('--name <folder>', 'Create or reuse this workspace folder under the managed work root')
|
|
14
|
+
.option('--repo <owner/name>', 'Reuse or clone this GitHub repository, or create it privately')
|
|
15
|
+
.addHelpText('after', '\nRun on your managed workspace host after connecting by SSH.\n' +
|
|
16
|
+
'Reads ~/.aifabrix/config.yaml; --coding overrides its codingPlatform for this run only.\n' +
|
|
17
|
+
'For portable onboarding use aifabrix agent-kit setup <controllerUrl>.\n\n' +
|
|
18
|
+
'Examples:\n' +
|
|
19
|
+
' $ af onboarding\n' +
|
|
20
|
+
' $ af onboarding --coding claude\n' +
|
|
21
|
+
' $ af onboarding --coding claude --name sales-workspace\n' +
|
|
22
|
+
' $ af onboarding --coding claude --name finance-workspace\n' +
|
|
23
|
+
' $ af onboarding --repo example-org/example-workspace\n' +
|
|
24
|
+
' $ af onboarding --repo my-org/new-repo\n' +
|
|
25
|
+
' $ af onboarding --coding codex\n' +
|
|
26
|
+
' $ af onboarding --coding cursor\n')
|
|
27
|
+
.action(async(options) => {
|
|
28
|
+
try {
|
|
29
|
+
await runManagedOnboarding(options);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
logger.error(formatBlockingError(maskSensitiveData(error.message)));
|
|
32
|
+
process.exitCode = 1;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = { setupOnboardingCommand };
|
|
@@ -99,7 +99,9 @@ function logRepairDryRunOutcome(options, result, changedFiles) {
|
|
|
99
99
|
*/
|
|
100
100
|
function logRepairSuccessOutcome(result, changedFiles) {
|
|
101
101
|
if (result.updated) {
|
|
102
|
-
logger.log(formatSuccessParagraph(
|
|
102
|
+
logger.log(formatSuccessParagraph(result.applicationReadme
|
|
103
|
+
? 'Regenerated README.md from application configuration.'
|
|
104
|
+
: 'Repaired external integration config.'));
|
|
103
105
|
logRepairChangedFiles(changedFiles, false);
|
|
104
106
|
logRepairNextActions(changedFiles, result.warnings);
|
|
105
107
|
return;
|
|
@@ -166,7 +168,7 @@ async function handleRepairCommand(appName, options) {
|
|
|
166
168
|
*/
|
|
167
169
|
function setupRepairCommand(program) {
|
|
168
170
|
program.command('repair <systemKey>')
|
|
169
|
-
.description('Fix external integration drift
|
|
171
|
+
.description('Fix external integration drift or regenerate application documentation (--doc)')
|
|
170
172
|
.option('--all', 'Run all repair actions (api, doc, expose, rbac, sync, test)')
|
|
171
173
|
.option(
|
|
172
174
|
'--api',
|
|
@@ -176,10 +178,10 @@ function setupRepairCommand(program) {
|
|
|
176
178
|
'--auth <method>',
|
|
177
179
|
'Set authentication method (oauth2, aad, apikey, bearerToken, basic, queryParam, oidc, hmac, none); updates system file and env.template'
|
|
178
180
|
)
|
|
179
|
-
.option('--doc', 'Regenerate README.md from deployment manifest')
|
|
181
|
+
.option('--doc', 'Regenerate README.md from application config or external integration deployment manifest')
|
|
180
182
|
.option('--expose', 'Set exposed.schema on each datasource from all fieldMappings.attributes keys (metadata.<key>); removes deprecated exposed.attributes if present')
|
|
181
183
|
.option('--rbac', 'Ensure RBAC permissions per datasource and add default Admin/Reader roles if none exist; warns when capabilities lack openapi.operations (auto-syncs operations)')
|
|
182
|
-
.option('--sync', 'Add
|
|
184
|
+
.option('--sync', 'Add enabled monthly UTC sync defaults when the sync section is absent')
|
|
183
185
|
.option(
|
|
184
186
|
'--auth-webhook',
|
|
185
187
|
'Ensure authentications[] slot usage=webhookInbound (454 webhook inbound auth)'
|
|
@@ -197,7 +199,7 @@ function setupRepairCommand(program) {
|
|
|
197
199
|
'--rbac-preset <preset>',
|
|
198
200
|
'RBAC preset for facade APIs (e.g. platform — dataplane role catalog)'
|
|
199
201
|
)
|
|
200
|
-
.option('--no-backup', 'Skip timestamped copies under
|
|
202
|
+
.option('--no-backup', 'Skip timestamped copies under the application folder backup/')
|
|
201
203
|
.option('--dry-run', 'Report changes only; do not write')
|
|
202
204
|
.addHelpText('after', REPAIR_HELP_AFTER)
|
|
203
205
|
.action(async(appName, options) => {
|
package/lib/cli/setup-utility.js
CHANGED
|
@@ -65,6 +65,23 @@ async function handleSplitJsonCommand(appName, options) {
|
|
|
65
65
|
return generator.splitDeployJson(deployJsonPath, outputDir);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Deployment target for manifest generation. A resource group resolves platform values; the
|
|
70
|
+
* environment key resolves the environments layer. Without either, {NAME} tokens are preserved.
|
|
71
|
+
* @param {Object} options - Command options
|
|
72
|
+
* @returns {Promise<{ resourceGroup: string|undefined, environment: string }>}
|
|
73
|
+
*/
|
|
74
|
+
async function buildGenerationTarget(options = {}) {
|
|
75
|
+
// Only an explicit target resolves. The default artifact keeps {NAME} tokens and carries the
|
|
76
|
+
// platforms/environments sections, so the Controller resolves them per installation.
|
|
77
|
+
if (!options.resourceGroup && !options.env) return undefined;
|
|
78
|
+
const { resolveEnvironment } = require('../core/config');
|
|
79
|
+
const environment = options.env
|
|
80
|
+
? String(options.env).trim().toLowerCase()
|
|
81
|
+
: await resolveEnvironment();
|
|
82
|
+
return { resourceGroup: options.resourceGroup, environment };
|
|
83
|
+
}
|
|
84
|
+
|
|
68
85
|
/**
|
|
69
86
|
* Logs split-json results
|
|
70
87
|
* @param {Object} result - Generated file paths
|
|
@@ -93,6 +110,11 @@ function logSplitJsonResult(result) {
|
|
|
93
110
|
function setupJsonCommand(program) {
|
|
94
111
|
program.command('json <appKey|systemKey>')
|
|
95
112
|
.description('Write deployment JSON to disk for version control')
|
|
113
|
+
.option(
|
|
114
|
+
'-g, --resource-group <name>',
|
|
115
|
+
'Target Azure resource group; resolves platforms/environments values instead of leaving {NAME} tokens'
|
|
116
|
+
)
|
|
117
|
+
.option('-e, --env <env>', 'Deployment environment key for environments resolution (default: current environment)')
|
|
96
118
|
.addHelpText('after', JSON_HELP_AFTER)
|
|
97
119
|
.action(async(appName, options) => {
|
|
98
120
|
try {
|
|
@@ -105,7 +127,8 @@ function setupJsonCommand(program) {
|
|
|
105
127
|
json: false
|
|
106
128
|
});
|
|
107
129
|
const result = await generator.generateDeployJsonWithValidation(appName, {
|
|
108
|
-
...options
|
|
130
|
+
...options,
|
|
131
|
+
target: await buildGenerationTarget(options)
|
|
109
132
|
});
|
|
110
133
|
if (result.success) {
|
|
111
134
|
const fileName = result.path.includes('application-schema.json') ? 'application-schema.json' : 'deployment JSON';
|
|
@@ -16,6 +16,7 @@ Coding hosts (--host) are Cursor, Claude Code, and/or Codex in this workspace.
|
|
|
16
16
|
GitHub remotes are a separate command (agent-kit remote create).
|
|
17
17
|
|
|
18
18
|
Examples:
|
|
19
|
+
$ aifabrix agent-kit setup https://controller.example.com
|
|
19
20
|
$ aifabrix agent-kit init cust-demo --host all --approve-all --yes
|
|
20
21
|
$ aifabrix agent-kit install --host claude --approve-all --yes
|
|
21
22
|
$ aifabrix agent-kit install --host all --approve-all claude --yes
|
|
@@ -94,10 +95,12 @@ Silent remote: --host all --remote --org <owner> --yes
|
|
|
94
95
|
const REMOTE_GROUP_HELP = `
|
|
95
96
|
This is GitHub only: create origin and push this workspace.
|
|
96
97
|
It does not choose Cursor, Claude Code, or Codex.
|
|
98
|
+
For an existing GitHub repository on a managed host, use af onboarding --repo owner/name.
|
|
97
99
|
|
|
98
100
|
Examples:
|
|
99
|
-
$
|
|
100
|
-
$
|
|
101
|
+
$ cd ~/agent-kit-workspace && af agent-kit remote create --org my-org --name my-repo --yes
|
|
102
|
+
$ af onboarding --repo my-org/existing-repo
|
|
103
|
+
$ af onboarding --repo my-org/new-repo
|
|
101
104
|
$ aifabrix agent-kit install --host claude --approve-all --yes
|
|
102
105
|
$ aifabrix agent-kit install --host codex --approve-all --yes
|
|
103
106
|
$ aifabrix agent-kit install --host all --approve-all claude --yes
|
|
@@ -105,12 +108,16 @@ Examples:
|
|
|
105
108
|
|
|
106
109
|
const REMOTE_HELP = `
|
|
107
110
|
Creates a GitHub repository (origin) and pushes this workspace.
|
|
111
|
+
Run inside the local workspace. --name sets the new GitHub repository name;
|
|
112
|
+
omit it to use the workspace folder name. This command does not clone an
|
|
113
|
+
existing GitHub repository.
|
|
108
114
|
Not coding-host selection — use --host on install/update for Claude or Codex.
|
|
109
115
|
|
|
110
116
|
Examples:
|
|
111
|
-
$ cd
|
|
112
|
-
$
|
|
113
|
-
$
|
|
117
|
+
$ cd ~/agent-kit-workspace && af agent-kit remote create --org my-org --name my-repo --yes
|
|
118
|
+
$ af agent-kit remote create --org my-org --name my-repo --dry-run --json
|
|
119
|
+
$ af onboarding --repo my-org/existing-repo
|
|
120
|
+
$ af onboarding --repo my-org/new-repo
|
|
114
121
|
|
|
115
122
|
Interactive (TTY): omit flags to be prompted. Silent: --org <owner> --yes
|
|
116
123
|
`;
|
|
@@ -134,7 +141,10 @@ Examples:
|
|
|
134
141
|
`;
|
|
135
142
|
|
|
136
143
|
const LIST_HELP = `
|
|
137
|
-
Lists
|
|
144
|
+
Lists active tmux sessions and direct Codex app servers owned by the current
|
|
145
|
+
Unix user. On a terminal, choose a tmux session to attach or Close. Codex app
|
|
146
|
+
servers are shown as information and cannot be selected from this menu.
|
|
147
|
+
--json and non-interactive output print the report without a prompt.
|
|
138
148
|
|
|
139
149
|
Examples:
|
|
140
150
|
$ aifabrix agent-kit list
|
|
@@ -142,9 +152,13 @@ Examples:
|
|
|
142
152
|
`;
|
|
143
153
|
|
|
144
154
|
const KILL_HELP = `
|
|
145
|
-
Stops exactly one tmux session.
|
|
155
|
+
Stops exactly one tmux session by name. Omit the name in an interactive
|
|
156
|
+
terminal to choose a tmux session or Codex app server. Stopping a Codex app
|
|
157
|
+
server requires confirmation and may disconnect an active desktop chat.
|
|
158
|
+
Pass an exact tmux name for scripts or --json.
|
|
146
159
|
|
|
147
160
|
Examples:
|
|
161
|
+
$ aifabrix agent-kit kill
|
|
148
162
|
$ aifabrix agent-kit kill aifabrix-miso
|
|
149
163
|
$ aifabrix agent-kit kill aifabrix-miso --json
|
|
150
164
|
`;
|