@pellux/goodvibes-agent 1.1.7 → 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.
Files changed (255) hide show
  1. package/CHANGELOG.md +170 -0
  2. package/README.md +46 -30
  3. package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
  4. package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
  5. package/dist/package/main.js +132577 -91483
  6. package/docs/README.md +14 -7
  7. package/docs/channels-remote-and-api.md +8 -5
  8. package/docs/connected-host.md +14 -12
  9. package/docs/getting-started.md +56 -30
  10. package/docs/knowledge-artifacts-and-multimodal.md +7 -5
  11. package/docs/project-planning.md +2 -2
  12. package/docs/providers-and-routing.md +11 -3
  13. package/docs/tools-and-commands.md +114 -45
  14. package/docs/voice-and-live-tts.md +3 -1
  15. package/package.json +3 -2
  16. package/release/release-notes.md +130 -5
  17. package/release/release-readiness.json +120 -90
  18. package/src/agent/assistant-cockpit.ts +247 -0
  19. package/src/agent/autonomy-schedule-format.ts +96 -0
  20. package/src/agent/autonomy-schedule.ts +514 -0
  21. package/src/agent/channel-delivery-receipts.ts +292 -0
  22. package/src/agent/competitive-feature-inventory.ts +296 -0
  23. package/src/agent/document-registry-types.ts +106 -0
  24. package/src/agent/document-registry.ts +734 -0
  25. package/src/agent/harness-control.ts +2 -2
  26. package/src/agent/memory-prompt.ts +2 -2
  27. package/src/agent/operator-actions.ts +50 -6
  28. package/src/agent/persona-registry.ts +8 -0
  29. package/src/agent/project-context-files.ts +273 -0
  30. package/src/agent/prompt-context-receipts.ts +502 -0
  31. package/src/agent/reminder-schedule-format.ts +16 -2
  32. package/src/agent/research-run-registry.ts +582 -0
  33. package/src/agent/research-source-registry.ts +441 -0
  34. package/src/agent/routine-registry.ts +19 -3
  35. package/src/agent/routine-schedule-format.ts +27 -2
  36. package/src/agent/runtime-profile-starters.ts +7 -0
  37. package/src/agent/runtime-profile.ts +106 -4
  38. package/src/agent/schedule-edit-format.ts +129 -0
  39. package/src/agent/schedule-edit.ts +496 -0
  40. package/src/agent/schedule-next-routes.ts +42 -0
  41. package/src/agent/setup-wizard-checkpoint.ts +140 -0
  42. package/src/agent/setup-wizard.ts +447 -0
  43. package/src/agent/skill-registry-types.ts +102 -0
  44. package/src/agent/skill-registry.ts +81 -107
  45. package/src/agent/vibe-confirmation-routes.ts +62 -0
  46. package/src/agent/vibe-file.ts +285 -0
  47. package/src/cli/agent-knowledge-command.ts +45 -2
  48. package/src/cli/help.ts +3 -0
  49. package/src/cli/profiles-command.ts +25 -11
  50. package/src/config/agent-settings-policy.ts +1 -18
  51. package/src/input/agent-workspace-activation.ts +53 -0
  52. package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
  53. package/src/input/agent-workspace-artifact-metadata.ts +17 -0
  54. package/src/input/agent-workspace-basic-command-editors.ts +5 -1
  55. package/src/input/agent-workspace-categories.ts +153 -155
  56. package/src/input/agent-workspace-channel-triage.ts +481 -0
  57. package/src/input/agent-workspace-channels.ts +263 -0
  58. package/src/input/agent-workspace-command-editor.ts +152 -0
  59. package/src/input/agent-workspace-context-snapshot.ts +349 -0
  60. package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
  61. package/src/input/agent-workspace-document-editor.ts +502 -0
  62. package/src/input/agent-workspace-document-ops-editor.ts +523 -0
  63. package/src/input/agent-workspace-host-category.ts +1 -1
  64. package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
  65. package/src/input/agent-workspace-model-compare-editor.ts +376 -0
  66. package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
  67. package/src/input/agent-workspace-model-compare-types.ts +82 -0
  68. package/src/input/agent-workspace-model-compare-utils.ts +35 -0
  69. package/src/input/agent-workspace-onboarding-categories.ts +141 -0
  70. package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
  71. package/src/input/agent-workspace-operations-command-editors.ts +22 -0
  72. package/src/input/agent-workspace-research-report-editor.ts +212 -0
  73. package/src/input/agent-workspace-research-run-editor.ts +144 -0
  74. package/src/input/agent-workspace-research-source-editor.ts +167 -0
  75. package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
  76. package/src/input/agent-workspace-review-packet-utils.ts +265 -0
  77. package/src/input/agent-workspace-settings.ts +262 -30
  78. package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
  79. package/src/input/agent-workspace-setup-snapshot.ts +198 -0
  80. package/src/input/agent-workspace-setup.ts +34 -1
  81. package/src/input/agent-workspace-snapshot.ts +162 -147
  82. package/src/input/agent-workspace-types.ts +287 -2
  83. package/src/input/agent-workspace.ts +18 -0
  84. package/src/input/command-registry.ts +9 -2
  85. package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
  86. package/src/input/commands/channels-runtime.ts +102 -114
  87. package/src/input/commands/delegation-runtime.ts +87 -24
  88. package/src/input/commands/knowledge-browser-flags.ts +12 -0
  89. package/src/input/commands/knowledge.ts +28 -14
  90. package/src/input/commands/operator-actions-runtime.ts +6 -3
  91. package/src/input/commands/schedule-runtime.ts +71 -14
  92. package/src/input/commands/session-content.ts +2 -2
  93. package/src/input/commands/shell-core.ts +2 -0
  94. package/src/input/commands/vibe-runtime.ts +140 -0
  95. package/src/input/commands.ts +2 -0
  96. package/src/input/connected-host-routes.ts +123 -0
  97. package/src/input/settings-modal-types.ts +14 -0
  98. package/src/main.ts +15 -15
  99. package/src/panels/qr-panel.ts +2 -2
  100. package/src/renderer/agent-workspace-context-lines.ts +686 -0
  101. package/src/renderer/agent-workspace.ts +30 -419
  102. package/src/renderer/settings-modal-helpers.ts +12 -0
  103. package/src/renderer/settings-modal.ts +12 -0
  104. package/src/runtime/bootstrap-command-context.ts +11 -1
  105. package/src/runtime/bootstrap-command-parts.ts +14 -3
  106. package/src/runtime/bootstrap-core.ts +39 -1
  107. package/src/runtime/bootstrap-shell.ts +6 -0
  108. package/src/runtime/bootstrap.ts +113 -30
  109. package/src/runtime/connected-host-auth.ts +3 -2
  110. package/src/runtime/execution-ledger.ts +231 -0
  111. package/src/runtime/services.ts +88 -10
  112. package/src/runtime/tool-permission-safety.ts +199 -5
  113. package/src/shell/session-continuity-hints.ts +39 -0
  114. package/src/tools/agent-artifacts-tool.ts +606 -0
  115. package/src/tools/agent-audit-tool.ts +155 -0
  116. package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
  117. package/src/tools/agent-autonomy-tool.ts +140 -0
  118. package/src/tools/agent-channel-send-tool.ts +24 -2
  119. package/src/tools/agent-channels-tool.ts +140 -0
  120. package/src/tools/agent-computer-tool.ts +168 -0
  121. package/src/tools/agent-context-policy.ts +137 -7
  122. package/src/tools/agent-context-tool.ts +143 -0
  123. package/src/tools/agent-delegation-tool.ts +128 -0
  124. package/src/tools/agent-device-tool.ts +240 -0
  125. package/src/tools/agent-documents-tool.ts +684 -0
  126. package/src/tools/agent-execution-tool.ts +230 -0
  127. package/src/tools/agent-harness-agent-orchestration.ts +703 -0
  128. package/src/tools/agent-harness-autonomy-intake.ts +785 -0
  129. package/src/tools/agent-harness-autonomy-live-records.ts +588 -0
  130. package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
  131. package/src/tools/agent-harness-autonomy-queue.ts +560 -0
  132. package/src/tools/agent-harness-background-processes-types.ts +35 -0
  133. package/src/tools/agent-harness-background-processes.ts +794 -0
  134. package/src/tools/agent-harness-browser-cockpit-route.ts +219 -0
  135. package/src/tools/agent-harness-browser-control.ts +338 -0
  136. package/src/tools/agent-harness-channel-metadata.ts +168 -10
  137. package/src/tools/agent-harness-cli-command-policy.ts +110 -0
  138. package/src/tools/agent-harness-command-catalog.ts +4 -2
  139. package/src/tools/agent-harness-command-runner.ts +42 -0
  140. package/src/tools/agent-harness-connected-host-status.ts +7 -4
  141. package/src/tools/agent-harness-delegation-posture.ts +234 -19
  142. package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
  143. package/src/tools/agent-harness-document-ops-types.ts +72 -0
  144. package/src/tools/agent-harness-document-ops.ts +671 -0
  145. package/src/tools/agent-harness-execution-history.ts +489 -0
  146. package/src/tools/agent-harness-execution-posture.ts +382 -0
  147. package/src/tools/agent-harness-file-recovery.ts +135 -0
  148. package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
  149. package/src/tools/agent-harness-learning-curator-common.ts +102 -0
  150. package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
  151. package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
  152. package/src/tools/agent-harness-learning-curator-types.ts +151 -0
  153. package/src/tools/agent-harness-learning-curator.ts +417 -0
  154. package/src/tools/agent-harness-local-model-benchmarks.ts +199 -0
  155. package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
  156. package/src/tools/agent-harness-local-model-endpoints.ts +673 -0
  157. package/src/tools/agent-harness-media-posture.ts +208 -2
  158. package/src/tools/agent-harness-memory-posture.ts +556 -0
  159. package/src/tools/agent-harness-metadata.ts +100 -168
  160. package/src/tools/agent-harness-mode-catalog.ts +84 -33
  161. package/src/tools/agent-harness-model-catalog.ts +162 -0
  162. package/src/tools/agent-harness-model-provider-health.ts +186 -0
  163. package/src/tools/agent-harness-model-readiness.ts +406 -0
  164. package/src/tools/agent-harness-model-routing-types.ts +266 -0
  165. package/src/tools/agent-harness-model-routing-utils.ts +30 -0
  166. package/src/tools/agent-harness-model-routing.ts +137 -190
  167. package/src/tools/agent-harness-operator-methods.ts +115 -133
  168. package/src/tools/agent-harness-pairing-posture.ts +431 -18
  169. package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
  170. package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
  171. package/src/tools/agent-harness-personal-ops-lanes.ts +204 -0
  172. package/src/tools/agent-harness-personal-ops-records.ts +732 -0
  173. package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
  174. package/src/tools/agent-harness-personal-ops-types.ts +222 -0
  175. package/src/tools/agent-harness-personal-ops.ts +606 -0
  176. package/src/tools/agent-harness-project-context.ts +144 -0
  177. package/src/tools/agent-harness-prompt-context.ts +589 -0
  178. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  179. package/src/tools/agent-harness-release-evidence.ts +9 -7
  180. package/src/tools/agent-harness-release-readiness.ts +9 -7
  181. package/src/tools/agent-harness-research-briefing.ts +427 -0
  182. package/src/tools/agent-harness-research-queue.ts +250 -0
  183. package/src/tools/agent-harness-research-runs.ts +295 -0
  184. package/src/tools/agent-harness-research-workflow.ts +322 -0
  185. package/src/tools/agent-harness-security-posture.ts +2 -2
  186. package/src/tools/agent-harness-service-posture.ts +9 -9
  187. package/src/tools/agent-harness-session-metadata.ts +3 -3
  188. package/src/tools/agent-harness-setup-connected-host.ts +501 -0
  189. package/src/tools/agent-harness-setup-describe.ts +557 -0
  190. package/src/tools/agent-harness-setup-handoffs.ts +502 -0
  191. package/src/tools/agent-harness-setup-model-helpers.ts +101 -0
  192. package/src/tools/agent-harness-setup-plan.ts +253 -0
  193. package/src/tools/agent-harness-setup-posture-types.ts +218 -0
  194. package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
  195. package/src/tools/agent-harness-setup-posture.ts +449 -221
  196. package/src/tools/agent-harness-setup-smoke.ts +508 -0
  197. package/src/tools/agent-harness-sudo-posture.ts +114 -0
  198. package/src/tools/agent-harness-tool-schema.ts +120 -7
  199. package/src/tools/agent-harness-tool-types.ts +78 -0
  200. package/src/tools/agent-harness-tool-utils.ts +43 -0
  201. package/src/tools/agent-harness-tool.ts +311 -370
  202. package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
  203. package/src/tools/agent-harness-ui-surface-types.ts +46 -0
  204. package/src/tools/agent-harness-vibe-health.ts +105 -0
  205. package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
  206. package/src/tools/agent-harness-workspace-actions.ts +114 -8
  207. package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
  208. package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
  209. package/src/tools/agent-host-tool.ts +159 -0
  210. package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
  211. package/src/tools/agent-learning-consolidation-core.ts +327 -0
  212. package/src/tools/agent-learning-consolidation-tool.ts +758 -0
  213. package/src/tools/agent-memory-tool.ts +214 -0
  214. package/src/tools/agent-model-compare-export.ts +315 -0
  215. package/src/tools/agent-model-compare-handoff.ts +592 -0
  216. package/src/tools/agent-model-compare-judgment.ts +633 -0
  217. package/src/tools/agent-model-compare-run.ts +722 -0
  218. package/src/tools/agent-model-compare-tool.ts +698 -0
  219. package/src/tools/agent-model-compare-types.ts +191 -0
  220. package/src/tools/agent-model-compare-utils.ts +93 -0
  221. package/src/tools/agent-models-tool.ts +208 -0
  222. package/src/tools/agent-operator-action-tool.ts +1 -1
  223. package/src/tools/agent-operator-method-tool.ts +643 -0
  224. package/src/tools/agent-personal-ops-tool.ts +197 -0
  225. package/src/tools/agent-policy-explanation.ts +415 -0
  226. package/src/tools/agent-research-report-tool.ts +608 -0
  227. package/src/tools/agent-research-runs-tool.ts +434 -0
  228. package/src/tools/agent-research-sources-tool.ts +443 -0
  229. package/src/tools/agent-research-tool.ts +687 -0
  230. package/src/tools/agent-review-packet-presets-core.ts +757 -0
  231. package/src/tools/agent-review-packet-presets-tool.ts +466 -0
  232. package/src/tools/agent-review-packet-share-tool.ts +305 -0
  233. package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
  234. package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
  235. package/src/tools/agent-route-planner-candidates-work.ts +251 -0
  236. package/src/tools/agent-route-planner-helpers.ts +667 -0
  237. package/src/tools/agent-route-planner.ts +185 -0
  238. package/src/tools/agent-route-tool.ts +105 -0
  239. package/src/tools/agent-schedule-edit-tool.ts +210 -0
  240. package/src/tools/agent-schedule-tool.ts +282 -0
  241. package/src/tools/agent-security-tool.ts +145 -0
  242. package/src/tools/agent-sessions-tool.ts +122 -0
  243. package/src/tools/agent-settings-import-tool.ts +104 -0
  244. package/src/tools/agent-settings-tool.ts +176 -0
  245. package/src/tools/agent-setup-tool.ts +226 -0
  246. package/src/tools/agent-support-tool.ts +122 -0
  247. package/src/tools/agent-terminal-process-tools.ts +167 -0
  248. package/src/tools/agent-tool-policy-guard-types.ts +77 -0
  249. package/src/tools/agent-tool-policy-guard.ts +106 -85
  250. package/src/tools/agent-vibe-tool.ts +297 -0
  251. package/src/tools/agent-work-plan-tool.ts +265 -6
  252. package/src/tools/agent-workspace-tool.ts +305 -0
  253. package/src/tools/artifact-archive.ts +169 -0
  254. package/src/tools/tool-definition-compaction.ts +36 -0
  255. package/src/version.ts +1 -1
@@ -4,109 +4,34 @@ import type { ShellPathService } from '@/runtime/index.ts';
4
4
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
5
5
  import { assertNoSecretLikeText } from './persona-registry.ts';
6
6
  import { formatAgentRecordReviewState } from './record-labels.ts';
7
-
8
- export type AgentSkillSource = 'user' | 'agent' | 'imported' | 'system';
9
- export type AgentSkillReviewState = 'fresh' | 'reviewed' | 'stale';
10
- export type AgentSkillRequirementKind = 'env' | 'command';
11
-
12
- export interface AgentSkillRequirement {
13
- readonly kind: AgentSkillRequirementKind;
14
- readonly name: string;
15
- readonly description?: string;
16
- }
17
-
18
- export interface AgentSkillReadiness {
19
- readonly ready: boolean;
20
- readonly met: readonly AgentSkillRequirement[];
21
- readonly missing: readonly AgentSkillRequirement[];
22
- }
23
-
24
- export interface AgentSkillBundleReadiness {
25
- readonly ready: boolean;
26
- readonly includedSkills: readonly AgentSkillRecord[];
27
- readonly missingSkillIds: readonly string[];
28
- readonly missingRequirements: readonly AgentSkillRequirement[];
29
- }
30
-
31
- export interface AgentSkillRecord {
32
- readonly id: string;
33
- readonly name: string;
34
- readonly description: string;
35
- readonly procedure: string;
36
- readonly triggers: readonly string[];
37
- readonly tags: readonly string[];
38
- readonly requirements: readonly AgentSkillRequirement[];
39
- readonly enabled: boolean;
40
- readonly source: AgentSkillSource;
41
- readonly provenance: string;
42
- readonly reviewState: AgentSkillReviewState;
43
- readonly staleReason?: string;
44
- readonly createdAt: string;
45
- readonly updatedAt: string;
46
- readonly reviewedAt?: string;
47
- }
48
-
49
- export interface AgentSkillBundleRecord {
50
- readonly id: string;
51
- readonly name: string;
52
- readonly description: string;
53
- readonly skillIds: readonly string[];
54
- readonly enabled: boolean;
55
- readonly source: AgentSkillSource;
56
- readonly provenance: string;
57
- readonly reviewState: AgentSkillReviewState;
58
- readonly staleReason?: string;
59
- readonly createdAt: string;
60
- readonly updatedAt: string;
61
- readonly reviewedAt?: string;
62
- }
63
-
64
- export interface AgentSkillCreateInput {
65
- readonly name: string;
66
- readonly description: string;
67
- readonly procedure: string;
68
- readonly triggers?: readonly string[];
69
- readonly tags?: readonly string[];
70
- readonly requirements?: readonly AgentSkillRequirement[];
71
- readonly enabled?: boolean;
72
- readonly source?: AgentSkillSource;
73
- readonly provenance?: string;
74
- }
75
-
76
- export interface AgentSkillBundleCreateInput {
77
- readonly name: string;
78
- readonly description: string;
79
- readonly skillIds: readonly string[];
80
- readonly enabled?: boolean;
81
- readonly source?: AgentSkillSource;
82
- readonly provenance?: string;
83
- }
84
-
85
- export interface AgentSkillUpdateInput {
86
- readonly name?: string;
87
- readonly description?: string;
88
- readonly procedure?: string;
89
- readonly triggers?: readonly string[];
90
- readonly tags?: readonly string[];
91
- readonly requirements?: readonly AgentSkillRequirement[];
92
- readonly provenance?: string;
93
- }
94
-
95
- export interface AgentSkillBundleUpdateInput {
96
- readonly name?: string;
97
- readonly description?: string;
98
- readonly skillIds?: readonly string[];
99
- readonly provenance?: string;
100
- }
101
-
102
- export interface AgentSkillSnapshot {
103
- readonly path: string;
104
- readonly skills: readonly AgentSkillRecord[];
105
- readonly enabledSkills: readonly AgentSkillRecord[];
106
- readonly bundles: readonly AgentSkillBundleRecord[];
107
- readonly enabledBundles: readonly AgentSkillBundleRecord[];
108
- readonly activeSkills: readonly AgentSkillRecord[];
109
- }
7
+ import type {
8
+ AgentSkillBundleCreateInput,
9
+ AgentSkillBundleReadiness,
10
+ AgentSkillBundleRecord,
11
+ AgentSkillBundleUpdateInput,
12
+ AgentSkillCreateInput,
13
+ AgentSkillReadiness,
14
+ AgentSkillRecord,
15
+ AgentSkillRequirement,
16
+ AgentSkillRequirementKind,
17
+ AgentSkillSnapshot,
18
+ AgentSkillUpdateInput,
19
+ } from './skill-registry-types.ts';
20
+ export type {
21
+ AgentSkillBundleCreateInput,
22
+ AgentSkillBundleReadiness,
23
+ AgentSkillBundleRecord,
24
+ AgentSkillBundleUpdateInput,
25
+ AgentSkillCreateInput,
26
+ AgentSkillReadiness,
27
+ AgentSkillRecord,
28
+ AgentSkillRequirement,
29
+ AgentSkillRequirementKind,
30
+ AgentSkillReviewState,
31
+ AgentSkillSnapshot,
32
+ AgentSkillSource,
33
+ AgentSkillUpdateInput,
34
+ } from './skill-registry-types.ts';
110
35
 
111
36
  interface SkillStoreFile {
112
37
  readonly version: 1;
@@ -754,13 +679,55 @@ export function evaluateAgentSkillBundleReadiness(
754
679
 
755
680
  export function buildEnabledSkillsPrompt(shellPaths: ShellPathService): string | null {
756
681
  const snapshot = AgentSkillRegistry.fromShellPaths(shellPaths).snapshot();
757
- const active = snapshot.activeSkills;
758
- if (active.length === 0 && snapshot.enabledBundles.length === 0) return null;
682
+ const enabledBundles = snapshot.enabledBundles.filter((bundle) => {
683
+ if (bundle.reviewState !== 'reviewed') return false;
684
+ const readiness = evaluateAgentSkillBundleReadiness(bundle, snapshot.skills);
685
+ return readiness.ready && readiness.includedSkills.every((skill) => skill.reviewState === 'reviewed');
686
+ });
687
+ const activeSkillIds = new Set([
688
+ ...snapshot.enabledSkills.map((skill) => skill.id),
689
+ ...enabledBundles.flatMap((bundle) => bundle.skillIds),
690
+ ]);
691
+ const active = snapshot.skills.filter((skill) => (
692
+ activeSkillIds.has(skill.id)
693
+ && skill.reviewState === 'reviewed'
694
+ && evaluateAgentSkillReadiness(skill).ready
695
+ ));
696
+ const candidateSkillIds = new Set([
697
+ ...snapshot.enabledSkills.map((skill) => skill.id),
698
+ ...snapshot.enabledBundles.flatMap((bundle) => bundle.skillIds),
699
+ ]);
700
+ const suppressedSkills = snapshot.skills
701
+ .filter((skill) => candidateSkillIds.has(skill.id) && !active.some((activeSkill) => activeSkill.id === skill.id))
702
+ .slice(0, 8)
703
+ .map((skill) => {
704
+ const readiness = evaluateAgentSkillReadiness(skill);
705
+ const review = skill.reviewState === 'reviewed' ? '' : `review=${formatAgentRecordReviewState(skill.reviewState)}`;
706
+ const setup = readiness.ready ? '' : `missing=${readiness.missing.map(formatAgentSkillRequirement).join(', ')}`;
707
+ return `- ${skill.name}: ${[review, setup].filter(Boolean).join('; ')}`;
708
+ });
709
+ const suppressedBundles = snapshot.enabledBundles
710
+ .filter((bundle) => !enabledBundles.some((activeBundle) => activeBundle.id === bundle.id))
711
+ .slice(0, 4)
712
+ .map((bundle) => {
713
+ const readiness = evaluateAgentSkillBundleReadiness(bundle, snapshot.skills);
714
+ const review = bundle.reviewState === 'reviewed' ? '' : `review=${formatAgentRecordReviewState(bundle.reviewState)}`;
715
+ const setup = readiness.ready ? '' : `missing=${[
716
+ ...readiness.missingRequirements.map(formatAgentSkillRequirement),
717
+ ...readiness.missingSkillIds.map((skillId) => `skill:${skillId}`),
718
+ ].join(', ')}`;
719
+ const unreviewedSkills = readiness.includedSkills
720
+ .filter((skill) => skill.reviewState !== 'reviewed')
721
+ .map((skill) => `${skill.id}:${formatAgentRecordReviewState(skill.reviewState)}`);
722
+ const memberReview = unreviewedSkills.length === 0 ? '' : `member-review=${unreviewedSkills.join(', ')}`;
723
+ return `- ${bundle.name}: ${[review, setup, memberReview].filter(Boolean).join('; ')}`;
724
+ });
725
+ if (active.length === 0 && enabledBundles.length === 0 && suppressedSkills.length === 0 && suppressedBundles.length === 0) return null;
759
726
  return [
760
727
  '## Enabled GoodVibes Agent Skills',
761
- 'Use these local reusable procedures inside the same serial assistant conversation when they fit the user request.',
728
+ 'Use only reviewed, setup-ready local reusable procedures inside the same serial assistant conversation when they fit the user request.',
762
729
  '',
763
- ...snapshot.enabledBundles.slice(0, 4).flatMap((bundle) => {
730
+ ...enabledBundles.slice(0, 4).flatMap((bundle) => {
764
731
  const readiness = evaluateAgentSkillBundleReadiness(bundle, snapshot.skills);
765
732
  const missing = [
766
733
  ...readiness.missingRequirements.map(formatAgentSkillRequirement),
@@ -784,5 +751,12 @@ export function buildEnabledSkillsPrompt(shellPaths: ShellPathService): string |
784
751
  skill.procedure,
785
752
  '',
786
753
  ]),
754
+ ...(suppressedBundles.length > 0 || suppressedSkills.length > 0 ? [
755
+ '### Suppressed Skills Pending Review Or Setup',
756
+ 'Do not apply these skills until the user reviews them or resolves setup through the learning curator.',
757
+ ...suppressedBundles,
758
+ ...suppressedSkills,
759
+ '',
760
+ ] : []),
787
761
  ].join('\n').trim();
788
762
  }
@@ -0,0 +1,62 @@
1
+ export function vibeRouteArg(value: string): string {
2
+ return JSON.stringify(value);
3
+ }
4
+
5
+ function routeLine(id: string, route: string): string {
6
+ return ` ${id} ${route}`;
7
+ }
8
+
9
+ export function vibeInitConfirmationRoutes(scope: 'project' | 'global', force = false): Record<string, string> {
10
+ const model = [
11
+ 'vibe action:"init"',
12
+ `scope:${vibeRouteArg(scope)}`,
13
+ force ? 'force:true' : '',
14
+ 'confirm:true',
15
+ 'explicitUserRequest:"..."',
16
+ ].filter(Boolean).join(' ');
17
+ const cli = [
18
+ '/vibe init',
19
+ scope === 'global' ? '--global' : '',
20
+ force ? '--force' : '',
21
+ '--yes',
22
+ ].filter(Boolean).join(' ');
23
+ return { model, cli };
24
+ }
25
+
26
+ export function vibeImportPersonaConfirmationRoutes(input: {
27
+ readonly reference: string;
28
+ readonly name: string;
29
+ readonly description: string;
30
+ readonly review: boolean;
31
+ readonly use: boolean;
32
+ }): Record<string, string> {
33
+ const model = [
34
+ 'vibe action:"import_persona"',
35
+ `reference:${vibeRouteArg(input.reference)}`,
36
+ input.name ? `name:${vibeRouteArg(input.name)}` : '',
37
+ input.description ? `description:${vibeRouteArg(input.description)}` : '',
38
+ input.review ? 'review:true' : '',
39
+ input.use ? 'use:true' : '',
40
+ 'confirm:true',
41
+ 'explicitUserRequest:"..."',
42
+ ].filter(Boolean).join(' ');
43
+ const cli = [
44
+ '/vibe import-persona',
45
+ vibeRouteArg(input.reference),
46
+ input.name ? `--name ${vibeRouteArg(input.name)}` : '',
47
+ input.description ? `--description ${vibeRouteArg(input.description)}` : '',
48
+ input.review ? '--review' : '',
49
+ input.use ? '--use' : '',
50
+ '--yes',
51
+ ].filter(Boolean).join(' ');
52
+ return { model, cli };
53
+ }
54
+
55
+ export function formatVibeConfirmationRouteLines(routes: Record<string, string>): readonly string[] {
56
+ const entries = Object.entries(routes).filter(([, route]) => route.trim() !== '');
57
+ if (entries.length === 0) return [];
58
+ return [
59
+ ' confirmationRoutes',
60
+ ...entries.map(([id, route]) => routeLine(id, route)),
61
+ ];
62
+ }
@@ -0,0 +1,285 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname, isAbsolute, join, resolve } from 'node:path';
3
+ import type { ShellPathService } from '@/runtime/index.ts';
4
+ import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
5
+ import { assertNoSecretLikeText } from './persona-registry.ts';
6
+
7
+ export type AgentVibeScope = 'project' | 'global';
8
+
9
+ export interface AgentVibeFile {
10
+ readonly path: string;
11
+ readonly scope: AgentVibeScope;
12
+ readonly body: string;
13
+ readonly frontmatter: Record<string, string>;
14
+ readonly truncated: boolean;
15
+ }
16
+
17
+ export interface BlockedAgentVibeFile {
18
+ readonly path: string;
19
+ readonly scope: AgentVibeScope;
20
+ readonly reason: string;
21
+ }
22
+
23
+ export interface AgentVibeSnapshot {
24
+ readonly files: readonly AgentVibeFile[];
25
+ readonly blocked: readonly BlockedAgentVibeFile[];
26
+ readonly searchedPaths: readonly string[];
27
+ readonly projectInitPath: string;
28
+ readonly globalInitPath: string;
29
+ }
30
+
31
+ export interface AgentVibeInitOptions {
32
+ readonly scope?: AgentVibeScope;
33
+ readonly force?: boolean;
34
+ }
35
+
36
+ export interface AgentVibeInitResult {
37
+ readonly path: string;
38
+ readonly created: boolean;
39
+ }
40
+
41
+ export interface AgentVibeImportSource {
42
+ readonly name: string;
43
+ readonly description: string;
44
+ readonly body: string;
45
+ readonly path: string;
46
+ readonly scope: AgentVibeScope;
47
+ }
48
+
49
+ const MAX_VIBE_BODY_CHARS = 8_000;
50
+ const MAX_PROJECT_DEPTH = 32;
51
+
52
+ const DEFAULT_VIBE_BODY = [
53
+ '# VIBE.md',
54
+ '',
55
+ 'Describe how GoodVibes Agent should feel and work with you.',
56
+ '',
57
+ '- Be direct about tradeoffs.',
58
+ '- Prefer visible, reversible actions.',
59
+ '- Keep autonomous work user-supervised with clear status and cancel paths.',
60
+ '- Ask before sending messages, changing settings, or starting recurring work.',
61
+ ].join('\n');
62
+
63
+ type AgentVibePaths = Pick<ShellPathService,
64
+ 'workingDirectory' | 'homeDirectory' | 'resolveUserPath' | 'expandHomePath' | 'resolveWorkspacePath'
65
+ >;
66
+
67
+ function parseFrontmatter(content: string): Record<string, string> {
68
+ const match = content.match(/^---\n([\s\S]*?)\n---\n?/);
69
+ if (!match) return {};
70
+ const result: Record<string, string> = {};
71
+ for (const line of match[1].split('\n')) {
72
+ const [key, ...rest] = line.split(':');
73
+ if (key && rest.length > 0) result[key.trim()] = rest.join(':').trim();
74
+ }
75
+ return result;
76
+ }
77
+
78
+ function markdownBody(content: string): string {
79
+ const frontmatter = parseFrontmatter(content);
80
+ const body = (frontmatter.system_prompt ?? content.replace(/^---\n[\s\S]*?\n---\n?/, '')).trim();
81
+ return body;
82
+ }
83
+
84
+ function readVibeCandidate(path: string, scope: AgentVibeScope): AgentVibeFile | BlockedAgentVibeFile | null {
85
+ if (!existsSync(path)) return null;
86
+ let content = '';
87
+ try {
88
+ content = readFileSync(path, 'utf-8');
89
+ } catch (error) {
90
+ return {
91
+ path,
92
+ scope,
93
+ reason: `Could not read file: ${error instanceof Error ? error.message : String(error)}`,
94
+ };
95
+ }
96
+
97
+ const body = markdownBody(content);
98
+ if (!body) return {
99
+ path,
100
+ scope,
101
+ reason: 'File is empty after frontmatter.',
102
+ };
103
+
104
+ try {
105
+ assertNoSecretLikeText([content], 'VIBE.md');
106
+ } catch (error) {
107
+ return {
108
+ path,
109
+ scope,
110
+ reason: error instanceof Error ? error.message : String(error),
111
+ };
112
+ }
113
+
114
+ return {
115
+ path,
116
+ scope,
117
+ body: body.length > MAX_VIBE_BODY_CHARS ? body.slice(0, MAX_VIBE_BODY_CHARS).trimEnd() : body,
118
+ frontmatter: parseFrontmatter(content),
119
+ truncated: body.length > MAX_VIBE_BODY_CHARS,
120
+ };
121
+ }
122
+
123
+ function projectWalkRoots(workingDirectory: string): readonly string[] {
124
+ const roots: string[] = [];
125
+ let current = resolve(workingDirectory);
126
+ let foundGitRoot = false;
127
+ for (let depth = 0; depth < MAX_PROJECT_DEPTH; depth += 1) {
128
+ roots.push(current);
129
+ if (existsSync(join(current, '.git'))) {
130
+ foundGitRoot = true;
131
+ break;
132
+ }
133
+ const parent = dirname(current);
134
+ if (parent === current) break;
135
+ current = parent;
136
+ }
137
+ if (!foundGitRoot) return [resolve(workingDirectory)];
138
+ return roots.reverse();
139
+ }
140
+
141
+ function candidatePaths(shellPaths: AgentVibePaths): readonly { readonly path: string; readonly scope: AgentVibeScope }[] {
142
+ const candidates: Array<{ path: string; scope: AgentVibeScope }> = [];
143
+ candidates.push({ path: join(shellPaths.homeDirectory, '.goodvibes', 'VIBE.md'), scope: 'global' });
144
+ candidates.push({ path: shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'VIBE.md'), scope: 'global' });
145
+ for (const root of projectWalkRoots(shellPaths.workingDirectory)) {
146
+ candidates.push({ path: join(root, 'VIBE.md'), scope: 'project' });
147
+ candidates.push({ path: join(root, '.goodvibes', 'VIBE.md'), scope: 'project' });
148
+ candidates.push({ path: join(root, '.goodvibes', GOODVIBES_AGENT_SURFACE_ROOT, 'VIBE.md'), scope: 'project' });
149
+ }
150
+ return candidates;
151
+ }
152
+
153
+ function dedupeCandidates(candidates: readonly { readonly path: string; readonly scope: AgentVibeScope }[]): readonly { readonly path: string; readonly scope: AgentVibeScope }[] {
154
+ const seen = new Set<string>();
155
+ const result: Array<{ path: string; scope: AgentVibeScope }> = [];
156
+ for (const candidate of candidates) {
157
+ const key = resolve(candidate.path);
158
+ if (seen.has(key)) continue;
159
+ seen.add(key);
160
+ result.push({ path: key, scope: candidate.scope });
161
+ }
162
+ return result;
163
+ }
164
+
165
+ export function projectVibeInitPath(shellPaths: Pick<ShellPathService, 'workingDirectory'>): string {
166
+ return join(shellPaths.workingDirectory, 'VIBE.md');
167
+ }
168
+
169
+ export function globalVibeInitPath(shellPaths: Pick<ShellPathService, 'resolveUserPath'>): string {
170
+ return shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'VIBE.md');
171
+ }
172
+
173
+ export function discoverVibeFiles(shellPaths: AgentVibePaths): AgentVibeSnapshot {
174
+ const files: AgentVibeFile[] = [];
175
+ const blocked: BlockedAgentVibeFile[] = [];
176
+ const candidates = dedupeCandidates(candidatePaths(shellPaths));
177
+ for (const candidate of candidates) {
178
+ const record = readVibeCandidate(candidate.path, candidate.scope);
179
+ if (!record) continue;
180
+ if ('body' in record) files.push(record);
181
+ else blocked.push(record);
182
+ }
183
+ return {
184
+ files,
185
+ blocked,
186
+ searchedPaths: candidates.map((candidate) => candidate.path),
187
+ projectInitPath: projectVibeInitPath(shellPaths),
188
+ globalInitPath: globalVibeInitPath(shellPaths),
189
+ };
190
+ }
191
+
192
+ function vibeHeading(file: AgentVibeFile): string {
193
+ const name = file.frontmatter.name?.trim();
194
+ const label = file.scope === 'global' ? 'Global' : 'Project';
195
+ return `${label} VIBE.md${name ? ` - ${name}` : ''}`;
196
+ }
197
+
198
+ export function buildVibePrompt(shellPaths: AgentVibePaths): string | null {
199
+ const snapshot = discoverVibeFiles(shellPaths);
200
+ if (snapshot.files.length === 0 && snapshot.blocked.length === 0) return null;
201
+
202
+ const lines: string[] = [
203
+ '## GoodVibes Agent VIBE.md',
204
+ 'These user-authored vibe/personality instructions shape the same serial assistant conversation. Follow them only when they do not conflict with explicit user instructions, safety policy, tool contracts, confirmation requirements, or secret-handling rules.',
205
+ ];
206
+
207
+ for (const file of snapshot.files) {
208
+ lines.push('', `### ${vibeHeading(file)}`, `Source: ${file.path}`, '', file.body);
209
+ if (file.truncated) lines.push('', `[VIBE.md truncated to ${MAX_VIBE_BODY_CHARS} characters for prompt safety.]`);
210
+ }
211
+
212
+ if (snapshot.blocked.length > 0) {
213
+ lines.push('', '### Blocked VIBE.md Files');
214
+ for (const blocked of snapshot.blocked) {
215
+ lines.push(`- ${blocked.path}: ${blocked.reason}`);
216
+ }
217
+ lines.push('Blocked VIBE.md content was not loaded.');
218
+ }
219
+
220
+ return lines.join('\n');
221
+ }
222
+
223
+ export function formatVibeStatus(snapshot: AgentVibeSnapshot): string {
224
+ const lines: string[] = [
225
+ 'GoodVibes Agent VIBE.md',
226
+ ` applied ${snapshot.files.length}`,
227
+ ` blocked ${snapshot.blocked.length}`,
228
+ ` project init ${snapshot.projectInitPath}`,
229
+ ` global init ${snapshot.globalInitPath}`,
230
+ ];
231
+ if (snapshot.files.length > 0) {
232
+ lines.push('', 'Applied files');
233
+ for (const file of snapshot.files) {
234
+ const suffix = file.truncated ? ' truncated' : '';
235
+ lines.push(` ${file.scope} ${file.path}${suffix}`);
236
+ }
237
+ }
238
+ if (snapshot.blocked.length > 0) {
239
+ lines.push('', 'Blocked files');
240
+ for (const blocked of snapshot.blocked) lines.push(` ${blocked.scope} ${blocked.path} - ${blocked.reason}`);
241
+ }
242
+ lines.push(
243
+ '',
244
+ 'Next',
245
+ ' /vibe init --yes',
246
+ ' /vibe init --global --yes',
247
+ ' /vibe import-persona project --review --use --yes',
248
+ );
249
+ return lines.join('\n');
250
+ }
251
+
252
+ export function initVibeFile(shellPaths: AgentVibePaths, options: AgentVibeInitOptions = {}): AgentVibeInitResult {
253
+ const path = options.scope === 'global' ? globalVibeInitPath(shellPaths) : projectVibeInitPath(shellPaths);
254
+ if (existsSync(path) && !options.force) return { path, created: false };
255
+ mkdirSync(dirname(path), { recursive: true });
256
+ writeFileSync(path, `${DEFAULT_VIBE_BODY}\n`, 'utf-8');
257
+ return { path, created: true };
258
+ }
259
+
260
+ export function resolveVibePathReference(shellPaths: AgentVibePaths, reference: string): string {
261
+ const trimmed = reference.trim();
262
+ if (!trimmed || trimmed === 'project') return projectVibeInitPath(shellPaths);
263
+ if (trimmed === 'global') return globalVibeInitPath(shellPaths);
264
+ const expanded = shellPaths.expandHomePath(trimmed);
265
+ return isAbsolute(expanded) ? resolve(expanded) : shellPaths.resolveWorkspacePath(expanded);
266
+ }
267
+
268
+ export function loadVibeImportSource(shellPaths: AgentVibePaths, reference: string): AgentVibeImportSource {
269
+ const path = resolveVibePathReference(shellPaths, reference);
270
+ const scope: AgentVibeScope = path.startsWith(resolve(shellPaths.homeDirectory, '.goodvibes')) ? 'global' : 'project';
271
+ const record = readVibeCandidate(path, scope);
272
+ if (!record) throw new Error(`No VIBE.md found at ${path}`);
273
+ if (!('body' in record)) throw new Error(`Cannot import VIBE.md from ${path}: ${record.reason}`);
274
+ const name = record.frontmatter.name?.trim() || (record.scope === 'global' ? 'Global Vibe' : 'Project Vibe');
275
+ const description = record.frontmatter.description?.trim()
276
+ || record.frontmatter.summary?.trim()
277
+ || `Imported ${record.scope} VIBE.md personality instructions.`;
278
+ return {
279
+ name,
280
+ description,
281
+ body: record.body,
282
+ path: record.path,
283
+ scope: record.scope,
284
+ };
285
+ }
@@ -282,7 +282,7 @@ export async function handleAgentKnowledgeCommand(runtime: CliCommandRuntime): P
282
282
  };
283
283
  }
284
284
 
285
- if (normalized === 'ingest-file' || normalized === 'ingest-artifact') {
285
+ if (normalized === 'ingest-file') {
286
286
  const values = commandValues(rest);
287
287
  const path = values[0];
288
288
  if (!path) return { output: 'Usage: goodvibes-agent knowledge ingest-file <path> [--title <title>] [--tags a,b] [--folder <path>] --yes', exitCode: 2 };
@@ -326,6 +326,49 @@ export async function handleAgentKnowledgeCommand(runtime: CliCommandRuntime): P
326
326
  };
327
327
  }
328
328
 
329
+ if (normalized === 'ingest-artifact') {
330
+ const values = commandValues(rest);
331
+ const artifactId = values[0];
332
+ if (!artifactId) return { output: 'Usage: goodvibes-agent knowledge ingest-artifact <artifactId> [--title <title>] [--tags a,b] [--folder <path>] --yes', exitCode: 2 };
333
+ if (!confirmation.present) {
334
+ const failure = {
335
+ ok: false,
336
+ kind: 'confirmation_required',
337
+ error: `Refusing to ingest artifact into Agent Knowledge ${artifactId} without --yes.`,
338
+ route: AGENT_KNOWLEDGE_METHODS.ingestArtifact.route,
339
+ };
340
+ return {
341
+ output: json ? JSON.stringify(failure, null, 2) : `${failure.error}\nUsage: goodvibes-agent knowledge ingest-artifact <artifactId> [--title <title>] [--tags a,b] [--folder <path>] --yes`,
342
+ exitCode: 2,
343
+ };
344
+ }
345
+ const title = readOptionValue(rest, '--title');
346
+ const tags = readStringList(rest, '--tags');
347
+ const folderPath = readOptionValue(rest, '--folder');
348
+ const connectorId = readOptionValue(rest, '--connector') ?? 'goodvibes-agent-artifact-browser';
349
+ const result = await runKnowledgeCall(runtime, AGENT_KNOWLEDGE_METHODS.ingestArtifact, async (connection) => (
350
+ await postAgentKnowledgeJson(connection, AGENT_KNOWLEDGE_METHODS.ingestArtifact.route, {
351
+ artifactId,
352
+ title,
353
+ tags,
354
+ folderPath,
355
+ connectorId,
356
+ metadata: { originSurface: 'goodvibes-agent-cli' },
357
+ })
358
+ ));
359
+ if (!result.ok) return { output: formatFailure(result, json), exitCode: 1 };
360
+ return {
361
+ output: formatJsonOrText(runtime.cli)(result, formatIngest(
362
+ result.data,
363
+ artifactId,
364
+ 'ingest-artifact',
365
+ '/api/goodvibes-agent/knowledge/ingest/artifact',
366
+ 'artifact',
367
+ )),
368
+ exitCode: 0,
369
+ };
370
+ }
371
+
329
372
  if (normalized === 'import-urls' || normalized === 'import-bookmarks') {
330
373
  const values = commandValues(rest);
331
374
  const path = values[0];
@@ -460,7 +503,7 @@ export async function handleAgentKnowledgeCommand(runtime: CliCommandRuntime): P
460
503
  }
461
504
 
462
505
  return {
463
- output: 'Usage: goodvibes-agent knowledge [status|ask <question>|search <query>|list|sources|nodes|issues|get <id>|map|connectors|ingest-url <url> --yes|ingest-file <path> --yes|ingest-connector <id> --yes|import-urls <path> --yes|import-bookmarks <path> --yes|import-browser-history --yes|reindex --yes]',
506
+ output: 'Usage: goodvibes-agent knowledge [status|ask <question>|search <query>|list|sources|nodes|issues|get <id>|map|connectors|ingest-url <url> --yes|ingest-file <path> --yes|ingest-artifact <artifactId> --yes|ingest-connector <id> --yes|import-urls <path> --yes|import-bookmarks <path> --yes|import-browser-history --yes|reindex --yes]',
464
507
  exitCode: 2,
465
508
  };
466
509
  }
package/src/cli/help.ts CHANGED
@@ -38,6 +38,7 @@ export function renderGoodVibesHelp(binary = 'goodvibes-agent'): string {
38
38
  ' /model Choose provider and model',
39
39
  ' /knowledge Use isolated Agent Knowledge',
40
40
  ' /notes Open Agent-local scratchpad notes',
41
+ ' /vibe Inspect or create VIBE.md personality',
41
42
  ' /personas, /skills Tune Agent-local behavior',
42
43
  ' /routines Run local routines in the main conversation',
43
44
  ' /schedule remind Create confirmed reminders or inspect schedules',
@@ -309,6 +310,7 @@ const COMMAND_HELP: Record<string, CommandHelp> = {
309
310
  'knowledge connectors [connectorId|doctor <connectorId>]',
310
311
  'knowledge ingest-url <url> [--title <title>] [--tags a,b] --yes',
311
312
  'knowledge ingest-file <path> [--title <title>] [--tags a,b] --yes',
313
+ 'knowledge ingest-artifact <artifactId> [--title <title>] [--tags a,b] --yes',
312
314
  'knowledge ingest-connector <connectorId> [--input <json-or-text>|--path <path>|--content <text>] --yes',
313
315
  'knowledge import-urls <path> --yes',
314
316
  'knowledge import-bookmarks <path> --yes',
@@ -325,6 +327,7 @@ const COMMAND_HELP: Record<string, CommandHelp> = {
325
327
  'knowledge connectors doctor url',
326
328
  'knowledge ingest-url https://example.com/page --title "Reference" --yes',
327
329
  'knowledge ingest-file ./docs/guide.md --title "Guide" --yes',
330
+ 'knowledge ingest-artifact artifact-123 --title "Reviewed Export" --yes',
328
331
  'knowledge ingest-connector url --input https://example.com/reference --yes',
329
332
  'knowledge import-urls ~/agent-links.txt --yes',
330
333
  'knowledge import-browser-history --browsers chrome,firefox --sources history,bookmark --yes',