agent-takkub 2.2.5 → 2.2.6

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/README.md CHANGED
@@ -96,11 +96,12 @@ A role's own model wins over the provider default, so `backend` can run Codex on
96
96
  ## ⚡ Quick Start
97
97
 
98
98
  ```bash
99
- # 1. Install the cockpit globally (isolated Python runtime + a Desktop icon)
99
+ # 1. Install the cockpit, plus Claude and Codex CLIs if missing
100
100
  npm install -g agent-takkub
101
101
 
102
- # 2. Authenticate with your Claude account (if you haven't already)
102
+ # 2. Authenticate with your Claude and OpenAI accounts
103
103
  claude login
104
+ codex login
104
105
 
105
106
  # 3. Provision recommended plugins + browser-automation tools (idempotent)
106
107
  takkub provision
@@ -117,7 +118,7 @@ agent-takkub
117
118
  <table>
118
119
  <tr><td>
119
120
 
120
- **Requirements** — Node.js ≥ 18 and Python ≥ 3.11 already on your system. They're **detected, never reinstalled**. Everything else lives in an isolated `~/.agent-takkub`; your existing `claude` CLI, plugins, and config are left completely untouched.
121
+ **Requirements** — Node.js ≥ 18 and Python ≥ 3.11 already on your system. The installer creates an isolated Python runtime and Desktop launcher, and installs missing Claude and Codex CLIs into your npm global prefix. Existing provider installations are reused. Authenticate with `claude login` and `codex login` before using those providers.
121
122
 
122
123
  **Optional: `graft` code-intelligence** needs Node ≥ 20 — stricter than the cockpit's own Node ≥ 18 floor. It's off until you run `takkub doctor --fix`; without it (or on Node 18–19), the cockpit runs exactly the same, just without the extra structural-search tools for code-reading roles.
123
124
 
@@ -3,12 +3,11 @@
3
3
  //
4
4
  // SAFETY MODEL — check first, never clobber:
5
5
  // • Detects what's already present (preflight.js, non-mutating) and REPORTS it.
6
- // • Provisions ONLY into the isolated AGENT_TAKKUB_HOME (default
6
+ // • Provisions the Python runtime into the isolated AGENT_TAKKUB_HOME (default
7
7
  // ~/.agent-takkub) — never a repo `.venv`, never shared user state.
8
8
  // • REUSES an existing cockpit venv (upgrade in place) instead of wiping it.
9
- // • Does NOT touch the global claude CLI, ~/.claude plugins, or ~/.takkub
10
- // config. Anything shared/missing is left for an explicit, detect-first
11
- // `takkub doctor --fix` the user runs consciously.
9
+ // • Installs missing Claude and Codex CLIs; existing installations are reused.
10
+ // Plugins and account configuration are managed separately by provision/login.
12
11
  // Cross-platform (win32 + darwin); idempotent; fails loudly on missing Python
13
12
  // or a missing bundled wheel.
14
13
 
@@ -17,6 +16,7 @@ const fs = require('fs');
17
16
  const path = require('path');
18
17
  const { agentTakkubHome, venvDir, venvPython, findWheelForVersion } = require('./lib');
19
18
  const preflight = require('./preflight');
19
+ const { ensureBaselineProviders } = require('./providers');
20
20
 
21
21
  // The wheel matching THIS install's declared version (#340) — not the
22
22
  // lexically-last filename in dist/. A string sort put "1.0.9" after
@@ -33,17 +33,6 @@ function run(cmd, args) {
33
33
  return spawnSync(cmd, args, { stdio: 'inherit' }).status === 0;
34
34
  }
35
35
 
36
- // Install the claude CLI only when it's missing — never overwrite an existing
37
- // (possibly version-pinned) global install. Returns true if claude is available
38
- // afterward. Best-effort: a failure just falls back to a "install it yourself"
39
- // hint in the next-steps.
40
- function ensureClaudeCli(present) {
41
- if (present) return true;
42
- const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
43
- console.log('[agent-takkub] claude CLI not found — installing @anthropic-ai/claude-code…');
44
- return run(npm, ['install', '-g', '@anthropic-ai/claude-code']);
45
- }
46
-
47
36
  // A local (non-global) install leaves a package that cannot work: the `takkub`
48
37
  // / `agent-takkub` bin shims never land on PATH, and the PATH provisioning
49
38
  // below targets the npm GLOBAL bin dir. Without this guard that failure is
@@ -114,7 +103,7 @@ function main() {
114
103
  // already succeeded, so a hiccup here shouldn't fail the whole install.
115
104
  run(vpy, ['-m', 'pip', 'install', '--force-reinstall', '--no-deps', wheel]);
116
105
 
117
- const claudeOk = ensureClaudeCli(env.claudeCli.present);
106
+ const providers = ensureBaselineProviders(env);
118
107
 
119
108
  // Keep the npm global bin dir on the persistent PATH — otherwise a broken
120
109
  // PATH makes claude/takkub/agent-takkub "command not found" in new shells
@@ -124,7 +113,7 @@ function main() {
124
113
  pathAdded = require('./pathfix').ensureGlobalBinOnPath();
125
114
  if (pathAdded) {
126
115
  console.log(
127
- '[agent-takkub] ✓ npm global bin dir added to your PATH (open a NEW terminal to use takkub/claude).'
116
+ '[agent-takkub] ✓ npm global bin dir added to your PATH (open a NEW terminal to use takkub/claude/codex).'
128
117
  );
129
118
  }
130
119
  } catch (_e) {
@@ -148,12 +137,16 @@ function main() {
148
137
  );
149
138
  console.log(' it backs up everything first, so this is safe to let run.');
150
139
  console.log('\n Next steps:');
151
- if (!claudeOk) {
140
+ if (!providers.claude) {
152
141
  console.log(' • install the claude CLI: npm i -g @anthropic-ai/claude-code');
153
142
  }
154
- console.log(' 1) claude login # authenticate (one-time, your account)');
155
- console.log(' 2) takkub provision # install recommended plugins + browser MCPs (idempotent)');
156
- console.log(' 3) double-click "Takkub Cockpit" on the Desktop (or run: agent-takkub)\n');
143
+ if (!providers.codex) {
144
+ console.log(' • install the codex CLI: npm i -g @openai/codex');
145
+ }
146
+ console.log(' 1) claude login # authenticate your Claude account');
147
+ console.log(' 2) codex login # authenticate your OpenAI account');
148
+ console.log(' 3) takkub provision # install recommended plugins + browser MCPs (idempotent)');
149
+ console.log(' 4) double-click "Takkub Cockpit" on the Desktop (or run: agent-takkub)\n');
157
150
  }
158
151
 
159
152
  try {
@@ -2,12 +2,13 @@
2
2
  // Non-mutating environment detection. Runs ONLY `--version`-style probes and
3
3
  // filesystem existence checks — nothing here installs, writes, or overwrites.
4
4
  // This is what lets the installer "check first": report what's already present
5
- // and provision ONLY the gaps, so a machine that already has Python / claude /
5
+ // and provision ONLY the gaps, so a machine that already has Python / Claude / Codex /
6
6
  // a cockpit venv is never clobbered.
7
7
 
8
8
  const { spawnSync } = require('child_process');
9
9
  const fs = require('fs');
10
10
  const { venvPython, agentTakkubHome } = require('./lib');
11
+ const { probeCli } = require('./providers');
11
12
 
12
13
  function probe(cmd, args) {
13
14
  const r = spawnSync(cmd, args, { encoding: 'utf8' });
@@ -36,11 +37,13 @@ function detectPython() {
36
37
 
37
38
  // Detect the whole environment without mutating anything.
38
39
  function detect() {
39
- const claude = probe('claude', ['--version']);
40
+ const claude = probeCli('claude');
41
+ const codex = probeCli('codex');
40
42
  return {
41
43
  python: detectPython(),
42
44
  node: probe('node', ['--version']),
43
45
  claudeCli: claude ? { present: true, version: claude } : { present: false },
46
+ codexCli: codex ? { present: true, version: codex } : { present: false },
44
47
  venv: { present: fs.existsSync(venvPython()), path: venvPython() },
45
48
  home: agentTakkubHome(),
46
49
  };
@@ -51,6 +54,7 @@ function report(d) {
51
54
  console.log(` Python >=3.11 : ${d.python.present ? '✓ ' + d.python.version + ' (reuse existing)' : '· missing'}`);
52
55
  console.log(` Node : ${d.node ? '✓ ' + d.node : '· missing'}`);
53
56
  console.log(` claude CLI : ${d.claudeCli.present ? '✓ ' + d.claudeCli.version + ' (kept as-is)' : '· not found'}`);
57
+ console.log(` codex CLI : ${d.codexCli.present ? '✓ ' + d.codexCli.version + ' (kept as-is)' : '· not found'}`);
54
58
  console.log(` cockpit venv : ${d.venv.present ? '✓ exists (reuse/upgrade)' : '· will create'} — ${d.home}`);
55
59
  }
56
60
 
@@ -0,0 +1,80 @@
1
+ 'use strict';
2
+
3
+ const { spawnSync } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const BASELINE_PROVIDERS = {
8
+ claude: '@anthropic-ai/claude-code',
9
+ codex: '@openai/codex',
10
+ };
11
+
12
+ function providerEnv(env) {
13
+ const prefix = env.npm_config_prefix;
14
+ if (!prefix) return env;
15
+ const bin = process.platform === 'win32' ? prefix : path.join(prefix, 'bin');
16
+ const pathKey = Object.keys(env).find((key) => key.toUpperCase() === 'PATH') || 'PATH';
17
+ return { ...env, [pathKey]: bin + path.delimiter + (env[pathKey] || '') };
18
+ }
19
+
20
+ function probeCli(name, env = process.env) {
21
+ if (!Object.hasOwn(BASELINE_PROVIDERS, name)) throw new Error(`Unknown baseline provider: ${name}`);
22
+ // Node rejects direct .cmd execution on Windows (EINVAL). These commands
23
+ // are fixed provider names, with no user input interpolated into the shell.
24
+ const command = process.platform === 'win32' ? 'cmd.exe' : name;
25
+ const args = process.platform === 'win32' ? ['/d', '/s', '/c', `${name} --version`] : ['--version'];
26
+ const result = spawnSync(command, args, {
27
+ env: providerEnv(env), encoding: 'utf8', timeout: 30_000, windowsHide: true,
28
+ });
29
+ if (result.status !== 0) return null;
30
+ return ((result.stdout || '') + (result.stderr || '')).trim() || null;
31
+ }
32
+
33
+ function npmInvocation(env) {
34
+ // Use the npm CLI that started this lifecycle, through Node rather than a
35
+ // .cmd shim. This also preserves custom prefixes and paths with spaces.
36
+ if (env.npm_execpath && fs.existsSync(env.npm_execpath) && /\.[cm]?js$/i.test(env.npm_execpath)) {
37
+ return [process.execPath, [env.npm_execpath]];
38
+ }
39
+ if (process.platform !== 'win32') return ['npm', []];
40
+ // The cockpit's repair/update flow can run postinstall directly, outside
41
+ // npm. Find its JS entry point without executing a batch shim.
42
+ const pathValue = Object.entries(env).find(([key]) => key.toUpperCase() === 'PATH')?.[1] || '';
43
+ for (const dir of [path.dirname(process.execPath), ...pathValue.split(path.delimiter)]) {
44
+ if (!dir) continue;
45
+ const cli = path.join(dir, 'node_modules', 'npm', 'bin', 'npm-cli.js');
46
+ if (fs.existsSync(cli)) return [process.execPath, [cli]];
47
+ }
48
+ throw new Error('npm CLI not found');
49
+ }
50
+
51
+ function ensureBaselineProviders(detected, { env = process.env, log = console.log, warn = console.warn } = {}) {
52
+ const available = {};
53
+ for (const [name, packageName] of Object.entries(BASELINE_PROVIDERS)) {
54
+ if (detected[`${name}Cli`]?.present) {
55
+ available[name] = true;
56
+ continue;
57
+ }
58
+ log(`[agent-takkub] ${name} CLI not found — installing ${packageName}…`);
59
+ let failure;
60
+ try {
61
+ const [command, npmArgs] = npmInvocation(env);
62
+ const args = [...npmArgs, 'install', '-g', packageName];
63
+ if (env.npm_config_prefix) args.push('--prefix', env.npm_config_prefix);
64
+ const result = spawnSync(command, args, {
65
+ env: providerEnv(env), stdio: 'inherit', timeout: 300_000, windowsHide: true,
66
+ });
67
+ failure = result.error?.message || (result.status !== 0 ? `npm exited with status ${result.status}` : null);
68
+ available[name] = !failure && Boolean(probeCli(name, env));
69
+ if (!failure && !available[name]) failure = 'installed CLI could not be started';
70
+ } catch (error) {
71
+ failure = error.message;
72
+ available[name] = false;
73
+ }
74
+ if (available[name]) log(`[agent-takkub] ✓ ${name} CLI ready.`);
75
+ else warn(`[agent-takkub] ${name} installation failed: ${failure}. Retry: npm install -g ${packageName}`);
76
+ }
77
+ return available;
78
+ }
79
+
80
+ module.exports = { probeCli, ensureBaselineProviders };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-takkub",
3
- "version": "2.2.5",
3
+ "version": "2.2.6",
4
4
  "description": "Desktop cockpit for orchestrating a team of Claude Code agents (Windows + macOS). Install globally: npm i -g agent-takkub",
5
5
  "keywords": [
6
6
  "claude",