@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.
Files changed (63) hide show
  1. package/.agent-src/commands/agents/user/init.md +7 -13
  2. package/.agent-src/commands/agents/user/show.md +4 -4
  3. package/.agent-src/commands/post-as/me.md +6 -6
  4. package/.agent-src/contexts/execution/autonomy-mechanics.md +1 -1
  5. package/.agent-src/contexts/execution/cheap-question-mechanics.md +4 -0
  6. package/.agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  7. package/.claude-plugin/marketplace.json +1 -1
  8. package/CHANGELOG.md +110 -66
  9. package/config/discovery/packs.yml +9 -1
  10. package/config/discovery/workspaces.yml +14 -1
  11. package/dist/cli/agent-config.js +5 -4
  12. package/dist/cli/agent-config.js.map +1 -1
  13. package/dist/cli/commands/uiServe.js +27 -11
  14. package/dist/cli/commands/uiServe.js.map +1 -1
  15. package/dist/discovery/deprecation-report.md +1 -1
  16. package/dist/discovery/discovery-manifest.json +51 -8
  17. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  18. package/dist/discovery/discovery-manifest.summary.md +3 -3
  19. package/dist/discovery/orphan-report.md +1 -1
  20. package/dist/discovery/packs.json +25 -4
  21. package/dist/discovery/trust-report.md +1 -1
  22. package/dist/discovery/workspaces.json +4 -4
  23. package/dist/install/selectedTools.js +52 -0
  24. package/dist/install/selectedTools.js.map +1 -0
  25. package/dist/install/toolDetection.js +104 -0
  26. package/dist/install/toolDetection.js.map +1 -0
  27. package/dist/mcp/registry-manifest.json +2 -2
  28. package/dist/server/app.js +36 -0
  29. package/dist/server/app.js.map +1 -1
  30. package/dist/server/routes/ping.js +17 -0
  31. package/dist/server/routes/ping.js.map +1 -1
  32. package/dist/server/routes/wizard.js +240 -28
  33. package/dist/server/routes/wizard.js.map +1 -1
  34. package/dist/server/serverInfo.js +54 -0
  35. package/dist/server/serverInfo.js.map +1 -0
  36. package/dist/shared/userMd/formAdapter.js +1 -5
  37. package/dist/shared/userMd/formAdapter.js.map +1 -1
  38. package/dist/shared/userMd/schema.js +2 -1
  39. package/dist/shared/userMd/schema.js.map +1 -1
  40. package/dist/ui/assets/index-J0-0d7RC.js +40 -0
  41. package/dist/ui/assets/index-J0-0d7RC.js.map +1 -0
  42. package/dist/ui/assets/index-ZiC8PbdW.css +1 -0
  43. package/dist/ui/index.html +2 -2
  44. package/docs/archive/CHANGELOG-pre-4.0.0.md +80 -0
  45. package/docs/contracts/agent-user-schema.md +1 -3
  46. package/docs/contracts/discovery-manifest.schema.json +3 -1
  47. package/docs/contracts/gui-wizard.md +96 -8
  48. package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +27 -0
  49. package/docs/decisions/ADR-021-deployment-shape.md +2 -2
  50. package/docs/deploy/connector-setup.md +2 -2
  51. package/docs/deploy/policy-cookbook.md +2 -2
  52. package/docs/examples/agent-user.example.md +0 -1
  53. package/package.json +1 -1
  54. package/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
  55. package/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
  56. package/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
  57. package/scripts/build_discovery_manifest.py +4 -0
  58. package/scripts/condense_memory.py +8 -2
  59. package/scripts/install.py +73 -0
  60. package/scripts/lint_discovery_vocabulary.py +8 -0
  61. package/dist/ui/assets/index-BDAhhpDV.js +0 -40
  62. package/dist/ui/assets/index-BDAhhpDV.js.map +0 -1
  63. 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": "b59a6d49e745"
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.3.0"
12
+ "version": "4.5.0"
13
13
  },
14
14
  "registries": [
15
15
  {
@@ -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: '/',
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/server/app.ts"],"names":[],"mappings":"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"}
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;CACrC,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;aAC/F,CAAC;YACF,OAAO,QAAQ,CAAC;QACpB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IACF,OAAO,MAAM,CAAC;AAClB,CAAC"}
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
- // and the chat-side `~/.claude/skills/onboard/SKILL.md`. Bump in lockstep.
21
- // Extended mode (road-to-global-only-install § Phase 1) prepends three
22
- // steps (ai-tools + packs + modules) to ship the unified 10-step flow.
23
- const DEFAULT_TOTAL_STEPS = 7;
24
- const EXTENDED_TOTAL_STEPS = 10;
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-process in-memory state for dry-run. One CLI invocation = one
286
- // server = one Map; cross-session leakage is impossible because each
287
- // `agent-config setup --dry-run` mints a fresh server. See § Dry-run
288
- // state contract in the roadmap.
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
- // Dry-run: in-memory write wins; fall back to disk so an
293
- // in-progress real run can be previewed.
294
- const existing = dryRun ? (memState ?? await readState(opts.writeRoot)) : await readState(opts.writeRoot);
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;