claude-flow 3.58.1 → 3.59.1
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/.claude/proven-config.json +1 -1
- package/README.md +2 -0
- package/package.json +2 -1
- package/v3/@claude-flow/cli/README.md +2 -0
- package/v3/@claude-flow/cli/bin/cli.js +19 -1
- package/v3/@claude-flow/cli/catalog-manifest.json +3 -3
- package/v3/@claude-flow/cli/dist/src/commands/harness.d.ts +40 -0
- package/v3/@claude-flow/cli/dist/src/commands/harness.js +142 -0
- package/v3/@claude-flow/cli/dist/src/commands/index.js +1 -0
- package/v3/@claude-flow/cli/dist/src/commands/init.js +116 -0
- package/v3/@claude-flow/cli/dist/src/commands/memory.js +6 -1
- package/v3/@claude-flow/cli/dist/src/commands/status.js +2 -2
- package/v3/@claude-flow/cli/dist/src/commands/tui.js +9 -4
- package/v3/@claude-flow/cli/dist/src/index.d.ts +3 -0
- package/v3/@claude-flow/cli/dist/src/index.js +12 -2
- package/v3/@claude-flow/cli/dist/src/init/grok-generator.d.ts +96 -0
- package/v3/@claude-flow/cli/dist/src/init/grok-generator.js +371 -0
- package/v3/@claude-flow/cli/dist/src/init/grok-templates.d.ts +11 -0
- package/v3/@claude-flow/cli/dist/src/init/grok-templates.js +28 -0
- package/v3/@claude-flow/cli/dist/src/init/index.d.ts +2 -0
- package/v3/@claude-flow/cli/dist/src/init/index.js +2 -0
- package/v3/@claude-flow/cli/dist/src/mcp-client.js +4 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agent-execute-core.js +59 -12
- package/v3/@claude-flow/cli/dist/src/mcp-tools/capability-brain.d.ts +1 -1
- package/v3/@claude-flow/cli/dist/src/mcp-tools/capability-brain.js +5 -3
- package/v3/@claude-flow/cli/dist/src/mcp-tools/embeddings-tools.js +11 -4
- package/v3/@claude-flow/cli/dist/src/mcp-tools/index.d.ts +1 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/index.js +2 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/memory-tools.js +42 -4
- package/v3/@claude-flow/cli/dist/src/mcp-tools/task-tools.js +7 -3
- package/v3/@claude-flow/cli/dist/src/mcp-tools/team-tools.d.ts +15 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/team-tools.js +244 -0
- package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.d.ts +19 -0
- package/v3/@claude-flow/cli/dist/src/memory/memory-bridge.js +163 -3
- package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.d.ts +4 -0
- package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +70 -37
- package/v3/@claude-flow/cli/dist/src/memory/rabitq-index.d.ts +19 -0
- package/v3/@claude-flow/cli/dist/src/memory/rabitq-index.js +117 -1
- package/v3/@claude-flow/cli/dist/src/missions/schemas.d.ts +113 -113
- package/v3/@claude-flow/cli/dist/src/mods/command-registry/schema.d.ts +193 -193
- package/v3/@claude-flow/cli/dist/src/services/live-harness.d.ts +111 -0
- package/v3/@claude-flow/cli/dist/src/services/live-harness.js +427 -0
- package/v3/@claude-flow/cli/package.json +4 -3
- package/v3/@claude-flow/cli/templates/grok/agents/ruflo-architect.md +35 -0
- package/v3/@claude-flow/cli/templates/grok/agents/ruflo-coder.md +34 -0
- package/v3/@claude-flow/cli/templates/grok/agents/ruflo-reviewer.md +30 -0
- package/v3/@claude-flow/cli/templates/grok/agents/ruflo-tester.md +26 -0
- package/v3/@claude-flow/cli/templates/grok/config.toml +63 -0
- package/v3/@claude-flow/cli/templates/grok/docs/README.md +186 -0
- package/v3/@claude-flow/cli/templates/grok/hooks/subagent-stop-team.json +15 -0
- package/v3/@claude-flow/cli/templates/grok/rules/ruflo-grok.md +132 -0
- package/v3/@claude-flow/cli/templates/grok/scripts/grok-subagent-stop-hook.mjs +90 -0
- package/v3/@claude-flow/cli/templates/grok/scripts/grok-team-bus.mjs +525 -0
- package/v3/@claude-flow/cli/templates/grok/scripts/grok-team-store.mjs +287 -0
- package/v3/@claude-flow/cli/templates/grok/scripts/host-statusline.mjs +281 -0
- package/v3/@claude-flow/cli/templates/grok/skills/agent-teams-grok/SKILL.md +98 -0
package/README.md
CHANGED
|
@@ -118,6 +118,8 @@ User → Ruflo (CLI/MCP) → Router → Swarm → Agents → Memory → LLM prov
|
|
|
118
118
|
|
|
119
119
|
A harness is the workbench around the model: it organizes tasks, carries context between steps and helps check results. **This establishes Ruflo's lineage, not a universal first across every Claude Code tool.** [See the illustrated explainer, exact commits and earlier ecosystem context](docs/harness-origins.md).
|
|
120
120
|
|
|
121
|
+
**Grok Build:** `npx ruflo init --grok` writes the project host surface (`.grok/`, the team bus, and the operator guide) and nothing outside the project; add `--dry-run` to preview. Setup, the `spawn_subagent` contract, the optional status row, and what to re-check when Grok updates: [the Grok operator guide](v3/@claude-flow/cli/templates/grok/docs/README.md).
|
|
122
|
+
|
|
121
123
|
<details>
|
|
122
124
|
<summary><strong>📖 Background — where the name comes from</strong></summary>
|
|
123
125
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.59.1",
|
|
4
4
|
"workspaces": [
|
|
5
5
|
"v3/@claude-flow/codex",
|
|
6
6
|
"v3/@claude-flow/mcp",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"!v3/@claude-flow/cli/dist/**/*.map",
|
|
31
31
|
"v3/@claude-flow/cli/package.json",
|
|
32
32
|
"v3/@claude-flow/cli/catalog-manifest.json",
|
|
33
|
+
"v3/@claude-flow/cli/templates/**",
|
|
33
34
|
"v3/@claude-flow/shared/dist/**/*.js",
|
|
34
35
|
"v3/@claude-flow/shared/dist/**/*.d.ts",
|
|
35
36
|
"!v3/@claude-flow/shared/dist/**/*.map",
|
|
@@ -118,6 +118,8 @@ User → Ruflo (CLI/MCP) → Router → Swarm → Agents → Memory → LLM prov
|
|
|
118
118
|
|
|
119
119
|
A harness is the workbench around the model: it organizes tasks, carries context between steps and helps check results. **This establishes Ruflo's lineage, not a universal first across every Claude Code tool.** [See the illustrated explainer, exact commits and earlier ecosystem context](docs/harness-origins.md).
|
|
120
120
|
|
|
121
|
+
**Grok Build:** `npx ruflo init --grok` writes the project host surface (`.grok/`, the team bus, and the operator guide) and nothing outside the project; add `--dry-run` to preview. Setup, the `spawn_subagent` contract, the optional status row, and what to re-check when Grok updates: [the Grok operator guide](v3/@claude-flow/cli/templates/grok/docs/README.md).
|
|
122
|
+
|
|
121
123
|
<details>
|
|
122
124
|
<summary><strong>📖 Background — where the name comes from</strong></summary>
|
|
123
125
|
|
|
@@ -161,7 +161,25 @@ const isMCPMode = !process.stdin.isTTY
|
|
|
161
161
|
&& !explicitNonStdioTransport
|
|
162
162
|
&& (process.argv.length === 2 || isExplicitMCP);
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
// `harness` observes the running system (it is the SessionStart hook), so it
|
|
165
|
+
// skips normal CLI startup entirely: no daemon autostart, update check, policy
|
|
166
|
+
// migration or config adoption, and no heavy imports. With --hook it fails
|
|
167
|
+
// silently (no stack on stderr) so a missing dist/ can't disturb a session.
|
|
168
|
+
const isHarness = cliArgs[0] === 'harness' && !cliArgs.includes('--help') && !cliArgs.includes('-h');
|
|
169
|
+
|
|
170
|
+
if (isHarness) {
|
|
171
|
+
const hook = cliArgs.includes('--hook');
|
|
172
|
+
try {
|
|
173
|
+
const { runHarnessCli } = await import('../dist/src/commands/harness.js');
|
|
174
|
+
process.exitCode = runHarnessCli(cliArgs.slice(1));
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (!hook) {
|
|
177
|
+
const missing = error && error.code === 'ERR_MODULE_NOT_FOUND';
|
|
178
|
+
console.error(`ruflo harness: ${missing ? 'the CLI is not built (dist/ is missing)' : (error && error.message) || error}`);
|
|
179
|
+
}
|
|
180
|
+
process.exitCode = hook ? 0 : 1;
|
|
181
|
+
}
|
|
182
|
+
} else if (isMCPMode) {
|
|
165
183
|
// Run MCP server mode
|
|
166
184
|
const { listMCPTools, callMCPTool, hasTool } = await import('../dist/src/mcp-client.js');
|
|
167
185
|
const { isPolicyEnforcementEnabled, loadMcpPolicy, evaluateToolCall } =
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generation": 7,
|
|
4
|
-
"generatedAt": "2026-10-
|
|
5
|
-
"gitSha": "
|
|
4
|
+
"generatedAt": "2026-10-20T17:15:56.251Z",
|
|
5
|
+
"gitSha": "9271be48",
|
|
6
6
|
"catalog": {
|
|
7
7
|
"agents": 176,
|
|
8
|
-
"tools":
|
|
8
|
+
"tools": 432,
|
|
9
9
|
"skills": 34
|
|
10
10
|
},
|
|
11
11
|
"benchmark": null
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live harness status.
|
|
3
|
+
*
|
|
4
|
+
* This is not `doctor` and not `status`. Those describe install health or
|
|
5
|
+
* call tool handlers inside this process. `harness` reports what is already
|
|
6
|
+
* running for this working tree: the host session, a live daemon pid, ruflo
|
|
7
|
+
* MCP servers whose cwd is this tree, processes holding the memory databases
|
|
8
|
+
* open, and teams that are still active.
|
|
9
|
+
*
|
|
10
|
+
* ruflo harness
|
|
11
|
+
* ruflo harness --json
|
|
12
|
+
* ruflo harness --hook # SessionStart payload for Codex (and Claude)
|
|
13
|
+
* ruflo harness --print-codex-hook # opt-in .codex/hooks.json for this install
|
|
14
|
+
*
|
|
15
|
+
* `harness` is observe-only: bin/cli.js runs it through `runHarnessCli`
|
|
16
|
+
* before the normal CLI starts, so no daemon autostart, update check, policy
|
|
17
|
+
* migration or config adoption runs, and nothing is written to disk. The CLI
|
|
18
|
+
* class also exempts it from those side effects (see OBSERVE_ONLY_COMMANDS).
|
|
19
|
+
*/
|
|
20
|
+
import type { Command } from '../types.js';
|
|
21
|
+
import { type LiveHarness } from '../services/live-harness.js';
|
|
22
|
+
export type { LiveHarness } from '../services/live-harness.js';
|
|
23
|
+
export { collectLiveHarness } from '../services/live-harness.js';
|
|
24
|
+
/** This install's bin/cli.js, from dist/src/commands/harness.js (or src/commands). */
|
|
25
|
+
export declare function installedCliPath(moduleUrl?: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* A .codex/hooks.json that runs this install's harness on SessionStart. The
|
|
28
|
+
* path is absolute, so the hook does not depend on the session's git root.
|
|
29
|
+
* Autostart and the update check are off, and failures stay silent.
|
|
30
|
+
*/
|
|
31
|
+
export declare function codexHookConfig(cliPath?: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Entry used by bin/cli.js before the CLI class loads. Returns the exit code.
|
|
34
|
+
* With --hook it never fails: on any error it prints nothing and returns 0,
|
|
35
|
+
* so a SessionStart hook can't break a session.
|
|
36
|
+
*/
|
|
37
|
+
export declare function runHarnessCli(argv: string[], write?: (text: string) => void, collect?: () => LiveHarness): number;
|
|
38
|
+
export declare const harnessCommand: Command;
|
|
39
|
+
export default harnessCommand;
|
|
40
|
+
//# sourceMappingURL=harness.d.ts.map
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live harness status.
|
|
3
|
+
*
|
|
4
|
+
* This is not `doctor` and not `status`. Those describe install health or
|
|
5
|
+
* call tool handlers inside this process. `harness` reports what is already
|
|
6
|
+
* running for this working tree: the host session, a live daemon pid, ruflo
|
|
7
|
+
* MCP servers whose cwd is this tree, processes holding the memory databases
|
|
8
|
+
* open, and teams that are still active.
|
|
9
|
+
*
|
|
10
|
+
* ruflo harness
|
|
11
|
+
* ruflo harness --json
|
|
12
|
+
* ruflo harness --hook # SessionStart payload for Codex (and Claude)
|
|
13
|
+
* ruflo harness --print-codex-hook # opt-in .codex/hooks.json for this install
|
|
14
|
+
*
|
|
15
|
+
* `harness` is observe-only: bin/cli.js runs it through `runHarnessCli`
|
|
16
|
+
* before the normal CLI starts, so no daemon autostart, update check, policy
|
|
17
|
+
* migration or config adoption runs, and nothing is written to disk. The CLI
|
|
18
|
+
* class also exempts it from those side effects (see OBSERVE_ONLY_COMMANDS).
|
|
19
|
+
*/
|
|
20
|
+
import { dirname, join } from 'node:path';
|
|
21
|
+
import { fileURLToPath } from 'node:url';
|
|
22
|
+
import { collectLiveHarness } from '../services/live-harness.js';
|
|
23
|
+
export { collectLiveHarness } from '../services/live-harness.js';
|
|
24
|
+
function renderText(report) {
|
|
25
|
+
const out = [report.line];
|
|
26
|
+
if (Object.keys(report.session).length) {
|
|
27
|
+
out.push(`session ${Object.entries(report.session).map(([k, v]) => `${k}=${v}`).join(' ')}`);
|
|
28
|
+
}
|
|
29
|
+
for (const server of report.mcp.servers)
|
|
30
|
+
out.push(`mcp ${server.pid} ${server.command}`);
|
|
31
|
+
if (report.memory.openPids?.length)
|
|
32
|
+
out.push(`memory held by ${report.memory.openPids.join(',')}`);
|
|
33
|
+
for (const team of report.teams)
|
|
34
|
+
out.push(`team ${team.name} ${team.status} members=${team.members}`);
|
|
35
|
+
if (report.staleTeams.length)
|
|
36
|
+
out.push(`stale teams (no activity, not shut down) ${report.staleTeams.join(',')}`);
|
|
37
|
+
return out.join('\n') + '\n';
|
|
38
|
+
}
|
|
39
|
+
function renderHook(report) {
|
|
40
|
+
return JSON.stringify({
|
|
41
|
+
hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: report.line },
|
|
42
|
+
}) + '\n';
|
|
43
|
+
}
|
|
44
|
+
function shellQuote(value) {
|
|
45
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
46
|
+
}
|
|
47
|
+
/** This install's bin/cli.js, from dist/src/commands/harness.js (or src/commands). */
|
|
48
|
+
export function installedCliPath(moduleUrl = import.meta.url) {
|
|
49
|
+
return join(dirname(fileURLToPath(moduleUrl)), '..', '..', '..', 'bin', 'cli.js');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A .codex/hooks.json that runs this install's harness on SessionStart. The
|
|
53
|
+
* path is absolute, so the hook does not depend on the session's git root.
|
|
54
|
+
* Autostart and the update check are off, and failures stay silent.
|
|
55
|
+
*/
|
|
56
|
+
export function codexHookConfig(cliPath = installedCliPath()) {
|
|
57
|
+
const command = `RUFLO_DAEMON_AUTOSTART=0 node ${shellQuote(cliPath)} harness --hook --no-update 2>/dev/null || true`;
|
|
58
|
+
return JSON.stringify({
|
|
59
|
+
hooks: {
|
|
60
|
+
SessionStart: [
|
|
61
|
+
{
|
|
62
|
+
matcher: 'startup|resume|clear|compact|fork',
|
|
63
|
+
hooks: [{ type: 'command', command, timeout: 8 }],
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
}, null, 2) + '\n';
|
|
68
|
+
}
|
|
69
|
+
function render(mode, collect) {
|
|
70
|
+
if (mode === 'codex-hook')
|
|
71
|
+
return { text: codexHookConfig() };
|
|
72
|
+
const report = collect();
|
|
73
|
+
if (mode === 'hook')
|
|
74
|
+
return { text: renderHook(report), report };
|
|
75
|
+
if (mode === 'json')
|
|
76
|
+
return { text: JSON.stringify(report, null, 2) + '\n', report };
|
|
77
|
+
return { text: renderText(report), report };
|
|
78
|
+
}
|
|
79
|
+
function modeOf(flags) {
|
|
80
|
+
if (flags.printCodexHook)
|
|
81
|
+
return 'codex-hook';
|
|
82
|
+
if (flags.hook)
|
|
83
|
+
return 'hook';
|
|
84
|
+
if (flags.json)
|
|
85
|
+
return 'json';
|
|
86
|
+
return 'text';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Entry used by bin/cli.js before the CLI class loads. Returns the exit code.
|
|
90
|
+
* With --hook it never fails: on any error it prints nothing and returns 0,
|
|
91
|
+
* so a SessionStart hook can't break a session.
|
|
92
|
+
*/
|
|
93
|
+
export function runHarnessCli(argv, write = (text) => { process.stdout.write(text); }, collect = () => collectLiveHarness()) {
|
|
94
|
+
const mode = modeOf({
|
|
95
|
+
hook: argv.includes('--hook'),
|
|
96
|
+
json: argv.includes('--json'),
|
|
97
|
+
printCodexHook: argv.includes('--print-codex-hook'),
|
|
98
|
+
});
|
|
99
|
+
try {
|
|
100
|
+
write(render(mode, collect).text);
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (mode === 'hook')
|
|
105
|
+
return 0;
|
|
106
|
+
process.stderr.write(`ruflo harness: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export const harnessCommand = {
|
|
111
|
+
name: 'harness',
|
|
112
|
+
description: 'Show the running harness for this tree (live pids and open state, not install config)',
|
|
113
|
+
options: [
|
|
114
|
+
{ name: 'json', description: 'Print the live report as JSON', type: 'boolean', default: false },
|
|
115
|
+
{
|
|
116
|
+
name: 'hook',
|
|
117
|
+
description: 'Print a SessionStart additionalContext payload for Codex or Claude',
|
|
118
|
+
type: 'boolean',
|
|
119
|
+
default: false,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'print-codex-hook',
|
|
123
|
+
description: 'Print an opt-in .codex/hooks.json that runs this install on SessionStart',
|
|
124
|
+
type: 'boolean',
|
|
125
|
+
default: false,
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
examples: [
|
|
129
|
+
{ command: 'ruflo harness', description: 'One line plus any live mcp, memory holders, and teams' },
|
|
130
|
+
{ command: 'ruflo harness --json', description: 'Machine-readable live report' },
|
|
131
|
+
{ command: 'ruflo harness --hook', description: 'SessionStart payload' },
|
|
132
|
+
{ command: 'ruflo harness --print-codex-hook > .codex/hooks.json', description: 'Opt in to the Codex SessionStart hook' },
|
|
133
|
+
],
|
|
134
|
+
action: async (ctx) => {
|
|
135
|
+
const mode = modeOf(ctx.flags);
|
|
136
|
+
const { text, report } = render(mode, () => collectLiveHarness());
|
|
137
|
+
process.stdout.write(text);
|
|
138
|
+
return { success: true, data: report };
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
export default harnessCommand;
|
|
142
|
+
//# sourceMappingURL=harness.js.map
|
|
@@ -45,6 +45,7 @@ const commandLoaders = {
|
|
|
45
45
|
// P0 Commands
|
|
46
46
|
completions: () => import('./completions.js'),
|
|
47
47
|
doctor: () => import('./doctor.js'),
|
|
48
|
+
harness: () => import('./harness.js'),
|
|
48
49
|
// Verification (ADR-095, signed witness manifest)
|
|
49
50
|
verify: () => import('./verify.js'),
|
|
50
51
|
// Analysis Commands
|
|
@@ -8,6 +8,7 @@ import * as fs from 'fs';
|
|
|
8
8
|
import * as path from 'path';
|
|
9
9
|
import { spawnSync } from 'node:child_process';
|
|
10
10
|
import { executeInit, executeUpgrade, executeUpgradeWithMissing, DEFAULT_INIT_OPTIONS, MINIMAL_INIT_OPTIONS, FULL_INIT_OPTIONS, } from '../init/index.js';
|
|
11
|
+
import { executeGrokInit } from '../init/grok-generator.js';
|
|
11
12
|
import { ENROLLMENT_SCREEN, recordEnrollmentOutcome, shouldOfferEnrollment, } from '../funnel/enrollment.js';
|
|
12
13
|
import { commandExists } from '../services/harness-hosts.js';
|
|
13
14
|
/**
|
|
@@ -361,6 +362,90 @@ async function maybeInstallSkillsSh(ctx) {
|
|
|
361
362
|
// Skills.sh registration is a bonus, never a requirement — swallow everything.
|
|
362
363
|
}
|
|
363
364
|
}
|
|
365
|
+
// Grok Build host initialization (ADR-402)
|
|
366
|
+
async function initGrokAction(ctx, options) {
|
|
367
|
+
const { force, statusLine, dryRun } = options;
|
|
368
|
+
output.writeln();
|
|
369
|
+
output.writeln(output.bold(dryRun ? 'Grok Build init (dry run — nothing is written)' : 'Initializing RuFlo for Grok Build'));
|
|
370
|
+
output.writeln();
|
|
371
|
+
try {
|
|
372
|
+
const result = executeGrokInit({
|
|
373
|
+
targetDir: ctx.cwd,
|
|
374
|
+
force,
|
|
375
|
+
docs: true,
|
|
376
|
+
statusLine,
|
|
377
|
+
dryRun,
|
|
378
|
+
});
|
|
379
|
+
if (!result.success) {
|
|
380
|
+
output.printError('Grok initialization failed');
|
|
381
|
+
for (const err of result.errors) {
|
|
382
|
+
output.printError(err);
|
|
383
|
+
}
|
|
384
|
+
return { success: false, exitCode: 1, message: 'Grok init failed' };
|
|
385
|
+
}
|
|
386
|
+
output.printBox([
|
|
387
|
+
`.grok/config.toml — project MCP (ruflo) + permissions`,
|
|
388
|
+
`.grok/rules/ruflo-grok.md — host doctrine / tool map`,
|
|
389
|
+
`.grok/agents/ — ruflo-architect/coder/tester/reviewer`,
|
|
390
|
+
`.grok/skills/ — agent-teams-grok`,
|
|
391
|
+
`.grok/hooks/ — SubagentStop advances the team plan`,
|
|
392
|
+
`scripts/grok-team-bus.mjs (+ grok-team-store.mjs) — ADR-402 team bus CLI`,
|
|
393
|
+
`scripts/host-statusline.mjs — "what is loaded" row`,
|
|
394
|
+
`docs/grok/README.md — operator guide`,
|
|
395
|
+
].join('\n'), 'Grok Build Integration (ADR-402)');
|
|
396
|
+
output.writeln();
|
|
397
|
+
const verb = dryRun ? 'Would write' : 'Wrote';
|
|
398
|
+
output.writeln(output.bold(`${verb} (${result.filesCreated.length}):`));
|
|
399
|
+
output.printList(result.filesCreated.map((f) => (path.relative(ctx.cwd, f).startsWith('..') ? f : path.relative(ctx.cwd, f))));
|
|
400
|
+
if (result.filesSkipped.length > 0) {
|
|
401
|
+
output.printInfo(`Skipped ${result.filesSkipped.length} existing file(s)${force ? '' : ' — use --force to overwrite'}`);
|
|
402
|
+
}
|
|
403
|
+
output.writeln();
|
|
404
|
+
const mcp = result.mcp;
|
|
405
|
+
output.printInfo(mcp.source === 'published'
|
|
406
|
+
? `MCP server pinned to ruflo@${mcp.version} (the release that ships the team_* tools)`
|
|
407
|
+
: `MCP server points at this checkout: ${mcp.args[0]} — rebuild it before use, and re-run init from a published release before committing .grok/config.toml`);
|
|
408
|
+
const uc = result.userConfig;
|
|
409
|
+
if (uc.action === 'not-requested' || uc.action === 'snippet') {
|
|
410
|
+
output.writeln();
|
|
411
|
+
output.writeln(uc.action === 'snippet'
|
|
412
|
+
? output.bold(`Did not change ${uc.path}: ${uc.reason}`)
|
|
413
|
+
: output.bold('Optional status row (Grok reads it only from your user config):'));
|
|
414
|
+
output.writeln(output.dim(` Add this to ${uc.path}, or re-run with --grok-statusline to have init merge it`));
|
|
415
|
+
output.writeln(output.dim(` (that also installs the script it runs under ~/.grok/ruflo/):`));
|
|
416
|
+
output.writeln(uc.snippet.trimEnd().split('\n').map((l) => ` ${l}`).join('\n'));
|
|
417
|
+
}
|
|
418
|
+
else if (uc.action === 'already-set') {
|
|
419
|
+
output.printInfo(uc.reason || `${uc.path} already has the Ruflo status row; refreshed the script it runs`);
|
|
420
|
+
}
|
|
421
|
+
output.writeln();
|
|
422
|
+
output.writeln(output.bold('Next steps:'));
|
|
423
|
+
output.printList([
|
|
424
|
+
'Trust this folder in Grok (/hooks-trust or grok --trust) so MCP, hooks, skills, and rules load together',
|
|
425
|
+
'Restart Grok so .grok/config.toml is applied',
|
|
426
|
+
'Read docs/grok/README.md — spawn contract checked on Grok Build 1.0.41',
|
|
427
|
+
'Verify: grok mcp list && grok mcp doctor ruflo',
|
|
428
|
+
'Optional: npx ruvnet-brain@latest then enable ruvnet-brain in .grok/config.toml',
|
|
429
|
+
'Teams: team_create / team_spawn MCP tools (or node scripts/grok-team-bus.mjs)',
|
|
430
|
+
]);
|
|
431
|
+
output.writeln();
|
|
432
|
+
return {
|
|
433
|
+
success: true,
|
|
434
|
+
data: {
|
|
435
|
+
adapter: 'grok',
|
|
436
|
+
dryRun,
|
|
437
|
+
filesCreated: result.filesCreated,
|
|
438
|
+
filesSkipped: result.filesSkipped,
|
|
439
|
+
mcp: result.mcp,
|
|
440
|
+
userConfig: { action: uc.action, path: uc.path },
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
catch (e) {
|
|
445
|
+
output.printError(`Grok initialization failed: ${e.message}`);
|
|
446
|
+
return { success: false, exitCode: 1, message: e.message };
|
|
447
|
+
}
|
|
448
|
+
}
|
|
364
449
|
// Codex initialization action
|
|
365
450
|
async function initCodexAction(ctx, options) {
|
|
366
451
|
const { force, minimal, full, dualMode } = options;
|
|
@@ -848,6 +933,15 @@ const initAction = async (ctx) => {
|
|
|
848
933
|
const full = ctx.flags.full;
|
|
849
934
|
const codexMode = ctx.flags.codex;
|
|
850
935
|
const dualMode = ctx.flags.dual;
|
|
936
|
+
const grokMode = ctx.flags.grok;
|
|
937
|
+
// Grok Build host (ADR-402) — separate surface under .grok/
|
|
938
|
+
if (grokMode) {
|
|
939
|
+
return initGrokAction(ctx, {
|
|
940
|
+
force,
|
|
941
|
+
statusLine: ctx.flags.grokStatusline === true || ctx.flags['grok-statusline'] === true,
|
|
942
|
+
dryRun: ctx.flags.dryRun === true || ctx.flags['dry-run'] === true,
|
|
943
|
+
});
|
|
944
|
+
}
|
|
851
945
|
if (codexMode && !dualMode) {
|
|
852
946
|
return initCodexAction(ctx, { codexMode, dualMode: false, force, minimal, full });
|
|
853
947
|
}
|
|
@@ -1598,6 +1692,24 @@ export const initCommand = {
|
|
|
1598
1692
|
type: 'boolean',
|
|
1599
1693
|
default: false,
|
|
1600
1694
|
},
|
|
1695
|
+
{
|
|
1696
|
+
name: 'grok',
|
|
1697
|
+
description: 'Initialize for Grok Build host (creates .grok/, team bus scripts, ADR-402 surface)',
|
|
1698
|
+
type: 'boolean',
|
|
1699
|
+
default: false,
|
|
1700
|
+
},
|
|
1701
|
+
{
|
|
1702
|
+
name: 'grok-statusline',
|
|
1703
|
+
description: 'With --grok: also merge the Ruflo status row into ~/.grok/config.toml (user file; off by default)',
|
|
1704
|
+
type: 'boolean',
|
|
1705
|
+
default: false,
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
name: 'dry-run',
|
|
1709
|
+
description: 'With --grok: list the files init would write, write nothing',
|
|
1710
|
+
type: 'boolean',
|
|
1711
|
+
default: false,
|
|
1712
|
+
},
|
|
1601
1713
|
{
|
|
1602
1714
|
name: 'dual',
|
|
1603
1715
|
description: 'Initialize for both Claude Code and OpenAI Codex',
|
|
@@ -1647,6 +1759,10 @@ export const initCommand = {
|
|
|
1647
1759
|
{ command: 'claude-flow init upgrade --verbose', description: 'Show detailed upgrade info' },
|
|
1648
1760
|
{ command: 'claude-flow init --codex', description: 'Initialize for OpenAI Codex (AGENTS.md)' },
|
|
1649
1761
|
{ command: 'claude-flow init --codex --full', description: 'Codex init with all canonical packaged skills' },
|
|
1762
|
+
{ command: 'claude-flow init --grok', description: 'Initialize for Grok Build (.grok/, team bus, ADR-402)' },
|
|
1763
|
+
{ command: 'claude-flow init --grok --force', description: 'Overwrite existing Grok host files' },
|
|
1764
|
+
{ command: 'claude-flow init --grok --dry-run', description: 'Show what init --grok would write' },
|
|
1765
|
+
{ command: 'claude-flow init --grok --grok-statusline', description: 'Also add the Ruflo status row to ~/.grok/config.toml' },
|
|
1650
1766
|
{ command: 'claude-flow init --dual', description: 'Initialize for both Claude Code and Codex' },
|
|
1651
1767
|
{ command: 'claude-flow init --no-codex-detect', description: 'Skip auto-configuring OpenAI Codex even if it is installed' },
|
|
1652
1768
|
{ command: 'claude-flow init --no-skills-sh', description: 'Skip the post-init skills.sh registration' },
|
|
@@ -814,11 +814,16 @@ const listCommand = {
|
|
|
814
814
|
const namespace = ctx.flags.namespace;
|
|
815
815
|
const limit = ctx.flags.limit;
|
|
816
816
|
const includeEmbedding = ctx.flags.embeddings === true && ctx.flags.format === 'json';
|
|
817
|
+
// Mirrors memory_list's MCP tool handling: comma-separated flag →
|
|
818
|
+
// non-empty string array, require entries to carry every tag (AND).
|
|
819
|
+
const tags = ctx.flags.tags
|
|
820
|
+
? ctx.flags.tags.split(',').map(t => t.trim()).filter((t) => t.length > 0)
|
|
821
|
+
: undefined;
|
|
817
822
|
// Use sql.js directly for consistent data access
|
|
818
823
|
try {
|
|
819
824
|
const { listEntries, resolveDbPath: _rdbList } = await import('../memory/memory-initializer.js');
|
|
820
825
|
const dbPathList = _rdbList(ctx.flags.path);
|
|
821
|
-
const listResult = await listEntries({ namespace, limit, offset: 0, dbPath: dbPathList, ...(includeEmbedding && { includeEmbedding: true }) });
|
|
826
|
+
const listResult = await listEntries({ namespace, limit, offset: 0, dbPath: dbPathList, tags, ...(includeEmbedding && { includeEmbedding: true }) });
|
|
822
827
|
if (!listResult.success) {
|
|
823
828
|
output.printError(`Failed to list: ${listResult.error}`);
|
|
824
829
|
return { success: false, exitCode: 1 };
|
|
@@ -484,11 +484,11 @@ const tasksCommand = {
|
|
|
484
484
|
{ key: 'progress', header: 'Progress', width: 10 }
|
|
485
485
|
],
|
|
486
486
|
data: result.tasks.map(t => ({
|
|
487
|
-
id: t.
|
|
487
|
+
id: t.taskId,
|
|
488
488
|
type: t.type,
|
|
489
489
|
status: formatHealth(t.status),
|
|
490
490
|
priority: t.priority,
|
|
491
|
-
agent: t.
|
|
491
|
+
agent: t.assignedTo?.length ? t.assignedTo.join(', ') : '-',
|
|
492
492
|
progress: `${t.progress}%`
|
|
493
493
|
}))
|
|
494
494
|
});
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* No bundle is a message and exit 1, never a crash; ruflo stays operational without it. Without a terminal (a pipe, CI) the live view cannot run:
|
|
9
9
|
* a one-line hint and exit 2, unless --plain asks for one frame as plain text and exit 0 (ADR-489 decision E).
|
|
10
10
|
*
|
|
11
|
-
* npx ruflo tui # interactive, in a terminal
|
|
11
|
+
* npx ruflo tui # interactive, in a terminal (mouse on: click a page in the bar, scroll with the wheel)
|
|
12
|
+
* npx ruflo tui --no-mouse # keyboard only, if SGR mouse reporting fights your terminal's text selection
|
|
12
13
|
* npx ruflo tui --view swarm # start on the Swarm page (keys 1-6 or o c s e m a switch pages)
|
|
13
14
|
* npx ruflo tui --plain | head # one plain frame, exit 0 (scripts, CI)
|
|
14
15
|
* npx ruflo tui | cat # not a terminal and no --plain: a hint on stderr, exit 2
|
|
@@ -45,7 +46,10 @@ export function lookFlags(flags) {
|
|
|
45
46
|
...(flags?.anim === false ? { anim: false } : {}),
|
|
46
47
|
...(flags?.pictures === false ? { pictures: false } : {}),
|
|
47
48
|
...(flags?.boot === true ? { boot: true } : {}),
|
|
48
|
-
|
|
49
|
+
// Mouse defaults ON at the CLI layer (the runTui library itself still defaults off, unchanged for other
|
|
50
|
+
// callers/tests): only --no-mouse turns it off. The CLI must say so explicitly either way rather than
|
|
51
|
+
// omit the key, since (unlike anim/pictures) the CLI's default disagrees with the library's own default.
|
|
52
|
+
...{ mouse: flags?.mouse !== false },
|
|
49
53
|
};
|
|
50
54
|
}
|
|
51
55
|
/** The AI page's settings from the flags (and one environment variable for the endpoint list). Absent flags leave the defaults; a bad number is ignored, never passed on. */
|
|
@@ -69,12 +73,13 @@ export const tuiCommand = {
|
|
|
69
73
|
{ name: 'fps', description: 'Frames per second for moving pictures, 0-30 (default 8; 0 draws every picture still)', type: 'number' },
|
|
70
74
|
{ name: 'anim', description: 'Animate the pictures. --no-anim draws them still', type: 'boolean', default: true },
|
|
71
75
|
{ name: 'pictures', description: 'Draw the pictures of the console (title art, swarm graph, gauges). --no-pictures shows their words only', type: 'boolean', default: true },
|
|
72
|
-
{ name: 'mouse', description: 'Read mouse reports: click a page in the bar, scroll with the wheel (every action also has a key)', type: 'boolean', default:
|
|
76
|
+
{ name: 'mouse', description: 'Read mouse reports: click a page in the bar, scroll with the wheel (every action also has a key). On by default; --no-mouse turns it off if SGR reporting fights your terminal\'s text selection', type: 'boolean', default: true },
|
|
73
77
|
{ name: 'boot', description: 'Play the look\'s start-up screen first (as the console\'s boot setting)', type: 'boolean', default: false },
|
|
74
78
|
{ name: 'plain', description: 'Print one frame as plain text and exit 0 (scripts and CI). Without it, a non-terminal gets a hint and exit 2', type: 'boolean', default: false },
|
|
75
79
|
],
|
|
76
80
|
examples: [
|
|
77
|
-
{ command: 'npx ruflo tui', description: 'Open the console in this terminal' },
|
|
81
|
+
{ command: 'npx ruflo tui', description: 'Open the console in this terminal (mouse on: click a page in the bar, scroll with the wheel)' },
|
|
82
|
+
{ command: 'npx ruflo tui --no-mouse', description: 'Keyboard only, if SGR mouse reporting fights your terminal\'s text selection' },
|
|
78
83
|
{ command: 'npx ruflo tui --view swarm', description: 'Start on the Swarm page (keys 1-6 switch pages, tab cycles, q quits)' },
|
|
79
84
|
{ command: 'npx ruflo tui --view ai --model openai/gpt-4o-mini --max-spend-usd 0.1', description: 'The AI page on a cheap OpenRouter model, stopping at $0.10 reported (key in $OPENROUTER_API_KEY, never shown)' },
|
|
80
85
|
{ command: 'npx ruflo tui --plain | head -40', description: 'One plain frame, exit 0: for scripts and CI (no terminal needed)' },
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import './log-filters.js';
|
|
8
8
|
export declare const VERSION: string;
|
|
9
|
+
/** Commands that only observe the running system and must not start or write anything. */
|
|
10
|
+
export declare const OBSERVE_ONLY_COMMANDS: ReadonlySet<string>;
|
|
11
|
+
export declare function isObserveOnlyCommand(name: string | undefined): boolean;
|
|
9
12
|
export interface CLIOptions {
|
|
10
13
|
name?: string;
|
|
11
14
|
description?: string;
|
|
@@ -36,6 +36,11 @@ function getPackageVersion() {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
export const VERSION = getPackageVersion();
|
|
39
|
+
/** Commands that only observe the running system and must not start or write anything. */
|
|
40
|
+
export const OBSERVE_ONLY_COMMANDS = new Set(['harness']);
|
|
41
|
+
export function isObserveOnlyCommand(name) {
|
|
42
|
+
return name !== undefined && OBSERVE_ONLY_COMMANDS.has(name);
|
|
43
|
+
}
|
|
39
44
|
/**
|
|
40
45
|
* V3 CLI Application
|
|
41
46
|
*/
|
|
@@ -113,8 +118,13 @@ export class CLI {
|
|
|
113
118
|
this.output.printDebug(`Flags: ${JSON.stringify(Object.fromEntries(Object.entries(flags).filter(([k]) => k !== '_')))}`);
|
|
114
119
|
this.output.printDebug(`CWD: ${process.cwd()}`);
|
|
115
120
|
}
|
|
121
|
+
// Observe-only commands (e.g. `harness`, run from SessionStart hooks)
|
|
122
|
+
// report on the running system, so they must not change it: no update
|
|
123
|
+
// check, no policy migration, no helper refresh, no proven-config
|
|
124
|
+
// adoption, no daemon autostart.
|
|
125
|
+
const observeOnly = isObserveOnlyCommand(commandPath[0] ?? positional[0]);
|
|
116
126
|
// Run startup update check (non-blocking, silent on skip)
|
|
117
|
-
if (!flags.noUpdate && flags.update !== false && commandPath[0] !== 'update' && !(commandPath[0] === 'doctor' && flags.json)) {
|
|
127
|
+
if (!flags.noUpdate && flags.update !== false && commandPath[0] !== 'update' && !(commandPath[0] === 'doctor' && flags.json) && !observeOnly) {
|
|
118
128
|
this.checkForUpdatesOnStartup().catch(() => { });
|
|
119
129
|
}
|
|
120
130
|
// Version-stamped helper auto-refresh — propagate hook fixes to an already
|
|
@@ -123,7 +133,7 @@ export class CLI {
|
|
|
123
133
|
// command can't exit before the copy lands; the fast path is a single
|
|
124
134
|
// stamp read + string compare (sub-ms), and the copy runs at most once per
|
|
125
135
|
// version bump. Best-effort + silent — never blocks or fails a command.
|
|
126
|
-
if (commandPath[0] !== 'init' && commandPath[0] !== 'update') {
|
|
136
|
+
if (commandPath[0] !== 'init' && commandPath[0] !== 'update' && !observeOnly) {
|
|
127
137
|
// ADR-324: existing installations acquire a versioned policy state on
|
|
128
138
|
// first use. Migration is additive and starts in legacy mode, so older
|
|
129
139
|
// AgentDB, MCP, hooks, and swarm workflows keep their exact behavior.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grok Build host init (ADR-402).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `init --codex`: writes project-scoped `.grok/` surface + team bus scripts
|
|
5
|
+
* so any repo can run Ruflo Agent Teams under Grok without Claude SendMessage.
|
|
6
|
+
*
|
|
7
|
+
* Writes outside the project only with `statusLine: true` (`--grok-statusline`):
|
|
8
|
+
* the status row lives in the user's ~/.grok/config.toml, which is parsed and
|
|
9
|
+
* merged with a real TOML parser, never blindly appended to.
|
|
10
|
+
*/
|
|
11
|
+
import { grokTemplatesRoot } from './grok-templates.js';
|
|
12
|
+
export interface GrokInitOptions {
|
|
13
|
+
targetDir: string;
|
|
14
|
+
force?: boolean;
|
|
15
|
+
/** Also write docs/grok/README.md operator guide */
|
|
16
|
+
docs?: boolean;
|
|
17
|
+
/** Install the status row into the user's ~/.grok/config.toml (opt-in). */
|
|
18
|
+
statusLine?: boolean;
|
|
19
|
+
/** Report what would be written; write nothing. */
|
|
20
|
+
dryRun?: boolean;
|
|
21
|
+
/** Home directory for the user-level status row (tests). */
|
|
22
|
+
homeDir?: string;
|
|
23
|
+
}
|
|
24
|
+
export type GrokUserConfigAction = 'not-requested' | 'created' | 'merged' | 'already-set' | 'snippet' | 'would-write';
|
|
25
|
+
export interface GrokUserConfigResult {
|
|
26
|
+
action: GrokUserConfigAction;
|
|
27
|
+
/** ~/.grok/config.toml */
|
|
28
|
+
path: string;
|
|
29
|
+
/** TOML to paste when init did not write it */
|
|
30
|
+
snippet: string;
|
|
31
|
+
reason?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface GrokMcpLaunch {
|
|
34
|
+
command: string;
|
|
35
|
+
args: string[];
|
|
36
|
+
/** published: pinned to this CLI's npm version; checkout: this local build */
|
|
37
|
+
source: 'published' | 'checkout';
|
|
38
|
+
version: string;
|
|
39
|
+
}
|
|
40
|
+
export interface GrokInitResult {
|
|
41
|
+
success: boolean;
|
|
42
|
+
dryRun: boolean;
|
|
43
|
+
/** Files written (or, in a dry run, that would be written) */
|
|
44
|
+
filesCreated: string[];
|
|
45
|
+
filesSkipped: string[];
|
|
46
|
+
errors: string[];
|
|
47
|
+
mcp: GrokMcpLaunch;
|
|
48
|
+
userConfig: GrokUserConfigResult;
|
|
49
|
+
}
|
|
50
|
+
export { grokTemplatesRoot };
|
|
51
|
+
/**
|
|
52
|
+
* How the project .grok/config.toml starts the Ruflo MCP server.
|
|
53
|
+
*
|
|
54
|
+
* The team_* tools ship in the same release as `init --grok`, so the server is
|
|
55
|
+
* pinned to the version that is running this init — never `@latest`, which can
|
|
56
|
+
* be an older release without them. Running from a source checkout (not under
|
|
57
|
+
* node_modules) points at that checkout's CLI, since its version may not be
|
|
58
|
+
* published yet.
|
|
59
|
+
*/
|
|
60
|
+
export declare function rufloMcpLaunch(root?: string): GrokMcpLaunch;
|
|
61
|
+
/**
|
|
62
|
+
* Fill the template placeholders. Every inserted value is escaped as a TOML
|
|
63
|
+
* string, so a Windows path such as C:\Users\x stays valid TOML.
|
|
64
|
+
*/
|
|
65
|
+
export declare function materializeGrokConfig(template: string, launch: GrokMcpLaunch, home: string): string;
|
|
66
|
+
/** Where the opt-in status row script is installed: a stable absolute path. */
|
|
67
|
+
export declare function grokStatusScriptPath(home: string): string;
|
|
68
|
+
/** `node "<abs path>"` — no shell builtins, and never a repo-relative script. */
|
|
69
|
+
export declare function grokStatusLineCommand(home: string): string;
|
|
70
|
+
export declare function grokStatusLineSnippet(home: string): string;
|
|
71
|
+
type MergeOutcome = {
|
|
72
|
+
kind: 'write';
|
|
73
|
+
text: string;
|
|
74
|
+
} | {
|
|
75
|
+
kind: 'already-set';
|
|
76
|
+
ours: boolean;
|
|
77
|
+
} | {
|
|
78
|
+
kind: 'unsafe';
|
|
79
|
+
reason: string;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Add the status row to an existing user config without disturbing it.
|
|
83
|
+
*
|
|
84
|
+
* Any existing `ui.status_line` — header, `[ ui.status_line ]`,
|
|
85
|
+
* `[ui."status_line"]`, dotted keys, or an inline table — is detected by
|
|
86
|
+
* parsing, and left alone. Otherwise the block is appended and the result is
|
|
87
|
+
* re-parsed: it is written only if it parses, carries exactly our status row,
|
|
88
|
+
* and every other value is unchanged. Anything else (unparseable file, `ui`
|
|
89
|
+
* as an inline table, …) falls back to printing the snippet.
|
|
90
|
+
*/
|
|
91
|
+
export declare function mergeGrokStatusLine(existing: string, home: string): MergeOutcome;
|
|
92
|
+
/**
|
|
93
|
+
* Initialize Grok host surface in targetDir.
|
|
94
|
+
*/
|
|
95
|
+
export declare function executeGrokInit(options: GrokInitOptions): GrokInitResult;
|
|
96
|
+
//# sourceMappingURL=grok-generator.d.ts.map
|