flowviant 0.103.0 → 0.105.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/bin/cli.mjs +87 -474
- package/bin/lib/admission.mjs +19 -3
- package/bin/lib/agentPlan.mjs +2 -2
- package/bin/lib/agentTaskKinds.mjs +130 -0
- package/bin/lib/agySessions.mjs +158 -0
- package/bin/lib/artifactContracts.mjs +153 -0
- package/bin/lib/artifactPolicy.mjs +45 -0
- package/bin/lib/artifactPreview.mjs +52 -0
- package/bin/lib/artifactReporter.mjs +163 -0
- package/bin/lib/artifacts.mjs +49 -228
- package/bin/lib/authReject.mjs +16 -4
- package/bin/lib/authproxy.mjs +47 -304
- package/bin/lib/boxIdentity.mjs +245 -0
- package/bin/lib/childEnv.mjs +11 -9
- package/bin/lib/claude.mjs +14 -851
- package/bin/lib/claudeAuth.mjs +3 -3
- package/bin/lib/claudePosture.mjs +370 -0
- package/bin/lib/claudeSessions.mjs +411 -0
- package/bin/lib/claudeStream.mjs +207 -0
- package/bin/lib/cliLimit.mjs +34 -0
- package/bin/lib/commandSpecs.mjs +173 -0
- package/bin/lib/config.mjs +11 -42
- package/bin/lib/credentialDate.mjs +22 -0
- package/bin/lib/credentials.mjs +21 -26
- package/bin/lib/daemonLogging.mjs +55 -0
- package/bin/lib/daemonState.mjs +64 -0
- package/bin/lib/deploy.mjs +148 -647
- package/bin/lib/deployCheckout.mjs +265 -0
- package/bin/lib/deployConfig.mjs +142 -0
- package/bin/lib/deployRunner.mjs +311 -0
- package/bin/lib/deployWire.mjs +41 -0
- package/bin/lib/desktopContract.mjs +56 -105
- package/bin/lib/env.mjs +49 -484
- package/bin/lib/fleet.mjs +183 -2383
- package/bin/lib/fleetJobs.mjs +120 -0
- package/bin/lib/fleetPost.mjs +40 -0
- package/bin/lib/fleetReports.mjs +392 -0
- package/bin/lib/fleetRoster.mjs +470 -0
- package/bin/lib/fleetStartup.mjs +196 -0
- package/bin/lib/fleetWake.mjs +45 -0
- package/bin/lib/fleetWire.mjs +46 -0
- package/bin/lib/git.mjs +2 -2
- package/bin/lib/gitMergeIdentity.mjs +51 -0
- package/bin/lib/grant.mjs +5 -3
- package/bin/lib/help.mjs +3 -125
- package/bin/lib/holder.mjs +482 -0
- package/bin/lib/instance.mjs +124 -46
- package/bin/lib/knowledge.mjs +16 -799
- package/bin/lib/knowledgeFetch.mjs +38 -0
- package/bin/lib/knowledgeFileSync.mjs +112 -0
- package/bin/lib/knowledgeFiles.mjs +489 -0
- package/bin/lib/knowledgeLibrary.mjs +299 -0
- package/bin/lib/landed.mjs +2 -1
- package/bin/lib/listeners.mjs +99 -141
- package/bin/lib/localSessions.mjs +30 -555
- package/bin/lib/login.mjs +3 -2
- package/bin/lib/loginPath.mjs +3 -5
- package/bin/lib/machineDisconnect.mjs +203 -0
- package/bin/lib/machineEnv.mjs +22 -0
- package/bin/lib/machineLimits.mjs +61 -0
- package/bin/lib/machineListing.mjs +338 -0
- package/bin/lib/machines.mjs +78 -455
- package/bin/lib/machinesCommand.mjs +214 -0
- package/bin/lib/mcp-cli.mjs +2 -1
- package/bin/lib/patchRevert.mjs +60 -0
- package/bin/lib/prWorkflow.mjs +157 -0
- package/bin/lib/preflight.mjs +2 -1
- package/bin/lib/pressurePolicy.mjs +104 -0
- package/bin/lib/preview.mjs +2 -272
- package/bin/lib/previewFramePolicy.mjs +112 -0
- package/bin/lib/previewGatePolicy.mjs +236 -0
- package/bin/lib/previewRegistry.mjs +235 -0
- package/bin/lib/printable.mjs +2 -2
- package/bin/lib/procRegistry.mjs +28 -18
- package/bin/lib/procScan.mjs +146 -0
- package/bin/lib/processes.mjs +29 -37
- package/bin/lib/projectToolRuntimes.mjs +138 -0
- package/bin/lib/projectTools.mjs +13 -88
- package/bin/lib/prompts.mjs +105 -139
- package/bin/lib/repoPath.mjs +26 -0
- package/bin/lib/resources.mjs +7 -69
- package/bin/lib/resumeLost.mjs +107 -0
- package/bin/lib/runTurn.mjs +324 -0
- package/bin/lib/runtimeAntigravity.mjs +230 -0
- package/bin/lib/runtimeCapabilities.mjs +334 -0
- package/bin/lib/runtimeClaude.mjs +126 -0
- package/bin/lib/runtimeCodex.mjs +217 -0
- package/bin/lib/runtimeDetection.mjs +121 -0
- package/bin/lib/runtimeEvents.mjs +482 -0
- package/bin/lib/runtimeOfferings.mjs +4 -1
- package/bin/lib/runtimes.mjs +42 -1402
- package/bin/lib/safeFileName.mjs +74 -0
- package/bin/lib/standDownExit.mjs +181 -0
- package/bin/lib/standDownGate.mjs +48 -0
- package/bin/lib/startProject.mjs +279 -0
- package/bin/lib/trace.mjs +3 -3
- package/bin/lib/turnLock.mjs +68 -0
- package/bin/lib/turnProfile.mjs +77 -0
- package/bin/lib/uninstall.mjs +55 -45
- package/bin/lib/uninstallCopies.mjs +112 -0
- package/bin/lib/update.mjs +30 -17
- package/bin/lib/uplinkScrub.mjs +265 -0
- package/bin/lib/vault.mjs +22 -151
- package/bin/lib/vaultDiff.mjs +183 -0
- package/bin/lib/versionOrder.mjs +42 -0
- package/bin/lib/views.mjs +17 -17
- package/bin/lib/wikiRunner.mjs +630 -0
- package/bin/lib/work.mjs +188 -3034
- package/bin/lib/workAdoptCarry.mjs +94 -0
- package/bin/lib/workAgentCheck.mjs +278 -0
- package/bin/lib/workAgentMerges.mjs +54 -142
- package/bin/lib/workAgentPlans.mjs +14 -12
- package/bin/lib/workAgentPrecheck.mjs +393 -0
- package/bin/lib/workAgentPublish.mjs +177 -0
- package/bin/lib/workAgentReview.mjs +8 -666
- package/bin/lib/workAgentTurnBegun.mjs +109 -0
- package/bin/lib/workAgentTurnExecution.mjs +604 -0
- package/bin/lib/workAgentTurnOutcome.mjs +219 -0
- package/bin/lib/workAgentTurnReports.mjs +189 -0
- package/bin/lib/workAgentTurns.mjs +91 -898
- package/bin/lib/workAttachments.mjs +93 -0
- package/bin/lib/workBrain.mjs +53 -0
- package/bin/lib/workChildren.mjs +110 -0
- package/bin/lib/workCommandAudit.mjs +62 -0
- package/bin/lib/workDiffs.mjs +2 -1
- package/bin/lib/workNarration.mjs +152 -0
- package/bin/lib/workPlaceReports.mjs +426 -0
- package/bin/lib/workPlaces.mjs +228 -0
- package/bin/lib/workPreviews.mjs +31 -9
- package/bin/lib/workProcesses.mjs +4 -5
- package/bin/lib/workPullRequests.mjs +52 -126
- package/bin/lib/workReportQueue.mjs +254 -0
- package/bin/lib/workRetire.mjs +185 -0
- package/bin/lib/workSessionGroups.mjs +166 -0
- package/bin/lib/workSessionRuntime.mjs +164 -0
- package/bin/lib/workSessionTokens.mjs +68 -0
- package/bin/lib/workSessionTurns.mjs +892 -0
- package/bin/lib/workShip.mjs +9 -29
- package/bin/lib/workToolLog.mjs +76 -0
- package/package.json +3 -2
- package/bin/lib/patch.mjs +0 -363
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHAT EACH CLI TAKES OF THE REPO'S TOOLS, AND HOW A TURN IS PREPARED FOR IT
|
|
3
|
+
* (2026-09-26, SOLID F064).
|
|
4
|
+
*
|
|
5
|
+
* One row per runtime: whether it can take MCP servers at all, which MCP
|
|
6
|
+
* configurations it refuses (Codex takes no SSE), whether it takes the base
|
|
7
|
+
* branch's skills, and the runner-specific filesystem work a turn needs
|
|
8
|
+
* (Claude: a reviewed plugin carrying the base skills; Codex: an isolated
|
|
9
|
+
* CODEX_HOME). Split out of projectTools.mjs, where a capability table sat
|
|
10
|
+
* beside `runner === 'codex'` / `runner === 'claude'` branches in
|
|
11
|
+
* prepareAgentTools and a second copy of the SSE rule in toolReadout, so a
|
|
12
|
+
* new runtime or a transport change needed coordinated edits in three places.
|
|
13
|
+
* prepareAgentTools, toolReadout and runtimeOfferings.mjs (the Codex MCP
|
|
14
|
+
* report) all ask this table; the base-branch snapshot reader stays in
|
|
15
|
+
* projectTools.mjs. projectTools.test.mjs pins every transport word to here.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
19
|
+
import { join, resolve } from 'node:path';
|
|
20
|
+
import { homedir } from 'node:os';
|
|
21
|
+
|
|
22
|
+
export const toml = (value) => JSON.stringify(String(value));
|
|
23
|
+
|
|
24
|
+
/** Keep personal Codex files, but do not copy its project trust grants. An
|
|
25
|
+
* untrusted worktree's .codex/config.toml is ignored by Codex 0.156.1. */
|
|
26
|
+
function isolatedCodexHome(dir, env, worktree) {
|
|
27
|
+
const source = resolve(env.CODEX_HOME || join(homedir(), '.codex'));
|
|
28
|
+
const dest = join(dir, 'codex-home');
|
|
29
|
+
mkdirSync(dest, { mode: 0o700 });
|
|
30
|
+
if (existsSync(source)) {
|
|
31
|
+
for (const name of readdirSync(source)) {
|
|
32
|
+
if (name === 'config.toml') continue;
|
|
33
|
+
symlinkSync(join(source, name), join(dest, name));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const configPath = join(source, 'config.toml');
|
|
37
|
+
const sourceConfig = existsSync(configPath) ? readFileSync(configPath, 'utf8') : '';
|
|
38
|
+
const topLevel = sourceConfig.split(/^\s*\[/m, 1)[0];
|
|
39
|
+
const personalDeveloperInstructions = /^\s*developer_instructions\s*=/m.test(topLevel);
|
|
40
|
+
// These sections alone grant a checkout permission to supply project
|
|
41
|
+
// settings. Keep every other personal setting, skill and session store.
|
|
42
|
+
const lines = sourceConfig.split('\n');
|
|
43
|
+
let inProject = false;
|
|
44
|
+
let config = lines.filter((line) => {
|
|
45
|
+
const header = /^\s*(?:\[\[([^\]]+)\]\]|\[([^\]]+)\])\s*(?:#.*)?$/.exec(line);
|
|
46
|
+
if (header) {
|
|
47
|
+
const section = header[1] ?? header[2];
|
|
48
|
+
inProject = section === 'projects' || section.startsWith('projects.');
|
|
49
|
+
}
|
|
50
|
+
return !inProject;
|
|
51
|
+
}).join('\n');
|
|
52
|
+
if (worktree) {
|
|
53
|
+
// Codex discovers these even in an untrusted project. Disable exactly the
|
|
54
|
+
// worktree skill paths; the person's ~/.codex/skills and config remain.
|
|
55
|
+
const worktreeSkills = [];
|
|
56
|
+
for (const sourceDir of ['.agents/skills', '.codex/skills', '.claude/skills']) {
|
|
57
|
+
const skillsDir = join(worktree, sourceDir);
|
|
58
|
+
if (!existsSync(skillsDir)) continue;
|
|
59
|
+
for (const name of readdirSync(skillsDir)) {
|
|
60
|
+
const skill = join(skillsDir, name, 'SKILL.md');
|
|
61
|
+
if (existsSync(skill)) worktreeSkills.push(skill);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (worktreeSkills.length && /^\s*skills\.config\s*=/m.test(config))
|
|
65
|
+
throw new Error('Cannot isolate Codex project skills with inline skills.config');
|
|
66
|
+
for (const skill of worktreeSkills) config += `\n[[skills.config]]\npath = ${toml(skill)}\nenabled = false\n`;
|
|
67
|
+
}
|
|
68
|
+
writeFileSync(join(dest, 'config.toml'), config, { mode: 0o600 });
|
|
69
|
+
return { path: dest, personalDeveloperInstructions };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Claude takes the base branch's skills as a plugin written for this turn. */
|
|
73
|
+
function reviewedClaudePlugin(dir, snapshot) {
|
|
74
|
+
if (!snapshot.skillFiles.length) return null;
|
|
75
|
+
const pluginDir = join(dir, 'reviewed-plugin');
|
|
76
|
+
mkdirSync(join(pluginDir, '.claude-plugin'), { recursive: true });
|
|
77
|
+
writeFileSync(join(pluginDir, '.claude-plugin/plugin.json'), JSON.stringify({ name: 'flowviant-reviewed', version: '1.0.0', description: 'Base-branch agent skills' }), { mode: 0o600 });
|
|
78
|
+
for (const { path, body } of snapshot.skillFiles) {
|
|
79
|
+
const dest = join(pluginDir, path.replace(/^\.claude\//, ''));
|
|
80
|
+
mkdirSync(join(dest, '..'), { recursive: true });
|
|
81
|
+
writeFileSync(dest, body, { mode: 0o600 });
|
|
82
|
+
}
|
|
83
|
+
return pluginDir;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The table. `refuseMcp(config)` names why this runtime cannot take one MCP
|
|
88
|
+
* configuration it otherwise could; `prepare(dir, snapshot, env, worktree)`
|
|
89
|
+
* returns the runner-specific part of prepareAgentTools' result.
|
|
90
|
+
*/
|
|
91
|
+
const TOOL_RUNTIMES = {
|
|
92
|
+
claude: {
|
|
93
|
+
mcp: true,
|
|
94
|
+
skills: true,
|
|
95
|
+
refuseMcp: () => null,
|
|
96
|
+
prepare: (dir, snapshot) => ({ pluginDir: reviewedClaudePlugin(dir, snapshot) }),
|
|
97
|
+
},
|
|
98
|
+
codex: {
|
|
99
|
+
mcp: true,
|
|
100
|
+
skills: true,
|
|
101
|
+
refuseMcp: (config) => (config.type === 'sse' ? 'Codex cannot take SSE MCP' : null),
|
|
102
|
+
prepare: (dir, _snapshot, env, worktree) => {
|
|
103
|
+
const isolated = isolatedCodexHome(dir, env, worktree);
|
|
104
|
+
return { codexHome: isolated.path, personalDeveloperInstructions: isolated.personalDeveloperInstructions };
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
antigravity: { mcp: false, skills: false },
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/** An unknown runner (or 'none', when no CLI is installed) takes nothing. */
|
|
111
|
+
const takesNothing = { mcp: false, skills: false };
|
|
112
|
+
const rowFor = (runner) => (Object.hasOwn(TOOL_RUNTIMES, runner) ? TOOL_RUNTIMES[runner] : takesNothing);
|
|
113
|
+
|
|
114
|
+
/** Pure mapping used before a future tool-attach gesture is offered. */
|
|
115
|
+
export function runnerToolCapabilities(runner) {
|
|
116
|
+
const { mcp, skills } = rowFor(runner);
|
|
117
|
+
return { mcp, skills };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Why `runner` cannot take this MCP configuration, or null when it can. The
|
|
121
|
+
* one answer both preparation (which drops it) and the readout (which says it)
|
|
122
|
+
* read. */
|
|
123
|
+
export function mcpRefusal(runner, config) {
|
|
124
|
+
const row = rowFor(runner);
|
|
125
|
+
if (!row.mcp) return runner === 'none' ? 'no installed CLI can take MCP' : `${runner} cannot take MCP`;
|
|
126
|
+
return row.refuseMcp?.(config) ?? null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Why `runner` cannot take the base branch's skills, or null when it can. */
|
|
130
|
+
export function skillsRefusal(runner) {
|
|
131
|
+
if (rowFor(runner).skills) return null;
|
|
132
|
+
return runner === 'none' ? 'no installed CLI can take instructions' : `${runner} cannot take instructions`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** The runner-specific files a turn needs, written under `dir`. */
|
|
136
|
+
export function prepareForRunner(runner, dir, snapshot, env, worktree) {
|
|
137
|
+
return { pluginDir: null, codexHome: null, personalDeveloperInstructions: false, ...(rowFor(runner).prepare?.(dir, snapshot, env, worktree) ?? {}) };
|
|
138
|
+
}
|
package/bin/lib/projectTools.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/** Repo-owned tool configuration, read from the base ref for every agent turn. */
|
|
2
2
|
import { execFileSync } from 'node:child_process';
|
|
3
|
-
import { accessSync, constants,
|
|
4
|
-
import { delimiter, isAbsolute, join
|
|
5
|
-
import {
|
|
3
|
+
import { accessSync, constants, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { delimiter, isAbsolute, join } from 'node:path';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { mcpRefusal, prepareForRunner, skillsRefusal, toml } from './projectToolRuntimes.mjs';
|
|
6
7
|
|
|
7
8
|
const MAX_TOOLS = 40;
|
|
8
9
|
const MAX_REPORT_TOOLS = 80; // 40 MCP servers plus 40 instruction directories
|
|
9
10
|
const MAX_INSTRUCTION_FILES = 80;
|
|
10
11
|
const MAX_INSTRUCTION_BYTES = 512 * 1024;
|
|
11
12
|
const nameOk = (name) => /^[A-Za-z0-9_-]{1,80}$/.test(name) && name !== 'flowviant';
|
|
12
|
-
const toml = (value) => JSON.stringify(String(value));
|
|
13
13
|
const show = (root, ref, path) => {
|
|
14
14
|
try {
|
|
15
15
|
return execFileSync('git', ['show', `${ref}:${path}`], {
|
|
@@ -39,12 +39,6 @@ function referenced(value) {
|
|
|
39
39
|
return [...String(value).matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g)].map((m) => m[1]);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
/** Pure mapping used before a future tool-attach gesture is offered. */
|
|
43
|
-
export function runnerToolCapabilities(runner) {
|
|
44
|
-
return ({ claude: { mcp: true, skills: true }, codex: { mcp: true, skills: true }, antigravity: { mcp: false, skills: false } })[runner]
|
|
45
|
-
?? { mcp: false, skills: false };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
42
|
export function readBaseTools(root, ref, env = process.env) {
|
|
49
43
|
// Resolve once: a base branch may advance while the turn is being prepared.
|
|
50
44
|
const commit = execFileSync('git', ['rev-parse', '--verify', ref], {
|
|
@@ -105,59 +99,10 @@ export function readBaseTools(root, ref, env = process.env) {
|
|
|
105
99
|
|
|
106
100
|
const expand = (value, env) => String(value).replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_, key) => env[key] ?? '');
|
|
107
101
|
|
|
108
|
-
/** Keep personal Codex files, but do not copy its project trust grants. An
|
|
109
|
-
* untrusted worktree's .codex/config.toml is ignored by Codex 0.156.1. */
|
|
110
|
-
function isolatedCodexHome(dir, env, worktree) {
|
|
111
|
-
const source = resolve(env.CODEX_HOME || join(homedir(), '.codex'));
|
|
112
|
-
const dest = join(dir, 'codex-home');
|
|
113
|
-
mkdirSync(dest, { mode: 0o700 });
|
|
114
|
-
if (existsSync(source)) {
|
|
115
|
-
for (const name of readdirSync(source)) {
|
|
116
|
-
if (name === 'config.toml') continue;
|
|
117
|
-
symlinkSync(join(source, name), join(dest, name));
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
const configPath = join(source, 'config.toml');
|
|
121
|
-
const sourceConfig = existsSync(configPath) ? readFileSync(configPath, 'utf8') : '';
|
|
122
|
-
const topLevel = sourceConfig.split(/^\s*\[/m, 1)[0];
|
|
123
|
-
const personalDeveloperInstructions = /^\s*developer_instructions\s*=/m.test(topLevel);
|
|
124
|
-
// These sections alone grant a checkout permission to supply project
|
|
125
|
-
// settings. Keep every other personal setting, skill and session store.
|
|
126
|
-
const lines = sourceConfig.split('\n');
|
|
127
|
-
let inProject = false;
|
|
128
|
-
let config = lines.filter((line) => {
|
|
129
|
-
const header = /^\s*(?:\[\[([^\]]+)\]\]|\[([^\]]+)\])\s*(?:#.*)?$/.exec(line);
|
|
130
|
-
if (header) {
|
|
131
|
-
const section = header[1] ?? header[2];
|
|
132
|
-
inProject = section === 'projects' || section.startsWith('projects.');
|
|
133
|
-
}
|
|
134
|
-
return !inProject;
|
|
135
|
-
}).join('\n');
|
|
136
|
-
if (worktree) {
|
|
137
|
-
// Codex discovers these even in an untrusted project. Disable exactly the
|
|
138
|
-
// worktree skill paths; the person's ~/.codex/skills and config remain.
|
|
139
|
-
const worktreeSkills = [];
|
|
140
|
-
for (const sourceDir of ['.agents/skills', '.codex/skills', '.claude/skills']) {
|
|
141
|
-
const skillsDir = join(worktree, sourceDir);
|
|
142
|
-
if (!existsSync(skillsDir)) continue;
|
|
143
|
-
for (const name of readdirSync(skillsDir)) {
|
|
144
|
-
const skill = join(skillsDir, name, 'SKILL.md');
|
|
145
|
-
if (existsSync(skill)) worktreeSkills.push(skill);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
if (worktreeSkills.length && /^\s*skills\.config\s*=/m.test(config))
|
|
149
|
-
throw new Error('Cannot isolate Codex project skills with inline skills.config');
|
|
150
|
-
for (const skill of worktreeSkills) config += `\n[[skills.config]]\npath = ${toml(skill)}\nenabled = false\n`;
|
|
151
|
-
}
|
|
152
|
-
writeFileSync(join(dest, 'config.toml'), config, { mode: 0o600 });
|
|
153
|
-
return { path: dest, personalDeveloperInstructions };
|
|
154
|
-
}
|
|
155
|
-
|
|
156
102
|
/** Temporary per-turn files are removed after the last retry. No personal CLI config is written. */
|
|
157
103
|
export function prepareAgentTools(snapshot, runner, env = process.env, worktree = null) {
|
|
158
104
|
const dir = mkdtempSync(join(tmpdir(), 'flowviant-agent-tools-'));
|
|
159
|
-
const
|
|
160
|
-
const usable = snapshot.tools.filter((t) => t.state === 'ready' && caps.mcp && !(runner === 'codex' && t.config.type === 'sse'));
|
|
105
|
+
const usable = snapshot.tools.filter((t) => t.state === 'ready' && mcpRefusal(runner, t.config) == null);
|
|
161
106
|
const mcpServers = {};
|
|
162
107
|
const codexArgs = [];
|
|
163
108
|
for (const { name, config } of usable) {
|
|
@@ -185,7 +130,7 @@ export function prepareAgentTools(snapshot, runner, env = process.env, worktree
|
|
|
185
130
|
const mcpPath = join(dir, 'mcp.json');
|
|
186
131
|
writeFileSync(mcpPath, JSON.stringify({ mcpServers }), { mode: 0o600 });
|
|
187
132
|
const pointers = [];
|
|
188
|
-
for (const { path, body } of [...snapshot.instructions, ...(
|
|
133
|
+
for (const { path, body } of [...snapshot.instructions, ...(skillsRefusal(runner) == null ? snapshot.skillFiles : [])]) {
|
|
189
134
|
const dest = join(dir, path);
|
|
190
135
|
mkdirSync(join(dest, '..'), { recursive: true });
|
|
191
136
|
writeFileSync(dest, body, { mode: 0o600 });
|
|
@@ -195,28 +140,14 @@ export function prepareAgentTools(snapshot, runner, env = process.env, worktree
|
|
|
195
140
|
const instructions = [baseInstructions,
|
|
196
141
|
pointers.length ? `Base-branch instruction and skill copies (read the relevant nested files and skill files before acting):\n${pointers.join('\n')}` : '',
|
|
197
142
|
].filter(Boolean).join('\n\n');
|
|
198
|
-
|
|
199
|
-
if (pluginDir) {
|
|
200
|
-
mkdirSync(join(pluginDir, '.claude-plugin'), { recursive: true });
|
|
201
|
-
writeFileSync(join(pluginDir, '.claude-plugin/plugin.json'), JSON.stringify({ name: 'flowviant-reviewed', version: '1.0.0', description: 'Base-branch agent skills' }), { mode: 0o600 });
|
|
202
|
-
for (const { path, body } of snapshot.skillFiles) {
|
|
203
|
-
const dest = join(pluginDir, path.replace(/^\.claude\//, ''));
|
|
204
|
-
mkdirSync(join(dest, '..'), { recursive: true });
|
|
205
|
-
writeFileSync(dest, body, { mode: 0o600 });
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
let codexHome = null;
|
|
209
|
-
let personalDeveloperInstructions = false;
|
|
143
|
+
let prepared;
|
|
210
144
|
try {
|
|
211
|
-
|
|
212
|
-
const isolated = isolatedCodexHome(dir, env, worktree);
|
|
213
|
-
codexHome = isolated.path;
|
|
214
|
-
personalDeveloperInstructions = isolated.personalDeveloperInstructions;
|
|
215
|
-
}
|
|
145
|
+
prepared = prepareForRunner(runner, dir, snapshot, env, worktree);
|
|
216
146
|
} catch (error) {
|
|
217
147
|
rmSync(dir, { recursive: true, force: true });
|
|
218
148
|
throw error;
|
|
219
149
|
}
|
|
150
|
+
const { pluginDir, codexHome, personalDeveloperInstructions } = prepared;
|
|
220
151
|
return {
|
|
221
152
|
mcpPath,
|
|
222
153
|
codexArgs,
|
|
@@ -229,20 +160,14 @@ export function prepareAgentTools(snapshot, runner, env = process.env, worktree
|
|
|
229
160
|
}
|
|
230
161
|
|
|
231
162
|
export function toolReadout(snapshot, runner) {
|
|
232
|
-
const caps = runnerToolCapabilities(runner);
|
|
233
163
|
const short = (reason) => reason == null ? null : String(reason).slice(0, 200);
|
|
234
164
|
const mcp = snapshot.tools.map(({ name, config, state, reason }) => {
|
|
235
|
-
const
|
|
236
|
-
return {
|
|
237
|
-
name, kind: 'mcp',
|
|
238
|
-
state: caps.mcp && !unsupported ? state : 'missing',
|
|
239
|
-
reason: short(!caps.mcp ? runner === 'none' ? 'no installed CLI can take MCP' : `${runner} cannot take MCP`
|
|
240
|
-
: unsupported ? 'Codex cannot take SSE MCP' : reason),
|
|
241
|
-
};
|
|
165
|
+
const refused = mcpRefusal(runner, config);
|
|
166
|
+
return { name, kind: 'mcp', state: refused ? 'missing' : state, reason: short(refused ?? reason) };
|
|
242
167
|
});
|
|
168
|
+
const skillsRefused = skillsRefusal(runner);
|
|
243
169
|
const instructions = snapshot.skills.map(({ path }) => ({
|
|
244
|
-
name: path.split('/')[2], kind: 'instruction', state:
|
|
245
|
-
reason: short(caps.skills ? null : runner === 'none' ? 'no installed CLI can take instructions' : `${runner} cannot take instructions`),
|
|
170
|
+
name: path.split('/')[2], kind: 'instruction', state: skillsRefused ? 'missing' : 'ready', reason: short(skillsRefused),
|
|
246
171
|
}));
|
|
247
172
|
return [...mcp, ...instructions].slice(0, MAX_REPORT_TOOLS);
|
|
248
173
|
}
|