@taurgis/bonsai 3.1.0 → 3.2.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/README.md +21 -4
- package/agents/agents/salesforce-docs-researcher.agent.md +14 -1
- package/agents/instructions/salesforce-research.instructions.md +2 -1
- package/bin/cli.mjs +9 -17
- package/dist/base-command.d.ts +37 -10
- package/dist/base-command.js +113 -46
- package/dist/commands/config/base.js +11 -2
- package/dist/commands/config/get.js +8 -12
- package/dist/commands/config/index.js +2 -2
- package/dist/commands/config/list.js +10 -16
- package/dist/commands/config/set.d.ts +2 -1
- package/dist/commands/config/set.js +34 -27
- package/dist/commands/config/unset.d.ts +2 -1
- package/dist/commands/config/unset.js +25 -24
- package/dist/commands/fetch.d.ts +7 -15
- package/dist/commands/fetch.js +58 -401
- package/dist/commands/import.d.ts +4 -9
- package/dist/commands/import.js +56 -280
- package/dist/commands/inspect.d.ts +7 -1
- package/dist/commands/inspect.js +103 -52
- package/dist/commands/list.d.ts +13 -1
- package/dist/commands/list.js +79 -32
- package/dist/commands/prune.d.ts +4 -1
- package/dist/commands/prune.js +56 -65
- package/dist/commands/status.d.ts +3 -2
- package/dist/commands/status.js +52 -79
- package/dist/hooks/command-not-found/suggest.d.ts +1 -0
- package/dist/hooks/command-not-found/suggest.js +66 -39
- package/dist/lib/argv.d.ts +24 -3
- package/dist/lib/argv.js +124 -53
- package/dist/lib/batch.d.ts +41 -0
- package/dist/lib/batch.js +39 -0
- package/dist/lib/cache-view.d.ts +21 -0
- package/dist/lib/cache-view.js +30 -0
- package/dist/lib/cli-emit.d.ts +28 -0
- package/dist/lib/cli-emit.js +44 -0
- package/dist/lib/cli-error-policy.d.ts +57 -0
- package/dist/lib/cli-error-policy.js +74 -0
- package/dist/lib/cli-flag-manifest.d.ts +5 -0
- package/dist/lib/cli-flag-manifest.js +8 -0
- package/dist/lib/cli-presentation.d.ts +39 -0
- package/dist/lib/cli-presentation.js +50 -0
- package/dist/lib/cli-result-types.d.ts +88 -0
- package/dist/lib/cli-result-types.js +2 -0
- package/dist/lib/config/index.d.ts +22 -4
- package/dist/lib/config/index.js +59 -4
- package/dist/lib/config/resolve.d.ts +21 -0
- package/dist/lib/config/resolve.js +55 -6
- package/dist/lib/config-persist.d.ts +28 -0
- package/dist/lib/config-persist.js +29 -0
- package/dist/lib/envelope.d.ts +41 -3
- package/dist/lib/envelope.js +147 -4
- package/dist/lib/help-preflight.d.ts +5 -8
- package/dist/lib/help-preflight.js +13 -32
- package/dist/lib/json-meta.d.ts +0 -2
- package/dist/lib/json-meta.js +21 -25
- package/dist/lib/limit-flag.d.ts +11 -1
- package/dist/lib/limit-flag.js +19 -6
- package/dist/lib/parse-error-ux.d.ts +5 -0
- package/dist/lib/parse-error-ux.js +73 -0
- package/dist/lib/prune-flags.d.ts +28 -0
- package/dist/lib/prune-flags.js +74 -0
- package/dist/lib/research/artifact-index.d.ts +11 -2
- package/dist/lib/research/artifact-index.js +7 -4
- package/dist/lib/research/browser.d.ts +41 -2
- package/dist/lib/research/browser.js +139 -50
- package/dist/lib/research/capture.d.ts +24 -2
- package/dist/lib/research/capture.js +24 -4
- package/dist/lib/research/cli-io.d.ts +33 -0
- package/dist/lib/research/cli-io.js +27 -0
- package/dist/lib/research/compress.d.ts +7 -0
- package/dist/lib/research/compress.js +7 -3
- package/dist/lib/research/docs/capabilities.d.ts +15 -0
- package/dist/lib/research/docs/capabilities.js +5 -0
- package/dist/lib/research/docs/clean-dom.d.ts +2 -0
- package/dist/lib/research/docs/clean-dom.js +2 -0
- package/dist/lib/research/docs/code-blocks.d.ts +2 -0
- package/dist/lib/research/docs/code-blocks.js +2 -0
- package/dist/lib/research/docs/detect.d.ts +4 -0
- package/dist/lib/research/docs/detect.js +4 -0
- package/dist/lib/research/docs/machine-readable.d.ts +18 -0
- package/dist/lib/research/docs/machine-readable.js +10 -0
- package/dist/lib/research/docs/markdown-source.d.ts +20 -0
- package/dist/lib/research/docs/markdown-source.js +19 -2
- package/dist/lib/research/docs/quality-gates.d.ts +5 -0
- package/dist/lib/research/docs/quality-gates.js +4 -0
- package/dist/lib/research/docs/rsc.d.ts +9 -2
- package/dist/lib/research/docs/rsc.js +5 -2
- package/dist/lib/research/docs/section-artifacts.d.ts +12 -0
- package/dist/lib/research/docs/section-artifacts.js +12 -0
- package/dist/lib/research/docs/sections.d.ts +18 -0
- package/dist/lib/research/docs/sections.js +17 -1
- package/dist/lib/research/docs/source-map.d.ts +28 -0
- package/dist/lib/research/docs/source-map.js +27 -0
- package/dist/lib/research/docs/validate.d.ts +35 -2
- package/dist/lib/research/docs/validate.js +47 -2
- package/dist/lib/research/extract.d.ts +16 -0
- package/dist/lib/research/extract.js +12 -1
- package/dist/lib/research/fetch-command-service.d.ts +36 -0
- package/dist/lib/research/fetch-command-service.js +310 -0
- package/dist/lib/research/fetch-result.d.ts +114 -0
- package/dist/lib/research/fetch-result.js +212 -0
- package/dist/lib/research/fetcher.d.ts +46 -8
- package/dist/lib/research/fetcher.js +58 -30
- package/dist/lib/research/freshness.d.ts +54 -11
- package/dist/lib/research/freshness.js +91 -31
- package/dist/lib/research/import-command-service.d.ts +56 -0
- package/dist/lib/research/import-command-service.js +381 -0
- package/dist/lib/research/keywords.js +5 -1
- package/dist/lib/research/markdown.d.ts +12 -1
- package/dist/lib/research/markdown.js +13 -5
- package/dist/lib/research/persist-artifact.d.ts +23 -0
- package/dist/lib/research/persist-artifact.js +27 -0
- package/dist/lib/research/prompt-injection.d.ts +8 -0
- package/dist/lib/research/prompt-injection.js +42 -13
- package/dist/lib/research/proxy.d.ts +14 -8
- package/dist/lib/research/proxy.js +14 -10
- package/dist/lib/research/revalidate.d.ts +49 -20
- package/dist/lib/research/revalidate.js +80 -15
- package/dist/lib/research/schema.d.ts +7 -0
- package/dist/lib/research/schema.js +2 -0
- package/dist/lib/research/secret-scan.d.ts +6 -0
- package/dist/lib/research/secret-scan.js +8 -0
- package/dist/lib/research/secure-write.d.ts +11 -1
- package/dist/lib/research/secure-write.js +38 -7
- package/dist/lib/research/storage.d.ts +5 -1
- package/dist/lib/research/storage.js +8 -3
- package/dist/lib/research/summarize.d.ts +15 -0
- package/dist/lib/research/summarize.js +11 -0
- package/dist/lib/research/url.d.ts +9 -6
- package/dist/lib/research/url.js +33 -21
- package/dist/lib/text.d.ts +7 -2
- package/dist/lib/text.js +13 -2
- package/dist/lib/value-flags.d.ts +14 -0
- package/dist/lib/value-flags.js +28 -0
- package/dist/sites/coveo.d.ts +10 -0
- package/dist/sites/coveo.js +10 -0
- package/dist/sites/index.d.ts +16 -0
- package/dist/sites/index.js +16 -4
- package/dist/sites/markdown-twin.d.ts +31 -0
- package/dist/sites/markdown-twin.js +56 -0
- package/dist/sites/salesforce/fetch-page.d.ts +8 -2
- package/dist/sites/salesforce/fetch-page.js +14 -3
- package/dist/sites/salesforce/help-tooling-markdown.d.ts +30 -0
- package/dist/sites/salesforce/help-tooling-markdown.js +74 -0
- package/dist/sites/salesforce/index.d.ts +1 -0
- package/dist/sites/salesforce/index.js +1 -0
- package/dist/sites/salesforce-developer/fetch-page.d.ts +6 -1
- package/dist/sites/salesforce-developer/fetch-page.js +6 -1
- package/dist/sites/salesforce-developer/index.d.ts +1 -0
- package/dist/sites/salesforce-developer/index.js +1 -0
- package/dist/sites/salesforce-developer/route-markdown.d.ts +18 -6
- package/dist/sites/salesforce-developer/route-markdown.js +29 -67
- package/dist/sites/salesforce-doc-fetch.d.ts +39 -5
- package/dist/sites/salesforce-doc-fetch.js +52 -7
- package/dist/sites/salesforce-dom-probe.d.ts +20 -2
- package/dist/sites/salesforce-dom-probe.js +20 -2
- package/dist/sites/types.d.ts +14 -8
- package/dist/sites/types.js +3 -0
- package/oclif.manifest.json +192 -87
- package/package.json +19 -7
- package/agents/agents/official-docs-researcher.agent.md +0 -87
- package/agents/instructions/web-research.instructions.md +0 -44
- package/agents/skills/web-research/SKILL.md +0 -118
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { cliErrorFields } from './envelope.js';
|
|
2
|
+
import { EXIT_RUNTIME_FAILURE } from './cli-error-policy.js';
|
|
3
|
+
/**
|
|
4
|
+
* Collapse a multi-URL command's per-URL rows into the CLI's single-vs-array return
|
|
5
|
+
* contract, and mark {@link EXIT_RUNTIME_FAILURE} when any row is a failure outcome.
|
|
6
|
+
*
|
|
7
|
+
* @param results - Per-URL result rows.
|
|
8
|
+
* @param isFailure - Predicate marking a row as a failure outcome.
|
|
9
|
+
* @returns The sole row when there is one URL; otherwise the full array.
|
|
10
|
+
*/
|
|
11
|
+
export function finalizeBatch(results, isFailure) {
|
|
12
|
+
if (results.some(isFailure))
|
|
13
|
+
process.exitCode = EXIT_RUNTIME_FAILURE;
|
|
14
|
+
return results.length === 1 ? results[0] : results;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* status/inspect batch rows: a miss or a validation error row is a failure outcome.
|
|
18
|
+
*
|
|
19
|
+
* @param row - Batch row with a `status` field.
|
|
20
|
+
* @returns `true` when the row should fail the batch exit code.
|
|
21
|
+
*/
|
|
22
|
+
export function isBatchReadFailure(row) {
|
|
23
|
+
return row.status === 'miss' || row.status === 'error';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Sparse validation-failure row for multi-URL status/inspect. Only the fields agents need —
|
|
27
|
+
* no fake cacheKey/freshness/metadata padding.
|
|
28
|
+
*
|
|
29
|
+
* @param url - Input URL that failed validation.
|
|
30
|
+
* @param err - Error-like object with optional code/message/suggestions/ref.
|
|
31
|
+
* @returns Sparse error row for the batch result array.
|
|
32
|
+
*/
|
|
33
|
+
export function urlValidationErrorRow(url, err) {
|
|
34
|
+
return {
|
|
35
|
+
status: 'error',
|
|
36
|
+
normalizedUrl: url,
|
|
37
|
+
error: cliErrorFields(err),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type HumanField } from './cli-presentation.js';
|
|
2
|
+
/**
|
|
3
|
+
* Shared URL / cache-key / path header used by status and inspect human output, plus any
|
|
4
|
+
* command-specific extra rows, formatted as label/value lines.
|
|
5
|
+
*
|
|
6
|
+
* @param target - Normalized URL, cache key, and store roots.
|
|
7
|
+
* @param extra - Optional additional label/value rows.
|
|
8
|
+
* @param artifactPath - Optional explicit path; defaults to the write-root artifact path.
|
|
9
|
+
* @returns Formatted human-output lines.
|
|
10
|
+
*/
|
|
11
|
+
export declare function formatCacheTargetHeader(target: {
|
|
12
|
+
normalizedUrl: string;
|
|
13
|
+
cacheKey: string;
|
|
14
|
+
roots: {
|
|
15
|
+
writeRoot: string;
|
|
16
|
+
};
|
|
17
|
+
}, extra?: HumanField[], artifactPath?: string): string[];
|
|
18
|
+
/** Stderr tip pointing at the fetch shorthand when a URL has no cache entry. */
|
|
19
|
+
export declare function cacheMissHint(cliBin: string, normalizedUrl: string): string;
|
|
20
|
+
/** Visual row separator between per-URL blocks in multi-URL human output; null for single URLs. */
|
|
21
|
+
export declare function batchSeparator(multi: boolean): string | null;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { colors } from './color.js';
|
|
2
|
+
import { formatHumanFields } from './cli-presentation.js';
|
|
3
|
+
import { getArtifactPath } from './research/storage.js';
|
|
4
|
+
/**
|
|
5
|
+
* Shared URL / cache-key / path header used by status and inspect human output, plus any
|
|
6
|
+
* command-specific extra rows, formatted as label/value lines.
|
|
7
|
+
*
|
|
8
|
+
* @param target - Normalized URL, cache key, and store roots.
|
|
9
|
+
* @param extra - Optional additional label/value rows.
|
|
10
|
+
* @param artifactPath - Optional explicit path; defaults to the write-root artifact path.
|
|
11
|
+
* @returns Formatted human-output lines.
|
|
12
|
+
*/
|
|
13
|
+
export function formatCacheTargetHeader(target, extra = [], artifactPath) {
|
|
14
|
+
const path = artifactPath ?? getArtifactPath(target.roots.writeRoot, target.cacheKey);
|
|
15
|
+
return formatHumanFields([
|
|
16
|
+
['URL', colors.bold(target.normalizedUrl)],
|
|
17
|
+
['Cache Key', colors.bold(target.cacheKey)],
|
|
18
|
+
['Cache Path', colors.gray(path)],
|
|
19
|
+
...extra,
|
|
20
|
+
]);
|
|
21
|
+
}
|
|
22
|
+
/** Stderr tip pointing at the fetch shorthand when a URL has no cache entry. */
|
|
23
|
+
export function cacheMissHint(cliBin, normalizedUrl) {
|
|
24
|
+
return `Cache miss — run: ${cliBin} ${normalizedUrl}`;
|
|
25
|
+
}
|
|
26
|
+
const BATCH_SEPARATOR_WIDTH = 40;
|
|
27
|
+
/** Visual row separator between per-URL blocks in multi-URL human output; null for single URLs. */
|
|
28
|
+
export function batchSeparator(multi) {
|
|
29
|
+
return multi ? '='.repeat(BATCH_SEPARATOR_WIDTH) : null;
|
|
30
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Preflight early-exit payload used before oclif command dispatch. */
|
|
2
|
+
export interface PreflightExit {
|
|
3
|
+
exitCode: number;
|
|
4
|
+
json: boolean;
|
|
5
|
+
envelope: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Print a preflight usage/error result (JSON envelope on stdout, or oclif-style human error) and exit.
|
|
9
|
+
*
|
|
10
|
+
* @param result - Exit code, JSON mode, and envelope to print.
|
|
11
|
+
* @returns Never — calls `process.exit()`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function exitWithPreflight(result: PreflightExit): never;
|
|
14
|
+
/**
|
|
15
|
+
* Command-not-found hook: print JSON error, set {@link EXIT_USAGE}, return envelope (no process.exit).
|
|
16
|
+
*
|
|
17
|
+
* @param options.command - Command id for the envelope.
|
|
18
|
+
* @param options.message - Human-readable error message.
|
|
19
|
+
* @param options.code - Stable error code.
|
|
20
|
+
* @param options.suggestions - Optional recovery tips.
|
|
21
|
+
* @returns The printed error envelope.
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeCommandNotFoundJson(options: {
|
|
24
|
+
command: string;
|
|
25
|
+
message: string;
|
|
26
|
+
code: string;
|
|
27
|
+
suggestions?: string[];
|
|
28
|
+
}): Record<string, unknown>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { buildCliErrorEnvelope } from './envelope.js';
|
|
2
|
+
import { EXIT_USAGE } from './cli-error-policy.js';
|
|
3
|
+
const JSON_STDOUT_INDENT = 2;
|
|
4
|
+
/** Print the envelope as pretty JSON on stdout (the machine-readable channel). */
|
|
5
|
+
function printJsonEnvelope(envelope) {
|
|
6
|
+
console.log(JSON.stringify(envelope, null, JSON_STDOUT_INDENT));
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Print a preflight usage/error result (JSON envelope on stdout, or oclif-style human error) and exit.
|
|
10
|
+
*
|
|
11
|
+
* @param result - Exit code, JSON mode, and envelope to print.
|
|
12
|
+
* @returns Never — calls `process.exit()`.
|
|
13
|
+
*/
|
|
14
|
+
export function exitWithPreflight(result) {
|
|
15
|
+
process.exitCode = result.exitCode;
|
|
16
|
+
const message = String(result.envelope.stderr ?? '');
|
|
17
|
+
if (result.json) {
|
|
18
|
+
printJsonEnvelope(result.envelope);
|
|
19
|
+
}
|
|
20
|
+
else if (message) {
|
|
21
|
+
console.error(` › Error: ${message.replaceAll('\n', '\n › ')}`);
|
|
22
|
+
}
|
|
23
|
+
process.exit();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Command-not-found hook: print JSON error, set {@link EXIT_USAGE}, return envelope (no process.exit).
|
|
27
|
+
*
|
|
28
|
+
* @param options.command - Command id for the envelope.
|
|
29
|
+
* @param options.message - Human-readable error message.
|
|
30
|
+
* @param options.code - Stable error code.
|
|
31
|
+
* @param options.suggestions - Optional recovery tips.
|
|
32
|
+
* @returns The printed error envelope.
|
|
33
|
+
*/
|
|
34
|
+
export function writeCommandNotFoundJson(options) {
|
|
35
|
+
const envelope = buildCliErrorEnvelope({
|
|
36
|
+
command: options.command,
|
|
37
|
+
message: options.message,
|
|
38
|
+
code: options.code,
|
|
39
|
+
suggestions: options.suggestions,
|
|
40
|
+
});
|
|
41
|
+
process.exitCode = EXIT_USAGE;
|
|
42
|
+
printJsonEnvelope(envelope);
|
|
43
|
+
return envelope;
|
|
44
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Process succeeded. */
|
|
2
|
+
export declare const EXIT_OK = 0;
|
|
3
|
+
/** Runtime / batch failure (agents treat as failed). */
|
|
4
|
+
export declare const EXIT_RUNTIME_FAILURE = 1;
|
|
5
|
+
/** Usage / validation failure (flags, URLs, missing args). */
|
|
6
|
+
export declare const EXIT_USAGE = 2;
|
|
7
|
+
/** Stale content served after failed revalidation; success envelope may still be `ok: true`. */
|
|
8
|
+
export declare const EXIT_STALE_SERVED = 5;
|
|
9
|
+
/**
|
|
10
|
+
* Resolves the process/envelope exit code from an oclif CLIError or plain Error.
|
|
11
|
+
*
|
|
12
|
+
* @param err - Error-like object with optional `oclif.exit` or `exitCode`.
|
|
13
|
+
* @returns Exit code; defaults to {@link EXIT_RUNTIME_FAILURE}.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveExitCode(err: {
|
|
16
|
+
oclif?: {
|
|
17
|
+
exit?: number;
|
|
18
|
+
};
|
|
19
|
+
exitCode?: number;
|
|
20
|
+
}): number;
|
|
21
|
+
/** Normalized error fields shared by human pretty-print and the `--json` envelope. */
|
|
22
|
+
export interface PreparedCliError {
|
|
23
|
+
exitCode: number;
|
|
24
|
+
code: string | undefined;
|
|
25
|
+
message: string | undefined;
|
|
26
|
+
suggestions: string[] | undefined;
|
|
27
|
+
ref: string | undefined;
|
|
28
|
+
stderr: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Normalize a thrown value into the fields humans and `--json` both need: stable code,
|
|
32
|
+
* suggestions (including fallbacks), and stderr lines that mirror human pretty-print.
|
|
33
|
+
*
|
|
34
|
+
* @param err - Thrown value (Error, CLIError, or unknown).
|
|
35
|
+
* @param options.bin - CLI binary name for help suggestions.
|
|
36
|
+
* @param options.command - Command id for help suggestions.
|
|
37
|
+
* @returns Prepared fields for exit handling and envelope construction.
|
|
38
|
+
*/
|
|
39
|
+
export declare function prepareCliError(err: unknown, options: {
|
|
40
|
+
bin: string;
|
|
41
|
+
command: string;
|
|
42
|
+
}): PreparedCliError;
|
|
43
|
+
/**
|
|
44
|
+
* Attach stable code + fallback suggestions onto a mutable error (human pretty-print path).
|
|
45
|
+
*
|
|
46
|
+
* @param err - Mutable error object receiving `code` / `suggestions`.
|
|
47
|
+
* @param options.bin - CLI binary name for help suggestions.
|
|
48
|
+
* @param options.command - Command id for help suggestions.
|
|
49
|
+
*/
|
|
50
|
+
export declare function enrichErrorForDisplay(err: {
|
|
51
|
+
code?: string;
|
|
52
|
+
suggestions?: string[];
|
|
53
|
+
message?: string;
|
|
54
|
+
}, options: {
|
|
55
|
+
bin: string;
|
|
56
|
+
command: string;
|
|
57
|
+
}): void;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { formatErrorForJson, normalizeCliErrorMessage, stableErrorCodeFrom, } from './envelope.js';
|
|
2
|
+
/** Process succeeded. */
|
|
3
|
+
export const EXIT_OK = 0;
|
|
4
|
+
/** Runtime / batch failure (agents treat as failed). */
|
|
5
|
+
export const EXIT_RUNTIME_FAILURE = 1;
|
|
6
|
+
/** Usage / validation failure (flags, URLs, missing args). */
|
|
7
|
+
export const EXIT_USAGE = 2;
|
|
8
|
+
/** Stale content served after failed revalidation; success envelope may still be `ok: true`. */
|
|
9
|
+
export const EXIT_STALE_SERVED = 5;
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the process/envelope exit code from an oclif CLIError or plain Error.
|
|
12
|
+
*
|
|
13
|
+
* @param err - Error-like object with optional `oclif.exit` or `exitCode`.
|
|
14
|
+
* @returns Exit code; defaults to {@link EXIT_RUNTIME_FAILURE}.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveExitCode(err) {
|
|
17
|
+
return err?.oclif?.exit ?? err?.exitCode ?? EXIT_RUNTIME_FAILURE;
|
|
18
|
+
}
|
|
19
|
+
/** Default recovery tips when a throw site set a stable code but no suggestions. */
|
|
20
|
+
function fallbackSuggestionsForCode(code, bin, command) {
|
|
21
|
+
const help = command === bin ? `${bin} --help` : `${bin} ${command} --help`;
|
|
22
|
+
switch (code) {
|
|
23
|
+
case 'UNKNOWN_FLAG':
|
|
24
|
+
case 'INVALID_FLAG_VALUE':
|
|
25
|
+
case 'MISSING_FLAG_VALUE':
|
|
26
|
+
case 'DUPLICATE_FLAG':
|
|
27
|
+
case 'MISSING_ARGUMENT':
|
|
28
|
+
case 'UNEXPECTED_ARGUMENT':
|
|
29
|
+
return [`Check usage: ${help}`];
|
|
30
|
+
case 'INVALID_DURATION':
|
|
31
|
+
return ['Use a whole number plus a unit, e.g. 2h, 7d, or 6m.'];
|
|
32
|
+
default:
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Normalize a thrown value into the fields humans and `--json` both need: stable code,
|
|
38
|
+
* suggestions (including fallbacks), and stderr lines that mirror human pretty-print.
|
|
39
|
+
*
|
|
40
|
+
* @param err - Thrown value (Error, CLIError, or unknown).
|
|
41
|
+
* @param options.bin - CLI binary name for help suggestions.
|
|
42
|
+
* @param options.command - Command id for help suggestions.
|
|
43
|
+
* @returns Prepared fields for exit handling and envelope construction.
|
|
44
|
+
*/
|
|
45
|
+
export function prepareCliError(err, options) {
|
|
46
|
+
const e = err;
|
|
47
|
+
const exitCode = resolveExitCode(e);
|
|
48
|
+
const code = stableErrorCodeFrom(e);
|
|
49
|
+
const message = typeof e?.message === 'string' ? normalizeCliErrorMessage(e.message) : undefined;
|
|
50
|
+
const suggestions = e.suggestions?.length
|
|
51
|
+
? e.suggestions
|
|
52
|
+
: fallbackSuggestionsForCode(code, options.bin, options.command);
|
|
53
|
+
const stderr = message || code || suggestions?.length || e?.ref
|
|
54
|
+
? formatErrorForJson({ ...e, message, code, suggestions })
|
|
55
|
+
: String(err);
|
|
56
|
+
return { exitCode, code, message, suggestions, ref: e.ref, stderr };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Attach stable code + fallback suggestions onto a mutable error (human pretty-print path).
|
|
60
|
+
*
|
|
61
|
+
* @param err - Mutable error object receiving `code` / `suggestions`.
|
|
62
|
+
* @param options.bin - CLI binary name for help suggestions.
|
|
63
|
+
* @param options.command - Command id for help suggestions.
|
|
64
|
+
*/
|
|
65
|
+
export function enrichErrorForDisplay(err, options) {
|
|
66
|
+
if (!err.code) {
|
|
67
|
+
const code = stableErrorCodeFrom(err);
|
|
68
|
+
if (code)
|
|
69
|
+
err.code = code;
|
|
70
|
+
}
|
|
71
|
+
if (err.code && !err.suggestions?.length) {
|
|
72
|
+
err.suggestions = fallbackSuggestionsForCode(err.code, options.bin, options.command);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseCommand } from '../base-command.js';
|
|
2
|
+
import { commands } from '../commands.js';
|
|
3
|
+
import { valueTakingFlagTokensFromCommands } from './value-flags.js';
|
|
4
|
+
/**
|
|
5
|
+
* Composition-root flag manifest: every CLI token that consumes a following argv value.
|
|
6
|
+
* Built from command class metadata so argv normalization stays free of command imports.
|
|
7
|
+
*/
|
|
8
|
+
export const VALUE_TAKING_FLAG_TOKENS = valueTakingFlagTokensFromCommands(commands, BaseCommand.baseFlags);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Shared flag/help copy so identical flags read identically across commands. */
|
|
2
|
+
export declare const CLI_FLAG_DESCRIPTIONS: {
|
|
3
|
+
readonly freshnessTierPolicy: "freshness tier policy";
|
|
4
|
+
readonly statusFreshnessTierPolicy: "freshness tier policy to evaluate; when omitted, uses the cached entry's own tier";
|
|
5
|
+
readonly fetchTtl: "TTL duration for freshness (e.g. \"2h\", \"7d\", \"6m\")";
|
|
6
|
+
readonly importTtl: "TTL duration for imported note freshness (e.g. \"2h\", \"7d\", \"6m\")";
|
|
7
|
+
readonly statusTtl: "TTL duration to evaluate freshness (e.g. \"2h\", \"7d\", \"6m\")";
|
|
8
|
+
readonly maxAge: "maximum cache age to accept (e.g. \"2h\", \"7d\", \"6m\")";
|
|
9
|
+
readonly fetchStorage: "override where this result is cached (secrets always stored globally)";
|
|
10
|
+
readonly importStorage: "override where this note is cached (secrets always stored globally)";
|
|
11
|
+
readonly fetchTopic: "main research topic for metadata";
|
|
12
|
+
readonly importTopic: "main topic for this research note";
|
|
13
|
+
readonly filterTopic: "exact topic (case-insensitive)";
|
|
14
|
+
readonly fetchTags: "taxonomic tags for this research (can be repeated)";
|
|
15
|
+
readonly importTags: "taxonomic tags (can be repeated)";
|
|
16
|
+
readonly filterTags: "tags to require (must match all)";
|
|
17
|
+
readonly format: "output format";
|
|
18
|
+
readonly readOnly: "(alias: --plan) block filesystem writes/deletes; network fetches still run; also honored via BONSAI_READ_ONLY/BONSAI_PLAN_MODE";
|
|
19
|
+
readonly sourceUrlGlob: "source URL glob (case-insensitive, supports * wildcard)";
|
|
20
|
+
readonly listArtifactType: "artifact type; section children are omitted from list - use inspect to see them";
|
|
21
|
+
readonly pruneArtifactType: "artifact type to prune, including section children";
|
|
22
|
+
};
|
|
23
|
+
/** One human-readable label/value pair for CLI stdout. */
|
|
24
|
+
export type HumanField = readonly [label: string, value: string];
|
|
25
|
+
/**
|
|
26
|
+
* Format one cyan-padded label/value line for human CLI output.
|
|
27
|
+
*
|
|
28
|
+
* @param label - Field label (without trailing colon).
|
|
29
|
+
* @param value - Field value.
|
|
30
|
+
* @returns A single formatted line.
|
|
31
|
+
*/
|
|
32
|
+
export declare function formatHumanField(label: string, value: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Format many label/value lines for human CLI output.
|
|
35
|
+
*
|
|
36
|
+
* @param fields - Label/value pairs.
|
|
37
|
+
* @returns Formatted lines in the same order.
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatHumanFields(fields: readonly HumanField[]): string[];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { colors } from './color.js';
|
|
2
|
+
const HUMAN_LABEL_WIDTH = 25;
|
|
3
|
+
// Repeated verbatim across several flag descriptions; single-use wording lives inline below.
|
|
4
|
+
const DURATION_EXAMPLES = 'e.g. "2h", "7d", "6m"';
|
|
5
|
+
const SECRET_STORAGE_NOTE = 'secrets always stored globally';
|
|
6
|
+
/** Shared flag/help copy so identical flags read identically across commands. */
|
|
7
|
+
export const CLI_FLAG_DESCRIPTIONS = {
|
|
8
|
+
freshnessTierPolicy: 'freshness tier policy',
|
|
9
|
+
statusFreshnessTierPolicy: "freshness tier policy to evaluate; when omitted, uses the cached entry's own tier",
|
|
10
|
+
fetchTtl: `TTL duration for freshness (${DURATION_EXAMPLES})`,
|
|
11
|
+
importTtl: `TTL duration for imported note freshness (${DURATION_EXAMPLES})`,
|
|
12
|
+
statusTtl: `TTL duration to evaluate freshness (${DURATION_EXAMPLES})`,
|
|
13
|
+
maxAge: `maximum cache age to accept (${DURATION_EXAMPLES})`,
|
|
14
|
+
fetchStorage: `override where this result is cached (${SECRET_STORAGE_NOTE})`,
|
|
15
|
+
importStorage: `override where this note is cached (${SECRET_STORAGE_NOTE})`,
|
|
16
|
+
fetchTopic: 'main research topic for metadata',
|
|
17
|
+
importTopic: 'main topic for this research note',
|
|
18
|
+
filterTopic: 'exact topic (case-insensitive)',
|
|
19
|
+
fetchTags: 'taxonomic tags for this research (can be repeated)',
|
|
20
|
+
importTags: 'taxonomic tags (can be repeated)',
|
|
21
|
+
filterTags: 'tags to require (must match all)',
|
|
22
|
+
format: 'output format',
|
|
23
|
+
readOnly: '(alias: --plan) block filesystem writes/deletes; network fetches still run; also honored via BONSAI_READ_ONLY/BONSAI_PLAN_MODE',
|
|
24
|
+
sourceUrlGlob: 'source URL glob (case-insensitive, supports * wildcard)',
|
|
25
|
+
listArtifactType: 'artifact type; section children are omitted from list - use inspect to see them',
|
|
26
|
+
pruneArtifactType: 'artifact type to prune, including section children',
|
|
27
|
+
};
|
|
28
|
+
function formatHumanLabel(label) {
|
|
29
|
+
const text = `${label}:`;
|
|
30
|
+
return colors.cyan(text.padEnd(Math.max(HUMAN_LABEL_WIDTH, text.length)));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Format one cyan-padded label/value line for human CLI output.
|
|
34
|
+
*
|
|
35
|
+
* @param label - Field label (without trailing colon).
|
|
36
|
+
* @param value - Field value.
|
|
37
|
+
* @returns A single formatted line.
|
|
38
|
+
*/
|
|
39
|
+
export function formatHumanField(label, value) {
|
|
40
|
+
return `${formatHumanLabel(label)} ${value}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Format many label/value lines for human CLI output.
|
|
44
|
+
*
|
|
45
|
+
* @param fields - Label/value pairs.
|
|
46
|
+
* @returns Formatted lines in the same order.
|
|
47
|
+
*/
|
|
48
|
+
export function formatHumanFields(fields) {
|
|
49
|
+
return fields.map(([label, value]) => formatHumanField(label, value));
|
|
50
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** Shared machine-facing write/result shapes for CLI JSON envelopes. */
|
|
2
|
+
import type { ArtifactType, CaptureMethod, ResearchArtifactMetadata, TokenEstimate } from './research/schema.js';
|
|
3
|
+
/** Result of `config set` / `config unset` for the JSON envelope. */
|
|
4
|
+
export interface ConfigWriteResult {
|
|
5
|
+
key: string;
|
|
6
|
+
scope: 'user' | 'project';
|
|
7
|
+
dryRun: boolean;
|
|
8
|
+
status: 'set' | 'would_set' | 'unset' | 'would_unset';
|
|
9
|
+
value?: unknown;
|
|
10
|
+
}
|
|
11
|
+
/** One prune candidate row before delete/preview. */
|
|
12
|
+
export interface PruneCandidate {
|
|
13
|
+
cacheKey: string;
|
|
14
|
+
path: string;
|
|
15
|
+
topic: string | null;
|
|
16
|
+
url: string;
|
|
17
|
+
}
|
|
18
|
+
/** Result of `prune` for the JSON envelope. */
|
|
19
|
+
export interface PruneWriteResult {
|
|
20
|
+
dryRun: boolean;
|
|
21
|
+
status: 'pruned' | 'would_prune';
|
|
22
|
+
wouldPruneCount: number;
|
|
23
|
+
prunedCount: number;
|
|
24
|
+
candidateCount: number;
|
|
25
|
+
files: Array<{
|
|
26
|
+
cacheKey: string;
|
|
27
|
+
path: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
/** Cache lookup outcome reported on fetch results. */
|
|
31
|
+
export type CacheHitStatus = 'hit' | 'miss' | 'stale' | 'refreshed' | 'revalidated';
|
|
32
|
+
/** Freshness tier for a cached entry; `none` means no entry exists. */
|
|
33
|
+
export type FreshnessState = 'fresh' | 'stale_grace' | 'stale_expired' | 'none';
|
|
34
|
+
/** Freshness values that appear on list rows (an entry always exists). */
|
|
35
|
+
export type ListFreshness = Exclude<FreshnessState, 'none'>;
|
|
36
|
+
/** One row in `list --json` output. */
|
|
37
|
+
export interface ListRow {
|
|
38
|
+
cacheKey: string;
|
|
39
|
+
path: string;
|
|
40
|
+
artifactType: ArtifactType;
|
|
41
|
+
sourceUrls: string[];
|
|
42
|
+
topic: string | null;
|
|
43
|
+
tags: string[];
|
|
44
|
+
freshness: ListFreshness;
|
|
45
|
+
captureMethod: CaptureMethod | null;
|
|
46
|
+
tokenEstimate: TokenEstimate;
|
|
47
|
+
qualityNotes: string[];
|
|
48
|
+
fetchedAt: string | null;
|
|
49
|
+
validatedAt: string | null;
|
|
50
|
+
}
|
|
51
|
+
/** Section child summary nested under an inspect hit. */
|
|
52
|
+
export interface InspectSectionRow {
|
|
53
|
+
cacheKey: string;
|
|
54
|
+
anchor: string | null;
|
|
55
|
+
headingPath: string | null;
|
|
56
|
+
tokenEstimate: TokenEstimate;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* An already-cached artifact (typically a multi-source `research_note`) that lists the requested
|
|
60
|
+
* URL among its own `source_urls`, surfaced on an `inspect` miss so the requested URL isn't
|
|
61
|
+
* mistaken for wholly uncached content when it is really a secondary source of an existing note.
|
|
62
|
+
*/
|
|
63
|
+
export interface InspectExistingNoteRow {
|
|
64
|
+
cacheKey: string;
|
|
65
|
+
artifactType: string;
|
|
66
|
+
topic: string | null;
|
|
67
|
+
sourceUrls: string[];
|
|
68
|
+
}
|
|
69
|
+
/** One row in `inspect --json` output. */
|
|
70
|
+
export interface InspectRow {
|
|
71
|
+
cacheKey: string;
|
|
72
|
+
cachePath: string;
|
|
73
|
+
normalizedUrl: string;
|
|
74
|
+
status: 'hit' | 'miss';
|
|
75
|
+
metadata: ResearchArtifactMetadata | null;
|
|
76
|
+
sections: InspectSectionRow[];
|
|
77
|
+
/** Set on a miss when the URL is already a source of a different cached artifact (see above). */
|
|
78
|
+
partOfExistingNote?: InspectExistingNoteRow | null;
|
|
79
|
+
}
|
|
80
|
+
/** One row in `status --json` output. */
|
|
81
|
+
export interface StatusRow {
|
|
82
|
+
cacheKey: string;
|
|
83
|
+
cachePath: string;
|
|
84
|
+
normalizedUrl: string;
|
|
85
|
+
status: 'hit' | 'miss' | 'stale';
|
|
86
|
+
freshness: FreshnessState;
|
|
87
|
+
action: 'would_fetch' | 'would_revalidate' | 'would_return_cached';
|
|
88
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { type ConfigValues, type ResolvedConfig, type ConfigKey, type StorageMode, type SummaryLevel, type KeyMeta, SCHEMA_VERSION, STORAGE_MODES, SUMMARY_LEVELS, ALL_KEYS, BUILT_IN_DEFAULTS, KEY_META, isKnownKey, suggestKey, validKeysHint, } from './schema.js';
|
|
2
2
|
export { readUserConfig, readProjectConfig, writeUserConfig, writeProjectConfig, USER_CONFIG_FILENAME, PROJECT_CONFIG_FILENAME, } from './io.js';
|
|
3
|
-
export { resolveStorageMode, resolveSummaryLevel, parseEnvStorage, parseEnvSummary, invalidEnvOverrideWarnings, STORAGE_ENV_VAR, SUMMARY_ENV_VAR, type ResolveStorageInput, type ResolveSummaryInput, } from './resolve.js';
|
|
4
|
-
import type
|
|
3
|
+
export { resolveStorageMode, resolveSummaryLevel, resolveReadOnly, parseEnvStorage, parseEnvSummary, parseEnvBoolean, invalidEnvOverrideWarnings, STORAGE_ENV_VAR, SUMMARY_ENV_VAR, READ_ONLY_ENV_VAR, PLAN_MODE_ENV_VAR, type ResolveStorageInput, type ResolveSummaryInput, type ResolveReadOnlyInput, } from './resolve.js';
|
|
4
|
+
import { type ConfigKey, type ConfigValues, type ResolvedConfig, type StorageMode, type SummaryLevel } from './schema.js';
|
|
5
5
|
/**
|
|
6
6
|
* Read both config files once and resolve the effective storage mode.
|
|
7
7
|
* `flag` (a per-invocation `--storage` override) wins over everything else.
|
|
@@ -17,7 +17,25 @@ export declare function effectiveConfig(configDir: string | undefined, cwd: stri
|
|
|
17
17
|
export type ConfigScope = 'global' | 'local' | 'effective';
|
|
18
18
|
/**
|
|
19
19
|
* The config values for a requested scope: the user file (`global`), the project file (`local`),
|
|
20
|
-
* or the fully merged result (`effective`). Shared by
|
|
21
|
-
*
|
|
20
|
+
* or the fully merged result (`effective`). Shared by write paths and callers that only need the
|
|
21
|
+
* raw scoped blob (not configured metadata).
|
|
22
22
|
*/
|
|
23
23
|
export declare function readScopedConfig(scope: ConfigScope, configDir: string | undefined, cwd: string): Partial<ConfigValues>;
|
|
24
|
+
/** One config key resolved against a scope: effective value + whether that scope set it. */
|
|
25
|
+
export interface ConfigEntry {
|
|
26
|
+
key: ConfigKey;
|
|
27
|
+
value: ResolvedConfig[ConfigKey];
|
|
28
|
+
configured: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** Resolve a single key; same semantics as {@link resolveConfigEntries}. */
|
|
31
|
+
export declare function resolveConfigEntry(key: ConfigKey, scope: ConfigScope, configDir: string | undefined, cwd: string, env?: Record<string, string | undefined>): ConfigEntry;
|
|
32
|
+
/**
|
|
33
|
+
* Resolve every config key for a scope. Unset keys fall back to the built-in default while
|
|
34
|
+
* `configured: false` tells agents the value is not pinned beyond that default.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveConfigEntries(scope: ConfigScope, configDir: string | undefined, cwd: string, env?: Record<string, string | undefined>): ConfigEntry[];
|
|
37
|
+
/**
|
|
38
|
+
* Human display for a resolved entry. Effective scope always has a usable value, so the
|
|
39
|
+
* "(not configured)" suffix is reserved for `--global`/`--local` reads where absence matters.
|
|
40
|
+
*/
|
|
41
|
+
export declare function formatConfigEntry(entry: ConfigEntry, scope?: ConfigScope): string;
|
package/dist/lib/config/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { SCHEMA_VERSION, STORAGE_MODES, SUMMARY_LEVELS, ALL_KEYS, BUILT_IN_DEFAULTS, KEY_META, isKnownKey, suggestKey, validKeysHint, } from './schema.js';
|
|
2
2
|
export { readUserConfig, readProjectConfig, writeUserConfig, writeProjectConfig, USER_CONFIG_FILENAME, PROJECT_CONFIG_FILENAME, } from './io.js';
|
|
3
|
-
export { resolveStorageMode, resolveSummaryLevel, parseEnvStorage, parseEnvSummary, invalidEnvOverrideWarnings, STORAGE_ENV_VAR, SUMMARY_ENV_VAR, } from './resolve.js';
|
|
3
|
+
export { resolveStorageMode, resolveSummaryLevel, resolveReadOnly, parseEnvStorage, parseEnvSummary, parseEnvBoolean, invalidEnvOverrideWarnings, STORAGE_ENV_VAR, SUMMARY_ENV_VAR, READ_ONLY_ENV_VAR, PLAN_MODE_ENV_VAR, } from './resolve.js';
|
|
4
4
|
import { readUserConfig, readProjectConfig } from './io.js';
|
|
5
|
-
import { resolveStorageMode, resolveSummaryLevel } from './resolve.js';
|
|
5
|
+
import { parseEnvStorage, parseEnvSummary, resolveStorageMode, resolveSummaryLevel, } from './resolve.js';
|
|
6
|
+
import { ALL_KEYS, BUILT_IN_DEFAULTS, KEY_META, } from './schema.js';
|
|
6
7
|
/**
|
|
7
8
|
* Read both config files once and resolve the effective storage mode.
|
|
8
9
|
* `flag` (a per-invocation `--storage` override) wins over everything else.
|
|
@@ -36,8 +37,8 @@ export function effectiveConfig(configDir, cwd) {
|
|
|
36
37
|
}
|
|
37
38
|
/**
|
|
38
39
|
* The config values for a requested scope: the user file (`global`), the project file (`local`),
|
|
39
|
-
* or the fully merged result (`effective`). Shared by
|
|
40
|
-
*
|
|
40
|
+
* or the fully merged result (`effective`). Shared by write paths and callers that only need the
|
|
41
|
+
* raw scoped blob (not configured metadata).
|
|
41
42
|
*/
|
|
42
43
|
export function readScopedConfig(scope, configDir, cwd) {
|
|
43
44
|
if (scope === 'global')
|
|
@@ -46,3 +47,57 @@ export function readScopedConfig(scope, configDir, cwd) {
|
|
|
46
47
|
return readProjectConfig(cwd);
|
|
47
48
|
return effectiveConfig(configDir, cwd);
|
|
48
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Whether any non-default layer pins `key`. For `--global`/`--local`, that is the file itself.
|
|
52
|
+
* For effective, project file, user file, or a valid BONSAI_* env override counts — so a bare
|
|
53
|
+
* default never reports `configured: true` just because `effectiveConfig` always fills values.
|
|
54
|
+
*/
|
|
55
|
+
function isKeyConfigured(key, scope, project, user, env) {
|
|
56
|
+
if (scope === 'global')
|
|
57
|
+
return key in user;
|
|
58
|
+
if (scope === 'local')
|
|
59
|
+
return key in project;
|
|
60
|
+
if (key in project || key in user)
|
|
61
|
+
return true;
|
|
62
|
+
if (key === 'storage')
|
|
63
|
+
return parseEnvStorage(env) !== undefined;
|
|
64
|
+
if (key === 'summary')
|
|
65
|
+
return parseEnvSummary(env) !== undefined;
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
function buildEntry(key, scope, project, user, env) {
|
|
69
|
+
const configured = isKeyConfigured(key, scope, project, user, env);
|
|
70
|
+
if (key === 'storage') {
|
|
71
|
+
const value = scope === 'effective'
|
|
72
|
+
? resolveStorageMode({ env, projectConfig: project, userConfig: user })
|
|
73
|
+
: ((scope === 'global' ? user : project).storage ?? BUILT_IN_DEFAULTS.storage);
|
|
74
|
+
return { key, value, configured };
|
|
75
|
+
}
|
|
76
|
+
const value = scope === 'effective'
|
|
77
|
+
? resolveSummaryLevel({ env, projectConfig: project, userConfig: user })
|
|
78
|
+
: ((scope === 'global' ? user : project).summary ?? BUILT_IN_DEFAULTS.summary);
|
|
79
|
+
return { key, value, configured };
|
|
80
|
+
}
|
|
81
|
+
/** Resolve a single key; same semantics as {@link resolveConfigEntries}. */
|
|
82
|
+
export function resolveConfigEntry(key, scope, configDir, cwd, env = process.env) {
|
|
83
|
+
return buildEntry(key, scope, readProjectConfig(cwd), readUserConfig(configDir), env);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve every config key for a scope. Unset keys fall back to the built-in default while
|
|
87
|
+
* `configured: false` tells agents the value is not pinned beyond that default.
|
|
88
|
+
*/
|
|
89
|
+
export function resolveConfigEntries(scope, configDir, cwd, env = process.env) {
|
|
90
|
+
const project = readProjectConfig(cwd);
|
|
91
|
+
const user = readUserConfig(configDir);
|
|
92
|
+
return ALL_KEYS.map((key) => buildEntry(key, scope, project, user, env));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Human display for a resolved entry. Effective scope always has a usable value, so the
|
|
96
|
+
* "(not configured)" suffix is reserved for `--global`/`--local` reads where absence matters.
|
|
97
|
+
*/
|
|
98
|
+
export function formatConfigEntry(entry, scope = 'local') {
|
|
99
|
+
const formatted = KEY_META[entry.key].format(entry.value);
|
|
100
|
+
if (scope === 'effective' || entry.configured)
|
|
101
|
+
return formatted;
|
|
102
|
+
return `${formatted} (not configured)`;
|
|
103
|
+
}
|
|
@@ -2,6 +2,15 @@ import type { ConfigValues, StorageMode, SummaryLevel } from './schema.js';
|
|
|
2
2
|
/** Scoped env override, following oclif's `<BIN>_*` env-var convention for this CLI. */
|
|
3
3
|
export declare const STORAGE_ENV_VAR = "BONSAI_STORAGE";
|
|
4
4
|
export declare const SUMMARY_ENV_VAR = "BONSAI_SUMMARY";
|
|
5
|
+
/** Two names for the same safety switch: `PLAN_MODE` mirrors agent-harness "plan mode" terminology. */
|
|
6
|
+
export declare const READ_ONLY_ENV_VAR = "BONSAI_READ_ONLY";
|
|
7
|
+
export declare const PLAN_MODE_ENV_VAR = "BONSAI_PLAN_MODE";
|
|
8
|
+
/**
|
|
9
|
+
* Parses a boolean-ish env value. Empty/unset is `undefined` (not present); an unrecognized
|
|
10
|
+
* non-empty value is also `undefined` (invalid — see {@link invalidEnvOverrideWarnings}), so a
|
|
11
|
+
* typo never silently reads as `true`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseEnvBoolean(raw: string | undefined): boolean | undefined;
|
|
5
14
|
/**
|
|
6
15
|
* Warnings for Bonsai env overrides that are set but hold an unrecognized value. Such a value is
|
|
7
16
|
* dropped during resolution (falling back to config/default), which would otherwise silently mask
|
|
@@ -33,3 +42,15 @@ export interface ResolveSummaryInput {
|
|
|
33
42
|
* flag > env > project file > user file > built-in default.
|
|
34
43
|
*/
|
|
35
44
|
export declare function resolveSummaryLevel(input: ResolveSummaryInput): SummaryLevel;
|
|
45
|
+
export interface ResolveReadOnlyInput {
|
|
46
|
+
/** True when `--read-only`/`--plan` was passed on this invocation. */
|
|
47
|
+
flag: boolean;
|
|
48
|
+
env: Record<string, string | undefined>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve whether read-only (plan) mode is active. Unlike storage/summary, this is a safety gate
|
|
52
|
+
* rather than a preference: composition is OR, not override-by-precedence — if the flag or either
|
|
53
|
+
* env var says read-only, the run is read-only. There is no way to force writes back on when an
|
|
54
|
+
* ambient `BONSAI_READ_ONLY`/`BONSAI_PLAN_MODE` is set, by design.
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolveReadOnly(input: ResolveReadOnlyInput): boolean;
|