@taurgis/bonsai 3.2.0 → 4.0.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.
Files changed (173) hide show
  1. package/README.md +9 -6
  2. package/agents/agents/salesforce-docs-researcher.agent.md +17 -4
  3. package/agents/instructions/salesforce-research.instructions.md +2 -1
  4. package/bin/cli.mjs +13 -18
  5. package/dist/base-command.d.ts +59 -12
  6. package/dist/base-command.js +179 -51
  7. package/dist/commands/config/base.js +12 -2
  8. package/dist/commands/config/get.js +8 -12
  9. package/dist/commands/config/index.js +2 -2
  10. package/dist/commands/config/list.js +11 -17
  11. package/dist/commands/config/set.d.ts +2 -1
  12. package/dist/commands/config/set.js +35 -28
  13. package/dist/commands/config/unset.d.ts +2 -1
  14. package/dist/commands/config/unset.js +26 -25
  15. package/dist/commands/fetch.d.ts +7 -15
  16. package/dist/commands/fetch.js +61 -401
  17. package/dist/commands/import.d.ts +4 -9
  18. package/dist/commands/import.js +56 -284
  19. package/dist/commands/inspect.d.ts +7 -1
  20. package/dist/commands/inspect.js +112 -52
  21. package/dist/commands/list.d.ts +18 -3
  22. package/dist/commands/list.js +121 -46
  23. package/dist/commands/prune.d.ts +6 -1
  24. package/dist/commands/prune.js +89 -78
  25. package/dist/commands/status.d.ts +3 -2
  26. package/dist/commands/status.js +62 -79
  27. package/dist/hooks/command-not-found/suggest.d.ts +2 -1
  28. package/dist/hooks/command-not-found/suggest.js +78 -41
  29. package/dist/lib/argv.d.ts +29 -3
  30. package/dist/lib/argv.js +147 -54
  31. package/dist/lib/batch.d.ts +41 -0
  32. package/dist/lib/batch.js +39 -0
  33. package/dist/lib/cache-view.d.ts +21 -0
  34. package/dist/lib/cache-view.js +30 -0
  35. package/dist/lib/cli-emit.d.ts +28 -0
  36. package/dist/lib/cli-emit.js +44 -0
  37. package/dist/lib/cli-error-policy.d.ts +57 -0
  38. package/dist/lib/cli-error-policy.js +74 -0
  39. package/dist/lib/cli-flag-manifest.d.ts +12 -0
  40. package/dist/lib/cli-flag-manifest.js +15 -0
  41. package/dist/lib/cli-presentation.d.ts +41 -0
  42. package/dist/lib/cli-presentation.js +53 -0
  43. package/dist/lib/cli-result-types.d.ts +112 -0
  44. package/dist/lib/cli-result-types.js +2 -0
  45. package/dist/lib/config/index.d.ts +23 -5
  46. package/dist/lib/config/index.js +60 -5
  47. package/dist/lib/config/io.d.ts +9 -0
  48. package/dist/lib/config/io.js +71 -21
  49. package/dist/lib/config/schema.d.ts +2 -0
  50. package/dist/lib/config/schema.js +7 -0
  51. package/dist/lib/config-persist.d.ts +28 -0
  52. package/dist/lib/config-persist.js +29 -0
  53. package/dist/lib/envelope.d.ts +41 -3
  54. package/dist/lib/envelope.js +154 -4
  55. package/dist/lib/help-preflight.d.ts +5 -8
  56. package/dist/lib/help-preflight.js +13 -32
  57. package/dist/lib/json-meta.d.ts +0 -2
  58. package/dist/lib/json-meta.js +21 -25
  59. package/dist/lib/limit-flag.d.ts +11 -1
  60. package/dist/lib/limit-flag.js +19 -6
  61. package/dist/lib/parse-error-ux.d.ts +5 -0
  62. package/dist/lib/parse-error-ux.js +73 -0
  63. package/dist/lib/prune-flags.d.ts +30 -0
  64. package/dist/lib/prune-flags.js +86 -0
  65. package/dist/lib/research/artifact-index.d.ts +11 -2
  66. package/dist/lib/research/artifact-index.js +14 -5
  67. package/dist/lib/research/artifact.js +20 -2
  68. package/dist/lib/research/browser.d.ts +53 -2
  69. package/dist/lib/research/browser.js +202 -58
  70. package/dist/lib/research/capture.d.ts +24 -2
  71. package/dist/lib/research/capture.js +24 -4
  72. package/dist/lib/research/cli-io.d.ts +40 -0
  73. package/dist/lib/research/cli-io.js +27 -0
  74. package/dist/lib/research/compress.d.ts +7 -0
  75. package/dist/lib/research/compress.js +7 -3
  76. package/dist/lib/research/docs/capabilities.d.ts +15 -0
  77. package/dist/lib/research/docs/capabilities.js +5 -0
  78. package/dist/lib/research/docs/clean-dom.d.ts +2 -0
  79. package/dist/lib/research/docs/clean-dom.js +2 -0
  80. package/dist/lib/research/docs/code-blocks.d.ts +2 -0
  81. package/dist/lib/research/docs/code-blocks.js +2 -0
  82. package/dist/lib/research/docs/detect.d.ts +4 -0
  83. package/dist/lib/research/docs/detect.js +4 -0
  84. package/dist/lib/research/docs/machine-readable.d.ts +18 -0
  85. package/dist/lib/research/docs/machine-readable.js +10 -0
  86. package/dist/lib/research/docs/markdown-source.d.ts +20 -0
  87. package/dist/lib/research/docs/markdown-source.js +19 -2
  88. package/dist/lib/research/docs/quality-gates.d.ts +5 -0
  89. package/dist/lib/research/docs/quality-gates.js +4 -0
  90. package/dist/lib/research/docs/rsc.d.ts +9 -2
  91. package/dist/lib/research/docs/rsc.js +5 -2
  92. package/dist/lib/research/docs/section-artifacts.d.ts +12 -0
  93. package/dist/lib/research/docs/section-artifacts.js +12 -0
  94. package/dist/lib/research/docs/sections.d.ts +18 -0
  95. package/dist/lib/research/docs/sections.js +17 -1
  96. package/dist/lib/research/docs/source-map.d.ts +28 -0
  97. package/dist/lib/research/docs/source-map.js +27 -0
  98. package/dist/lib/research/docs/validate.d.ts +35 -2
  99. package/dist/lib/research/docs/validate.js +47 -2
  100. package/dist/lib/research/extract.d.ts +16 -0
  101. package/dist/lib/research/extract.js +12 -1
  102. package/dist/lib/research/fetch-command-service.d.ts +36 -0
  103. package/dist/lib/research/fetch-command-service.js +367 -0
  104. package/dist/lib/research/fetch-result.d.ts +114 -0
  105. package/dist/lib/research/fetch-result.js +212 -0
  106. package/dist/lib/research/fetcher.d.ts +46 -8
  107. package/dist/lib/research/fetcher.js +61 -31
  108. package/dist/lib/research/freshness.d.ts +54 -11
  109. package/dist/lib/research/freshness.js +91 -31
  110. package/dist/lib/research/import-command-service.d.ts +56 -0
  111. package/dist/lib/research/import-command-service.js +402 -0
  112. package/dist/lib/research/keywords.js +5 -1
  113. package/dist/lib/research/markdown.d.ts +12 -1
  114. package/dist/lib/research/markdown.js +13 -5
  115. package/dist/lib/research/metadata-filters.d.ts +18 -0
  116. package/dist/lib/research/metadata-filters.js +37 -0
  117. package/dist/lib/research/metadata-flags.d.ts +34 -0
  118. package/dist/lib/research/metadata-flags.js +45 -0
  119. package/dist/lib/research/persist-artifact.d.ts +23 -0
  120. package/dist/lib/research/persist-artifact.js +27 -0
  121. package/dist/lib/research/prompt-injection.d.ts +9 -0
  122. package/dist/lib/research/prompt-injection.js +59 -14
  123. package/dist/lib/research/proxy.d.ts +14 -8
  124. package/dist/lib/research/proxy.js +14 -10
  125. package/dist/lib/research/resolve-target.d.ts +2 -0
  126. package/dist/lib/research/resolve-target.js +1 -1
  127. package/dist/lib/research/revalidate.d.ts +49 -20
  128. package/dist/lib/research/revalidate.js +80 -15
  129. package/dist/lib/research/schema.d.ts +7 -0
  130. package/dist/lib/research/schema.js +2 -0
  131. package/dist/lib/research/secret-scan.d.ts +6 -0
  132. package/dist/lib/research/secret-scan.js +8 -0
  133. package/dist/lib/research/secure-write.d.ts +4 -0
  134. package/dist/lib/research/secure-write.js +31 -2
  135. package/dist/lib/research/storage.d.ts +9 -8
  136. package/dist/lib/research/storage.js +34 -28
  137. package/dist/lib/research/summarize.d.ts +15 -0
  138. package/dist/lib/research/summarize.js +11 -0
  139. package/dist/lib/research/url.d.ts +9 -6
  140. package/dist/lib/research/url.js +33 -21
  141. package/dist/lib/text.d.ts +19 -8
  142. package/dist/lib/text.js +32 -9
  143. package/dist/lib/value-flags.d.ts +14 -0
  144. package/dist/lib/value-flags.js +28 -0
  145. package/dist/sites/coveo.d.ts +10 -0
  146. package/dist/sites/coveo.js +10 -0
  147. package/dist/sites/index.d.ts +16 -0
  148. package/dist/sites/index.js +16 -4
  149. package/dist/sites/markdown-twin.d.ts +31 -0
  150. package/dist/sites/markdown-twin.js +56 -0
  151. package/dist/sites/salesforce/fetch-page.d.ts +8 -2
  152. package/dist/sites/salesforce/fetch-page.js +14 -3
  153. package/dist/sites/salesforce/help-tooling-markdown.d.ts +30 -0
  154. package/dist/sites/salesforce/help-tooling-markdown.js +74 -0
  155. package/dist/sites/salesforce/index.d.ts +1 -0
  156. package/dist/sites/salesforce/index.js +1 -0
  157. package/dist/sites/salesforce-developer/fetch-page.d.ts +6 -1
  158. package/dist/sites/salesforce-developer/fetch-page.js +6 -1
  159. package/dist/sites/salesforce-developer/index.d.ts +1 -0
  160. package/dist/sites/salesforce-developer/index.js +1 -0
  161. package/dist/sites/salesforce-developer/route-markdown.d.ts +18 -6
  162. package/dist/sites/salesforce-developer/route-markdown.js +29 -67
  163. package/dist/sites/salesforce-doc-fetch.d.ts +39 -5
  164. package/dist/sites/salesforce-doc-fetch.js +52 -7
  165. package/dist/sites/salesforce-dom-probe.d.ts +20 -2
  166. package/dist/sites/salesforce-dom-probe.js +20 -2
  167. package/dist/sites/types.d.ts +14 -8
  168. package/dist/sites/types.js +3 -0
  169. package/oclif.manifest.json +216 -102
  170. package/package.json +20 -7
  171. package/agents/agents/official-docs-researcher.agent.md +0 -87
  172. package/agents/instructions/web-research.instructions.md +0 -44
  173. package/agents/skills/web-research/SKILL.md +0 -118
@@ -1,10 +1,10 @@
1
1
  import { Args } from '@oclif/core';
2
2
  import { ConfigCommand, configScopeFlags } from './base.js';
3
- import { KEY_META, BUILT_IN_DEFAULTS, readScopedConfig, validKeysHint, } from '../../lib/config/index.js';
3
+ import { formatConfigEntry, resolveConfigEntry, keyValuesHint } from '../../lib/config/index.js';
4
4
  export default class ConfigGet extends ConfigCommand {
5
5
  static id = 'config get';
6
- static summary = 'Get the effective value of a research configuration key.';
7
- static description = `Print a config value. Without --global/--local, shows the merged effective value (flag > env > project > user > default).\n\nValid keys: ${validKeysHint()}.`;
6
+ static summary = 'Get a research configuration value';
7
+ static description = `Print a config value. Without --global/--local, shows the merged effective value, in precedence order: a per-command override flag (e.g. \`fetch --storage\`) > env var > project file > user file > built-in default.\n\nValid keys: ${keyValuesHint()}.`;
8
8
  static examples = [
9
9
  {
10
10
  description: 'get the effective storage mode',
@@ -20,8 +20,8 @@ export default class ConfigGet extends ConfigCommand {
20
20
  };
21
21
  static flags = {
22
22
  ...configScopeFlags({
23
- global: 'Read from user-level config only.',
24
- local: 'Read from project-level config only.',
23
+ global: 'read user-level config only',
24
+ local: 'read project-level config only',
25
25
  }),
26
26
  };
27
27
  static stdoutIsPrimaryData = true;
@@ -29,13 +29,9 @@ export default class ConfigGet extends ConfigCommand {
29
29
  const key = this.args.key;
30
30
  this.validateConfigKeyAndScope(key, this.flags.global, this.flags.local);
31
31
  const scope = this.readScope(this.flags.global, this.flags.local);
32
- const value = readScopedConfig(scope, this.config.configDir, process.cwd())[key];
33
- const meta = KEY_META[key];
34
- const displayValue = value !== undefined ? value : BUILT_IN_DEFAULTS[key];
35
- const formatted = meta.format(displayValue);
36
- const suffix = value === undefined ? ' (not configured)' : '';
32
+ const entry = resolveConfigEntry(key, scope, this.config.configDir, process.cwd());
37
33
  if (!this.jsonEnabled())
38
- this.log(formatted + suffix);
39
- return { key, value: displayValue };
34
+ this.log(formatConfigEntry(entry, scope));
35
+ return entry;
40
36
  }
41
37
  }
@@ -2,7 +2,7 @@ import { Help, toConfiguredId } from '@oclif/core';
2
2
  import { BaseCommand } from '../../base-command.js';
3
3
  export default class ConfigIndex extends BaseCommand {
4
4
  static id = 'config';
5
- static summary = 'Manage research cache storage configuration (global vs project).';
5
+ static summary = 'Manage research cache configuration';
6
6
  static description = 'Show config subcommands for reading and writing Bonsai research cache configuration.';
7
7
  static examples = [
8
8
  {
@@ -10,7 +10,7 @@ export default class ConfigIndex extends BaseCommand {
10
10
  command: '<%= config.bin %> <%= command.id %> get storage',
11
11
  },
12
12
  {
13
- description: 'set a configuration value for the current project',
13
+ description: 'set project storage mode',
14
14
  command: '<%= config.bin %> <%= command.id %> set storage project --local',
15
15
  },
16
16
  ];
@@ -1,9 +1,9 @@
1
1
  import { ConfigCommand, configScopeFlags } from './base.js';
2
- import { ALL_KEYS, KEY_META, BUILT_IN_DEFAULTS, readScopedConfig, validKeysHint, } from '../../lib/config/index.js';
2
+ import { formatConfigEntry, resolveConfigEntries, keyValuesHint } from '../../lib/config/index.js';
3
3
  export default class ConfigList extends ConfigCommand {
4
4
  static id = 'config list';
5
- static summary = 'List all research configuration keys and their effective values.';
6
- static description = `Show every configuration key with its current value. Use --global/--local to show a single scope.\n\nValid keys: ${validKeysHint()}.`;
5
+ static summary = 'List research configuration values';
6
+ static description = `Show every configuration key with its current value. Use --global/--local to show a single scope.\n\nValid keys: ${keyValuesHint()}.`;
7
7
  static examples = [
8
8
  {
9
9
  description: 'show all effective config values',
@@ -16,28 +16,22 @@ export default class ConfigList extends ConfigCommand {
16
16
  ];
17
17
  static flags = {
18
18
  ...configScopeFlags({
19
- global: 'Show user-level config only.',
20
- local: 'Show project-level config only.',
19
+ global: 'show user-level config only',
20
+ local: 'show project-level config only',
21
21
  }),
22
22
  };
23
23
  static stdoutIsPrimaryData = true;
24
24
  async run() {
25
25
  this.assertScopeFlagsExclusive(this.flags.global, this.flags.local);
26
26
  const scope = this.readScope(this.flags.global, this.flags.local);
27
- const scoped = readScopedConfig(scope, this.config.configDir, process.cwd());
27
+ const entries = resolveConfigEntries(scope, this.config.configDir, process.cwd());
28
28
  if (!this.jsonEnabled()) {
29
- const width = Math.max(...ALL_KEYS.map((k) => k.length)) + 2;
30
- for (const key of ALL_KEYS) {
31
- const raw = scoped[key];
32
- const formatted = raw !== undefined ? KEY_META[key].format(raw) : '(not configured)';
33
- this.log(`${key.padEnd(width)}${formatted}`);
29
+ const width = Math.max(...entries.map((e) => e.key.length)) + 2;
30
+ for (const entry of entries) {
31
+ this.log(`${entry.key.padEnd(width)}${formatConfigEntry(entry, scope)}`);
34
32
  }
35
33
  }
36
- const values = {};
37
- for (const key of ALL_KEYS) {
38
- const raw = scoped[key];
39
- values[key] = raw !== undefined ? raw : BUILT_IN_DEFAULTS[key];
40
- }
41
- return values;
34
+ // Bare array — same shape as `list`'s data payload; no `{ entries }` wrapper.
35
+ return entries;
42
36
  }
43
37
  }
@@ -1,4 +1,5 @@
1
1
  import { ConfigCommand } from './base.js';
2
+ import type { ConfigWriteResult } from '../../lib/cli-result-types.js';
2
3
  export default class ConfigSet extends ConfigCommand<typeof ConfigSet> {
3
4
  static id: string;
4
5
  static summary: string;
@@ -17,5 +18,5 @@ export default class ConfigSet extends ConfigCommand<typeof ConfigSet> {
17
18
  local: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
19
  };
19
20
  static stdoutIsPrimaryData: boolean;
20
- run(): Promise<unknown>;
21
+ run(): Promise<ConfigWriteResult>;
21
22
  }
@@ -1,18 +1,19 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import { ConfigCommand, configScopeFlags } from './base.js';
3
- import { KEY_META, writeUserConfig, writeProjectConfig, validKeysHint, } from '../../lib/config/index.js';
3
+ import { KEY_META, keyValuesHint } from '../../lib/config/index.js';
4
+ import { persistConfigPatch } from '../../lib/config-persist.js';
4
5
  export default class ConfigSet extends ConfigCommand {
5
6
  static id = 'config set';
6
- static summary = 'Set a research configuration key.';
7
- static description = 'Persist a configuration value. Writes user-level config by default; pass --local to write the project-level config (.bonsai.json in cwd).\n\n' +
8
- `Valid keys: ${validKeysHint()}. The inline form \`<key>=<value>\` is also accepted.`;
7
+ static summary = 'Set a research configuration key';
8
+ static description = 'Persist a configuration value. Writes user-level config by default; pass --local for project-level config (.bonsai.json in cwd).\n\n' +
9
+ `Valid keys: ${keyValuesHint()}. The inline form \`<key>=<value>\` is also accepted.`;
9
10
  static examples = [
10
11
  {
11
- description: 'store research cache inside the current project',
12
+ description: 'store research cache in the current project',
12
13
  command: '<%= config.bin %> config set storage project --local',
13
14
  },
14
15
  {
15
- description: 'set the user-level default using the inline key=value form',
16
+ description: 'set the user-level default with key=value',
16
17
  command: '<%= config.bin %> config set storage=global',
17
18
  },
18
19
  ];
@@ -22,11 +23,11 @@ export default class ConfigSet extends ConfigCommand {
22
23
  };
23
24
  static flags = {
24
25
  ...configScopeFlags({
25
- global: 'Write to user-level config (default).',
26
- local: 'Write to project-level config (.bonsai.json in cwd).',
26
+ global: 'write user-level config (default)',
27
+ local: 'write project-level config (.bonsai.json in cwd)',
27
28
  }),
28
29
  'dry-run': Flags.boolean({
29
- description: 'show what would be written without saving',
30
+ description: 'preview write without saving',
30
31
  default: false,
31
32
  }),
32
33
  };
@@ -39,6 +40,11 @@ export default class ConfigSet extends ConfigCommand {
39
40
  this.error(`Missing required argument: value for key "${keyArg}"`, {
40
41
  exit: 2,
41
42
  code: 'MISSING_ARGUMENT',
43
+ suggestions: [
44
+ meta.values
45
+ ? `Use one of: ${meta.values.join(', ')}`
46
+ : `Provide a value for ${keyArg}: ${meta.description}`,
47
+ ],
42
48
  });
43
49
  }
44
50
  const parsed = meta.parseValue(valueArg);
@@ -47,35 +53,36 @@ export default class ConfigSet extends ConfigCommand {
47
53
  this.error(`Invalid value "${valueArg}" for "${keyArg}". ${guidance}`, {
48
54
  exit: 2,
49
55
  code: 'INVALID_VALUE',
56
+ suggestions: meta.values?.map((value) => `Set ${keyArg} to "${value}": ${this.config.bin} config set ${keyArg} ${value}`),
50
57
  });
51
58
  }
52
59
  const scope = this.writeScope(this.flags.local);
53
60
  const formatted = meta.format(parsed);
54
- if (this.effectiveDryRun(this.flags['dry-run'])) {
61
+ const dryRun = this.effectiveDryRun(this.flags['dry-run']);
62
+ if (dryRun) {
55
63
  if (!this.jsonEnabled())
56
64
  this.log(`[dry-run] Would set ${keyArg} = ${formatted} (${scope})`);
57
- return { key: keyArg, value: parsed, scope, dryRun: true };
65
+ return { key: keyArg, value: parsed, scope, dryRun: true, status: 'would_set' };
58
66
  }
59
- const patch = { [keyArg]: parsed };
60
- if (scope === 'project') {
61
- writeProjectConfig(process.cwd(), patch);
62
- }
63
- else {
64
- const configDir = this.config.configDir;
65
- if (!configDir) {
66
- this.error('Could not determine user config directory. Use --local to write project config.', {
67
- exit: 1,
68
- code: 'CONFIG_DIR_UNAVAILABLE',
69
- suggestions: [
70
- `Write project config instead: ${this.config.bin} config set <key> <value> --local`,
71
- ],
72
- });
73
- }
74
- writeUserConfig(configDir, patch);
67
+ const persisted = persistConfigPatch({
68
+ scope,
69
+ cwd: process.cwd(),
70
+ configDir: this.config.configDir,
71
+ patch: { [keyArg]: parsed },
72
+ action: 'set',
73
+ bin: this.config.bin,
74
+ key: keyArg,
75
+ });
76
+ if (!persisted.ok) {
77
+ this.error(persisted.message, {
78
+ exit: 1,
79
+ code: persisted.code,
80
+ suggestions: persisted.suggestions,
81
+ });
75
82
  }
76
83
  if (!this.jsonEnabled())
77
84
  this.log(`Set ${keyArg} = ${formatted} (${scope})`);
78
- return { key: keyArg, value: parsed, scope, dryRun: false };
85
+ return { key: keyArg, value: parsed, scope, dryRun: false, status: 'set' };
79
86
  }
80
87
  }
81
88
  /**
@@ -1,4 +1,5 @@
1
1
  import { ConfigCommand } from './base.js';
2
+ import type { ConfigWriteResult } from '../../lib/cli-result-types.js';
2
3
  export default class ConfigUnset extends ConfigCommand<typeof ConfigUnset> {
3
4
  static id: string;
4
5
  static summary: string;
@@ -16,5 +17,5 @@ export default class ConfigUnset extends ConfigCommand<typeof ConfigUnset> {
16
17
  local: import("@oclif/core/interfaces").BooleanFlag<boolean>;
17
18
  };
18
19
  static stdoutIsPrimaryData: boolean;
19
- run(): Promise<unknown>;
20
+ run(): Promise<ConfigWriteResult>;
20
21
  }
@@ -1,10 +1,11 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import { ConfigCommand, configScopeFlags } from './base.js';
3
- import { writeUserConfig, writeProjectConfig, validKeysHint } from '../../lib/config/index.js';
3
+ import { keyValuesHint } from '../../lib/config/index.js';
4
+ import { persistConfigPatch } from '../../lib/config-persist.js';
4
5
  export default class ConfigUnset extends ConfigCommand {
5
6
  static id = 'config unset';
6
- static summary = 'Remove a research configuration key.';
7
- static description = `Delete a key from user-level config (default) or project-level config (--local), restoring the built-in default.\n\nValid keys: ${validKeysHint()}.`;
7
+ static summary = 'Remove a research configuration key';
8
+ static description = `Delete a key from user-level config (default) or project-level config (--local), restoring the built-in default.\n\nValid keys: ${keyValuesHint()}.`;
8
9
  static examples = [
9
10
  {
10
11
  description: 'remove the user-level storage setting',
@@ -20,11 +21,11 @@ export default class ConfigUnset extends ConfigCommand {
20
21
  };
21
22
  static flags = {
22
23
  ...configScopeFlags({
23
- global: 'Remove from user-level config (default).',
24
- local: 'Remove from project-level config (.bonsai.json in cwd).',
24
+ global: 'remove from user-level config (default)',
25
+ local: 'remove from project-level config (.bonsai.json in cwd)',
25
26
  }),
26
27
  'dry-run': Flags.boolean({
27
- description: 'show what would be removed without saving',
28
+ description: 'preview removal without saving',
28
29
  default: false,
29
30
  }),
30
31
  };
@@ -33,30 +34,30 @@ export default class ConfigUnset extends ConfigCommand {
33
34
  const key = this.args.key;
34
35
  this.validateConfigKeyAndScope(key, this.flags.global, this.flags.local);
35
36
  const scope = this.writeScope(this.flags.local);
36
- if (this.effectiveDryRun(this.flags['dry-run'])) {
37
+ const dryRun = this.effectiveDryRun(this.flags['dry-run']);
38
+ if (dryRun) {
37
39
  if (!this.jsonEnabled())
38
40
  this.log(`[dry-run] Would unset ${key} (${scope})`);
39
- return { key, scope, dryRun: true };
41
+ return { key, scope, dryRun: true, status: 'would_unset' };
40
42
  }
41
- const patch = { [key]: undefined };
42
- if (scope === 'project') {
43
- writeProjectConfig(process.cwd(), patch);
44
- }
45
- else {
46
- const configDir = this.config.configDir;
47
- if (!configDir) {
48
- this.error('Could not determine user config directory. Use --local to remove project config.', {
49
- exit: 1,
50
- code: 'CONFIG_DIR_UNAVAILABLE',
51
- suggestions: [
52
- `Remove project config instead: ${this.config.bin} config unset ${key} --local`,
53
- ],
54
- });
55
- }
56
- writeUserConfig(configDir, patch);
43
+ const persisted = persistConfigPatch({
44
+ scope,
45
+ cwd: process.cwd(),
46
+ configDir: this.config.configDir,
47
+ patch: { [key]: undefined },
48
+ action: 'unset',
49
+ bin: this.config.bin,
50
+ key,
51
+ });
52
+ if (!persisted.ok) {
53
+ this.error(persisted.message, {
54
+ exit: 1,
55
+ code: persisted.code,
56
+ suggestions: persisted.suggestions,
57
+ });
57
58
  }
58
59
  if (!this.jsonEnabled())
59
60
  this.log(`Unset ${key} (${scope})`);
60
- return { key, scope, dryRun: false };
61
+ return { key, scope, dryRun: false, status: 'unset' };
61
62
  }
62
63
  }
@@ -1,4 +1,5 @@
1
1
  import { BaseCommand } from '../base-command.js';
2
+ /** Hidden named `fetch` command; usually invoked as `bonsai <url>`. */
2
3
  export default class FetchCommand extends BaseCommand<typeof FetchCommand> {
3
4
  static id: string;
4
5
  static hidden: boolean;
@@ -26,20 +27,11 @@ export default class FetchCommand extends BaseCommand<typeof FetchCommand> {
26
27
  storage: import("@oclif/core/interfaces").OptionFlag<"global" | "project" | undefined, import("@oclif/core/interfaces").CustomOptions>;
27
28
  };
28
29
  static stdoutIsPrimaryData: boolean;
29
- protected envelopeCommandId(): string;
30
- private executeCacheHit;
31
- private executeCacheMiss;
32
- private buildResultData;
33
- private validateDurationFlags;
34
- private emitFetchError;
35
- private resolveArtifact;
36
- private persistFreshArtifact;
37
- private persistSectionsIfFresh;
30
+ /**
31
+ * When a multi-URL batch has any per-URL failure, keep the result array (including hits) and
32
+ * surface FETCH_FAILED on the envelope — same batch contract as status/inspect CACHE_MISS.
33
+ */
34
+ protected toSuccessJson(data: unknown): Record<string, unknown>;
35
+ private serviceFlags;
38
36
  run(): Promise<unknown>;
39
- private fetchSingleTarget;
40
37
  }
41
- export declare function describeError(err: unknown): string;
42
- export declare function fetchFailureGuidance(message: string, url: string): {
43
- suggestions: string[];
44
- ref?: string;
45
- } | undefined;