@moda-ai/cli 1.22.0 → 1.22.2
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/dist/cli-g8qs2tj9.js +9777 -0
- package/dist/cli-pwbvtes8.js +2312 -0
- package/dist/cli-qszcpda3.js +284 -0
- package/dist/cli.js +4775 -1159
- package/dist/index-6h0nc1r5.js +2765 -0
- package/dist/provision-j5gq8cvx.js +72 -0
- package/package.json +3 -2
- package/skills/integration/index.json +2 -2
- package/dist/agent-schemas.d.ts +0 -3
- package/dist/agent-schemas.js +0 -358
- package/dist/agent.d.ts +0 -5
- package/dist/agent.js +0 -477
- package/dist/analyst-tui.d.ts +0 -81
- package/dist/analyst-tui.js +0 -314
- package/dist/api-client.d.ts +0 -46
- package/dist/api-client.js +0 -120
- package/dist/ask-stream.d.ts +0 -146
- package/dist/ask-stream.js +0 -473
- package/dist/auth-storage.d.ts +0 -35
- package/dist/auth-storage.js +0 -159
- package/dist/auth.d.ts +0 -50
- package/dist/auth.js +0 -694
- package/dist/cli-session.d.ts +0 -26
- package/dist/cli-session.js +0 -169
- package/dist/cli.d.ts +0 -44
- package/dist/command-context.d.ts +0 -62
- package/dist/command-context.js +0 -57
- package/dist/command-registry.d.ts +0 -22
- package/dist/command-registry.js +0 -15
- package/dist/config.d.ts +0 -60
- package/dist/config.js +0 -110
- package/dist/doctor.d.ts +0 -79
- package/dist/doctor.js +0 -1182
- package/dist/errors.d.ts +0 -50
- package/dist/errors.js +0 -64
- package/dist/exit-funnel.d.ts +0 -14
- package/dist/exit-funnel.js +0 -53
- package/dist/harness-artifact-bodies.d.ts +0 -28
- package/dist/harness-artifact-bodies.js +0 -276
- package/dist/harness-candidates.d.ts +0 -77
- package/dist/harness-candidates.js +0 -482
- package/dist/harness-remote.d.ts +0 -135
- package/dist/harness-remote.js +0 -540
- package/dist/harness-report.d.ts +0 -145
- package/dist/harness-report.js +0 -1579
- package/dist/harness-sync-limits.d.ts +0 -8
- package/dist/harness-sync-limits.js +0 -21
- package/dist/harness.d.ts +0 -463
- package/dist/harness.js +0 -4009
- package/dist/init/index.d.ts +0 -78
- package/dist/init/index.js +0 -1442
- package/dist/init/mcp.d.ts +0 -2
- package/dist/init/mcp.js +0 -27
- package/dist/init/progress-board.d.ts +0 -80
- package/dist/init/progress-board.js +0 -225
- package/dist/init/rules.d.ts +0 -6
- package/dist/init/rules.js +0 -171
- package/dist/init/sdk-catalog.d.ts +0 -10
- package/dist/init/sdk-catalog.js +0 -80
- package/dist/init/sdk-guide.d.ts +0 -19
- package/dist/init/sdk-guide.js +0 -185
- package/dist/init/sdk-integration.d.ts +0 -53
- package/dist/init/sdk-integration.js +0 -835
- package/dist/init/sdk-protocol.d.ts +0 -135
- package/dist/init/sdk-protocol.js +0 -152
- package/dist/init/sdk-verification.d.ts +0 -27
- package/dist/init/sdk-verification.js +0 -123
- package/dist/init/tenant.d.ts +0 -67
- package/dist/init/tenant.js +0 -421
- package/dist/intelligence-schema.d.ts +0 -349
- package/dist/intelligence-schema.js +0 -174
- package/dist/keys.d.ts +0 -47
- package/dist/keys.js +0 -136
- package/dist/manifest.d.ts +0 -5
- package/dist/manifest.js +0 -114
- package/dist/markdown-terminal.d.ts +0 -49
- package/dist/markdown-terminal.js +0 -212
- package/dist/output.d.ts +0 -191
- package/dist/output.js +0 -624
- package/dist/production-intelligence.d.ts +0 -175
- package/dist/production-intelligence.js +0 -1430
- package/dist/profile-commands.d.ts +0 -10
- package/dist/profile-commands.js +0 -342
- package/dist/profiles.d.ts +0 -112
- package/dist/profiles.js +0 -573
- package/dist/prompts-ab.d.ts +0 -71
- package/dist/prompts-ab.js +0 -313
- package/dist/prompts-propose.d.ts +0 -15
- package/dist/prompts-propose.js +0 -212
- package/dist/prompts.d.ts +0 -58
- package/dist/prompts.js +0 -418
- package/dist/provision.d.ts +0 -28
- package/dist/provision.js +0 -104
- package/dist/redact.d.ts +0 -2
- package/dist/redact.js +0 -90
- package/dist/schemas.d.ts +0 -225
- package/dist/schemas.js +0 -126
- package/dist/skills-bundled.d.ts +0 -35
- package/dist/skills-bundled.js +0 -157
- package/dist/skills-manifest.d.ts +0 -33
- package/dist/skills-manifest.js +0 -244
- package/dist/skills.d.ts +0 -57
- package/dist/skills.js +0 -777
- package/dist/sync.d.ts +0 -5
- package/dist/sync.js +0 -36
- package/dist/telemetry.d.ts +0 -56
- package/dist/telemetry.js +0 -167
- package/dist/transforms.d.ts +0 -25
- package/dist/transforms.js +0 -102
- package/dist/tui.d.ts +0 -48
- package/dist/tui.js +0 -393
- package/dist/update-check.d.ts +0 -31
- package/dist/update-check.js +0 -141
- package/dist/workspace.d.ts +0 -12
- package/dist/workspace.js +0 -1294
package/dist/init/mcp.d.ts
DELETED
package/dist/init/mcp.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// src/init/mcp.ts — Coding agent detection
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { execSync } from 'node:child_process';
|
|
5
|
-
function isOnPath(cmd) {
|
|
6
|
-
try {
|
|
7
|
-
execSync(`which ${cmd}`, { stdio: 'pipe' });
|
|
8
|
-
return true;
|
|
9
|
-
}
|
|
10
|
-
catch {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
export function detectAgents() {
|
|
15
|
-
const cwd = process.cwd();
|
|
16
|
-
const agents = [];
|
|
17
|
-
// Claude Code
|
|
18
|
-
if (existsSync(join(cwd, '.claude')) || isOnPath('claude')) {
|
|
19
|
-
agents.push('Claude Code');
|
|
20
|
-
}
|
|
21
|
-
// Cursor
|
|
22
|
-
if (existsSync(join(cwd, '.cursor'))) {
|
|
23
|
-
agents.push('Cursor');
|
|
24
|
-
}
|
|
25
|
-
return agents;
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=mcp.js.map
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
export type ProgressLaneStatus = 'running' | 'done' | 'warning' | 'failed';
|
|
2
|
-
export interface ProgressLane {
|
|
3
|
-
id: string;
|
|
4
|
-
title: string;
|
|
5
|
-
status: ProgressLaneStatus;
|
|
6
|
-
/** Latest one-line detail while running; frozen summary note when terminal. */
|
|
7
|
-
detail?: string;
|
|
8
|
-
/** Duration expectation appended to long-running lanes, e.g. "usually 2-4 min". */
|
|
9
|
-
expectation?: string;
|
|
10
|
-
startedAt: number;
|
|
11
|
-
finishedAt?: number;
|
|
12
|
-
}
|
|
13
|
-
export interface ProgressBoardFrameOptions {
|
|
14
|
-
now?: number;
|
|
15
|
-
spinnerFrame?: string;
|
|
16
|
-
color?: boolean;
|
|
17
|
-
/** Max visible line width; longer lines are truncated so in-place rewrites never wrap. */
|
|
18
|
-
width?: number;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Pure frame renderer (unit-testable without a TTY): one line per lane, in
|
|
22
|
-
* insertion order. Running lanes show spinner, title, elapsed, latest detail,
|
|
23
|
-
* and the "(usually X min)" expectation; terminal lanes freeze to a glyph,
|
|
24
|
-
* title, and their summary note.
|
|
25
|
-
*/
|
|
26
|
-
export declare function renderProgressBoardFrame(lanes: readonly ProgressLane[], options?: ProgressBoardFrameOptions): string[];
|
|
27
|
-
export interface InitProgressBoardOptions {
|
|
28
|
-
stream?: NodeJS.WriteStream;
|
|
29
|
-
/** Overrides TTY detection (in-place rendering); defaults to stream.isTTY with TERM=dumb treated as non-TTY. */
|
|
30
|
-
isTTY?: boolean;
|
|
31
|
-
color?: boolean;
|
|
32
|
-
now?: () => number;
|
|
33
|
-
renderIntervalMs?: number;
|
|
34
|
-
fallbackIntervalMs?: number;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Stateful board driver. TTY mode repaints on a ~150ms interval (unref'd so it
|
|
38
|
-
* never holds the process open); non-TTY mode prints plain lines on lane
|
|
39
|
-
* start/terminal transitions and throttles intermediate updates to one line
|
|
40
|
-
* per lane per 10s.
|
|
41
|
-
*/
|
|
42
|
-
export declare class InitProgressBoard {
|
|
43
|
-
private readonly stream;
|
|
44
|
-
private readonly tty;
|
|
45
|
-
private readonly color;
|
|
46
|
-
private readonly now;
|
|
47
|
-
private readonly renderIntervalMs;
|
|
48
|
-
private readonly fallbackIntervalMs;
|
|
49
|
-
private readonly laneList;
|
|
50
|
-
private readonly lanesById;
|
|
51
|
-
private readonly lastFallbackPrint;
|
|
52
|
-
private timer;
|
|
53
|
-
private renderedLines;
|
|
54
|
-
private spinnerIndex;
|
|
55
|
-
private stopped;
|
|
56
|
-
constructor(options?: InitProgressBoardOptions);
|
|
57
|
-
get lanes(): readonly ProgressLane[];
|
|
58
|
-
startLane(id: string, title: string, options?: {
|
|
59
|
-
detail?: string;
|
|
60
|
-
expectation?: string;
|
|
61
|
-
}): void;
|
|
62
|
-
update(id: string, detail: string): void;
|
|
63
|
-
complete(id: string, note?: string): void;
|
|
64
|
-
warn(id: string, note?: string): void;
|
|
65
|
-
fail(id: string, note?: string): void;
|
|
66
|
-
/** Freeze the final frame (TTY) and release the repaint timer. Idempotent. */
|
|
67
|
-
stop(): void;
|
|
68
|
-
/**
|
|
69
|
-
* Terminal transitions are refinable: finishing an already-terminal lane
|
|
70
|
-
* updates its glyph/note (keeping the first finish time for elapsed), so a
|
|
71
|
-
* lane frozen early (e.g. "analysis finished on Moda; finalizing after
|
|
72
|
-
* setup") can be corrected once the final outcome is known. Exact duplicate
|
|
73
|
-
* finishes stay no-ops; `update()` still applies to running lanes only.
|
|
74
|
-
*/
|
|
75
|
-
private finish;
|
|
76
|
-
private ensureTimer;
|
|
77
|
-
private render;
|
|
78
|
-
private writeLine;
|
|
79
|
-
}
|
|
80
|
-
//# sourceMappingURL=progress-board.d.ts.map
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
// src/init/progress-board.ts. Multi-lane live progress board for moda init
|
|
2
|
-
// Step 4 (Set up), where several activities run at once (hosted harness
|
|
3
|
-
// analysis, fast local tasks, the SDK integration agent).
|
|
4
|
-
//
|
|
5
|
-
// Hand-rolled, no dependencies, stderr only. On a TTY the lane block is
|
|
6
|
-
// rewritten in place with cursor-up ANSI, throttled to ~150ms; completed lanes
|
|
7
|
-
// freeze to a check line so the board never grows unbounded. Non-TTY human
|
|
8
|
-
// mode falls back to plain progress lines at most every 10s per lane.
|
|
9
|
-
// Agent/json modes never construct a board (init emits NDJSON progress events
|
|
10
|
-
// instead). Color gating follows tui.ts conventions (NO_COLOR / TERM=dumb
|
|
11
|
-
// respected); spinner and duration helpers follow analyst-tui.ts.
|
|
12
|
-
import { stripAnsi } from '../markdown-terminal.js';
|
|
13
|
-
const SPINNER_FRAMES = ['◐', '◓', '◑', '◒'];
|
|
14
|
-
const GLYPHS = {
|
|
15
|
-
done: '✓',
|
|
16
|
-
warning: '!',
|
|
17
|
-
failed: '✗',
|
|
18
|
-
};
|
|
19
|
-
const GLYPH_COLORS = {
|
|
20
|
-
done: 32,
|
|
21
|
-
warning: 33,
|
|
22
|
-
failed: 31,
|
|
23
|
-
};
|
|
24
|
-
/** Same one-line cap as ask-stream's tool cards. */
|
|
25
|
-
const DETAIL_MAX = 100;
|
|
26
|
-
const RENDER_INTERVAL_MS = 150;
|
|
27
|
-
const NON_TTY_LANE_INTERVAL_MS = 10_000;
|
|
28
|
-
/**
|
|
29
|
-
* Pure frame renderer (unit-testable without a TTY): one line per lane, in
|
|
30
|
-
* insertion order. Running lanes show spinner, title, elapsed, latest detail,
|
|
31
|
-
* and the "(usually X min)" expectation; terminal lanes freeze to a glyph,
|
|
32
|
-
* title, and their summary note.
|
|
33
|
-
*/
|
|
34
|
-
export function renderProgressBoardFrame(lanes, options = {}) {
|
|
35
|
-
const now = options.now ?? Date.now();
|
|
36
|
-
const color = options.color ?? false;
|
|
37
|
-
const width = Math.max(48, Math.min(options.width ?? 120, 200));
|
|
38
|
-
const paint = (code, text) => color ? `\u001b[${code}m${text}\u001b[0m` : text;
|
|
39
|
-
const titleWidth = Math.min(32, lanes.reduce((max, lane) => Math.max(max, lane.title.length), 0));
|
|
40
|
-
return lanes.map((lane) => {
|
|
41
|
-
const title = lane.title.padEnd(titleWidth);
|
|
42
|
-
if (lane.status === 'running') {
|
|
43
|
-
const elapsed = formatDuration(Math.max(0, Math.round((now - lane.startedAt) / 1000)));
|
|
44
|
-
const detail = lane.detail ? ` ${oneLine(lane.detail)}` : '';
|
|
45
|
-
const expectation = lane.expectation ? ` ${paint(90, `(${lane.expectation})`)}` : '';
|
|
46
|
-
const glyph = paint(36, options.spinnerFrame ?? SPINNER_FRAMES[0]);
|
|
47
|
-
return truncateVisible(` ${glyph} ${title} ${paint(90, elapsed.padStart(6))}${detail}${expectation}`, width);
|
|
48
|
-
}
|
|
49
|
-
const glyph = paint(GLYPH_COLORS[lane.status], GLYPHS[lane.status]);
|
|
50
|
-
const note = lane.detail
|
|
51
|
-
? oneLine(lane.detail)
|
|
52
|
-
: formatDuration(Math.max(0, Math.round(((lane.finishedAt ?? now) - lane.startedAt) / 1000)));
|
|
53
|
-
return truncateVisible(` ${glyph} ${title} ${note}`, width);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Stateful board driver. TTY mode repaints on a ~150ms interval (unref'd so it
|
|
58
|
-
* never holds the process open); non-TTY mode prints plain lines on lane
|
|
59
|
-
* start/terminal transitions and throttles intermediate updates to one line
|
|
60
|
-
* per lane per 10s.
|
|
61
|
-
*/
|
|
62
|
-
export class InitProgressBoard {
|
|
63
|
-
stream;
|
|
64
|
-
tty;
|
|
65
|
-
color;
|
|
66
|
-
now;
|
|
67
|
-
renderIntervalMs;
|
|
68
|
-
fallbackIntervalMs;
|
|
69
|
-
laneList = [];
|
|
70
|
-
lanesById = new Map();
|
|
71
|
-
lastFallbackPrint = new Map();
|
|
72
|
-
timer;
|
|
73
|
-
renderedLines = 0;
|
|
74
|
-
spinnerIndex = 0;
|
|
75
|
-
stopped = false;
|
|
76
|
-
constructor(options = {}) {
|
|
77
|
-
this.stream = options.stream ?? process.stderr;
|
|
78
|
-
const dumbTerm = process.env.TERM === 'dumb';
|
|
79
|
-
this.tty = options.isTTY ?? (this.stream.isTTY === true && !dumbTerm);
|
|
80
|
-
// NO_COLOR disables color when set to any value, per no-color.org.
|
|
81
|
-
this.color = options.color ?? (this.tty && process.env.NO_COLOR === undefined);
|
|
82
|
-
this.now = options.now ?? Date.now;
|
|
83
|
-
this.renderIntervalMs = options.renderIntervalMs ?? RENDER_INTERVAL_MS;
|
|
84
|
-
this.fallbackIntervalMs = options.fallbackIntervalMs ?? NON_TTY_LANE_INTERVAL_MS;
|
|
85
|
-
}
|
|
86
|
-
get lanes() {
|
|
87
|
-
return this.laneList;
|
|
88
|
-
}
|
|
89
|
-
startLane(id, title, options = {}) {
|
|
90
|
-
if (this.stopped || this.lanesById.has(id))
|
|
91
|
-
return;
|
|
92
|
-
const lane = {
|
|
93
|
-
id,
|
|
94
|
-
title,
|
|
95
|
-
status: 'running',
|
|
96
|
-
detail: options.detail,
|
|
97
|
-
expectation: options.expectation,
|
|
98
|
-
startedAt: this.now(),
|
|
99
|
-
};
|
|
100
|
-
this.laneList.push(lane);
|
|
101
|
-
this.lanesById.set(id, lane);
|
|
102
|
-
if (this.tty) {
|
|
103
|
-
this.ensureTimer();
|
|
104
|
-
this.render();
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
this.lastFallbackPrint.set(id, this.now());
|
|
108
|
-
this.writeLine(` ${title}: ${lane.detail ? oneLine(lane.detail) : 'started'}${lane.expectation ? ` (${lane.expectation})` : ''}`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
update(id, detail) {
|
|
112
|
-
const lane = this.lanesById.get(id);
|
|
113
|
-
if (!lane || this.stopped || lane.status !== 'running')
|
|
114
|
-
return;
|
|
115
|
-
lane.detail = detail;
|
|
116
|
-
if (this.tty)
|
|
117
|
-
return; // interval repaints
|
|
118
|
-
const last = this.lastFallbackPrint.get(id) ?? 0;
|
|
119
|
-
if (this.now() - last < this.fallbackIntervalMs)
|
|
120
|
-
return;
|
|
121
|
-
this.lastFallbackPrint.set(id, this.now());
|
|
122
|
-
const elapsed = formatDuration(Math.max(0, Math.round((this.now() - lane.startedAt) / 1000)));
|
|
123
|
-
this.writeLine(` ${lane.title}: ${oneLine(detail)} (${elapsed} elapsed)`);
|
|
124
|
-
}
|
|
125
|
-
complete(id, note) {
|
|
126
|
-
this.finish(id, 'done', note);
|
|
127
|
-
}
|
|
128
|
-
warn(id, note) {
|
|
129
|
-
this.finish(id, 'warning', note);
|
|
130
|
-
}
|
|
131
|
-
fail(id, note) {
|
|
132
|
-
this.finish(id, 'failed', note);
|
|
133
|
-
}
|
|
134
|
-
/** Freeze the final frame (TTY) and release the repaint timer. Idempotent. */
|
|
135
|
-
stop() {
|
|
136
|
-
if (this.stopped)
|
|
137
|
-
return;
|
|
138
|
-
this.stopped = true;
|
|
139
|
-
if (this.timer) {
|
|
140
|
-
clearInterval(this.timer);
|
|
141
|
-
this.timer = undefined;
|
|
142
|
-
}
|
|
143
|
-
if (this.tty && this.laneList.length > 0)
|
|
144
|
-
this.render();
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Terminal transitions are refinable: finishing an already-terminal lane
|
|
148
|
-
* updates its glyph/note (keeping the first finish time for elapsed), so a
|
|
149
|
-
* lane frozen early (e.g. "analysis finished on Moda; finalizing after
|
|
150
|
-
* setup") can be corrected once the final outcome is known. Exact duplicate
|
|
151
|
-
* finishes stay no-ops; `update()` still applies to running lanes only.
|
|
152
|
-
*/
|
|
153
|
-
finish(id, status, note) {
|
|
154
|
-
const lane = this.lanesById.get(id);
|
|
155
|
-
if (!lane || this.stopped)
|
|
156
|
-
return;
|
|
157
|
-
if (lane.status !== 'running' && lane.status === status && lane.detail === note)
|
|
158
|
-
return;
|
|
159
|
-
lane.status = status;
|
|
160
|
-
lane.detail = note;
|
|
161
|
-
lane.finishedAt ??= this.now();
|
|
162
|
-
if (this.tty) {
|
|
163
|
-
this.render();
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
const label = status === 'done' ? 'done' : status === 'warning' ? 'warning' : 'failed';
|
|
167
|
-
this.writeLine(` ${lane.title}: ${label}${note ? ` (${oneLine(note)})` : ''}`);
|
|
168
|
-
}
|
|
169
|
-
ensureTimer() {
|
|
170
|
-
if (this.timer || !this.tty)
|
|
171
|
-
return;
|
|
172
|
-
this.timer = setInterval(() => this.render(), this.renderIntervalMs);
|
|
173
|
-
// Never keep the process alive just to animate a spinner.
|
|
174
|
-
this.timer.unref?.();
|
|
175
|
-
}
|
|
176
|
-
render() {
|
|
177
|
-
if (!this.tty || this.laneList.length === 0)
|
|
178
|
-
return;
|
|
179
|
-
const lines = renderProgressBoardFrame(this.laneList, {
|
|
180
|
-
now: this.now(),
|
|
181
|
-
spinnerFrame: SPINNER_FRAMES[this.spinnerIndex++ % SPINNER_FRAMES.length],
|
|
182
|
-
color: this.color,
|
|
183
|
-
width: this.stream.columns ?? 120,
|
|
184
|
-
});
|
|
185
|
-
const up = this.renderedLines > 0 ? `\u001b[${this.renderedLines}A` : '';
|
|
186
|
-
this.stream.write(`${up}${lines.map((line) => `\u001b[2K${line}`).join('\n')}\n`);
|
|
187
|
-
this.renderedLines = lines.length;
|
|
188
|
-
}
|
|
189
|
-
writeLine(line) {
|
|
190
|
-
this.stream.write(`${line}\n`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* One-line convention shared with ask-stream tool cards: strip escapes,
|
|
195
|
-
* collapse whitespace, cap ~100 chars. Lane details carry backend/agent
|
|
196
|
-
* controlled text (hosted progress messages, tool inputs like file paths and
|
|
197
|
-
* shell commands), so ANSI/OSC escapes and remaining C0 controls must be
|
|
198
|
-
* removed before the text reaches the terminal; an embedded escape would
|
|
199
|
-
* otherwise corrupt the in-place cursor-up rewrite or inject control output.
|
|
200
|
-
*/
|
|
201
|
-
function oneLine(text) {
|
|
202
|
-
const collapsed = stripAnsi(text)
|
|
203
|
-
.replace(/[\u0000-\u001f\u007f]+/g, ' ')
|
|
204
|
-
.replace(/\s+/g, ' ')
|
|
205
|
-
.trim();
|
|
206
|
-
return collapsed.length > DETAIL_MAX ? `${collapsed.slice(0, DETAIL_MAX - 1)}…` : collapsed;
|
|
207
|
-
}
|
|
208
|
-
/** Same shape as analyst-tui.ts formatDuration. */
|
|
209
|
-
function formatDuration(seconds) {
|
|
210
|
-
if (seconds < 60)
|
|
211
|
-
return `${seconds}s`;
|
|
212
|
-
const minutes = Math.floor(seconds / 60);
|
|
213
|
-
const remaining = seconds % 60;
|
|
214
|
-
return `${minutes}m ${remaining}s`;
|
|
215
|
-
}
|
|
216
|
-
function truncateVisible(value, width) {
|
|
217
|
-
if (visibleLength(value) <= width)
|
|
218
|
-
return value;
|
|
219
|
-
const stripped = stripAnsi(value);
|
|
220
|
-
return `${stripped.slice(0, Math.max(0, width - 3))}...`;
|
|
221
|
-
}
|
|
222
|
-
function visibleLength(value) {
|
|
223
|
-
return stripAnsi(value).length;
|
|
224
|
-
}
|
|
225
|
-
//# sourceMappingURL=progress-board.js.map
|
package/dist/init/rules.d.ts
DELETED
package/dist/init/rules.js
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
// src/init/rules.ts — Install Moda agent skills into the user's project.
|
|
2
|
-
//
|
|
3
|
-
// Each entry in SKILLS is a directory under <package>/skills/ that contains a
|
|
4
|
-
// SKILL.md (Claude Code format). At install time we copy each skill into every
|
|
5
|
-
// detected coding agent, translating frontmatter where the agent expects a
|
|
6
|
-
// different shape (e.g. Cursor's .mdc rules).
|
|
7
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
8
|
-
import { dirname, join } from 'node:path';
|
|
9
|
-
import { fileURLToPath } from 'node:url';
|
|
10
|
-
import { confirm } from '@inquirer/prompts';
|
|
11
|
-
// --- Package path resolution ---
|
|
12
|
-
//
|
|
13
|
-
// Resolved relative to this module's URL so it works whether we're running
|
|
14
|
-
// from src/ in dev or from the published dist/ inside node_modules.
|
|
15
|
-
const PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
16
|
-
const SKILLS_SOURCE_DIR = join(PACKAGE_ROOT, 'skills');
|
|
17
|
-
const SKILLS = [
|
|
18
|
-
{
|
|
19
|
-
id: 'moda-cli',
|
|
20
|
-
label: 'moda-cli — let coding agents query Moda analytics via the CLI',
|
|
21
|
-
},
|
|
22
|
-
];
|
|
23
|
-
const ADAPTERS = {
|
|
24
|
-
'Claude Code': {
|
|
25
|
-
name: 'Claude Code',
|
|
26
|
-
targetFor: (skillId) => ({
|
|
27
|
-
dir: join('.claude', 'skills', skillId),
|
|
28
|
-
filename: 'SKILL.md',
|
|
29
|
-
}),
|
|
30
|
-
transform: (content) => content,
|
|
31
|
-
},
|
|
32
|
-
'Cursor': {
|
|
33
|
-
name: 'Cursor',
|
|
34
|
-
targetFor: (skillId) => ({
|
|
35
|
-
dir: join('.cursor', 'rules'),
|
|
36
|
-
filename: `${skillId}.mdc`,
|
|
37
|
-
}),
|
|
38
|
-
transform: claudeSkillToCursorRule,
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
// --- Frontmatter translation ---
|
|
42
|
-
//
|
|
43
|
-
// Cursor's .mdc rules use a different frontmatter shape:
|
|
44
|
-
// ---
|
|
45
|
-
// description: "..."
|
|
46
|
-
// alwaysApply: false
|
|
47
|
-
// ---
|
|
48
|
-
// The body markdown is identical, so we strip the Claude frontmatter, lift
|
|
49
|
-
// the description out of it, and emit Cursor's variant.
|
|
50
|
-
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
|
|
51
|
-
const DESCRIPTION_RE = /^description:\s*(.+?)\s*$/m;
|
|
52
|
-
export function claudeSkillToCursorRule(skillContent) {
|
|
53
|
-
const match = FRONTMATTER_RE.exec(skillContent);
|
|
54
|
-
if (!match) {
|
|
55
|
-
// Body without frontmatter — pass through untouched rather than guess.
|
|
56
|
-
return skillContent;
|
|
57
|
-
}
|
|
58
|
-
const [, frontmatter, body] = match;
|
|
59
|
-
const descMatch = DESCRIPTION_RE.exec(frontmatter);
|
|
60
|
-
const description = descMatch?.[1].trim() ?? '';
|
|
61
|
-
// JSON.stringify gives us a YAML-safe double-quoted string with proper
|
|
62
|
-
// escaping for any quotes or backslashes inside the description.
|
|
63
|
-
const cursorFrontmatter = `---\n` +
|
|
64
|
-
`description: ${JSON.stringify(description)}\n` +
|
|
65
|
-
`alwaysApply: false\n` +
|
|
66
|
-
`---\n`;
|
|
67
|
-
return `${cursorFrontmatter}\n${body.replace(/^\s+/, '')}`;
|
|
68
|
-
}
|
|
69
|
-
// --- I/O helpers ---
|
|
70
|
-
function loadSkillSource(skillId) {
|
|
71
|
-
const path = join(SKILLS_SOURCE_DIR, skillId, 'SKILL.md');
|
|
72
|
-
if (!existsSync(path)) {
|
|
73
|
-
throw new Error(`Skill source missing: ${path}`);
|
|
74
|
-
}
|
|
75
|
-
return readFileSync(path, 'utf8');
|
|
76
|
-
}
|
|
77
|
-
function installSkillForAgent(skill, adapter, content) {
|
|
78
|
-
const { dir, filename } = adapter.targetFor(skill.id);
|
|
79
|
-
const dirPath = join(process.cwd(), dir);
|
|
80
|
-
const filePath = join(dirPath, filename);
|
|
81
|
-
const relativePath = join(dir, filename);
|
|
82
|
-
try {
|
|
83
|
-
mkdirSync(dirPath, { recursive: true });
|
|
84
|
-
if (existsSync(filePath)) {
|
|
85
|
-
return { agent: adapter.name, relativePath, status: 'exists' };
|
|
86
|
-
}
|
|
87
|
-
writeFileSync(filePath, adapter.transform(content));
|
|
88
|
-
return { agent: adapter.name, relativePath, status: 'wrote' };
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
return {
|
|
92
|
-
agent: adapter.name,
|
|
93
|
-
relativePath,
|
|
94
|
-
status: 'failed',
|
|
95
|
-
error: err instanceof Error ? err.message : String(err),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// --- Public entry point ---
|
|
100
|
-
export async function installRules(detectedAgents, options = {}) {
|
|
101
|
-
const adapters = detectedAgents
|
|
102
|
-
.map((a) => ADAPTERS[a])
|
|
103
|
-
.filter((a) => a !== undefined);
|
|
104
|
-
if (adapters.length === 0) {
|
|
105
|
-
if (!options.silent)
|
|
106
|
-
console.log(' No supported coding agents detected');
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
const agentList = adapters.map((a) => a.name).join(', ');
|
|
110
|
-
const skillList = SKILLS.map((s) => `\n • ${s.label}`).join('');
|
|
111
|
-
const shouldInstall = options.yes
|
|
112
|
-
? true
|
|
113
|
-
: await confirm({
|
|
114
|
-
message: `Install Moda skills for ${agentList}?${skillList}\n Continue?`,
|
|
115
|
-
default: true,
|
|
116
|
-
});
|
|
117
|
-
if (!shouldInstall) {
|
|
118
|
-
if (!options.silent)
|
|
119
|
-
console.log(' Skipped');
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
let wrote = 0;
|
|
123
|
-
let skipped = 0;
|
|
124
|
-
let failed = 0;
|
|
125
|
-
for (const skill of SKILLS) {
|
|
126
|
-
let content;
|
|
127
|
-
try {
|
|
128
|
-
content = loadSkillSource(skill.id);
|
|
129
|
-
}
|
|
130
|
-
catch (err) {
|
|
131
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
132
|
-
console.error(` Warning: ${message}`);
|
|
133
|
-
failed += adapters.length;
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
for (const adapter of adapters) {
|
|
137
|
-
const outcome = installSkillForAgent(skill, adapter, content);
|
|
138
|
-
switch (outcome.status) {
|
|
139
|
-
case 'wrote':
|
|
140
|
-
if (!options.silent)
|
|
141
|
-
console.log(` ${outcome.agent}: wrote ${outcome.relativePath}`);
|
|
142
|
-
wrote++;
|
|
143
|
-
break;
|
|
144
|
-
case 'exists':
|
|
145
|
-
if (!options.silent) {
|
|
146
|
-
console.log(` ${outcome.agent}: ${outcome.relativePath} already exists — skipping`);
|
|
147
|
-
}
|
|
148
|
-
skipped++;
|
|
149
|
-
break;
|
|
150
|
-
case 'failed':
|
|
151
|
-
if (!options.silent) {
|
|
152
|
-
console.error(` ${outcome.agent}: failed to write ${outcome.relativePath} — ${outcome.error}`);
|
|
153
|
-
}
|
|
154
|
-
failed++;
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
const summary = [
|
|
160
|
-
wrote && `${wrote} written`,
|
|
161
|
-
skipped && `${skipped} already present`,
|
|
162
|
-
failed && `${failed} failed`,
|
|
163
|
-
]
|
|
164
|
-
.filter(Boolean)
|
|
165
|
-
.join(', ');
|
|
166
|
-
if (summary) {
|
|
167
|
-
if (!options.silent)
|
|
168
|
-
console.log(` Done — ${summary}`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
//# sourceMappingURL=rules.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type BundledSkillIndex } from '../skills-bundled.js';
|
|
2
|
-
export interface MaterializedSdkCatalog {
|
|
3
|
-
dir: string;
|
|
4
|
-
relativeDir: string;
|
|
5
|
-
index: BundledSkillIndex;
|
|
6
|
-
}
|
|
7
|
-
export declare function materializeSdkCatalog(cwd: string, runId: string): MaterializedSdkCatalog;
|
|
8
|
-
export declare function cleanupSdkCatalog(dir: string): void;
|
|
9
|
-
export declare function renderCatalogListing(index: BundledSkillIndex): string;
|
|
10
|
-
//# sourceMappingURL=sdk-catalog.d.ts.map
|
package/dist/init/sdk-catalog.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
// src/init/sdk-catalog.ts — Ephemeral, run-scoped materialization of the
|
|
2
|
-
// complete bundled SDK integration-skill catalog for a coding agent to browse.
|
|
3
|
-
import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync, statSync, } from 'node:fs';
|
|
4
|
-
import { join, relative, resolve } from 'node:path';
|
|
5
|
-
import { bundledSkillsDir, readBundledIndex, } from '../skills-bundled.js';
|
|
6
|
-
export function materializeSdkCatalog(cwd, runId) {
|
|
7
|
-
if (!/^[a-z0-9-]+$/.test(runId)) {
|
|
8
|
-
throw new Error(`Invalid SDK catalog run id: ${JSON.stringify(runId).slice(0, 80)}`);
|
|
9
|
-
}
|
|
10
|
-
const sourceDir = bundledSkillsDir();
|
|
11
|
-
const indexPath = join(sourceDir, 'index.json');
|
|
12
|
-
if (!existsSync(sourceDir) || !existsSync(indexPath)) {
|
|
13
|
-
throw missingBundleError(sourceDir);
|
|
14
|
-
}
|
|
15
|
-
const index = readBundledIndex();
|
|
16
|
-
if (!index) {
|
|
17
|
-
throw missingBundleError(sourceDir);
|
|
18
|
-
}
|
|
19
|
-
const dir = join(cwd, '.moda', 'tmp', `sdk-catalog-${runId}`);
|
|
20
|
-
cleanupSdkCatalog(dir);
|
|
21
|
-
copyDirectoryRecursive(sourceDir, dir);
|
|
22
|
-
return {
|
|
23
|
-
dir,
|
|
24
|
-
relativeDir: relative(cwd, dir).replace(/\\/g, '/'),
|
|
25
|
-
index,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
export function cleanupSdkCatalog(dir) {
|
|
29
|
-
const normalized = resolve(dir).replace(/\\/g, '/');
|
|
30
|
-
if (!normalized.includes('.moda/tmp/sdk-catalog-'))
|
|
31
|
-
return;
|
|
32
|
-
try {
|
|
33
|
-
rmSync(dir, { recursive: true, force: true });
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
// Catalog cleanup is best-effort and must never mask the integration result.
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
export function renderCatalogListing(index) {
|
|
40
|
-
return index.skills.map((skill) => {
|
|
41
|
-
const targets = [`language: ${skill.targets.language}`];
|
|
42
|
-
if (skill.targets.frameworks.length > 0) {
|
|
43
|
-
targets.push(`frameworks: ${skill.targets.frameworks.join(',')}`);
|
|
44
|
-
}
|
|
45
|
-
if (skill.targets.providers.length > 0) {
|
|
46
|
-
targets.push(`providers: ${skill.targets.providers.join(',')}`);
|
|
47
|
-
}
|
|
48
|
-
return `- ${skill.id} — ${skill.summary} [${targets.join('; ')}]`;
|
|
49
|
-
}).join('\n');
|
|
50
|
-
}
|
|
51
|
-
function copyDirectoryRecursive(sourceDir, targetDir) {
|
|
52
|
-
mkdirSync(targetDir, { recursive: true });
|
|
53
|
-
for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
|
|
54
|
-
const source = join(sourceDir, entry.name);
|
|
55
|
-
const target = join(targetDir, entry.name);
|
|
56
|
-
if (entry.isDirectory()) {
|
|
57
|
-
copyDirectoryRecursive(source, target);
|
|
58
|
-
}
|
|
59
|
-
else if (entry.isFile()) {
|
|
60
|
-
copyFileSync(source, target);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
function missingBundleError(sourceDir) {
|
|
65
|
-
let detail = 'is absent';
|
|
66
|
-
try {
|
|
67
|
-
if (existsSync(sourceDir) && !statSync(sourceDir).isDirectory()) {
|
|
68
|
-
detail = 'is not a directory';
|
|
69
|
-
}
|
|
70
|
-
else if (existsSync(sourceDir)) {
|
|
71
|
-
detail = 'has no readable index.json';
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
detail = 'is not readable';
|
|
76
|
-
}
|
|
77
|
-
return new Error(`Bundled SDK skill catalog ${detail} at ${sourceDir}. ` +
|
|
78
|
-
'Set MODA_BUNDLED_SKILLS_DIR to a built bundle, or run the integration-skill bundle build in a dev tree.');
|
|
79
|
-
}
|
|
80
|
-
//# sourceMappingURL=sdk-catalog.js.map
|
package/dist/init/sdk-guide.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export declare const SDK_GUIDE_PATH = ".moda/SDK_INTEGRATION.md";
|
|
2
|
-
type RuntimeSummary = {
|
|
3
|
-
runtimeAgents: number;
|
|
4
|
-
agentFamilies: number;
|
|
5
|
-
frameworks: string[];
|
|
6
|
-
providers: string[];
|
|
7
|
-
runtimeAgentNames: string[];
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Write the human/agent-readable fallback guide (.moda/SDK_INTEGRATION.md).
|
|
11
|
-
* Used when automatic SDK integration did not complete successfully.
|
|
12
|
-
*/
|
|
13
|
-
export declare function writeSdkIntegrationGuide(cwd?: string): string;
|
|
14
|
-
export declare function renderSdkIntegrationGuideContent(): string;
|
|
15
|
-
/** Read optional harness discovery context from `.moda/harness.json`. */
|
|
16
|
-
export declare function readRuntimeSummary(cwd: string): RuntimeSummary;
|
|
17
|
-
export declare function renderRuntimeSummaryBlock(summary: RuntimeSummary): string;
|
|
18
|
-
export {};
|
|
19
|
-
//# sourceMappingURL=sdk-guide.d.ts.map
|