@aifabrix/builder 2.55.0 → 2.55.2
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/app/deploy.js +7 -4
- package/lib/app/offer-create-from-template.js +184 -0
- package/lib/cli/setup-app.js +8 -1
- package/lib/cli/setup-auth.js +11 -2
- 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/role-assistant.js +24 -12
- 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/external-system/download.js +1 -2
- package/lib/generator/helpers.js +12 -1
- package/lib/integration-definition/apply-static-enterprise.js +5 -2
- 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 +476 -40
- 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 +23 -5
- 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/secrets-helpers.js +2 -2
- package/lib/utils/write-stream-and-wait.js +63 -0
- package/package.json +20 -6
- 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/dataplane/application.yaml +1 -2
- package/templates/applications/dataplane/env.template +5 -5
- package/templates/applications/miso-controller/application.yaml +21 -2
- package/templates/applications/miso-controller/env.template +89 -17
- package/templates/applications/miso-controller/rbac.yaml +5 -0
|
@@ -177,6 +177,21 @@ function handleGenericError(errorData, statusCode) {
|
|
|
177
177
|
return createErrorResult('generic', errorData.message || errorData.error || 'Unknown error', formatGenericError(errorData, statusCode), errorData);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
function unwrapNestedErrorData(errorData) {
|
|
181
|
+
if (!errorData || !errorData.data || typeof errorData.data !== 'object') {
|
|
182
|
+
return errorData;
|
|
183
|
+
}
|
|
184
|
+
const nested = errorData.data;
|
|
185
|
+
return {
|
|
186
|
+
...nested,
|
|
187
|
+
cliPermissionService: errorData.cliPermissionService || nested.cliPermissionService,
|
|
188
|
+
requiredPermissions: errorData.requiredPermissions || nested.requiredPermissions,
|
|
189
|
+
method: errorData.method || nested.method,
|
|
190
|
+
url: nested.instance || nested.url || errorData.url,
|
|
191
|
+
instance: nested.instance || errorData.instance
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
180
195
|
/**
|
|
181
196
|
* Parses error response and determines error type
|
|
182
197
|
* @param {string|Object} errorResponse - Error response (string or parsed JSON)
|
|
@@ -200,7 +215,7 @@ function parseErrorResponse(errorResponse, statusCode, isNetworkError) {
|
|
|
200
215
|
|
|
201
216
|
// Handle nested response structure (some APIs wrap errors in data field)
|
|
202
217
|
if (errorData.data && typeof errorData.data === 'object') {
|
|
203
|
-
errorData = errorData
|
|
218
|
+
errorData = unwrapNestedErrorData(errorData);
|
|
204
219
|
}
|
|
205
220
|
|
|
206
221
|
// Handle network errors
|
|
@@ -42,6 +42,9 @@ function extractRequiredPermissions(errorData) {
|
|
|
42
42
|
if (errorData.requiredPermissions && Array.isArray(errorData.requiredPermissions)) {
|
|
43
43
|
return errorData.requiredPermissions;
|
|
44
44
|
}
|
|
45
|
+
if (typeof errorData.requiredPermission === 'string' && errorData.requiredPermission.trim()) {
|
|
46
|
+
return [errorData.requiredPermission.trim()];
|
|
47
|
+
}
|
|
45
48
|
if (errorData.required && errorData.required.permissions && Array.isArray(errorData.required.permissions)) {
|
|
46
49
|
return errorData.required.permissions;
|
|
47
50
|
}
|
|
@@ -97,6 +100,19 @@ function getPermissionDetailLines(errorData) {
|
|
|
97
100
|
return lines;
|
|
98
101
|
}
|
|
99
102
|
|
|
103
|
+
function appendPermissionAssignHint(lines, errorData) {
|
|
104
|
+
const service = errorData.cliPermissionService;
|
|
105
|
+
if (service) {
|
|
106
|
+
lines.push(chalk.gray(`Required on: ${service}`));
|
|
107
|
+
}
|
|
108
|
+
lines.push(chalk.gray(
|
|
109
|
+
service
|
|
110
|
+
? `Assign this permission on the ${service} for this environment (roles and groups).`
|
|
111
|
+
: 'Assign the required permission on the Controller or Dataplane for this environment (roles and groups).'
|
|
112
|
+
));
|
|
113
|
+
lines.push('');
|
|
114
|
+
}
|
|
115
|
+
|
|
100
116
|
/**
|
|
101
117
|
* Formats permission error with missing and required permissions
|
|
102
118
|
* @param {Object} errorData - Error response data
|
|
@@ -111,11 +127,9 @@ function formatPermissionError(errorData) {
|
|
|
111
127
|
lines.push('');
|
|
112
128
|
}
|
|
113
129
|
|
|
114
|
-
|
|
115
|
-
addPermissionList(lines,
|
|
116
|
-
|
|
117
|
-
const requiredPerms = extractRequiredPermissions(errorData);
|
|
118
|
-
addPermissionList(lines, requiredPerms, 'Required permissions');
|
|
130
|
+
addPermissionList(lines, extractMissingPermissions(errorData), 'Missing permissions');
|
|
131
|
+
addPermissionList(lines, extractRequiredPermissions(errorData), 'Required permissions');
|
|
132
|
+
appendPermissionAssignHint(lines, errorData);
|
|
119
133
|
|
|
120
134
|
const requestUrl = errorData.instance || errorData.url;
|
|
121
135
|
const method = errorData.method || 'POST';
|
|
@@ -82,15 +82,18 @@ async function waitForKeycloakRealmReady(opts = {}) {
|
|
|
82
82
|
const directUrl = directBase ? buildRealmWellKnownUrl(directBase) : null;
|
|
83
83
|
const deadline = Date.now() + timeoutSeconds * 1000;
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
do {
|
|
86
86
|
if (await probeRealmWellKnown(url)) {
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
if (directUrl && (await probeRealmWellKnown(directUrl))) {
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
|
+
if (Date.now() >= deadline) {
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
92
95
|
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
93
|
-
}
|
|
96
|
+
} while (Date.now() < deadline);
|
|
94
97
|
|
|
95
98
|
throw new Error(
|
|
96
99
|
`Keycloak realm "aifabrix" was not ready within ${timeoutSeconds}s (checked ${url}${directUrl ? ` and ${directUrl}` : ''}). ` +
|
package/lib/utils/logger.js
CHANGED
package/lib/utils/paths.js
CHANGED
|
@@ -957,6 +957,24 @@ async function ensureShippedBuilderAppTemplate(appName) {
|
|
|
957
957
|
return true;
|
|
958
958
|
}
|
|
959
959
|
|
|
960
|
+
/**
|
|
961
|
+
* Finds an existing local app workspace without copying shipped templates.
|
|
962
|
+
*
|
|
963
|
+
* @param {string} appName - Application name
|
|
964
|
+
* @param {Object} [options] - Detection options (reserved; options.type is ignored)
|
|
965
|
+
* @returns {{isExternal: boolean, appPath: string, appType: string, baseDir?: string}|null}
|
|
966
|
+
*/
|
|
967
|
+
function findExistingAppType(appName, options = {}) {
|
|
968
|
+
if (!appName || typeof appName !== 'string') {
|
|
969
|
+
return null;
|
|
970
|
+
}
|
|
971
|
+
const externalResult = checkExternalWorkspaceFolder(appName, options);
|
|
972
|
+
if (externalResult) {
|
|
973
|
+
return externalResult;
|
|
974
|
+
}
|
|
975
|
+
return checkBuilderFolder(appName);
|
|
976
|
+
}
|
|
977
|
+
|
|
960
978
|
/**
|
|
961
979
|
* Detects if an app is external type by checking application config.
|
|
962
980
|
* Resolution order: integration/ first, then builder/; if neither exists, throws.
|
|
@@ -971,13 +989,15 @@ async function detectAppType(appName, options = {}) {
|
|
|
971
989
|
if (!appName || typeof appName !== 'string') {
|
|
972
990
|
throw new Error('App name is required and must be a string');
|
|
973
991
|
}
|
|
974
|
-
const
|
|
975
|
-
if (
|
|
976
|
-
|
|
977
|
-
|
|
992
|
+
const existing = findExistingAppType(appName, options);
|
|
993
|
+
if (existing) {
|
|
994
|
+
return existing;
|
|
995
|
+
}
|
|
978
996
|
await ensureShippedBuilderAppTemplate(appName);
|
|
979
997
|
const builderAfterTemplate = checkBuilderFolder(appName);
|
|
980
|
-
if (builderAfterTemplate)
|
|
998
|
+
if (builderAfterTemplate) {
|
|
999
|
+
return builderAfterTemplate;
|
|
1000
|
+
}
|
|
981
1001
|
throw new Error(
|
|
982
1002
|
`App '${appName}' not found in integration/${appName}, enterprise-knowledge/${appName}, role-assistant/${appName}, or builder/${appName}`
|
|
983
1003
|
);
|
|
@@ -1121,6 +1141,7 @@ module.exports = {
|
|
|
1121
1141
|
resolveApplicationConfigPath,
|
|
1122
1142
|
resolveRbacPath,
|
|
1123
1143
|
ensureShippedBuilderAppTemplate,
|
|
1144
|
+
findExistingAppType,
|
|
1124
1145
|
detectAppType,
|
|
1125
1146
|
getResolveAppPath,
|
|
1126
1147
|
resolveIntegrationAppKeyFromCwd,
|
|
@@ -47,7 +47,8 @@ const { resolveBashKvFromProcessEnv } = require('./secrets-bash-kv');
|
|
|
47
47
|
const EMPTY_ALLOWED_KV_FALLBACK = new Set([
|
|
48
48
|
'redis-passwordKeyVault',
|
|
49
49
|
'azure-openaiapi-urlKeyVault',
|
|
50
|
-
'secrets-azureOpenaiApiKeyVault'
|
|
50
|
+
'secrets-azureOpenaiApiKeyVault',
|
|
51
|
+
'miso-controller-secrets-apiKeyVault'
|
|
51
52
|
]);
|
|
52
53
|
|
|
53
54
|
/**
|
|
@@ -486,4 +487,3 @@ module.exports = {
|
|
|
486
487
|
rewriteInfraEndpoints,
|
|
487
488
|
getEnvHosts
|
|
488
489
|
};
|
|
489
|
-
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flush a writable stream chunk without hanging on Jest write mocks.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Shared stdout/stderr write + wait for CLI exits.
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {unknown} writeFn - Stream write implementation
|
|
13
|
+
* @returns {boolean}
|
|
14
|
+
*/
|
|
15
|
+
function isJestMockWrite(writeFn) {
|
|
16
|
+
return typeof jest !== 'undefined'
|
|
17
|
+
&& typeof jest.isMockFunction === 'function'
|
|
18
|
+
&& jest.isMockFunction(writeFn);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Write `chunk` and resolve after the stream flushes.
|
|
23
|
+
*
|
|
24
|
+
* Piped stdout/stderr on Linux is asynchronous; exiting before the write
|
|
25
|
+
* callback can truncate output. Jest spies that ignore the callback, and
|
|
26
|
+
* native writes inside a Jest worker, must not hang the test.
|
|
27
|
+
*
|
|
28
|
+
* @param {NodeJS.WritableStream} stream - stdout or stderr
|
|
29
|
+
* @param {string} chunk - Bytes to write
|
|
30
|
+
* @returns {Promise<void>}
|
|
31
|
+
*/
|
|
32
|
+
function writeStreamAndWait(stream, chunk) {
|
|
33
|
+
return new Promise(resolve => {
|
|
34
|
+
let settled = false;
|
|
35
|
+
const finish = () => {
|
|
36
|
+
if (settled) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
settled = true;
|
|
40
|
+
resolve();
|
|
41
|
+
};
|
|
42
|
+
if (!stream || typeof stream.write !== 'function') {
|
|
43
|
+
finish();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const writeFn = stream.write;
|
|
47
|
+
try {
|
|
48
|
+
writeFn.call(stream, chunk, finish);
|
|
49
|
+
} catch {
|
|
50
|
+
finish();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (isJestMockWrite(writeFn) && writeFn.length < 2) {
|
|
54
|
+
finish();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!isJestMockWrite(writeFn) && process.env.JEST_WORKER_ID) {
|
|
58
|
+
setImmediate(finish);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = { writeStreamAndWait };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aifabrix/builder",
|
|
3
|
-
"version": "2.55.
|
|
3
|
+
"version": "2.55.2",
|
|
4
4
|
"description": "AI Fabrix Builder — CLI and developer scripts (pnpm + af)",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -86,28 +86,42 @@
|
|
|
86
86
|
"overrides": {
|
|
87
87
|
"@babel/core": "^7.29.7",
|
|
88
88
|
"@babel/plugin-transform-modules-systemjs": "^7.29.7",
|
|
89
|
-
"
|
|
89
|
+
"baseline-browser-mapping": "^2.11.21",
|
|
90
|
+
"brace-expansion@5": "5.0.9",
|
|
91
|
+
"browserslist": "^4.28.9",
|
|
92
|
+
"fast-uri": "^4.1.4",
|
|
90
93
|
"flatted": "^3.4.2",
|
|
91
94
|
"follow-redirects": "^1.16.0",
|
|
92
95
|
"form-data": "^4.0.6",
|
|
96
|
+
"js-yaml@3": "3.15.2",
|
|
97
|
+
"js-yaml@5": "5.4.1",
|
|
93
98
|
"lodash": "^4.18.1",
|
|
94
99
|
"minimatch": "^10.2.5",
|
|
100
|
+
"multer": "^2.3.0",
|
|
95
101
|
"picomatch": "^4.0.5",
|
|
96
|
-
"qs": "^6.
|
|
102
|
+
"qs": "^6.16.0",
|
|
103
|
+
"smol-toml": "^1.8.0"
|
|
97
104
|
},
|
|
98
105
|
"pnpm": {
|
|
99
106
|
"overrides": {
|
|
100
107
|
"@bcoe/v8-coverage": "^1.0.2",
|
|
101
108
|
"@babel/core": "^7.29.7",
|
|
102
109
|
"@babel/plugin-transform-modules-systemjs": "^7.29.7",
|
|
103
|
-
"
|
|
110
|
+
"baseline-browser-mapping": "^2.11.21",
|
|
111
|
+
"brace-expansion@5": "5.0.9",
|
|
112
|
+
"browserslist": "^4.28.9",
|
|
113
|
+
"fast-uri": "^4.1.4",
|
|
104
114
|
"flatted": "^3.4.2",
|
|
105
115
|
"follow-redirects": "^1.16.0",
|
|
106
116
|
"form-data": "^4.0.6",
|
|
117
|
+
"js-yaml@3": "3.15.2",
|
|
118
|
+
"js-yaml@5": "5.4.1",
|
|
107
119
|
"lodash": "^4.18.1",
|
|
108
120
|
"minimatch": "^10.2.5",
|
|
121
|
+
"multer": "^2.3.0",
|
|
109
122
|
"picomatch": "^4.0.5",
|
|
110
|
-
"qs": "^6.
|
|
123
|
+
"qs": "^6.16.0",
|
|
124
|
+
"smol-toml": "^1.8.0"
|
|
111
125
|
}
|
|
112
126
|
},
|
|
113
127
|
"dependencies": {
|
|
@@ -121,7 +135,7 @@
|
|
|
121
135
|
"handlebars": "^4.7.9",
|
|
122
136
|
"inquirer": "^8.2.5",
|
|
123
137
|
"inquirer-autocomplete-prompt": "^2.0.0",
|
|
124
|
-
"js-yaml": "^4.3.
|
|
138
|
+
"js-yaml": "^4.3.2",
|
|
125
139
|
"ora": "^5.4.1",
|
|
126
140
|
"yaml": "^2.9.0"
|
|
127
141
|
},
|
|
@@ -34,7 +34,7 @@ New workspace instead of an existing repo: `aifabrix agent-kit init <workspaceNa
|
|
|
34
34
|
Install the coding app, then sign in. How to **run** it locally or over SSH is in `.agents/skills/shared/hosts.md` (linked from every Agent Kit skill).
|
|
35
35
|
{{#if autoApprove}}
|
|
36
36
|
|
|
37
|
-
On TTY, install **asks** to auto-approve
|
|
37
|
+
On TTY, install **asks** which hosts to support (omit `--host`) and which tools to auto-approve. `--approve-all claude` or `--approve-all codex` writes only that host's config. Claude Code also allows `Bash(aifabrix *)` (delivery CLI) and `Read(~/**)` (home Read). Silent (`--yes` / non-TTY) writes them; `--skip-approve-all` skips.
|
|
38
38
|
{{#if claude}}
|
|
39
39
|
- Claude Code writes `.claude/settings.local.json` (gitignored).
|
|
40
40
|
{{/if}}
|
|
@@ -57,22 +57,43 @@ curl -fsSL https://claude.ai/install.sh | bash
|
|
|
57
57
|
claude auth login
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
**Run in tmux** from this workspace so closing the terminal does not kill Claude. `--remote-control` is the **same** session on this PC, [claude.ai/code](https://claude.ai/code), and the Claude mobile app (Code). That is not `claude --cloud` (a separate cloud VM). Claude `--tmux` is for worktrees only.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
aifabrix agent-kit start claude --remote-control --approve-all --yes
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
tmux session name defaults to this folder. Remote Control name is `hostname-user-folder` (for example `builder01-dev03-aifabrix-docs`). Override the folder with `--name`. Detach: `Ctrl-b` then `d`. Reattach: `tmux attach -t <folder>`. Several workspaces can run at once. Same account on phone and PC (`claude auth login`, Pro/Max/Team — not an API key). On the phone: Claude app → **Code**. Skills: `/aifabrix-plan` (and the other `/aifabrix-*` names). First `claude` must run inside this workspace, not your home directory. Full notes: `.agents/skills/shared/hosts.md`.
|
|
61
67
|
{{/if}}
|
|
62
68
|
{{#if codex}}
|
|
63
69
|
|
|
64
70
|
### Codex
|
|
65
71
|
|
|
66
|
-
Install the Codex CLI, then sign in with
|
|
72
|
+
Install the Codex CLI (`@openai/codex`, not the unrelated `codex` package), then sign in with ChatGPT (Plus, Pro, Business, Edu, or Enterprise):
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npm install -g @openai/codex
|
|
76
|
+
codex login
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Run in tmux** from this workspace so the session stays if you close the terminal:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
aifabrix agent-kit start codex --approve-all --yes
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Detach: `Ctrl-b` then `d`. Reattach: `tmux attach -t <folder>`, or `aifabrix agent-kit start codex` from this workspace. Default session name is this folder. Skills: `$aifabrix-plan` (and the other `$aifabrix-*` names). Codex reads `AGENTS.md`. Full notes: `.agents/skills/shared/hosts.md`.
|
|
67
86
|
{{/if}}
|
|
68
87
|
|
|
69
88
|
## Auth for delivery CLI
|
|
70
89
|
|
|
90
|
+
Do not tell the user to open a terminal for Builder login. Follow `.agents/skills/shared/login.md`.
|
|
91
|
+
|
|
71
92
|
```bash
|
|
72
93
|
aifabrix auth status
|
|
73
94
|
```
|
|
74
95
|
|
|
75
|
-
If
|
|
96
|
+
If that is not authenticated, ask for the Miso Controller URL, run device login, and paste the printed authenticate URL into chat.
|
|
76
97
|
|
|
77
98
|
## How to start
|
|
78
99
|
|
|
@@ -28,7 +28,7 @@ Do not collapse these into a generic success boolean. Do not start the next life
|
|
|
28
28
|
## Coding hosts
|
|
29
29
|
|
|
30
30
|
Cursor, Claude Code, and Codex — local machine or SSH (tmux, Claude Remote Control): `.agents/skills/shared/hosts.md`.
|
|
31
|
-
Install and sign-in: `AGENTKIT.md`.
|
|
31
|
+
Install and sign-in: `AGENTKIT.md`. Builder CLI login from chat: `.agents/skills/shared/login.md`.
|
|
32
32
|
|
|
33
33
|
## Docs
|
|
34
34
|
|
|
@@ -24,6 +24,7 @@ Stop at the phase gate. Do not run the next phase without `next-yes`
|
|
|
24
24
|
|
|
25
25
|
Read current CLI help before composing commands. You own orchestration, not CLI implementation.
|
|
26
26
|
Host runtimes (local vs SSH): [hosts.md](../shared/hosts.md).
|
|
27
|
+
CLI login from chat: [login.md](../shared/login.md).
|
|
27
28
|
|
|
28
29
|
## Always
|
|
29
30
|
|
|
@@ -31,7 +32,7 @@ Host runtimes (local vs SSH): [hosts.md](../shared/hosts.md).
|
|
|
31
32
|
aifabrix auth status
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
Refresh first.
|
|
35
|
+
Refresh first. If still unauthenticated, follow [login.md](../shared/login.md). Re-run on 401, then retry once.
|
|
35
36
|
|
|
36
37
|
System key: argument → active plan → sole `integration/` folder → ask once. Never invent. Reject `ra-` / `ek-` ([scripts/reserved-system-key.js](scripts/reserved-system-key.js)).
|
|
37
38
|
|
|
@@ -41,7 +41,7 @@ Never mark live E2E pass when it did not run.
|
|
|
41
41
|
|
|
42
42
|
## Identity and protection order
|
|
43
43
|
|
|
44
|
-
1. `aifabrix auth status`
|
|
44
|
+
1. `aifabrix auth status` — if unauthenticated, [login.md](../../shared/login.md)
|
|
45
45
|
2. Catalog roles + fixtures + `identity apply` / `identity sync` / `role set-groups`
|
|
46
46
|
3. Load partitioned fixtures
|
|
47
47
|
4. `aifabrix protection upload <sourceStorageDs> --sync` (storage DS, not the view)
|
|
@@ -15,6 +15,7 @@ Output: one delivery plan from [plan-template.md](references/plan-template.md).
|
|
|
15
15
|
Score completeness with [challenge-checklist.md](references/challenge-checklist.md).
|
|
16
16
|
Next-step interaction: [interaction.md](references/interaction.md).
|
|
17
17
|
Host runtimes (local vs SSH): [hosts.md](../shared/hosts.md).
|
|
18
|
+
CLI login from chat: [login.md](../shared/login.md).
|
|
18
19
|
|
|
19
20
|
## Sequence
|
|
20
21
|
|
|
@@ -44,7 +45,7 @@ aifabrix auth status
|
|
|
44
45
|
aifabrix role list --page-size 1000
|
|
45
46
|
```
|
|
46
47
|
|
|
47
|
-
If
|
|
48
|
+
If unauthenticated after refresh, follow [login.md](../shared/login.md) before listing catalog roles.
|
|
48
49
|
|
|
49
50
|
## Trigger examples
|
|
50
51
|
|
|
@@ -19,6 +19,7 @@ Evidence rules: [evidence-lifecycle.md](references/evidence-lifecycle.md).
|
|
|
19
19
|
Demo shape: [demo-template.md](references/demo-template.md).
|
|
20
20
|
Next-step: [interaction.md](../aifabrix-plan/references/interaction.md).
|
|
21
21
|
Host runtimes (local vs SSH): [hosts.md](../shared/hosts.md).
|
|
22
|
+
CLI login from chat: [login.md](../shared/login.md).
|
|
22
23
|
|
|
23
24
|
## Keys
|
|
24
25
|
|
|
@@ -10,6 +10,7 @@ description: >
|
|
|
10
10
|
|
|
11
11
|
See [package-boundary.md](references/package-boundary.md) and nested `role-assistant/AGENTS.md`.
|
|
12
12
|
Host runtimes (local vs SSH): [hosts.md](../shared/hosts.md).
|
|
13
|
+
CLI login from chat: [login.md](../shared/login.md).
|
|
13
14
|
|
|
14
15
|
## Preconditions
|
|
15
16
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use this workspace from **Cursor**, **Claude Code**, and **Codex**. Skills live in `.agents/skills/`. Invoke `/aifabrix-*` in Cursor and Claude Code, and `$aifabrix-*` in Codex.
|
|
4
4
|
|
|
5
|
-
Install and sign-in steps are in `AGENTKIT.md`. This file is how to **run** each host on a local machine or over SSH.
|
|
5
|
+
Install and sign-in steps are in `AGENTKIT.md`. This file is how to **run** each host on a local machine or over SSH. Builder CLI login from chat: [login.md](login.md).
|
|
6
6
|
|
|
7
7
|
Do not start Claude or Codex in your home directory. `cd` into this git workspace first.
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ Do not start Claude or Codex in your home directory. `cd` into this git workspac
|
|
|
13
13
|
- Claude Code: `.claude/settings.local.json` (`permissions.defaultMode` = `bypassPermissions`, `allow` = `Bash(aifabrix *)` and `Read(~/**)`)
|
|
14
14
|
- Codex: `.codex/config.toml` (`approval_policy = "never"`, `sandbox_mode = "workspace-write"`)
|
|
15
15
|
|
|
16
|
-
Those files stay in **this workspace**. Claude may **read** files under the developer home (`Read(~/**)`) and run the delivery CLI (`Bash(aifabrix *)`). They do not add sibling folders as extra workspaces, do not grant Write outside this repo, and do not allow every shell command. TTY asks
|
|
16
|
+
Those files stay in **this workspace**. Claude may **read** files under the developer home (`Read(~/**)`) and run the delivery CLI (`Bash(aifabrix *)`). They do not add sibling folders as extra workspaces, do not grant Write outside this repo, and do not allow every shell command. TTY asks which host to auto-approve when both are selected. `--approve-all claude` or `--approve-all codex` writes only that host. `--yes` or a non-TTY / `--json` run writes them. `--skip-approve-all` skips. `--force` overwrites existing local files. Builder never writes `~/.claude` or `~/.codex`.
|
|
17
17
|
|
|
18
18
|
## Cursor
|
|
19
19
|
|
|
@@ -23,48 +23,35 @@ Those files stay in **this workspace**. Claude may **read** files under the deve
|
|
|
23
23
|
|
|
24
24
|
## Claude Code
|
|
25
25
|
|
|
26
|
-
**Local.**
|
|
26
|
+
**Local or SSH — tmux.** Closing the terminal must not kill Claude. Agent Kit starts Claude **inside tmux**. `--remote-control` is the **same** session on this PC, [claude.ai/code](https://claude.ai/code), and the Claude mobile app (**Code**). Do not use `claude --cloud` for this — that starts a different machine that clones GitHub. Claude `--tmux` is only for `--worktree` sessions, not this wrapper.
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
|
|
30
|
-
claude
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Then `/aifabrix-plan` (or another `/aifabrix-*` skill). First run in a project asks you to trust the folder; accept only this workspace.
|
|
34
|
-
|
|
35
|
-
**SSH (keep the session after you disconnect).** tmux holds the process on the remote machine:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
tmux new -s claude -c /path/to/this-workspace
|
|
39
|
-
claude --remote-control
|
|
29
|
+
aifabrix agent-kit start claude --remote-control --approve-all --yes
|
|
40
30
|
```
|
|
41
31
|
|
|
42
|
-
Detach without killing Claude: `Ctrl-b` then `d`. Reattach: `tmux attach -t
|
|
32
|
+
tmux session name is this folder (for example `aifabrix-docs`). Remote Control name is `hostname-user-folder` (for example `builder01-dev03-aifabrix-docs`). `--name` overrides the folder. Several workspaces can run at once. Detach without killing Claude: `Ctrl-b` then `d`. Reattach: `tmux attach -t aifabrix-docs`, or run `start` again from the same folder. Then `/aifabrix-plan` (or another `/aifabrix-*` skill). First run in a project asks you to trust the folder; accept only this workspace.
|
|
43
33
|
|
|
44
|
-
**Phone and
|
|
34
|
+
**Phone and PC.** Sign in with the same Claude Pro/Max/Team account (`claude auth login` — not an API key). After Remote Control starts, open **Code** in the Claude mobile app and/or [claude.ai/code](https://claude.ai/code) on the PC. In an already-running session, `/remote-control` or `/mobile`.
|
|
45
35
|
|
|
46
|
-
Closing SSH does not stop a tmux session. Stopping tmux or the machine does.
|
|
36
|
+
Closing the terminal (or SSH) does not stop a tmux session. Stopping tmux or the machine does. Remote Control also stops if this host goes down.
|
|
47
37
|
|
|
48
38
|
## Codex
|
|
49
39
|
|
|
50
|
-
**Local.**
|
|
40
|
+
**Local or SSH — tmux (recommended).** Same recipe on your PC and on a remote host. tmux keeps Codex running if you close the terminal or disconnect SSH. Codex has no Claude-style phone/web Remote Control.
|
|
51
41
|
|
|
52
42
|
```bash
|
|
53
|
-
|
|
54
|
-
codex
|
|
43
|
+
aifabrix agent-kit start codex --approve-all --yes
|
|
55
44
|
```
|
|
56
45
|
|
|
57
|
-
Then `$aifabrix-plan` (and the other `$aifabrix-*` skills). Codex reads `AGENTS.md`.
|
|
46
|
+
Equivalent: `tmux new -s aifabrix-docs -c /path/to/this-workspace` then `codex`. Default `--name` is the last folder. If that session already exists, `start` attaches. Detach: `Ctrl-b` then `d`. Then `$aifabrix-plan` (and the other `$aifabrix-*` skills). Codex reads `AGENTS.md`.
|
|
58
47
|
|
|
59
|
-
**
|
|
48
|
+
**Foreground only (no tmux).**
|
|
60
49
|
|
|
61
50
|
```bash
|
|
62
|
-
|
|
51
|
+
cd /path/to/this-workspace
|
|
63
52
|
codex
|
|
64
53
|
```
|
|
65
54
|
|
|
66
|
-
Detach: `Ctrl-b` then `d`. Reattach: `tmux attach -t codex`. Codex has no Claude-style phone/web Remote Control; stay in tmux (or reattach later) to see the session.
|
|
67
|
-
|
|
68
55
|
## tmux cheat sheet
|
|
69
56
|
|
|
70
57
|
| Action | Keys / command |
|
|
@@ -75,4 +62,4 @@ Detach: `Ctrl-b` then `d`. Reattach: `tmux attach -t codex`. Codex has no Claude
|
|
|
75
62
|
| Attach | `tmux attach -t <name>` |
|
|
76
63
|
| Kill session | `tmux kill-session -t <name>` |
|
|
77
64
|
|
|
78
|
-
Use
|
|
65
|
+
Use a different `--name` per workspace so several Claude or Codex sessions can run on the same host. Claude and Codex in the **same** folder also need two names.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Delivery CLI login (no terminal)
|
|
2
|
+
|
|
3
|
+
Before any online Builder command (`deploy`, `upload`, `role list`, `show --online`):
|
|
4
|
+
|
|
5
|
+
1. Run `aifabrix auth status`. If authenticated, continue.
|
|
6
|
+
2. If not, ask the user in chat for the Miso Controller URL. Do not invent it. Paste whatever they give you; extra path segments are ignored.
|
|
7
|
+
3. Run (environment **dev** unless they named another):
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
aifabrix login --method device -c <url> -e dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
4. As soon as the command prints **Open this URL to authenticate:**, copy that full URL into chat and ask the user to open it and approve. Do not ask them to use a terminal.
|
|
14
|
+
5. Leave the login command running until it reports success (or fails). Then run `aifabrix auth status` again.
|
|
15
|
+
|
|
16
|
+
On 401 later, repeat this flow once, then retry the original command.
|
|
@@ -9,7 +9,7 @@ Vendor limits, credentials, designated test subjects, and PII live only in each
|
|
|
9
9
|
## How to start
|
|
10
10
|
|
|
11
11
|
1. Open **this folder** in Cursor, Claude Code, or Codex. Host install and sign-in: **[AGENTKIT.md](./AGENTKIT.md)**.
|
|
12
|
-
2.
|
|
12
|
+
2. The agent checks `aifabrix auth status`. If you are not signed in, it asks for the Miso Controller URL and gives you a browser link. You do not need a terminal. Details: **[AGENTKIT.md](./AGENTKIT.md)**.
|
|
13
13
|
3. In chat, either **invoke a skill** or **paste a prompt** from the tables below. Work in order. Wait for the gate (`PLAN_READY`, `READY`, `BUILT`, then `PASS` or `PASS_WITH_SKIPS`) before the next step.
|
|
14
14
|
|
|
15
15
|
### How to use prompts
|
|
@@ -5,7 +5,7 @@ app:
|
|
|
5
5
|
description: "AI Fabrix Dataplane is a secure, in-tenant integration and automation layer that supplies governed, normalized, and explainable enterprise data to AI agents. Using CIP as a declarative standard, it enforces RBAC and ABAC, executes integrations, and exposes trusted data via MCP and OpenAPI."
|
|
6
6
|
type: webapp
|
|
7
7
|
language: python # Explicitly specify Python language
|
|
8
|
-
version: 2.0.
|
|
8
|
+
version: 2.0.65
|
|
9
9
|
# Image Configuration
|
|
10
10
|
# Set tag to match your build (example: aifabrix build dataplane -t 1.0.0).
|
|
11
11
|
# Registry is required so the controller can pull the image (avoids docker-not-found on the controller host).
|
|
@@ -240,4 +240,3 @@ configuration:
|
|
|
240
240
|
field: text
|
|
241
241
|
label: "Default LLM provider (system key when two or more providers)"
|
|
242
242
|
placeholder: "openai"
|
|
243
|
-
|
|
@@ -30,8 +30,8 @@ LOCAL_MODE=false
|
|
|
30
30
|
# CELERY_WORKER_RUNTIME is set automatically by python -m app.core.celery_worker_main (NullPool per task).
|
|
31
31
|
# CELERY_LOG_LEVEL=info
|
|
32
32
|
|
|
33
|
-
# When API_KEY is set, a matching Bearer token bypasses OAuth2 validation
|
|
34
|
-
# Same kv:// as miso-controller API_KEY
|
|
33
|
+
# When API_KEY is set, a matching Bearer token bypasses OAuth2 validation.
|
|
34
|
+
# Same kv:// as miso-controller API_KEY; Azure may leave this optional key empty.
|
|
35
35
|
API_KEY=kv://miso-controller-secrets-apiKeyVault
|
|
36
36
|
# Comma-separated realm roles attached to API_KEY bypass (JWT realm_access.roles). Default: operator.
|
|
37
37
|
# Dev manual tests (437 governance, enterprise-llm llm.call): use full-access locally; restrict in tst/pro.
|
|
@@ -44,7 +44,7 @@ API_KEY_BYPASS_ROLES=full-access
|
|
|
44
44
|
|
|
45
45
|
# API Configuration
|
|
46
46
|
API_V1_STR=/api/v1
|
|
47
|
-
VERSION=2.0.
|
|
47
|
+
VERSION=2.0.65
|
|
48
48
|
# Minimum supported aifabrix-builder CLI semver (advertised on /health and /api/v1/health; empty = no gate)
|
|
49
49
|
# MIN_BUILDER_CLI_VERSION=2.45.0
|
|
50
50
|
MIN_BUILDER_CLI_VERSION=2.45.5
|
|
@@ -258,7 +258,7 @@ DATAPLANE_PUBLIC_KEY_ID=
|
|
|
258
258
|
CERTIFICATE_PRIVATE_KEY=kv://secrets-certificatePrivateKeyVault
|
|
259
259
|
CERTIFICATE_PUBLIC_KEY=kv://secrets-certificatePublicKeyVault
|
|
260
260
|
# Optional public key identifier for issued certificates; default if unset: dataplane-signing-key
|
|
261
|
-
CERTIFICATE_PUBLIC_KEY_ID=
|
|
261
|
+
CERTIFICATE_PUBLIC_KEY_ID=dataplane-signing-key
|
|
262
262
|
|
|
263
263
|
# =============================================================================
|
|
264
264
|
# VALIDATION ENGINE — YAML CONTRACTS
|
|
@@ -333,4 +333,4 @@ TRUST_AI_EXPOSURE_GATE_ENABLED=false
|
|
|
333
333
|
# app/schemas/json/external-datasource.schema.json metadata.version. Set CERTIFICATION_RULES_VERSION
|
|
334
334
|
# when 346.rules / §17 revisions must invalidate existing certificates without matching rulesVersion.
|
|
335
335
|
CERTIFICATION_DATASOURCE_SCHEMA_VERSION=
|
|
336
|
-
CERTIFICATION_RULES_VERSION=
|
|
336
|
+
CERTIFICATION_RULES_VERSION=
|
|
@@ -4,7 +4,7 @@ app:
|
|
|
4
4
|
displayName: 'Miso Controller'
|
|
5
5
|
description: 'Miso is the AI Fabrix in-tenant controller and portal layer for securely operating enterprise AI apps inside a customer’s Azure tenant. It provides Entra ID SSO, RBAC, audit logs, environment/app configuration via schemas, and safe secret handling via Key Vault references—ensuring governance, traceability, and predictable UX across portal, SDK, and CLI.'
|
|
6
6
|
type: webapp
|
|
7
|
-
version: '2.0.
|
|
7
|
+
version: '2.0.66'
|
|
8
8
|
# Image Configuration
|
|
9
9
|
# Set tag to match your build (e.g. aifabrix build miso-controller -t 1.0.0 then tag: 1.0.0)
|
|
10
10
|
# Registry is required so the controller can pull the image (avoids "docker: not found" on the controller host).
|
|
@@ -72,10 +72,29 @@ repository:
|
|
|
72
72
|
#
|
|
73
73
|
# NOT included (auto-configured):
|
|
74
74
|
# - DATABASE_URL, REDIS_URL, KEYCLOAK_* → auto-generated during Azure install
|
|
75
|
-
# - MISO_*, AZURE_*, kv:// → credentials and system parameters
|
|
75
|
+
# - Other MISO_*, AZURE_*, kv:// → credentials and system parameters
|
|
76
76
|
# - PORT, NODE_ENV, MISO_ENVIRONMENT → set by deployment target
|
|
77
77
|
|
|
78
78
|
configuration:
|
|
79
|
+
# -------------------------------------------------------------------------
|
|
80
|
+
# Security & browser session
|
|
81
|
+
# -------------------------------------------------------------------------
|
|
82
|
+
- name: MISO_APPLICATION_SECRETS_UI_ENABLED
|
|
83
|
+
category: Security
|
|
84
|
+
portalInput:
|
|
85
|
+
field: select
|
|
86
|
+
label: 'Enable Settings System Secrets tab'
|
|
87
|
+
options:
|
|
88
|
+
- 'false'
|
|
89
|
+
- 'true'
|
|
90
|
+
|
|
91
|
+
- name: AUTH_BROWSER_SESSION_TTL_SECONDS
|
|
92
|
+
category: Security
|
|
93
|
+
portalInput:
|
|
94
|
+
field: text
|
|
95
|
+
label: 'Browser Session Idle Timeout (seconds)'
|
|
96
|
+
placeholder: '1800'
|
|
97
|
+
|
|
79
98
|
# -------------------------------------------------------------------------
|
|
80
99
|
# Operations & Debugging
|
|
81
100
|
# -------------------------------------------------------------------------
|