@moda-ai/cli 1.1.0 → 1.2.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/README.md +36 -0
- package/dist/agent.d.ts +5 -0
- package/dist/agent.js +477 -0
- package/dist/analyst-tui.d.ts +81 -0
- package/dist/analyst-tui.js +314 -0
- package/dist/api-client.d.ts +4 -0
- package/dist/api-client.js +20 -3
- package/dist/auth.d.ts +22 -3
- package/dist/auth.js +230 -66
- package/dist/cli.d.ts +20 -3
- package/dist/cli.js +768 -93
- package/dist/command-context.d.ts +34 -0
- package/dist/command-context.js +38 -0
- package/dist/command-registry.d.ts +22 -0
- package/dist/command-registry.js +15 -0
- package/dist/config.d.ts +41 -2
- package/dist/config.js +73 -5
- package/dist/doctor.d.ts +79 -0
- package/dist/doctor.js +1102 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +9 -0
- package/dist/harness-report.d.ts +138 -0
- package/dist/harness-report.js +1464 -0
- package/dist/harness.d.ts +233 -0
- package/dist/harness.js +3264 -0
- package/dist/init/index.d.ts +30 -1
- package/dist/init/index.js +383 -23
- package/dist/init/rules.d.ts +5 -1
- package/dist/init/rules.js +22 -16
- package/dist/init/sdk-guide.d.ts +3 -0
- package/dist/init/sdk-guide.js +397 -0
- package/dist/init/tenant.js +12 -3
- package/dist/keys.d.ts +47 -0
- package/dist/keys.js +136 -0
- package/dist/output.d.ts +118 -0
- package/dist/output.js +228 -0
- package/dist/production-intelligence.d.ts +134 -0
- package/dist/production-intelligence.js +1113 -0
- package/dist/profile-commands.d.ts +10 -0
- package/dist/profile-commands.js +252 -0
- package/dist/profiles.d.ts +90 -0
- package/dist/profiles.js +432 -0
- package/dist/prompts.d.ts +6 -0
- package/dist/prompts.js +368 -0
- package/dist/schemas.d.ts +4 -4
- package/dist/skills.d.ts +25 -0
- package/dist/skills.js +468 -0
- package/dist/sync.d.ts +5 -0
- package/dist/sync.js +27 -0
- package/dist/telemetry.d.ts +18 -0
- package/dist/telemetry.js +63 -0
- package/dist/tui.d.ts +40 -0
- package/dist/tui.js +387 -0
- package/dist/workspace.d.ts +12 -0
- package/dist/workspace.js +1294 -0
- package/hooks/moda-snapshot.sh +41 -0
- package/package.json +10 -7
- package/skills/moda-cli/SKILL.md +48 -4
- package/skills/integrate-moda/SKILL.md +0 -63
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type CliOutput, type CliOutputMode } from './output.js';
|
|
2
|
+
export interface CommandContextInput {
|
|
3
|
+
command: string;
|
|
4
|
+
positional: string | undefined;
|
|
5
|
+
positionals: string[];
|
|
6
|
+
flags: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export interface CommandContext {
|
|
9
|
+
command: string;
|
|
10
|
+
positional: string | undefined;
|
|
11
|
+
positionals: string[];
|
|
12
|
+
flags: Record<string, string>;
|
|
13
|
+
rawFlags: Record<string, string>;
|
|
14
|
+
startedAt: number;
|
|
15
|
+
cwd: string;
|
|
16
|
+
env: NodeJS.ProcessEnv;
|
|
17
|
+
outputMode: CliOutputMode;
|
|
18
|
+
output: CliOutput;
|
|
19
|
+
profile: string | undefined;
|
|
20
|
+
dryRun: boolean;
|
|
21
|
+
yes: boolean;
|
|
22
|
+
quiet: boolean;
|
|
23
|
+
verbose: boolean;
|
|
24
|
+
interactive: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function createCommandContext(input: CommandContextInput, options?: {
|
|
27
|
+
commandName?: string;
|
|
28
|
+
commandFlags?: Record<string, string>;
|
|
29
|
+
rawFlags?: Record<string, string>;
|
|
30
|
+
startedAt?: number;
|
|
31
|
+
cwd?: string;
|
|
32
|
+
env?: NodeJS.ProcessEnv;
|
|
33
|
+
}): CommandContext;
|
|
34
|
+
//# sourceMappingURL=command-context.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createCliOutput, outputModeFromFlags } from './output.js';
|
|
2
|
+
function flagEnabled(flags, key) {
|
|
3
|
+
return flags[key] === 'true';
|
|
4
|
+
}
|
|
5
|
+
export function createCommandContext(input, options = {}) {
|
|
6
|
+
const flags = options.commandFlags ?? input.flags;
|
|
7
|
+
const rawFlags = options.rawFlags ?? input.flags;
|
|
8
|
+
const outputMode = outputModeFromFlags(flags);
|
|
9
|
+
const quiet = flagEnabled(flags, 'quiet');
|
|
10
|
+
const interactive = outputMode === 'human' &&
|
|
11
|
+
!quiet &&
|
|
12
|
+
!flagEnabled(flags, 'yes') &&
|
|
13
|
+
process.stdin.isTTY === true &&
|
|
14
|
+
process.stderr.isTTY === true;
|
|
15
|
+
return {
|
|
16
|
+
command: options.commandName ?? input.command,
|
|
17
|
+
positional: input.positional,
|
|
18
|
+
positionals: input.positionals,
|
|
19
|
+
flags,
|
|
20
|
+
rawFlags,
|
|
21
|
+
startedAt: options.startedAt ?? Date.now(),
|
|
22
|
+
cwd: options.cwd ?? process.cwd(),
|
|
23
|
+
env: options.env ?? process.env,
|
|
24
|
+
outputMode,
|
|
25
|
+
output: createCliOutput({
|
|
26
|
+
command: options.commandName ?? input.command,
|
|
27
|
+
mode: outputMode,
|
|
28
|
+
quiet,
|
|
29
|
+
}),
|
|
30
|
+
profile: flags.profile,
|
|
31
|
+
dryRun: flagEnabled(flags, 'dry-run'),
|
|
32
|
+
yes: flagEnabled(flags, 'yes'),
|
|
33
|
+
quiet,
|
|
34
|
+
verbose: flagEnabled(flags, 'verbose'),
|
|
35
|
+
interactive,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=command-context.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CliOutputMode } from './output.js';
|
|
2
|
+
export type CommandAuthRequirement = 'none' | 'api-key';
|
|
3
|
+
export type CommandMutability = 'read' | 'write';
|
|
4
|
+
export interface CommandMetadata {
|
|
5
|
+
name: string;
|
|
6
|
+
aliases?: string[];
|
|
7
|
+
description: string;
|
|
8
|
+
examples: string[];
|
|
9
|
+
auth: CommandAuthRequirement;
|
|
10
|
+
outputModes: readonly CliOutputMode[];
|
|
11
|
+
mutability: CommandMutability;
|
|
12
|
+
}
|
|
13
|
+
export interface CommandDefinition<TContext, TResult> extends CommandMetadata {
|
|
14
|
+
handler: (context: TContext) => Promise<TResult>;
|
|
15
|
+
}
|
|
16
|
+
export interface CommandRegistry<TContext, TResult, TDefinition extends CommandDefinition<TContext, TResult> = CommandDefinition<TContext, TResult>> {
|
|
17
|
+
all(): TDefinition[];
|
|
18
|
+
find(name: string): TDefinition | undefined;
|
|
19
|
+
has(name: string): boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function createCommandRegistry<TContext, TResult, TDefinition extends CommandDefinition<TContext, TResult>>(definitions: TDefinition[]): CommandRegistry<TContext, TResult, TDefinition>;
|
|
22
|
+
//# sourceMappingURL=command-registry.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function createCommandRegistry(definitions) {
|
|
2
|
+
const lookup = new Map();
|
|
3
|
+
for (const definition of definitions) {
|
|
4
|
+
lookup.set(definition.name, definition);
|
|
5
|
+
for (const alias of definition.aliases ?? []) {
|
|
6
|
+
lookup.set(alias, definition);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
all: () => [...definitions],
|
|
11
|
+
find: (name) => lookup.get(name),
|
|
12
|
+
has: (name) => lookup.has(name),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=command-registry.js.map
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const
|
|
1
|
+
import { type ProfileIOOptions } from './profiles.js';
|
|
2
|
+
export declare const VERSION: string;
|
|
3
3
|
export declare const MODA_BASE_URL: string;
|
|
4
|
+
/**
|
|
5
|
+
* Persisted CLI configuration written by `moda init` to `~/.moda/config.json`
|
|
6
|
+
* (mode 0600). This lets the snapshot/session-end hook authenticate without
|
|
7
|
+
* the user having to export MODA_API_KEY into whatever shell launched Claude
|
|
8
|
+
* (e.g. via Infisical, a login shell, or a `.claude/settings.json` env block).
|
|
9
|
+
* Mirrors the existing token persistence in `auth.ts`.
|
|
10
|
+
*/
|
|
11
|
+
export interface CliConfig {
|
|
12
|
+
api_key?: string;
|
|
13
|
+
ingest_url?: string;
|
|
14
|
+
tenant_id?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function loadCliConfig(options?: ProfileIOOptions): CliConfig;
|
|
17
|
+
/**
|
|
18
|
+
* Merge-and-write the persisted config. Always chmod 0600 since it holds the
|
|
19
|
+
* API key. Best-effort: never throws on chmod failure (some filesystems).
|
|
20
|
+
*/
|
|
21
|
+
export declare function saveCliConfig(update: CliConfig): void;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the API key: prefer the environment (so CI / explicit exports win),
|
|
24
|
+
* then fall back to the persisted `~/.moda/config.json`. Read lazily so a
|
|
25
|
+
* long-lived process (or a test) sees the current value.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveApiKey(options?: ProfileIOOptions): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the ingest worker base URL used by `moda workspace snapshot`.
|
|
30
|
+
* Env override -> persisted config -> production default.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveIngestUrl(options?: ProfileIOOptions): string;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the active tenant id: env override first, then the persisted
|
|
35
|
+
* `~/.moda/config.json` written by `moda init`. Used by the local dev
|
|
36
|
+
* orchestrator hook so the user doesn't have to export MODA_TENANT_ID.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveTenantId(options?: ProfileIOOptions): string | undefined;
|
|
39
|
+
export declare const MODA_API_KEY: string | undefined;
|
|
40
|
+
export declare const MODA_INGEST_URL: string;
|
|
41
|
+
export declare function resolveModaBaseUrl(options?: ProfileIOOptions): string;
|
|
4
42
|
export declare function validateConfig(): void;
|
|
43
|
+
export declare function legacyConfigPath(): string;
|
|
5
44
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.js
CHANGED
|
@@ -1,12 +1,80 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { DEFAULT_INGEST_URL, PROD_BASE_URL, getLegacyConfigPath, loadLegacyCliConfig, resolveApiKeyFromActiveProfile, resolveBaseUrl, resolveIngestUrlFromActiveProfile, resolveTenantIdFromActiveProfile, syncLegacyConfigToProfile, writeLegacyCliConfig, } from './profiles.js';
|
|
3
|
+
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
4
|
+
export const VERSION = pkg.version;
|
|
5
|
+
// Canonical host is www.moda.dev. The apex `moda.dev` 308-redirects to it, and
|
|
6
|
+
// cross-host redirects strip the Authorization header (fetch/undici), so using
|
|
7
|
+
// the apex breaks `moda init`'s authenticated calls with a 401. Default to the
|
|
8
|
+
// canonical host directly.
|
|
9
|
+
export const MODA_BASE_URL = resolveBaseUrl();
|
|
10
|
+
export function loadCliConfig(options = {}) {
|
|
11
|
+
return loadLegacyCliConfig(options);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Merge-and-write the persisted config. Always chmod 0600 since it holds the
|
|
15
|
+
* API key. Best-effort: never throws on chmod failure (some filesystems).
|
|
16
|
+
*/
|
|
17
|
+
export function saveCliConfig(update) {
|
|
18
|
+
const merged = writeLegacyCliConfig(update);
|
|
19
|
+
try {
|
|
20
|
+
syncLegacyConfigToProfile(merged);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// The legacy config write is the compatibility contract; profile sync is a
|
|
24
|
+
// best-effort migration aid until profile commands own the flow.
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the API key: prefer the environment (so CI / explicit exports win),
|
|
29
|
+
* then fall back to the persisted `~/.moda/config.json`. Read lazily so a
|
|
30
|
+
* long-lived process (or a test) sees the current value.
|
|
31
|
+
*/
|
|
32
|
+
export function resolveApiKey(options = {}) {
|
|
33
|
+
const env = options.env ?? process.env;
|
|
34
|
+
return (env.MODA_API_KEY ||
|
|
35
|
+
resolveApiKeyFromActiveProfile(options) ||
|
|
36
|
+
loadCliConfig(options).api_key ||
|
|
37
|
+
undefined);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the ingest worker base URL used by `moda workspace snapshot`.
|
|
41
|
+
* Env override -> persisted config -> production default.
|
|
42
|
+
*/
|
|
43
|
+
export function resolveIngestUrl(options = {}) {
|
|
44
|
+
const env = options.env ?? process.env;
|
|
45
|
+
return (env.MODA_INGEST_URL ||
|
|
46
|
+
resolveIngestUrlFromActiveProfile(options) ||
|
|
47
|
+
loadCliConfig(options).ingest_url ||
|
|
48
|
+
DEFAULT_INGEST_URL);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the active tenant id: env override first, then the persisted
|
|
52
|
+
* `~/.moda/config.json` written by `moda init`. Used by the local dev
|
|
53
|
+
* orchestrator hook so the user doesn't have to export MODA_TENANT_ID.
|
|
54
|
+
*/
|
|
55
|
+
export function resolveTenantId(options = {}) {
|
|
56
|
+
const env = options.env ?? process.env;
|
|
57
|
+
return (env.MODA_TENANT_ID ||
|
|
58
|
+
resolveTenantIdFromActiveProfile(options) ||
|
|
59
|
+
loadCliConfig(options).tenant_id ||
|
|
60
|
+
undefined);
|
|
61
|
+
}
|
|
62
|
+
// Back-compat exports. Prefer resolveApiKey()/resolveIngestUrl() for the lazy
|
|
63
|
+
// file fallback; these only reflect the environment at module-load time.
|
|
3
64
|
export const MODA_API_KEY = process.env.MODA_API_KEY;
|
|
4
|
-
export const
|
|
65
|
+
export const MODA_INGEST_URL = process.env.MODA_INGEST_URL || DEFAULT_INGEST_URL;
|
|
66
|
+
export function resolveModaBaseUrl(options = {}) {
|
|
67
|
+
return resolveBaseUrl(options) || PROD_BASE_URL;
|
|
68
|
+
}
|
|
5
69
|
export function validateConfig() {
|
|
6
|
-
if (!
|
|
7
|
-
console.error('Error: MODA_API_KEY
|
|
70
|
+
if (!resolveApiKey()) {
|
|
71
|
+
console.error('Error: no Moda API key found. Set MODA_API_KEY or run "moda init".');
|
|
8
72
|
console.error('Get your API key from https://moda.dev/settings');
|
|
9
73
|
process.exit(1);
|
|
10
74
|
}
|
|
11
75
|
}
|
|
76
|
+
// Kept for callers/tests that need the legacy path during migration.
|
|
77
|
+
export function legacyConfigPath() {
|
|
78
|
+
return getLegacyConfigPath();
|
|
79
|
+
}
|
|
12
80
|
//# sourceMappingURL=config.js.map
|
package/dist/doctor.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { CommandContext } from './command-context.js';
|
|
2
|
+
export type DoctorCheckStatus = 'pass' | 'warning' | 'fail' | 'skipped';
|
|
3
|
+
export type DoctorSeverity = 'info' | 'warning' | 'critical';
|
|
4
|
+
export interface DoctorEvidence {
|
|
5
|
+
label: string;
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
export interface DoctorCheck {
|
|
9
|
+
id: string;
|
|
10
|
+
group: string;
|
|
11
|
+
title: string;
|
|
12
|
+
status: DoctorCheckStatus;
|
|
13
|
+
severity: DoctorSeverity;
|
|
14
|
+
evidence: DoctorEvidence[];
|
|
15
|
+
remediation?: string;
|
|
16
|
+
nextCommand?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface DoctorReport {
|
|
19
|
+
schemaVersion: 'doctor.v0.1';
|
|
20
|
+
generatedAt: string;
|
|
21
|
+
profile: {
|
|
22
|
+
active: string;
|
|
23
|
+
requested?: string;
|
|
24
|
+
};
|
|
25
|
+
summary: {
|
|
26
|
+
status: DoctorCheckStatus;
|
|
27
|
+
pass: number;
|
|
28
|
+
warning: number;
|
|
29
|
+
fail: number;
|
|
30
|
+
skipped: number;
|
|
31
|
+
};
|
|
32
|
+
checks: DoctorCheck[];
|
|
33
|
+
nextCommands: string[];
|
|
34
|
+
fixPlan: Array<{
|
|
35
|
+
checkId: string;
|
|
36
|
+
command?: string;
|
|
37
|
+
action: string;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
export interface StatusPayload {
|
|
41
|
+
schemaVersion: 'status.v0.1';
|
|
42
|
+
generatedAt: string;
|
|
43
|
+
status: DoctorCheckStatus;
|
|
44
|
+
activeProfile: string;
|
|
45
|
+
auth: {
|
|
46
|
+
apiKey: 'configured' | 'missing';
|
|
47
|
+
};
|
|
48
|
+
workspace: {
|
|
49
|
+
tenantId: string | null;
|
|
50
|
+
baseUrl: string;
|
|
51
|
+
ingestUrl: string;
|
|
52
|
+
};
|
|
53
|
+
dataFlow: DoctorCheckStatus;
|
|
54
|
+
harness: DoctorCheckStatus;
|
|
55
|
+
harnessSync: DoctorCheckStatus;
|
|
56
|
+
harnessReport: DoctorCheckStatus;
|
|
57
|
+
shadowSpark: DoctorCheckStatus;
|
|
58
|
+
prompts: DoctorCheckStatus;
|
|
59
|
+
skills: DoctorCheckStatus;
|
|
60
|
+
topBrokenCheck: {
|
|
61
|
+
id: string;
|
|
62
|
+
status: DoctorCheckStatus;
|
|
63
|
+
severity: DoctorSeverity;
|
|
64
|
+
nextCommand?: string;
|
|
65
|
+
} | null;
|
|
66
|
+
nextCommands: string[];
|
|
67
|
+
}
|
|
68
|
+
interface DoctorOptions {
|
|
69
|
+
offline: boolean;
|
|
70
|
+
}
|
|
71
|
+
export declare function runDoctorCommand(context: CommandContext): Promise<{
|
|
72
|
+
exitCode: number;
|
|
73
|
+
}>;
|
|
74
|
+
export declare function runStatusCommand(context: CommandContext): Promise<{
|
|
75
|
+
exitCode: number;
|
|
76
|
+
}>;
|
|
77
|
+
export declare function buildDoctorReport(context: CommandContext, options: DoctorOptions): Promise<DoctorReport>;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=doctor.d.ts.map
|