@event4u/agent-config 4.3.0 → 4.5.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/.agent-src/commands/agents/user/init.md +7 -13
- package/.agent-src/commands/agents/user/show.md +4 -4
- package/.agent-src/commands/post-as/me.md +6 -6
- package/.agent-src/contexts/execution/autonomy-mechanics.md +1 -1
- package/.agent-src/contexts/execution/cheap-question-mechanics.md +4 -0
- package/.agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +110 -66
- package/config/discovery/packs.yml +9 -1
- package/config/discovery/workspaces.yml +14 -1
- package/dist/cli/agent-config.js +5 -4
- package/dist/cli/agent-config.js.map +1 -1
- package/dist/cli/commands/uiServe.js +27 -11
- package/dist/cli/commands/uiServe.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +51 -8
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +25 -4
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +4 -4
- package/dist/install/selectedTools.js +52 -0
- package/dist/install/selectedTools.js.map +1 -0
- package/dist/install/toolDetection.js +104 -0
- package/dist/install/toolDetection.js.map +1 -0
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/server/app.js +36 -0
- package/dist/server/app.js.map +1 -1
- package/dist/server/routes/ping.js +17 -0
- package/dist/server/routes/ping.js.map +1 -1
- package/dist/server/routes/wizard.js +240 -28
- package/dist/server/routes/wizard.js.map +1 -1
- package/dist/server/serverInfo.js +54 -0
- package/dist/server/serverInfo.js.map +1 -0
- package/dist/shared/userMd/formAdapter.js +1 -5
- package/dist/shared/userMd/formAdapter.js.map +1 -1
- package/dist/shared/userMd/schema.js +2 -1
- package/dist/shared/userMd/schema.js.map +1 -1
- package/dist/ui/assets/index-J0-0d7RC.js +40 -0
- package/dist/ui/assets/index-J0-0d7RC.js.map +1 -0
- package/dist/ui/assets/index-ZiC8PbdW.css +1 -0
- package/dist/ui/index.html +2 -2
- package/docs/archive/CHANGELOG-pre-4.0.0.md +80 -0
- package/docs/contracts/agent-user-schema.md +1 -3
- package/docs/contracts/discovery-manifest.schema.json +3 -1
- package/docs/contracts/gui-wizard.md +96 -8
- package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +27 -0
- package/docs/decisions/ADR-021-deployment-shape.md +2 -2
- package/docs/deploy/connector-setup.md +2 -2
- package/docs/deploy/policy-cookbook.md +2 -2
- package/docs/examples/agent-user.example.md +0 -1
- package/package.json +1 -1
- package/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
- package/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
- package/scripts/build_discovery_manifest.py +4 -0
- package/scripts/condense_memory.py +8 -2
- package/scripts/install.py +73 -0
- package/scripts/lint_discovery_vocabulary.py +8 -0
- package/dist/ui/assets/index-BDAhhpDV.js +0 -40
- package/dist/ui/assets/index-BDAhhpDV.js.map +0 -1
- package/dist/ui/assets/index-BXZILUxe.css +0 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native AI-tool presence detection (road-to-wizard-ux-improvements § Phase 2).
|
|
3
|
+
*
|
|
4
|
+
* Distinct from `detectToolPresence` (detect.ts), which checks the *project*
|
|
5
|
+
* for agent-config bridge dirs ("we set up a bridge here"). This module
|
|
6
|
+
* answers "is the AI tool itself installed on this machine?" by probing the
|
|
7
|
+
* user's home dir, well-known app bundles, and `$PATH` — so the wizard's
|
|
8
|
+
* Step-1 list can pre-select detected tools (first run) and show a per-tool
|
|
9
|
+
* installed/not-installed badge.
|
|
10
|
+
*
|
|
11
|
+
* The signal table is intentionally data-driven and best-effort: a tool with
|
|
12
|
+
* no reliable signal (e.g. a VS Code extension) simply reports `false`
|
|
13
|
+
* (badge = not installed, no pre-select) — false negatives are acceptable,
|
|
14
|
+
* false positives are not. Extend `TOOL_SIGNALS` as new tools/signals are
|
|
15
|
+
* learned; that is the single place to maintain (the accepted trade-off).
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { homedir } from 'node:os';
|
|
19
|
+
import { delimiter, join } from 'node:path';
|
|
20
|
+
/**
|
|
21
|
+
* Best-effort signal table keyed by the tool id used in the wizard's
|
|
22
|
+
* `VALID_TOOLS` (src/ui/wizard/state.ts). Keep ids in sync with that list.
|
|
23
|
+
*/
|
|
24
|
+
const TOOL_SIGNALS = {
|
|
25
|
+
'claude-code': { bins: ['claude'], homePaths: ['.claude', '.claude.json', '.config/claude'] },
|
|
26
|
+
'claude-desktop': { absPaths: ['/Applications/Claude.app'], homePaths: ['Library/Application Support/Claude', '.config/Claude'] },
|
|
27
|
+
'cursor': { bins: ['cursor'], absPaths: ['/Applications/Cursor.app'], homePaths: ['.cursor'] },
|
|
28
|
+
'windsurf': { bins: ['windsurf'], absPaths: ['/Applications/Windsurf.app'], homePaths: ['.codeium/windsurf'] },
|
|
29
|
+
'cline': { homePaths: ['Documents/Cline'] },
|
|
30
|
+
'gemini-cli': { bins: ['gemini'], homePaths: ['.gemini'] },
|
|
31
|
+
'copilot': { bins: ['copilot'], homePaths: ['.config/github-copilot'] },
|
|
32
|
+
'augment': { bins: ['auggie', 'augment'], homePaths: ['.augment'] },
|
|
33
|
+
'aider': { bins: ['aider'], homePaths: ['.aider.conf.yml'] },
|
|
34
|
+
'codex': { bins: ['codex'], homePaths: ['.codex'] },
|
|
35
|
+
'roocode': {},
|
|
36
|
+
'continue': { homePaths: ['.continue'] },
|
|
37
|
+
'kilocode': {},
|
|
38
|
+
'zed': { bins: ['zed'], absPaths: ['/Applications/Zed.app'], homePaths: ['.config/zed'] },
|
|
39
|
+
'jetbrains': { homePaths: ['Library/Application Support/JetBrains', '.config/JetBrains'] },
|
|
40
|
+
'kiro': { bins: ['kiro'], absPaths: ['/Applications/Kiro.app'], homePaths: ['.kiro'] },
|
|
41
|
+
'qoder': { absPaths: ['/Applications/Qoder.app'], homePaths: ['.qoder'] },
|
|
42
|
+
'opencode': { bins: ['opencode'], homePaths: ['.opencode', '.config/opencode'] },
|
|
43
|
+
'trae': { absPaths: ['/Applications/Trae.app'], homePaths: ['.trae'] },
|
|
44
|
+
'antigravity': { absPaths: ['/Applications/Antigravity.app'], homePaths: ['.antigravity'] },
|
|
45
|
+
'codebuddy': { homePaths: ['.codebuddy'] },
|
|
46
|
+
'droid': { bins: ['droid'], homePaths: ['.factory', '.droid'] },
|
|
47
|
+
'warp': { absPaths: ['/Applications/Warp.app', '/Applications/Warp.app/Contents'], homePaths: ['.warp', '.local/share/warp-terminal'] },
|
|
48
|
+
};
|
|
49
|
+
/** Tool ids this module knows how to probe (the wizard's full tool set). */
|
|
50
|
+
export function knownToolIds() {
|
|
51
|
+
return Object.keys(TOOL_SIGNALS);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Is an executable named `name` resolvable on `$PATH`? Exported for one-off
|
|
55
|
+
* presence checks (e.g. `rtk` on the Editor-and-tooling step). Defaults to
|
|
56
|
+
* `process.env.PATH`.
|
|
57
|
+
*/
|
|
58
|
+
export function isBinaryOnPath(name, pathEnv) {
|
|
59
|
+
return binOnPath(name, pathEnv ?? process.env['PATH'] ?? '');
|
|
60
|
+
}
|
|
61
|
+
function binOnPath(name, pathEnv) {
|
|
62
|
+
if (pathEnv.length === 0)
|
|
63
|
+
return false;
|
|
64
|
+
for (const dir of pathEnv.split(delimiter)) {
|
|
65
|
+
if (dir.length === 0)
|
|
66
|
+
continue;
|
|
67
|
+
if (existsSync(join(dir, name)))
|
|
68
|
+
return true;
|
|
69
|
+
// Windows-style executables.
|
|
70
|
+
if (existsSync(join(dir, `${name}.exe`)) || existsSync(join(dir, `${name}.cmd`)))
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
function isToolInstalled(signal, home, pathEnv) {
|
|
76
|
+
for (const rel of signal.homePaths ?? []) {
|
|
77
|
+
if (existsSync(join(home, rel)))
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
for (const abs of signal.absPaths ?? []) {
|
|
81
|
+
if (existsSync(abs))
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
for (const bin of signal.bins ?? []) {
|
|
85
|
+
if (binOnPath(bin, pathEnv))
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Probe every known tool and return a `{ <toolId>: installed }` map. Tools
|
|
92
|
+
* with no reliable signal report `false`. Pure w.r.t. injected `home`/`pathEnv`
|
|
93
|
+
* (only reads the filesystem), so it's safe to call per wizard boot.
|
|
94
|
+
*/
|
|
95
|
+
export function detectInstalledTools(opts = {}) {
|
|
96
|
+
const home = opts.home ?? homedir();
|
|
97
|
+
const pathEnv = opts.pathEnv ?? process.env['PATH'] ?? '';
|
|
98
|
+
const out = {};
|
|
99
|
+
for (const [id, signal] of Object.entries(TOOL_SIGNALS)) {
|
|
100
|
+
out[id] = isToolInstalled(signal, home, pathEnv);
|
|
101
|
+
}
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=toolDetection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolDetection.js","sourceRoot":"","sources":["../../src/install/toolDetection.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"discovery": {
|
|
3
3
|
"artefact_count": 432,
|
|
4
|
-
"scanner_version": "
|
|
4
|
+
"scanner_version": "d75eba636abb"
|
|
5
5
|
},
|
|
6
6
|
"generated_at": "2026-05-27",
|
|
7
7
|
"package": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"homepage": "https://github.com/event4u-app/agent-config#readme",
|
|
10
10
|
"name": "@event4u/agent-config",
|
|
11
11
|
"repository": "https://github.com/event4u-app/agent-config",
|
|
12
|
-
"version": "4.
|
|
12
|
+
"version": "4.5.0"
|
|
13
13
|
},
|
|
14
14
|
"registries": [
|
|
15
15
|
{
|
package/dist/server/app.js
CHANGED
|
@@ -80,6 +80,42 @@ export async function createApp(opts) {
|
|
|
80
80
|
}
|
|
81
81
|
return undefined;
|
|
82
82
|
});
|
|
83
|
+
// Browser-lifecycle watchdog (real-serve only — see CreateAppOptions).
|
|
84
|
+
if (opts.idleShutdown !== undefined) {
|
|
85
|
+
const { onIdle } = opts.idleShutdown;
|
|
86
|
+
const timeoutMs = opts.idleShutdown.timeoutMs ?? 1_800_000;
|
|
87
|
+
const intervalMs = opts.idleShutdown.intervalMs ?? 30_000;
|
|
88
|
+
let lastActivity = 0; // 0 = disarmed: no client has connected yet.
|
|
89
|
+
let fired = false;
|
|
90
|
+
const timer = setInterval(() => {
|
|
91
|
+
if (lastActivity === 0)
|
|
92
|
+
return; // not yet armed
|
|
93
|
+
if (Date.now() - lastActivity > timeoutMs)
|
|
94
|
+
fire();
|
|
95
|
+
}, intervalMs);
|
|
96
|
+
function fire() {
|
|
97
|
+
if (fired)
|
|
98
|
+
return;
|
|
99
|
+
fired = true;
|
|
100
|
+
clearInterval(timer);
|
|
101
|
+
void onIdle();
|
|
102
|
+
}
|
|
103
|
+
// Never let the watchdog alone keep the process alive.
|
|
104
|
+
if (typeof timer.unref === 'function')
|
|
105
|
+
timer.unref();
|
|
106
|
+
app.addHook('onClose', async () => { clearInterval(timer); });
|
|
107
|
+
// Any authed /api/* request marks the client alive and arms the
|
|
108
|
+
// backstop. The dedicated shutdown beacon fires immediately.
|
|
109
|
+
app.addHook('onRequest', async (request) => {
|
|
110
|
+
if (request.url.startsWith('/api/'))
|
|
111
|
+
lastActivity = Date.now();
|
|
112
|
+
return undefined;
|
|
113
|
+
});
|
|
114
|
+
app.post('/api/v1/shutdown', async () => {
|
|
115
|
+
fire();
|
|
116
|
+
return { ok: true };
|
|
117
|
+
});
|
|
118
|
+
}
|
|
83
119
|
await app.register(fastifyStatic, {
|
|
84
120
|
root: opts.uiDistDir,
|
|
85
121
|
prefix: '/',
|
package/dist/server/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/server/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,OAAiC,MAAM,SAAS,CAAC;AACxD,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAA4B,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/server/app.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,17 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { z } from 'zod';
|
|
10
10
|
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { userInfo } from 'node:os';
|
|
11
12
|
import { PACKAGE_JSON } from '../../cli/paths.js';
|
|
13
|
+
function systemUserName() {
|
|
14
|
+
try {
|
|
15
|
+
const name = userInfo().username;
|
|
16
|
+
return typeof name === 'string' ? name : '';
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
12
22
|
export const PingResponseSchema = z.object({
|
|
13
23
|
ok: z.literal(true),
|
|
14
24
|
version: z.string().min(1),
|
|
@@ -27,6 +37,12 @@ export const PingResponseSchema = z.object({
|
|
|
27
37
|
* operator pinned `writeRoot` via `--project`.
|
|
28
38
|
*/
|
|
29
39
|
projectScopeAvailable: z.boolean(),
|
|
40
|
+
/**
|
|
41
|
+
* Best-effort OS account name (e.g. `matze`), used to pre-fill the
|
|
42
|
+
* welcome step's name field on a fresh wizard. Empty string when the
|
|
43
|
+
* platform does not expose it.
|
|
44
|
+
*/
|
|
45
|
+
systemUser: z.string(),
|
|
30
46
|
});
|
|
31
47
|
function readPackageVersion() {
|
|
32
48
|
try {
|
|
@@ -48,6 +64,7 @@ export function pingRoute(opts) {
|
|
|
48
64
|
mode: opts.mode,
|
|
49
65
|
dryRun: opts.dryRun === true,
|
|
50
66
|
projectScopeAvailable: opts.projectScopeRoot !== undefined && opts.projectScopeRoot !== null,
|
|
67
|
+
systemUser: systemUserName(),
|
|
51
68
|
};
|
|
52
69
|
return response;
|
|
53
70
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ping.js","sourceRoot":"","sources":["../../../src/server/routes/ping.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B;;;OAGG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAC3C,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB;;;;;OAKG;IACH,qBAAqB,EAAE,CAAC,CAAC,OAAO,EAAE;
|
|
1
|
+
{"version":3,"file":"ping.js","sourceRoot":"","sources":["../../../src/server/routes/ping.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,SAAS,cAAc;IACnB,IAAI,CAAC;QACD,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC,QAAQ,CAAC;QACjC,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B;;;OAGG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAC3C,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB;;;;;OAKG;IACH,qBAAqB,EAAE,CAAC,CAAC,OAAO,EAAE;IAClC;;;;OAIG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;CACzB,CAAC,CAAC;AAIH,SAAS,kBAAkB;IACvB,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAA0B,CAAC;QACpF,OAAO,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,OAAO,CAAC;IACnB,CAAC;AACL,CAAC;AAcD,MAAM,UAAU,SAAS,CAAC,IAAsB;IAC5C,MAAM,MAAM,GAAuB,KAAK,EAAE,GAAoB,EAAE,EAAE;QAC9D,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE;YAC/B,MAAM,QAAQ,GAAiB;gBAC3B,EAAE,EAAE,IAAI;gBACR,OAAO,EAAE,kBAAkB,EAAE;gBAC7B,WAAW,EAAE,IAAI,CAAC,SAAS;gBAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,IAAI,CAAC,MAAM,KAAK,IAAI;gBAC5B,qBAAqB,EAAE,IAAI,CAAC,gBAAgB,KAAK,SAAS,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI;gBAC5F,UAAU,EAAE,cAAc,EAAE;aAC/B,CAAC;YACF,OAAO,QAAQ,CAAC;QACpB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IACF,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { promises as fs, existsSync } from 'node:fs';
|
|
2
|
-
import { tmpdir } from 'node:os';
|
|
2
|
+
import { tmpdir, homedir } from 'node:os';
|
|
3
3
|
import { join, dirname } from 'node:path';
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
5
|
import { randomBytes } from 'node:crypto';
|
|
@@ -7,21 +7,35 @@ import { z } from 'zod';
|
|
|
7
7
|
import { settingsSchema } from '../schemas/settings.js';
|
|
8
8
|
import { userIdentitySchema } from '../../shared/userMd/schema.js';
|
|
9
9
|
import { composeUserIdentity } from '../../shared/userMd/utils.js';
|
|
10
|
-
import { mergeIntoTemplate } from '../io/yamlIO.js';
|
|
10
|
+
import { mergeIntoTemplate, parseYaml, replaceScalar } from '../io/yamlIO.js';
|
|
11
11
|
import { commitMulti } from '../io/atomicMultiWrite.js';
|
|
12
12
|
import { writeAtomic } from '../io/atomicWrite.js';
|
|
13
|
+
import { detectInstalledTools, isBinaryOnPath, knownToolIds } from '../../install/toolDetection.js';
|
|
14
|
+
import { readSelectedTools, writeSelectedTools } from '../../install/selectedTools.js';
|
|
13
15
|
const STATE_REL = join('state', 'wizard-state.json');
|
|
14
16
|
const SETTINGS_REL = join('settings', '.agent-settings.yml');
|
|
15
17
|
const USER_IDENTITY_REL = join('settings', '.agent-user.yml');
|
|
18
|
+
// road-to-wizard-ux-improvements § Phase 8 — AI Council config file. Lives
|
|
19
|
+
// beside the other settings under <writeRoot>/settings/; seeded from the
|
|
20
|
+
// package's hand-tuned reference when the target is absent (first run).
|
|
21
|
+
const AI_COUNCIL_REL = join('settings', '.ai-council.yml');
|
|
22
|
+
const PACKAGE_AI_COUNCIL_REL = join('agents', 'settings', '.ai-council.yml');
|
|
23
|
+
const AI_COUNCIL_PROVIDERS = ['anthropic', 'openai', 'gemini', 'xai', 'perplexity'];
|
|
24
|
+
// Only these two ship an interactive 0600-key installer; the rest use env vars.
|
|
25
|
+
const AI_COUNCIL_KEY_INSTALL = {
|
|
26
|
+
anthropic: 'bash scripts/install_anthropic_key.sh',
|
|
27
|
+
openai: 'bash scripts/install_openai_key.sh',
|
|
28
|
+
};
|
|
16
29
|
/** Legacy flat-root files — read for migration, deleted on successful finish. */
|
|
17
30
|
const LEGACY_USER_MD_REL = '.agent-user.md';
|
|
18
31
|
const LEGACY_SETTINGS_REL = '.agent-settings.yml';
|
|
19
|
-
// Step count mirrors the UI's `WIZARD_STEPS` array in `src/ui/wizard/steps.ts
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
const
|
|
32
|
+
// Step count mirrors the UI's `WIZARD_STEPS` array in `src/ui/wizard/steps.ts`.
|
|
33
|
+
// Bump in lockstep. Core flow = 8 steps (editor, personality, cost,
|
|
34
|
+
// roadmap-quality, memory, ai-council, user-md, review —
|
|
35
|
+
// road-to-wizard-ux-improvements § Phase 8 added ai-council). Extended mode
|
|
36
|
+
// prepends three install-only steps (ai-tools + packs + modules) → 11.
|
|
37
|
+
const DEFAULT_TOTAL_STEPS = 9;
|
|
38
|
+
const EXTENDED_TOTAL_STEPS = 13;
|
|
25
39
|
/**
|
|
26
40
|
* Discovery-manifest path. Resolved from the package root the server
|
|
27
41
|
* was booted with — same artefact the installer reads (ADR-015 locks
|
|
@@ -60,18 +74,6 @@ const applyPayloadSchema = z.discriminatedUnion('schema_version', [
|
|
|
60
74
|
function statePath(root) {
|
|
61
75
|
return join(root, STATE_REL);
|
|
62
76
|
}
|
|
63
|
-
async function readState(root) {
|
|
64
|
-
try {
|
|
65
|
-
const raw = await fs.readFile(statePath(root), 'utf8');
|
|
66
|
-
const parsed = wizardStateSchema.safeParse(JSON.parse(raw));
|
|
67
|
-
return parsed.success ? parsed.data : null;
|
|
68
|
-
}
|
|
69
|
-
catch (err) {
|
|
70
|
-
if (err.code === 'ENOENT')
|
|
71
|
-
return null;
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
77
|
async function writeState(root, state) {
|
|
76
78
|
const path = statePath(root);
|
|
77
79
|
await fs.mkdir(dirname(path), { recursive: true });
|
|
@@ -80,6 +82,70 @@ async function writeState(root, state) {
|
|
|
80
82
|
async function readTemplate(packageRoot) {
|
|
81
83
|
return fs.readFile(join(packageRoot, 'config', 'agent-settings.template.yml'), 'utf8');
|
|
82
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Read the AI-council YAML body for editing (road-to-wizard-ux-improvements
|
|
87
|
+
* § Phase 8): prefer the target under `<writeRoot>/settings/.ai-council.yml`;
|
|
88
|
+
* fall back to the package's hand-tuned reference so a first-run consumer edits
|
|
89
|
+
* a fully-commented file rather than a synthesised stub.
|
|
90
|
+
*/
|
|
91
|
+
async function readCouncilBody(writeRoot, packageRoot) {
|
|
92
|
+
try {
|
|
93
|
+
return await fs.readFile(join(writeRoot, AI_COUNCIL_REL), 'utf8');
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
if (err.code !== 'ENOENT')
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
return fs.readFile(join(packageRoot, PACKAGE_AI_COUNCIL_REL), 'utf8');
|
|
100
|
+
}
|
|
101
|
+
/** Which provider key files exist on disk (`~/.event4u/agent-config/<p>.key`). */
|
|
102
|
+
function councilKeyPresence() {
|
|
103
|
+
const roots = [
|
|
104
|
+
join(homedir(), '.event4u', 'agent-config'),
|
|
105
|
+
join(homedir(), '.config', 'agent-config'),
|
|
106
|
+
];
|
|
107
|
+
const out = {};
|
|
108
|
+
for (const p of AI_COUNCIL_PROVIDERS) {
|
|
109
|
+
out[p] = roots.some((r) => existsSync(join(r, `${p}.key`)));
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/** Pull the wizard-controlled scalar subset out of a parsed council config. */
|
|
114
|
+
function extractCouncilConfig(body) {
|
|
115
|
+
const doc = parseYaml(body);
|
|
116
|
+
const obj = (v) => (typeof v === 'object' && v !== null ? v : {});
|
|
117
|
+
const defaults = obj(doc['defaults']);
|
|
118
|
+
const costBudget = obj(doc['cost_budget']);
|
|
119
|
+
const membersRaw = obj(doc['members']);
|
|
120
|
+
const dr = obj(doc['decision_resolution']);
|
|
121
|
+
const classes = obj(dr['classes']);
|
|
122
|
+
const members = {};
|
|
123
|
+
for (const p of AI_COUNCIL_PROVIDERS) {
|
|
124
|
+
const m = obj(membersRaw[p]);
|
|
125
|
+
members[p] = {
|
|
126
|
+
enabled: m['enabled'] === true,
|
|
127
|
+
participate_low_impact: m['participate_low_impact'] === true,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const decision = {};
|
|
131
|
+
for (const cls of ['trivial', 'low_impact', 'medium_impact']) {
|
|
132
|
+
const c = obj(classes[cls]);
|
|
133
|
+
if (typeof c['mode'] === 'string')
|
|
134
|
+
decision[cls] = c['mode'];
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
enabled: doc['enabled'] === true,
|
|
138
|
+
defaults: {
|
|
139
|
+
mode: typeof defaults['mode'] === 'string' ? defaults['mode'] : 'api',
|
|
140
|
+
min_rounds: typeof defaults['min_rounds'] === 'number' ? defaults['min_rounds'] : 2,
|
|
141
|
+
},
|
|
142
|
+
cost_budget: {
|
|
143
|
+
max_total_usd: typeof costBudget['max_total_usd'] === 'number' ? costBudget['max_total_usd'] : 0,
|
|
144
|
+
},
|
|
145
|
+
members,
|
|
146
|
+
decision,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
83
149
|
function detectProjectSignals(root) {
|
|
84
150
|
const out = [];
|
|
85
151
|
const exists = (rel) => existsSync(join(root, rel));
|
|
@@ -271,6 +337,22 @@ const modulesConfigSchema = z.object({
|
|
|
271
337
|
agent_folder: z.string().optional(),
|
|
272
338
|
skip_dirs: z.array(z.string()).optional(),
|
|
273
339
|
}).strict();
|
|
340
|
+
// road-to-wizard-ux-improvements § Phase 8 — wizard-controlled scalar subset of
|
|
341
|
+
// `.ai-council.yml`. Scalar leaves only (safe for `replaceScalar`); the LOCKED
|
|
342
|
+
// decision classes (high_impact / user_required) and deep knobs (advisors,
|
|
343
|
+
// model_ladder, …) are intentionally NOT writable here — hand-edit only.
|
|
344
|
+
const aiCouncilPayloadSchema = z.object({
|
|
345
|
+
enabled: z.boolean().optional(),
|
|
346
|
+
defaultMode: z.enum(['manual', 'api', 'cli']).optional(),
|
|
347
|
+
minRounds: z.number().int().min(1).optional(),
|
|
348
|
+
maxTotalUsd: z.number().min(0).optional(),
|
|
349
|
+
members: z.record(z.object({
|
|
350
|
+
enabled: z.boolean().optional(),
|
|
351
|
+
participateLowImpact: z.boolean().optional(),
|
|
352
|
+
})).optional(),
|
|
353
|
+
// keys ∈ {trivial, low_impact, medium_impact} — others ignored.
|
|
354
|
+
decision: z.record(z.enum(['agent', 'council', 'user'])).optional(),
|
|
355
|
+
}).strict();
|
|
274
356
|
export function wizardRoute(opts) {
|
|
275
357
|
const extended = opts.extendedSteps === true;
|
|
276
358
|
const totalSteps = opts.totalSteps ?? (extended ? EXTENDED_TOTAL_STEPS : DEFAULT_TOTAL_STEPS);
|
|
@@ -282,16 +364,19 @@ export function wizardRoute(opts) {
|
|
|
282
364
|
const dryRun = opts.dryRun === true;
|
|
283
365
|
const legacyReadRoot = opts.legacyReadRoot ?? null;
|
|
284
366
|
const projectScopeRoot = opts.projectScopeRoot ?? null;
|
|
285
|
-
// Per-
|
|
286
|
-
//
|
|
287
|
-
//
|
|
288
|
-
//
|
|
367
|
+
// Per-server-session in-memory wizard state (road-to-wizard-ux-improvements
|
|
368
|
+
// § Phase 1 — "server-boot = fresh"). Each `init`/`setup`/`--dry-run`
|
|
369
|
+
// launch mints a fresh server, so a brand-new launch ALWAYS starts at
|
|
370
|
+
// `initialStep`. Resume happens only within the same running server
|
|
371
|
+
// lifetime (e.g. a browser refresh while the server is up), driven by this
|
|
372
|
+
// in-memory state — never from the on-disk `wizard-state.json`, which is a
|
|
373
|
+
// crash breadcrumb, not a cross-launch resume source.
|
|
289
374
|
let memState = null;
|
|
290
375
|
const plugin = async (app) => {
|
|
291
376
|
app.get('/api/v1/wizard/state', async () => {
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
const existing =
|
|
377
|
+
// Resume from the in-memory session only — a fresh server boot has
|
|
378
|
+
// no session state and therefore starts fresh at `initialStep`.
|
|
379
|
+
const existing = memState;
|
|
295
380
|
if (existing === null) {
|
|
296
381
|
return {
|
|
297
382
|
step: initialStep,
|
|
@@ -322,6 +407,124 @@ export function wizardRoute(opts) {
|
|
|
322
407
|
const signals = detectProjectSignals(root);
|
|
323
408
|
return { root, signals };
|
|
324
409
|
});
|
|
410
|
+
// road-to-wizard-ux-improvements § Phase 2 — AI-tool presence on the
|
|
411
|
+
// machine running the wizard. Probes the user's home dir + app bundles
|
|
412
|
+
// + $PATH (NOT the project) so Step 1 can pre-select installed tools on
|
|
413
|
+
// first run and badge each tool. Read-only; extended-mode only.
|
|
414
|
+
app.get('/api/v1/wizard/detect-tools', async (_request, reply) => {
|
|
415
|
+
if (!extended) {
|
|
416
|
+
await reply.code(404).send({ error: { code: 'NOT_FOUND', message: 'extended-mode endpoint disabled' } });
|
|
417
|
+
return reply;
|
|
418
|
+
}
|
|
419
|
+
// `configured` = the tools the user selected in a prior wizard run
|
|
420
|
+
// (wizard-tools.json), NOT every deployed tool. Step 1 pre-selects
|
|
421
|
+
// these on a repeat run; only when none are recorded does it fall
|
|
422
|
+
// back to pre-selecting every installed tool (first-run convenience).
|
|
423
|
+
return {
|
|
424
|
+
tools: detectInstalledTools(),
|
|
425
|
+
configured: readSelectedTools(new Set(knownToolIds())),
|
|
426
|
+
};
|
|
427
|
+
});
|
|
428
|
+
// road-to-wizard-ux-improvements § Phase 7 — rtk presence on the
|
|
429
|
+
// Editor-and-tooling step. Detection is the ONLY source of truth (the
|
|
430
|
+
// value is never loaded from `.agent-settings.yml`). When rtk is
|
|
431
|
+
// missing, return the suggested per-OS install command + repo so the
|
|
432
|
+
// UI can offer a copy-and-run button (we surface the command rather
|
|
433
|
+
// than shelling out an unverified package install — non-destructive
|
|
434
|
+
// by default). Read-only; extended-mode only.
|
|
435
|
+
app.get('/api/v1/wizard/detect-rtk', async (_request, reply) => {
|
|
436
|
+
if (!extended) {
|
|
437
|
+
await reply.code(404).send({ error: { code: 'NOT_FOUND', message: 'extended-mode endpoint disabled' } });
|
|
438
|
+
return reply;
|
|
439
|
+
}
|
|
440
|
+
const installed = isBinaryOnPath('rtk');
|
|
441
|
+
// Per-OS install hint (maintainer-tunable). `cargo install --git`
|
|
442
|
+
// is the portable fallback for the Rust tool when no packaged
|
|
443
|
+
// formula is known.
|
|
444
|
+
const repo = 'https://github.com/event4u-app/rtk';
|
|
445
|
+
const installCommandByOs = {
|
|
446
|
+
darwin: 'brew install rtk',
|
|
447
|
+
linux: `cargo install --git ${repo}`,
|
|
448
|
+
win32: `cargo install --git ${repo}`,
|
|
449
|
+
};
|
|
450
|
+
return {
|
|
451
|
+
installed,
|
|
452
|
+
platform: process.platform,
|
|
453
|
+
repo,
|
|
454
|
+
installCommand: installed ? null : (installCommandByOs[process.platform] ?? `cargo install --git ${repo}`),
|
|
455
|
+
};
|
|
456
|
+
});
|
|
457
|
+
// road-to-wizard-ux-improvements § Phase 8 — AI Council config.
|
|
458
|
+
// GET returns the wizard-controlled scalar subset (read from the write
|
|
459
|
+
// root, or seeded from the package's hand-tuned reference), plus which
|
|
460
|
+
// provider keys exist + the install-command affordance. Extended only.
|
|
461
|
+
app.get('/api/v1/wizard/ai-council', async (_request, reply) => {
|
|
462
|
+
if (!extended) {
|
|
463
|
+
await reply.code(404).send({ error: { code: 'NOT_FOUND', message: 'extended-mode endpoint disabled' } });
|
|
464
|
+
return reply;
|
|
465
|
+
}
|
|
466
|
+
try {
|
|
467
|
+
const body = await readCouncilBody(opts.writeRoot, opts.packageRoot);
|
|
468
|
+
return {
|
|
469
|
+
config: extractCouncilConfig(body),
|
|
470
|
+
providers: AI_COUNCIL_PROVIDERS,
|
|
471
|
+
keyPresence: councilKeyPresence(),
|
|
472
|
+
keyInstall: AI_COUNCIL_KEY_INSTALL,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
catch (err) {
|
|
476
|
+
const message = err instanceof Error ? err.message : 'failed to read .ai-council.yml';
|
|
477
|
+
await reply.code(500).send({ error: { code: 'COUNCIL_READ_FAILED', message } });
|
|
478
|
+
return reply;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
// POST applies the scalar subset into `.ai-council.yml` via
|
|
482
|
+
// comment-preserving `replaceScalar` edits (never a full dump), then
|
|
483
|
+
// atomic-writes <writeRoot>/settings/.ai-council.yml.
|
|
484
|
+
app.post('/api/v1/wizard/ai-council', async (request, reply) => {
|
|
485
|
+
if (!extended) {
|
|
486
|
+
await reply.code(404).send({ error: { code: 'NOT_FOUND', message: 'extended-mode endpoint disabled' } });
|
|
487
|
+
return reply;
|
|
488
|
+
}
|
|
489
|
+
const parsed = aiCouncilPayloadSchema.safeParse(request.body ?? {});
|
|
490
|
+
if (!parsed.success) {
|
|
491
|
+
await reply.code(422).send({
|
|
492
|
+
error: { code: 'VALIDATION', message: 'invalid ai-council payload', fields: zodIssuesToFields(parsed.error.issues) },
|
|
493
|
+
});
|
|
494
|
+
return reply;
|
|
495
|
+
}
|
|
496
|
+
const p = parsed.data;
|
|
497
|
+
try {
|
|
498
|
+
let body = await readCouncilBody(opts.writeRoot, opts.packageRoot);
|
|
499
|
+
const set = (path, value) => {
|
|
500
|
+
if (value !== undefined)
|
|
501
|
+
body = replaceScalar(body, path, value);
|
|
502
|
+
};
|
|
503
|
+
set(['enabled'], p.enabled);
|
|
504
|
+
set(['defaults', 'mode'], p.defaultMode);
|
|
505
|
+
set(['defaults', 'min_rounds'], p.minRounds);
|
|
506
|
+
set(['cost_budget', 'max_total_usd'], p.maxTotalUsd);
|
|
507
|
+
for (const provider of AI_COUNCIL_PROVIDERS) {
|
|
508
|
+
const m = p.members?.[provider];
|
|
509
|
+
if (m === undefined)
|
|
510
|
+
continue;
|
|
511
|
+
set(['members', provider, 'enabled'], m.enabled);
|
|
512
|
+
set(['members', provider, 'participate_low_impact'], m.participateLowImpact);
|
|
513
|
+
}
|
|
514
|
+
for (const cls of ['trivial', 'low_impact', 'medium_impact']) {
|
|
515
|
+
set(['decision_resolution', 'classes', cls, 'mode'], p.decision?.[cls]);
|
|
516
|
+
}
|
|
517
|
+
const target = join(opts.writeRoot, AI_COUNCIL_REL);
|
|
518
|
+
await fs.mkdir(dirname(target), { recursive: true });
|
|
519
|
+
await writeAtomic(target, body, { mode: 0o600 });
|
|
520
|
+
return { ok: true, written: target };
|
|
521
|
+
}
|
|
522
|
+
catch (err) {
|
|
523
|
+
const message = err instanceof Error ? err.message : 'failed to write .ai-council.yml';
|
|
524
|
+
await reply.code(500).send({ error: { code: 'COUNCIL_WRITE_FAILED', message } });
|
|
525
|
+
return reply;
|
|
526
|
+
}
|
|
527
|
+
});
|
|
325
528
|
// road-to-configurable-modules § Phase E — Modules detect endpoint.
|
|
326
529
|
// Read-only scan: spawns `scripts/propose_modules_config.py --json`
|
|
327
530
|
// against the consumer project so the wizard's modules step can
|
|
@@ -510,10 +713,13 @@ export function wizardRoute(opts) {
|
|
|
510
713
|
});
|
|
511
714
|
return reply;
|
|
512
715
|
}
|
|
716
|
+
// Always update the in-memory session state (the resume source).
|
|
717
|
+
memState = parsed.data;
|
|
513
718
|
if (dryRun) {
|
|
514
|
-
memState = parsed.data;
|
|
515
719
|
return { ok: true, dryRun: true };
|
|
516
720
|
}
|
|
721
|
+
// Disk write is a crash breadcrumb only (not read back for resume);
|
|
722
|
+
// the finish handler clears it on a successful commit.
|
|
517
723
|
await writeState(opts.writeRoot, parsed.data);
|
|
518
724
|
return { ok: true };
|
|
519
725
|
});
|
|
@@ -586,6 +792,12 @@ export function wizardRoute(opts) {
|
|
|
586
792
|
controller.abort();
|
|
587
793
|
};
|
|
588
794
|
reply.raw.on('close', onClose);
|
|
795
|
+
// Record the user's tool selection so the next wizard run
|
|
796
|
+
// pre-selects exactly these (detect-tools `configured`). Written
|
|
797
|
+
// on the real-apply path only — a dry-run preview must not.
|
|
798
|
+
if (payload.schema_version === 'wizard-v2') {
|
|
799
|
+
writeSelectedTools(payload.tools);
|
|
800
|
+
}
|
|
589
801
|
let written = 0;
|
|
590
802
|
let total = 0;
|
|
591
803
|
let sawTerminal = false;
|