@moda-ai/cli 1.13.3 → 1.13.5
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.js +5 -3
- package/dist/harness-remote.js +12 -1
- package/dist/init/index.d.ts +6 -0
- package/dist/init/index.js +66 -16
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -238,9 +238,11 @@ Init flags:
|
|
|
238
238
|
--yes Accept all defaults (non-interactive)
|
|
239
239
|
--analyst=auto|claude|codex|cursor|local-scan
|
|
240
240
|
Choose harness analyst adapter
|
|
241
|
-
--remote Run harness analysis server-side (Moda-hosted
|
|
242
|
-
upload a safe source snapshot; no
|
|
243
|
-
|
|
241
|
+
--remote Run harness analysis server-side (Moda-hosted,
|
|
242
|
+
the default): upload a safe source snapshot; no
|
|
243
|
+
local coding agent required
|
|
244
|
+
--local Run harness analysis with a LOCAL coding agent
|
|
245
|
+
instead of server-side (opt out of remote)
|
|
244
246
|
--tui Show full-screen analyst dashboard in human TTYs
|
|
245
247
|
--no-tui Show raw external analyst output
|
|
246
248
|
--sdk-integrate Run your coding agent to install the Moda SDK and instrument LLM calls
|
package/dist/harness-remote.js
CHANGED
|
@@ -27,7 +27,18 @@ export function isRemoteHarnessAnalyze(context) {
|
|
|
27
27
|
// The CLI normalizes numeric flag values to numbers, so `--remote=1` arrives
|
|
28
28
|
// as the number 1 rather than the string '1'; accept every truthy spelling.
|
|
29
29
|
const flag = context.flags.remote;
|
|
30
|
-
|
|
30
|
+
// An explicit local opt-out (`--local` / `--no-remote` / `--remote=false|0`)
|
|
31
|
+
// wins over the `MODA_HARNESS_REMOTE` env, so callers that force local — the
|
|
32
|
+
// `moda init` local path and its remote-failure fallback — stay local even
|
|
33
|
+
// when the env is set. `no-remote` may arrive kebab- or snake-cased depending
|
|
34
|
+
// on the caller (real CLI parsing snake-cases; internal callers do not).
|
|
35
|
+
const noRemote = context.flags['no-remote'] ?? context.flags.no_remote;
|
|
36
|
+
const local = context.flags.local;
|
|
37
|
+
const isTruthy = (v) => v === true || v === 1 || v === 'true' || v === '1' || v === 'yes';
|
|
38
|
+
const isFalsy = (v) => v === false || v === 0 || v === 'false' || v === '0' || v === 'no';
|
|
39
|
+
if (isFalsy(flag) || isTruthy(noRemote) || isTruthy(local))
|
|
40
|
+
return false;
|
|
41
|
+
if (isTruthy(flag))
|
|
31
42
|
return true;
|
|
32
43
|
const env = (context.env.MODA_HARNESS_REMOTE ?? '').trim().toLowerCase();
|
|
33
44
|
return env !== '' && env !== '0' && env !== 'false';
|
package/dist/init/index.d.ts
CHANGED
|
@@ -28,4 +28,10 @@ export interface InitRunOptions {
|
|
|
28
28
|
onEvent?: (event: InitProgressEvent) => void;
|
|
29
29
|
}
|
|
30
30
|
export declare function runInit(flags: Record<string, unknown>, options?: InitRunOptions): Promise<InitResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Onboarding runs harness discovery SERVER-SIDE by default so the customer
|
|
33
|
+
* needs no local coding agent. Opt out with `--local`, `--no-remote`, or
|
|
34
|
+
* `--remote=false` to use a local coding-agent analyst instead.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveHarnessRemote(flags: Record<string, unknown>): boolean;
|
|
31
37
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/init/index.js
CHANGED
|
@@ -85,7 +85,12 @@ export async function runInit(flags, options = {}) {
|
|
|
85
85
|
// --tenant-id flag wins over MODA_TENANT_ID; the source drives the
|
|
86
86
|
// env-shadow warning so we don't warn when the env var was the selection.
|
|
87
87
|
const tenantIdFlag = stringFlag(flagValue(flags, 'tenant-id', 'tenant_id'));
|
|
88
|
-
|
|
88
|
+
// Normalize the env var the same way as the flag: an empty/whitespace
|
|
89
|
+
// MODA_TENANT_ID (e.g. `export MODA_TENANT_ID=`, or a harness that blanks it
|
|
90
|
+
// to clear an inherited value) means "unset", not an explicit empty-id
|
|
91
|
+
// selection — otherwise the exact-id match below fails with
|
|
92
|
+
// "No organization with id ''" instead of auto-selecting a sole org.
|
|
93
|
+
const tenantIdEnv = stringFlag(process.env.MODA_TENANT_ID);
|
|
89
94
|
const { apiKey, tenantName } = await selectTenantAndCreateKey({
|
|
90
95
|
tenantId: tenantIdFlag ?? tenantIdEnv,
|
|
91
96
|
tenantIdSource: tenantIdFlag ? 'flag' : tenantIdEnv ? 'env' : undefined,
|
|
@@ -97,17 +102,14 @@ export async function runInit(flags, options = {}) {
|
|
|
97
102
|
log(renderInitNote(`Active workspace: ${tenantName}`));
|
|
98
103
|
emit('workspace', `Active workspace: ${tenantName}`, 'completed');
|
|
99
104
|
phases.push({ id: 'workspace', title: 'Workspace & Profile', status: 'completed', details: tenantName });
|
|
100
|
-
// Step 4: Harness analyst report.
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
? 'Running Moda-hosted harness discovery.'
|
|
109
|
-
: 'Running Moda Analyst harness discovery.');
|
|
110
|
-
const harnessResult = await runHarnessCommand(createCommandContext({
|
|
105
|
+
// Step 4: Harness analyst report. Onboarding runs the analyst SERVER-SIDE by
|
|
106
|
+
// default (Moda uploads a safe source snapshot and runs the agent on its own
|
|
107
|
+
// infra) so the customer needs no local coding agent. Opt out with `--local`
|
|
108
|
+
// (or `--remote=false`) to run a local coding-agent analyst instead. If the
|
|
109
|
+
// remote run fails (service/network), we fall back to the local analyst so
|
|
110
|
+
// onboarding never hard-fails.
|
|
111
|
+
const remote = resolveHarnessRemote(flags);
|
|
112
|
+
const runAnalyze = (useRemote) => runHarnessCommand(createCommandContext({
|
|
111
113
|
command: 'harness',
|
|
112
114
|
positional: 'analyze',
|
|
113
115
|
positionals: ['analyze'],
|
|
@@ -122,14 +124,44 @@ export async function runInit(flags, options = {}) {
|
|
|
122
124
|
json: json || agent,
|
|
123
125
|
agent,
|
|
124
126
|
analyst: stringFlag(flags.analyst) ?? 'auto',
|
|
125
|
-
remote
|
|
127
|
+
// Pass the remote/local decision EXPLICITLY. `commandFlags` drops
|
|
128
|
+
// `remote: false`, so a bare `remote: useRemote` would leave the child
|
|
129
|
+
// with no signal and it would re-derive remoteness from
|
|
130
|
+
// `MODA_HARNESS_REMOTE` — silently overriding `--local` and the
|
|
131
|
+
// remote-failure fallback below. `--no-remote` survives (it's `true`)
|
|
132
|
+
// and takes precedence over the env in `isRemoteHarnessAnalyze`.
|
|
133
|
+
remote: useRemote ? true : undefined,
|
|
134
|
+
'no-remote': useRemote ? undefined : true,
|
|
126
135
|
quiet: true,
|
|
127
136
|
progress: true,
|
|
128
137
|
'no-telemetry': true,
|
|
129
138
|
}),
|
|
130
139
|
}));
|
|
140
|
+
log(renderInitStep(4, 7, 'Harness Discovery', remote
|
|
141
|
+
? 'Moda runs the harness analyst server-side and writes cited local artifacts.'
|
|
142
|
+
: 'Moda Analyst investigates the harness and writes cited local artifacts.'));
|
|
143
|
+
emit('harness', remote
|
|
144
|
+
? 'Running Moda-hosted harness discovery.'
|
|
145
|
+
: 'Running Moda Analyst harness discovery.');
|
|
146
|
+
let harnessResult;
|
|
147
|
+
try {
|
|
148
|
+
harnessResult = await runAnalyze(remote);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
// A remote failure (service down, upload error) must not sink onboarding —
|
|
152
|
+
// fall back to the local analyst path. If the caller pinned `--remote`
|
|
153
|
+
// explicitly, respect that and surface the failure.
|
|
154
|
+
if (remote && !isTruthyFlag(flagValue(flags, 'remote'))) {
|
|
155
|
+
warn(renderInitNote(`Server-side harness discovery unavailable (${error instanceof Error ? error.message : String(error)}); falling back to local analyst.`, 'warning'));
|
|
156
|
+
emit('harness', 'Server-side discovery failed; falling back to local analyst.', 'warning');
|
|
157
|
+
harnessResult = await runAnalyze(false);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
131
163
|
if (harnessResult.exitCode !== 0) {
|
|
132
|
-
throw new CliInputError('Moda Analyst produced a harness report that did not pass validation.', 'Review .moda/harness-report-validation.json, then rerun `moda init --analyst=claude|cursor|codex` or `moda harness analyze --analyst=local-scan --summary`.');
|
|
164
|
+
throw new CliInputError('Moda Analyst produced a harness report that did not pass validation.', 'Review .moda/harness-report-validation.json, then rerun `moda init --local --analyst=claude|cursor|codex` or `moda harness analyze --analyst=local-scan --summary`.');
|
|
133
165
|
}
|
|
134
166
|
log(renderInitNote('Wrote or verified .moda/harness-report.json, .moda/harness.json, and .moda/HARNESS.md'));
|
|
135
167
|
if (human)
|
|
@@ -628,9 +660,12 @@ async function shouldIntegrateSdk(flags, yes) {
|
|
|
628
660
|
function parseOptionalBoolean(value) {
|
|
629
661
|
if (value === undefined)
|
|
630
662
|
return undefined;
|
|
631
|
-
|
|
663
|
+
// The CLI parser normalizes numeric-looking flag values to numbers, so
|
|
664
|
+
// `--remote=1` arrives as number 1 and `--remote=0` as number 0 (not the
|
|
665
|
+
// string spellings); accept both alongside the string/boolean forms.
|
|
666
|
+
if (value === true || value === 1 || value === 'true' || value === '1' || value === 'yes')
|
|
632
667
|
return true;
|
|
633
|
-
if (value === false || value === 'false' || value === '0' || value === 'no')
|
|
668
|
+
if (value === false || value === 0 || value === 'false' || value === '0' || value === 'no')
|
|
634
669
|
return false;
|
|
635
670
|
return undefined;
|
|
636
671
|
}
|
|
@@ -639,6 +674,21 @@ function isTruthyFlag(value) {
|
|
|
639
674
|
// number 1), so accept the numeric `1` alongside the string spellings.
|
|
640
675
|
return value === true || value === 1 || value === 'true' || value === '1' || value === 'yes';
|
|
641
676
|
}
|
|
677
|
+
/**
|
|
678
|
+
* Onboarding runs harness discovery SERVER-SIDE by default so the customer
|
|
679
|
+
* needs no local coding agent. Opt out with `--local`, `--no-remote`, or
|
|
680
|
+
* `--remote=false` to use a local coding-agent analyst instead.
|
|
681
|
+
*/
|
|
682
|
+
export function resolveHarnessRemote(flags) {
|
|
683
|
+
if (isTruthyFlag(flagValue(flags, 'local')))
|
|
684
|
+
return false;
|
|
685
|
+
if (isTruthyFlag(flagValue(flags, 'no-remote', 'no_remote')))
|
|
686
|
+
return false;
|
|
687
|
+
const remote = parseOptionalBoolean(flagValue(flags, 'remote'));
|
|
688
|
+
if (remote !== undefined)
|
|
689
|
+
return remote;
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
642
692
|
function flagValue(flags, ...keys) {
|
|
643
693
|
for (const key of keys) {
|
|
644
694
|
if (flags[key] !== undefined)
|
package/package.json
CHANGED