@pellux/goodvibes-agent 1.1.6 → 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 (256) hide show
  1. package/CHANGELOG.md +176 -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 +132662 -91399
  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 +43 -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 +287 -0
  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 +267 -10
  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 +110 -89
  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/tools/tool-execution-safety.ts +41 -0
  256. package/src/version.ts +1 -1
@@ -1,9 +1,10 @@
1
1
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
2
- import { dirname, join } from 'node:path';
2
+ import { dirname, isAbsolute, join, resolve } from 'node:path';
3
3
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
4
- import { AgentPersonaRegistry } from './persona-registry.ts';
4
+ import { AgentPersonaRegistry, assertNoSecretLikeText } from './persona-registry.ts';
5
5
  import { AgentRoutineRegistry } from './routine-registry.ts';
6
6
  import { AgentSkillRegistry } from './skill-registry.ts';
7
+ import { discoverVibeFiles } from './vibe-file.ts';
7
8
  import { discoverPersonas, type DiscoveredPersonaRecord } from './persona-discovery.ts';
8
9
  import { discoverRoutines, type DiscoveredRoutineRecord } from './routine-discovery.ts';
9
10
  import { discoverSkills, type SkillRecord } from './skill-discovery.ts';
@@ -20,6 +21,7 @@ export interface AgentRuntimeProfileTemplateSummary {
20
21
  readonly personaName: string;
21
22
  readonly skillNames: readonly string[];
22
23
  readonly routineNames: readonly string[];
24
+ readonly vibeIncluded?: boolean;
23
25
  readonly source: AgentRuntimeProfileTemplateSource;
24
26
  readonly path?: string;
25
27
  }
@@ -50,12 +52,22 @@ export interface AgentRuntimeProfileTemplateApplication {
50
52
  readonly personaIds: readonly string[];
51
53
  readonly skillIds: readonly string[];
52
54
  readonly routineIds: readonly string[];
55
+ readonly vibePath?: string;
53
56
  }
54
57
 
55
58
  export interface CreateAgentRuntimeProfileOptions {
56
59
  readonly templateId?: AgentRuntimeProfileTemplateId;
57
60
  }
58
61
 
62
+ type AgentRuntimeProfileTemplateShellPaths =
63
+ Pick<ShellPathService, 'homeDirectory' | 'workingDirectory'>
64
+ & Partial<Pick<ShellPathService, 'resolveUserPath' | 'expandHomePath' | 'resolveWorkspacePath'>>;
65
+
66
+ export interface AgentRuntimeProfileTemplateExportOptions {
67
+ readonly includeVibe?: boolean;
68
+ readonly shellPaths?: AgentRuntimeProfileTemplateShellPaths;
69
+ }
70
+
59
71
  export interface CreateAgentRuntimeProfileTemplateFromDiscoveredOptions {
60
72
  readonly id: AgentRuntimeProfileTemplateId;
61
73
  readonly name?: string;
@@ -63,6 +75,7 @@ export interface CreateAgentRuntimeProfileTemplateFromDiscoveredOptions {
63
75
  readonly persona?: string;
64
76
  readonly skills?: readonly string[];
65
77
  readonly routines?: readonly string[];
78
+ readonly includeVibe?: boolean;
66
79
  readonly replace?: boolean;
67
80
  }
68
81
 
@@ -242,6 +255,7 @@ function summarizeTemplate(template: AgentRuntimeProfileStarterTemplate): AgentR
242
255
  personaName: template.personaName,
243
256
  skillNames: [...template.skillNames],
244
257
  routineNames: [...template.routineNames],
258
+ vibeIncluded: Boolean(template.vibe?.body.trim()),
245
259
  source: template.source,
246
260
  path: template.path,
247
261
  };
@@ -350,6 +364,73 @@ function parseTemplateRoutine(value: unknown): AgentRuntimeProfileStarterTemplat
350
364
  };
351
365
  }
352
366
 
367
+ function parseTemplateVibe(value: unknown): AgentRuntimeProfileStarterTemplate['vibe'] | undefined {
368
+ if (value === undefined || value === null) return undefined;
369
+ const record = readTemplateObject(value, 'vibe');
370
+ const body = readTemplateTextBlock(record.body, 'vibe.body');
371
+ assertNoSecretLikeText([body], 'Agent starter VIBE.md');
372
+ const source = record.source === 'template' ? 'template' : 'discovered';
373
+ const appliedAs = record.appliedAs === 'global' ? 'global' : 'global';
374
+ const truncated = typeof record.truncated === 'number' && Number.isFinite(record.truncated)
375
+ ? Math.max(0, Math.trunc(record.truncated))
376
+ : 0;
377
+ return {
378
+ body,
379
+ source,
380
+ appliedAs,
381
+ sourcePaths: parseStringArray(record.sourcePaths),
382
+ truncated,
383
+ };
384
+ }
385
+
386
+ function profileTemplateVibeShellPaths(shellPaths: AgentRuntimeProfileTemplateShellPaths): Parameters<typeof discoverVibeFiles>[0] {
387
+ return {
388
+ homeDirectory: shellPaths.homeDirectory,
389
+ workingDirectory: shellPaths.workingDirectory,
390
+ resolveUserPath: shellPaths.resolveUserPath ?? ((...parts: string[]) => join(shellPaths.homeDirectory, '.goodvibes', ...parts)),
391
+ expandHomePath: shellPaths.expandHomePath ?? ((value: string) => value.startsWith('~/') ? join(shellPaths.homeDirectory, value.slice(2)) : value),
392
+ resolveWorkspacePath: shellPaths.resolveWorkspacePath ?? ((value: string) => {
393
+ const expanded = value.startsWith('~/') ? join(shellPaths.homeDirectory, value.slice(2)) : value;
394
+ return isAbsolute(expanded) ? resolve(expanded) : resolve(shellPaths.workingDirectory, expanded);
395
+ }),
396
+ };
397
+ }
398
+
399
+ function discoveredVibeToTemplate(
400
+ shellPaths: AgentRuntimeProfileTemplateExportOptions['shellPaths'],
401
+ ): AgentRuntimeProfileStarterTemplate['vibe'] | undefined {
402
+ if (!shellPaths) throw new Error('Including VIBE.md in a starter template requires shell path context.');
403
+ const snapshot = discoverVibeFiles(profileTemplateVibeShellPaths(shellPaths));
404
+ if (snapshot.blocked.length > 0) {
405
+ throw new Error(`Cannot include VIBE.md in a starter template while ${snapshot.blocked.length} VIBE.md file is blocked. Run /vibe status and repair it first.`);
406
+ }
407
+ if (snapshot.files.length === 0) return undefined;
408
+ const body = snapshot.files.map((file) => [
409
+ `## ${file.scope === 'global' ? 'Global' : 'Project'} VIBE.md`,
410
+ `Source: ${file.path}`,
411
+ '',
412
+ file.body,
413
+ file.truncated ? '[This VIBE.md was truncated before profile starter export.]' : '',
414
+ ].filter(Boolean).join('\n')).join('\n\n');
415
+ assertNoSecretLikeText([body], 'Agent starter VIBE.md');
416
+ return {
417
+ body,
418
+ source: 'discovered',
419
+ appliedAs: 'global',
420
+ sourcePaths: snapshot.files.map((file) => file.path),
421
+ truncated: snapshot.files.filter((file) => file.truncated).length,
422
+ };
423
+ }
424
+
425
+ function withOptionalVibe(
426
+ template: AgentRuntimeProfileStarterTemplate,
427
+ options: AgentRuntimeProfileTemplateExportOptions | undefined,
428
+ ): AgentRuntimeProfileStarterTemplate {
429
+ if (options?.includeVibe !== true) return template;
430
+ const vibe = discoveredVibeToTemplate(options.shellPaths);
431
+ return vibe ? { ...template, vibe } : template;
432
+ }
433
+
353
434
  function parseStarterTemplate(raw: unknown, source: AgentRuntimeProfileTemplateSource, path?: string): AgentRuntimeProfileStarterTemplate {
354
435
  const file = readTemplateObject(raw, 'file');
355
436
  const templateRecord = readTemplateObject(file.template ?? raw, 'template');
@@ -357,6 +438,7 @@ function parseStarterTemplate(raw: unknown, source: AgentRuntimeProfileTemplateS
357
438
  const personaRecord = readTemplateObject(templateRecord.persona, 'persona');
358
439
  const skills = Array.isArray(templateRecord.skills) ? templateRecord.skills.map(parseTemplateSkill) : [];
359
440
  const routines = Array.isArray(templateRecord.routines) ? templateRecord.routines.map(parseTemplateRoutine) : [];
441
+ const vibe = parseTemplateVibe(templateRecord.vibe);
360
442
  if (skills.length === 0) throw new Error(`Starter template ${id} must include at least one skill.`);
361
443
  if (routines.length === 0) throw new Error(`Starter template ${id} must include at least one routine.`);
362
444
  const persona = {
@@ -378,6 +460,7 @@ function parseStarterTemplate(raw: unknown, source: AgentRuntimeProfileTemplateS
378
460
  persona,
379
461
  skills,
380
462
  routines,
463
+ ...(vibe ? { vibe: { ...vibe, source: 'template' } } : {}),
381
464
  };
382
465
  }
383
466
 
@@ -434,8 +517,13 @@ function templateFilePayload(template: AgentRuntimeProfileStarterTemplate): Agen
434
517
  };
435
518
  }
436
519
 
437
- export function exportAgentRuntimeProfileTemplate(baseHomeDirectory: string, templateId: AgentRuntimeProfileTemplateId, outputPath: string): AgentRuntimeProfileTemplateSummary {
438
- const template = resolveAgentRuntimeProfileTemplate(templateId, baseHomeDirectory);
520
+ export function exportAgentRuntimeProfileTemplate(
521
+ baseHomeDirectory: string,
522
+ templateId: AgentRuntimeProfileTemplateId,
523
+ outputPath: string,
524
+ options: AgentRuntimeProfileTemplateExportOptions = {},
525
+ ): AgentRuntimeProfileTemplateSummary {
526
+ const template = withOptionalVibe(resolveAgentRuntimeProfileTemplate(templateId, baseHomeDirectory), options);
439
527
  const target = outputPath.trim();
440
528
  if (!target) throw new Error('Template export path is required.');
441
529
  mkdirSync(dirname(target), { recursive: true });
@@ -472,6 +560,7 @@ export async function createAgentRuntimeProfileTemplateFromDiscovered(
472
560
  throw new Error(`Agent starter template already exists ${id}. Rerun with --replace to overwrite it.`);
473
561
  }
474
562
  const persona = discoveredPersonaToTemplate(selectedPersona);
563
+ const vibe = options.includeVibe ? discoveredVibeToTemplate(shellPaths) : undefined;
475
564
  const template: AgentRuntimeProfileStarterTemplate = {
476
565
  id,
477
566
  source: 'local',
@@ -484,6 +573,7 @@ export async function createAgentRuntimeProfileTemplateFromDiscovered(
484
573
  persona,
485
574
  skills: selectedSkills.map(discoveredSkillToTemplate),
486
575
  routines: selectedRoutines.map(discoveredRoutineToTemplate),
576
+ ...(vibe ? { vibe } : {}),
487
577
  };
488
578
  mkdirSync(dirname(target), { recursive: true });
489
579
  writeFileSync(target, `${JSON.stringify(templateFilePayload(template), null, 2)}\n`, 'utf-8');
@@ -510,6 +600,7 @@ export async function createAgentRuntimeProfileFromDiscovered(
510
600
  persona: options.persona,
511
601
  skills: options.skills,
512
602
  routines: options.routines,
603
+ includeVibe: options.includeVibe,
513
604
  replace: options.replace,
514
605
  });
515
606
  const profile = createAgentRuntimeProfile(shellPaths.homeDirectory, profileId, { templateId: template.id });
@@ -546,6 +637,15 @@ function createMissingRoutine(registry: AgentRoutineRegistry, template: AgentRun
546
637
  }).id;
547
638
  }
548
639
 
640
+ function writeTemplateVibe(homeDirectory: string, template: AgentRuntimeProfileStarterTemplate): string | undefined {
641
+ if (!template.vibe?.body.trim()) return undefined;
642
+ assertNoSecretLikeText([template.vibe.body], 'Agent starter VIBE.md');
643
+ const path = join(homeDirectory, '.goodvibes', GOODVIBES_AGENT_SURFACE_ROOT, 'VIBE.md');
644
+ mkdirSync(dirname(path), { recursive: true });
645
+ writeFileSync(path, `${template.vibe.body.trimEnd()}\n`, 'utf-8');
646
+ return path;
647
+ }
648
+
549
649
  export function applyAgentRuntimeProfileTemplate(homeDirectory: string, templateId: AgentRuntimeProfileTemplateId, baseHomeDirectory?: string): AgentRuntimeProfileTemplateApplication {
550
650
  const template = resolveAgentRuntimeProfileTemplate(templateId, baseHomeDirectory);
551
651
  const personaRegistry = new AgentPersonaRegistry(profileStorePath(homeDirectory, 'personas', 'personas.json'));
@@ -564,6 +664,7 @@ export function applyAgentRuntimeProfileTemplate(homeDirectory: string, template
564
664
  personaRegistry.setActive(persona.id);
565
665
  const skillIds = template.skills.map((skill) => createMissingSkill(skillRegistry, skill));
566
666
  const routineIds = template.routines.map((routine) => createMissingRoutine(routineRegistry, routine));
667
+ const vibePath = writeTemplateVibe(homeDirectory, template);
567
668
  return {
568
669
  id: template.id,
569
670
  name: template.name,
@@ -572,6 +673,7 @@ export function applyAgentRuntimeProfileTemplate(homeDirectory: string, template
572
673
  personaIds: [persona.id],
573
674
  skillIds,
574
675
  routineIds,
676
+ ...(vibePath ? { vibePath } : {}),
575
677
  };
576
678
  }
577
679
 
@@ -0,0 +1,129 @@
1
+ import { formatEveryInterval } from '@pellux/goodvibes-sdk/platform/automation';
2
+ import type {
3
+ ScheduleEditFailure,
4
+ ScheduleEditPreview,
5
+ ScheduleEditSuccess,
6
+ } from './schedule-edit.ts';
7
+ import { scheduleConfirmationRouteLines, scheduleNextRouteLines, scheduleRouteArg } from './schedule-next-routes.ts';
8
+
9
+ function isRecord(value: unknown): value is Record<string, unknown> {
10
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
11
+ }
12
+
13
+ function readString(record: Record<string, unknown>, key: string): string | null {
14
+ const value = record[key];
15
+ return typeof value === 'string' ? value : null;
16
+ }
17
+
18
+ function scheduleValue(schedule: unknown): string {
19
+ if (!isRecord(schedule)) return 'unchanged';
20
+ if (schedule.kind === 'cron') {
21
+ return [
22
+ readString(schedule, 'expression') ?? '',
23
+ readString(schedule, 'timezone') ? `[${readString(schedule, 'timezone')}]` : '',
24
+ typeof schedule.staggerMs === 'number' ? `[stagger ${schedule.staggerMs}ms]` : '',
25
+ ].filter(Boolean).join(' ');
26
+ }
27
+ if (schedule.kind === 'every' && typeof schedule.intervalMs === 'number') return formatEveryInterval(schedule.intervalMs);
28
+ if (schedule.kind === 'at' && typeof schedule.at === 'number') return new Date(schedule.at).toISOString();
29
+ return String(schedule.kind ?? 'unknown');
30
+ }
31
+
32
+ function patchScheduleValue(preview: ScheduleEditPreview): string {
33
+ return scheduleValue(preview.payload.schedule);
34
+ }
35
+
36
+ function scheduleEditConfirmationRoute(preview: ScheduleEditPreview): string {
37
+ const args = [
38
+ 'schedule action:"edit"',
39
+ `scheduleId:${scheduleRouteArg(preview.scheduleId)}`,
40
+ ];
41
+ if (preview.payload.name) args.push(`name:${scheduleRouteArg(String(preview.payload.name))}`);
42
+ if (preview.payload.schedule) {
43
+ const schedule = preview.payload.schedule;
44
+ if (isRecord(schedule) && typeof schedule.kind === 'string') {
45
+ args.push(`scheduleKind:${scheduleRouteArg(schedule.kind)}`);
46
+ args.push(`scheduleValue:${scheduleRouteArg(scheduleValue(schedule))}`);
47
+ }
48
+ }
49
+ if (preview.payload.prompt) args.push('prompt:"..."');
50
+ args.push('confirm:true', 'explicitUserRequest:"..."');
51
+ return args.join(' ');
52
+ }
53
+
54
+ function formatCurrentScheduleDiff(preview: ScheduleEditPreview): readonly string[] {
55
+ const current = preview.current;
56
+ if (!current) return [];
57
+ const lines = [
58
+ ` current source ${current.method} GET ${current.route}`,
59
+ current.found
60
+ ? ` current status ${current.status ?? 'unknown'}`
61
+ : ` current schedule not found`,
62
+ current.note ? ` current note ${current.note}` : '',
63
+ ];
64
+ for (const diff of current.diffs) {
65
+ lines.push(` ${diff.field} ${diff.before} -> ${diff.after}${diff.changed ? '' : ' (unchanged)'}`);
66
+ }
67
+ return lines.filter((line) => line !== '');
68
+ }
69
+
70
+ function responseRecord(result: ScheduleEditSuccess): Record<string, unknown> {
71
+ return isRecord(result.schedule) ? result.schedule : {};
72
+ }
73
+
74
+ function formatScheduleEditFailureKind(kind: ScheduleEditFailure['kind']): string {
75
+ if (kind === 'confirmation_required') return 'confirmation required';
76
+ if (kind === 'auth_required') return 'authorization required';
77
+ if (kind === 'connected_host_unavailable') return 'connected host unavailable';
78
+ if (kind === 'connected_host_incompatible') return 'connected host incompatible';
79
+ if (kind === 'connected_host_route_unavailable') return 'connected host route unavailable';
80
+ return 'connected host error';
81
+ }
82
+
83
+ export function formatScheduleEditPreview(preview: ScheduleEditPreview): string {
84
+ return [
85
+ 'GoodVibes schedule edit preview',
86
+ ` method ${preview.method}`,
87
+ ` route PATCH ${preview.route.replace('{jobId}', preview.scheduleId)}`,
88
+ ` schedule ${preview.scheduleId}`,
89
+ ` changes ${preview.changes.join(', ')}`,
90
+ ...formatCurrentScheduleDiff(preview),
91
+ preview.payload.name ? ` name ${preview.payload.name}` : '',
92
+ preview.payload.schedule ? ` schedule ${patchScheduleValue(preview)}` : '',
93
+ preview.payload.prompt ? ' prompt replacement prepared' : '',
94
+ ` requested by ${preview.explicitUserRequest}`,
95
+ '',
96
+ 'Confirmation required: rerun with --yes or call the model tool with confirm:true only when the user explicitly asked for this exact schedule edit.',
97
+ ...scheduleConfirmationRouteLines({ model: scheduleEditConfirmationRoute(preview) }),
98
+ ].filter((line) => line !== '').join('\n');
99
+ }
100
+
101
+ export function formatScheduleEditSuccess(result: ScheduleEditSuccess): string {
102
+ const record = responseRecord(result);
103
+ const id = readString(record, 'id') ?? result.scheduleId;
104
+ const status = readString(record, 'status') ?? (record.enabled === false ? 'paused' : record.enabled === true ? 'enabled' : 'ok');
105
+ return [
106
+ 'Updated GoodVibes schedule',
107
+ ` schedule ${id}`,
108
+ ` method ${result.kind}`,
109
+ ` route PATCH ${result.route.replace('{jobId}', result.scheduleId)}`,
110
+ ` status ${status}`,
111
+ isRecord(record.schedule) ? ` schedule ${scheduleValue(record.schedule)}` : '',
112
+ ...scheduleNextRouteLines(id),
113
+ ].filter((line) => line !== '').join('\n');
114
+ }
115
+
116
+ export function formatScheduleEditFailure(failure: ScheduleEditFailure): string {
117
+ return [
118
+ `GoodVibes schedule edit error ${formatScheduleEditFailureKind(failure.kind)}`,
119
+ ` route PATCH ${failure.route}`,
120
+ failure.baseUrl ? ` connected host ${failure.baseUrl}` : '',
121
+ ` error ${failure.error}`,
122
+ failure.kind === 'auth_required'
123
+ ? ' next pair or start the connected GoodVibes host so an operator token is available.'
124
+ : '',
125
+ failure.kind === 'connected_host_incompatible'
126
+ ? ' next update the connected GoodVibes host so automation.jobs.patch is available.'
127
+ : '',
128
+ ].filter((line) => line !== '').join('\n');
129
+ }