@pellux/goodvibes-agent 0.1.55 → 0.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.goodvibes/GOODVIBES.md +1 -1
- package/CHANGELOG.md +19 -8
- package/README.md +10 -3
- package/docs/README.md +1 -1
- package/docs/getting-started.md +10 -3
- package/docs/release-and-publishing.md +12 -3
- package/package.json +1 -3
- package/scripts/check-bun.sh +5 -1
- package/src/agent/routine-schedule-args.ts +219 -0
- package/src/agent/routine-schedule-format.ts +173 -0
- package/src/agent/routine-schedule-promotion.ts +3 -811
- package/src/agent/routine-schedule-receipts.ts +502 -0
- package/src/cli/agent-knowledge-command.ts +6 -6
- package/src/cli/help.ts +3 -25
- package/src/cli/package-verification.ts +23 -16
- package/src/cli/redaction.ts +4 -1
- package/src/cli/routines-command.ts +10 -6
- package/src/cli/service-posture.ts +47 -280
- package/src/cli/status.ts +0 -1
- package/src/config/secret-config.ts +0 -2
- package/src/input/agent-workspace-categories.ts +219 -0
- package/src/input/agent-workspace-editors.ts +143 -0
- package/src/input/agent-workspace-snapshot.ts +265 -0
- package/src/input/agent-workspace-types.ts +142 -0
- package/src/input/agent-workspace.ts +22 -766
- package/src/input/commands/agent-runtime-profile-runtime.ts +1 -1
- package/src/input/commands/delegation-runtime.ts +1 -1
- package/src/input/commands/experience-runtime.ts +3 -4
- package/src/input/commands/guidance-runtime.ts +1 -2
- package/src/input/commands/health-runtime.ts +3 -65
- package/src/input/commands/knowledge.ts +7 -7
- package/src/input/commands/local-setup-review.ts +0 -61
- package/src/input/commands/local-setup-transfer.ts +0 -3
- package/src/input/commands/local-setup.ts +2 -15
- package/src/input/commands/planning-runtime.ts +4 -1
- package/src/input/commands/platform-access-runtime.ts +1 -10
- package/src/input/commands/platform-services-runtime.ts +0 -1
- package/src/input/commands/recall-query.ts +1 -1
- package/src/input/commands/routines-runtime.ts +10 -6
- package/src/input/commands/schedule-runtime.ts +10 -6
- package/src/input/commands/session-workflow.ts +1 -1
- package/src/input/commands/tasks-runtime.ts +1 -14
- package/src/input/commands.ts +0 -4
- package/src/input/handler-onboarding.ts +10 -120
- package/src/input/onboarding/onboarding-wizard-apply.ts +5 -196
- package/src/input/onboarding/onboarding-wizard-constants.ts +8 -119
- package/src/input/onboarding/onboarding-wizard-helpers.ts +2 -53
- package/src/input/onboarding/onboarding-wizard-rules.ts +2 -236
- package/src/input/onboarding/onboarding-wizard-state.ts +1 -69
- package/src/input/onboarding/onboarding-wizard-steps.ts +584 -737
- package/src/input/onboarding/onboarding-wizard-types.ts +8 -26
- package/src/input/onboarding/onboarding-wizard.ts +4 -109
- package/src/input/settings-modal-agent-policy.ts +10 -0
- package/src/input/settings-modal-types.ts +2 -4
- package/src/input/settings-modal.ts +3 -1
- package/src/input/submission-router.ts +0 -1
- package/src/panels/approval-panel.ts +1 -2
- package/src/panels/builtin/operations.ts +1 -2
- package/src/panels/knowledge-panel.ts +2 -2
- package/src/panels/project-planning-panel.ts +4 -1
- package/src/panels/provider-health-domains.ts +0 -22
- package/src/panels/provider-health-panel.ts +1 -5
- package/src/panels/session-browser-panel.ts +0 -5
- package/src/panels/tasks-panel.ts +2 -64
- package/src/renderer/agent-workspace.ts +1 -1
- package/src/renderer/help-overlay.ts +1 -2
- package/src/renderer/semantic-diff.ts +1 -1
- package/src/renderer/settings-modal-helpers.ts +0 -16
- package/src/renderer/settings-modal.ts +3 -5
- package/src/runtime/bootstrap-hook-bridge.ts +0 -3
- package/src/runtime/bootstrap-shell.ts +2 -1
- package/src/runtime/bootstrap.ts +1 -1
- package/src/runtime/index.ts +0 -1
- package/src/runtime/onboarding/derivation.ts +1 -28
- package/src/runtime/onboarding/snapshot.ts +0 -1
- package/src/runtime/onboarding/types.ts +1 -4
- package/src/runtime/services.ts +4 -23
- package/src/runtime/ui-read-models.ts +4 -3
- package/src/shell/service-settings-sync.ts +15 -244
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/wrfc-agent-guard.ts +3 -3
- package/src/verification/live-verifier.ts +11 -5
- package/src/verification/verification-ledger.ts +3 -6
- package/src/version.ts +1 -1
- package/src/input/commands/agent-externalized-tui.ts +0 -73
- package/src/input/commands/cloudflare-runtime.ts +0 -385
- package/src/input/handler-onboarding-cloudflare.ts +0 -322
- package/src/input/onboarding/onboarding-runtime-status.ts +0 -87
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +0 -494
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +0 -199
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +0 -130
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +0 -762
- package/src/runtime/cloudflare-control-plane.ts +0 -350
- package/src/runtime/sandbox-public-gaps.ts +0 -358
package/.goodvibes/GOODVIBES.md
CHANGED
|
@@ -22,7 +22,7 @@ GoodVibes Agent is a proactive personal operator assistant built on the GoodVibe
|
|
|
22
22
|
## Product Boundaries
|
|
23
23
|
|
|
24
24
|
- Agent connects to an already-running GoodVibes daemon. It does not start, restart, install, or own daemon/listener services.
|
|
25
|
-
- GoodVibes TUI owns coding execution, file edits, git/worktree lifecycle,
|
|
25
|
+
- GoodVibes TUI owns coding execution, file edits, git/worktree lifecycle, runtime-isolation UX, and WRFC owner chains.
|
|
26
26
|
- Agent owns personal operator flow, setup/config surfaces, local memory, local skills, local personas, Agent knowledge, status/approval/automation observability, and explicit delegation receipts.
|
|
27
27
|
|
|
28
28
|
## Engineering Rules
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GoodVibes Agent will be recorded here.
|
|
4
4
|
|
|
5
|
+
## 0.1.57 - 2026-05-31
|
|
6
|
+
|
|
7
|
+
- 90edab3 Expand Agent onboarding setup surfaces
|
|
8
|
+
- 251ae62 Guard package-facing Agent product language
|
|
9
|
+
|
|
10
|
+
## 0.1.56 - 2026-05-31
|
|
11
|
+
|
|
12
|
+
- a0b54e8 Document Bun global PATH setup
|
|
13
|
+
- f845cca Rename onboarding setup step
|
|
14
|
+
- 4462e52 Clarify Bun-only install path
|
|
15
|
+
|
|
5
16
|
## 0.1.55 - 2026-05-31
|
|
6
17
|
|
|
7
18
|
- d8f4eee Remove copied developer audit surfaces
|
|
@@ -188,7 +199,7 @@ All notable changes to GoodVibes Agent will be recorded here.
|
|
|
188
199
|
|
|
189
200
|
- d20a93e Allow explicit recall review without yes
|
|
190
201
|
- 601f41c Require confirmation for eval execution
|
|
191
|
-
- f41befb Block
|
|
202
|
+
- f41befb Block copied infrastructure onboarding mutations
|
|
192
203
|
- 79071ec Block implicit block file saves
|
|
193
204
|
- 40aca02 Block inline diff file edits in Agent
|
|
194
205
|
- 854eda8 Block MCP workspace config mutations
|
|
@@ -259,24 +270,24 @@ All notable changes to GoodVibes Agent will be recorded here.
|
|
|
259
270
|
## 0.1.7 - 2026-05-31
|
|
260
271
|
|
|
261
272
|
- Replaced active planning-loop output and tests that still described planning as TUI-owned with Agent-owned planning state and planning namespace language.
|
|
262
|
-
- Added `LICENSE` to the explicit package file contract and release verification so
|
|
273
|
+
- Added `LICENSE` to the explicit package file contract and release verification so registry tarballs cannot omit license text.
|
|
263
274
|
- Prevented the operator workspace from dispatching placeholder delegation commands such as `/delegate --wrfc <task>`; those actions now provide guidance until the user supplies real task text.
|
|
264
275
|
- Added local Agent routines with `/routines`: create/list/search/show/enable/disable/start/review/stale/delete, secret-looking value rejection, enabled routine prompt injection, and operator workspace status. Starting a routine stays in the main conversation and does not create hidden background jobs.
|
|
265
|
-
- Removed copied TUI release, UAT, and WRFC artifact docs from the Agent source tree and updated remaining source docs so channel,
|
|
276
|
+
- Removed copied TUI release, UAT, and WRFC artifact docs from the Agent source tree and updated remaining source docs so channel, voice, integration, and panel guidance speaks in Agent/external-daemon terms.
|
|
266
277
|
|
|
267
278
|
## 0.1.6 - 2026-05-31
|
|
268
279
|
|
|
269
280
|
- Made the publish helper use exported `NODE_AUTH_TOKEN` or `NPM_TOKEN` automatically by writing a temporary npm user config for publish commands.
|
|
270
|
-
- Rewrote source docs for tools, commands, knowledge, artifacts, and multimodal behavior so they describe Agent-only Knowledge/Wiki and never teach default Knowledge/Wiki or
|
|
281
|
+
- Rewrote source docs for tools, commands, knowledge, artifacts, and multimodal behavior so they describe Agent-only Knowledge/Wiki and never teach default Knowledge/Wiki or non-Agent graph fallback.
|
|
271
282
|
- Updated `/plan` command and Planning panel language from copied TUI-owned wording to Agent-owned workspace planning state.
|
|
272
283
|
- Added regression tests that keep source docs and active planning surfaces aligned with Agent Knowledge isolation and Agent product language.
|
|
273
284
|
|
|
274
285
|
## 0.1.5 - 2026-05-31
|
|
275
286
|
|
|
276
|
-
- Hardened package-facing release checks so shipped docs and Agent guidance cannot reintroduce default Knowledge/Wiki,
|
|
287
|
+
- Hardened package-facing release checks so shipped docs and Agent guidance cannot reintroduce default Knowledge/Wiki, non-Agent graph, copied daemon, or copied WRFC-first policy text.
|
|
277
288
|
- Removed the generic default `knowledgeApi` client from the active Agent command context so slash commands must use the isolated Agent Knowledge API.
|
|
278
289
|
- Changed CLI `knowledge ingest-url` to post directly to `/api/goodvibes-agent/knowledge/ingest/url` instead of invoking the generic knowledge operator method.
|
|
279
|
-
- Rejected
|
|
290
|
+
- Rejected default-space and broad cross-space query flags in CLI and slash Agent Knowledge commands before any daemon call.
|
|
280
291
|
|
|
281
292
|
## 0.1.4 - 2026-05-31
|
|
282
293
|
|
|
@@ -288,12 +299,12 @@ All notable changes to GoodVibes Agent will be recorded here.
|
|
|
288
299
|
|
|
289
300
|
- Added local Agent personas with `/personas`: create/list/search/show/use/review/stale/delete, secret-looking value rejection, active persona prompt injection, and operator workspace status.
|
|
290
301
|
- Added local Agent skills with `/agent-skills` and `/skills local`: create/list/search/show/enable/disable/review/stale/delete, secret-looking value rejection, enabled skill prompt injection, and operator workspace status.
|
|
291
|
-
- Kept persona and skill state Agent-local with no default Knowledge/Wiki or
|
|
302
|
+
- Kept persona and skill state Agent-local with no default Knowledge/Wiki or non-Agent graph fallback.
|
|
292
303
|
|
|
293
304
|
## 0.1.2 - 2026-05-30
|
|
294
305
|
|
|
295
306
|
- Added `goodvibes-agent compat` for package SDK pin, external daemon version, auth presence, and isolated Agent Knowledge route readiness.
|
|
296
|
-
- Added `goodvibes-agent knowledge ...` commands for the isolated `/api/goodvibes-agent/knowledge/*` environment with no default Knowledge/Wiki or
|
|
307
|
+
- Added `goodvibes-agent knowledge ...` commands for the isolated `/api/goodvibes-agent/knowledge/*` environment with no default Knowledge/Wiki or non-Agent graph fallback.
|
|
297
308
|
- Added explicit GoodVibes TUI build delegation through `goodvibes-agent delegate` and `/delegate`; WRFC is requested only through explicit `--wrfc`, `/wrfc`, or `/review` delegation.
|
|
298
309
|
- Removed the copied WRFC panel from the default Agent panel registry while preserving explicit TUI delegation for build/fix/review work.
|
|
299
310
|
- Hardened the Agent release helper and CLI help output for the current Agent changelog and command set.
|
package/README.md
CHANGED
|
@@ -19,6 +19,13 @@ goodvibes-agent profiles templates
|
|
|
19
19
|
goodvibes-agent knowledge status
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
If `goodvibes-agent` is not found after installation, add Bun's global bin directory to `PATH`:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
export PATH="$(bun pm bin -g):$PATH"
|
|
26
|
+
goodvibes-agent --help
|
|
27
|
+
```
|
|
28
|
+
|
|
22
29
|
If Bun reports untrusted lifecycle dependencies, trust only the package and dependencies required by this package:
|
|
23
30
|
|
|
24
31
|
```sh
|
|
@@ -74,7 +81,7 @@ Local Agent behavior is editable from the TUI:
|
|
|
74
81
|
/skills local list
|
|
75
82
|
```
|
|
76
83
|
|
|
77
|
-
Starting a routine records local usage and prints its steps; it does not spawn background agents or daemon automation jobs. Promotion to a daemon schedule is separate and explicit: it calls the public `schedules.create` route on the externally managed daemon only after `--yes`, can include explicit delivery targets such as `--delivery-surface slack`, records a redacted local receipt, and the generated scheduled prompt keeps Agent Knowledge isolated from default Knowledge/Wiki and
|
|
84
|
+
Starting a routine records local usage and prints its steps; it does not spawn background agents or daemon automation jobs. Promotion to a daemon schedule is separate and explicit: it calls the public `schedules.create` route on the externally managed daemon only after `--yes`, can include explicit delivery targets such as `--delivery-surface slack`, records a redacted local receipt, and the generated scheduled prompt keeps Agent Knowledge isolated from default Knowledge/Wiki and non-Agent knowledge segments. Use `/schedule reconcile` to compare those local receipts against live externally owned daemon schedules through public `schedules.list`.
|
|
78
85
|
|
|
79
86
|
## Daemon Prerequisite
|
|
80
87
|
|
|
@@ -94,9 +101,9 @@ Those commands should return explicit external-daemon guidance instead of mutati
|
|
|
94
101
|
|
|
95
102
|
GoodVibes Agent owns the operator assistant surface: serial assistant flow, proactive safe actions, local memory/routines/skills/personas, Agent knowledge routes, companion chat, approvals/automation observability, and explicit build delegation.
|
|
96
103
|
|
|
97
|
-
Agent Knowledge/Wiki is its own product segment. Agent uses `/api/goodvibes-agent/knowledge/*` and must not fall back to default Knowledge/Wiki
|
|
104
|
+
Agent Knowledge/Wiki is its own product segment. Agent uses `/api/goodvibes-agent/knowledge/*` and must not fall back to default Knowledge/Wiki or other product-specific knowledge routes.
|
|
98
105
|
|
|
99
|
-
GoodVibes TUI owns coding execution: file edits, git/worktree workflows, coding panels,
|
|
106
|
+
GoodVibes TUI owns coding execution: file edits, git/worktree workflows, coding panels, runtime-isolation UX, and WRFC execution. Agent may delegate explicit build/fix/review work to TUI through public daemon/session contracts; normal assistant chat must not use shared coding sessions.
|
|
100
107
|
|
|
101
108
|
## Package Docs
|
|
102
109
|
|
package/docs/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Important baseline constraints:
|
|
|
17
17
|
- Agent depends on `@pellux/goodvibes-sdk@0.33.35`.
|
|
18
18
|
- Agent connects to an externally managed daemon.
|
|
19
19
|
- Agent does not start, stop, restart, install, uninstall, or own daemon/listener/web/service lifecycle.
|
|
20
|
-
- Agent Knowledge/Wiki uses only `/api/goodvibes-agent/knowledge/*`; there is no default Knowledge/Wiki
|
|
20
|
+
- Agent Knowledge/Wiki uses only `/api/goodvibes-agent/knowledge/*`; there is no default Knowledge/Wiki or non-Agent product fallback.
|
|
21
21
|
- Agent supports isolated runtime homes with `GOODVIBES_AGENT_HOME=<path>` and named profile homes with `goodvibes-agent profiles create <name> --template <starter> --yes` plus `--agent-profile <name>`.
|
|
22
22
|
- Agent ships starter profile templates for household, research, travel, operations, and personal productivity local state; `profiles templates export/import` and `/agent-profile guide` support local custom starters.
|
|
23
23
|
- Local personas, routines, and Agent skills are stored under the Agent surface root and are injected only into the serial Agent conversation.
|
package/docs/getting-started.md
CHANGED
|
@@ -18,6 +18,13 @@ goodvibes-agent --help
|
|
|
18
18
|
goodvibes-agent status
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
If the installed command is not found, add Bun's global bin directory to `PATH`:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
export PATH="$(bun pm bin -g):$PATH"
|
|
25
|
+
goodvibes-agent --help
|
|
26
|
+
```
|
|
27
|
+
|
|
21
28
|
If Bun requires lifecycle trust:
|
|
22
29
|
|
|
23
30
|
```sh
|
|
@@ -64,7 +71,7 @@ Named profiles isolate Agent-local config, sessions, memory, personas, skills, r
|
|
|
64
71
|
|
|
65
72
|
## Local Personas, Routines, And Skills
|
|
66
73
|
|
|
67
|
-
Personas, routines, and reusable Agent skills are local to GoodVibes Agent. They do not write into default Knowledge/Wiki or
|
|
74
|
+
Personas, routines, and reusable Agent skills are local to GoodVibes Agent. They do not write into default Knowledge/Wiki or non-Agent knowledge segments.
|
|
68
75
|
|
|
69
76
|
```text
|
|
70
77
|
/personas list
|
|
@@ -78,7 +85,7 @@ Personas, routines, and reusable Agent skills are local to GoodVibes Agent. They
|
|
|
78
85
|
/skills local list
|
|
79
86
|
```
|
|
80
87
|
|
|
81
|
-
The active persona plus enabled Agent routines and skills are injected into the main serial assistant conversation. Starting a routine records local usage and prints its steps; it does not spawn background agents or daemon automation jobs. Promoting a routine to a schedule is an explicit `schedules.create` call to the external daemon, requires `--yes`, writes a local redacted promotion receipt, and preserves the rule that Agent Knowledge never falls back to default Knowledge/Wiki or
|
|
88
|
+
The active persona plus enabled Agent routines and skills are injected into the main serial assistant conversation. Starting a routine records local usage and prints its steps; it does not spawn background agents or daemon automation jobs. Promoting a routine to a schedule is an explicit `schedules.create` call to the external daemon, requires `--yes`, writes a local redacted promotion receipt, and preserves the rule that Agent Knowledge never falls back to default Knowledge/Wiki or non-Agent knowledge segments.
|
|
82
89
|
|
|
83
90
|
## External Daemon
|
|
84
91
|
|
|
@@ -90,7 +97,7 @@ Start the daemon from GoodVibes TUI or the daemon host before using daemon-backe
|
|
|
90
97
|
- `/api/goodvibes-agent/knowledge/search`
|
|
91
98
|
- `/api/goodvibes-agent/knowledge/ingest/url`
|
|
92
99
|
|
|
93
|
-
Agent Knowledge/Wiki is an Agent-owned product segment. Agent commands must not fall back to default Knowledge/Wiki
|
|
100
|
+
Agent Knowledge/Wiki is an Agent-owned product segment. Agent commands must not fall back to default Knowledge/Wiki or other product-specific knowledge spaces.
|
|
94
101
|
|
|
95
102
|
Agent lifecycle commands that would start or mutate daemon posture are blocked intentionally. Use `goodvibes-agent status`, `goodvibes-agent doctor`, and read-only surface checks for diagnostics.
|
|
96
103
|
|
|
@@ -4,13 +4,22 @@ GoodVibes Agent's current installable public alpha version is recorded in `packa
|
|
|
4
4
|
|
|
5
5
|
## Package Identity
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- registry package: `@pellux/goodvibes-agent`
|
|
8
8
|
- executable: `goodvibes-agent`
|
|
9
9
|
- SDK dependency: exact pin to `@pellux/goodvibes-sdk@0.33.35`
|
|
10
10
|
- runtime: Bun
|
|
11
11
|
- source language: TypeScript
|
|
12
12
|
- daemon ownership: external only
|
|
13
13
|
|
|
14
|
+
End users install and run GoodVibes Agent with Bun:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
bun add -g @pellux/goodvibes-agent
|
|
18
|
+
goodvibes-agent --help
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Do not add non-Bun install instructions for this product. The package is hosted on the public package registry, but the supported install and smoke path is Bun.
|
|
22
|
+
|
|
14
23
|
## Required Gates
|
|
15
24
|
|
|
16
25
|
Before any release candidate:
|
|
@@ -25,7 +34,7 @@ bun pm pack --dry-run
|
|
|
25
34
|
git diff --check
|
|
26
35
|
```
|
|
27
36
|
|
|
28
|
-
`bun run publish:package` publishes from a staged package directory. If `NPM_CONFIG_USERCONFIG` is already set,
|
|
37
|
+
`bun run publish:package` publishes from a staged package directory to the package registry. If `NPM_CONFIG_USERCONFIG` is already set, the registry publish command uses it. Otherwise the script creates a temporary 0600 registry userconfig from `NODE_AUTH_TOKEN` or `NPM_TOKEN`, uses it for that publish command, and removes it with the staging directory.
|
|
29
38
|
|
|
30
39
|
Also run the package install smoke from a packed artifact. It must prove:
|
|
31
40
|
|
|
@@ -42,7 +51,7 @@ Also run the package install smoke from a packed artifact. It must prove:
|
|
|
42
51
|
|
|
43
52
|
Do not publish if package-facing docs or install commands refer to another package name, another executable, or Agent-owned daemon lifecycle.
|
|
44
53
|
|
|
45
|
-
Do not publish if Agent Knowledge commands can fall back to default Knowledge/Wiki
|
|
54
|
+
Do not publish if Agent Knowledge commands can fall back to default Knowledge/Wiki or another product-specific knowledge route. Agent Knowledge must use the isolated `/api/goodvibes-agent/knowledge/*` segment.
|
|
46
55
|
|
|
47
56
|
Do not ship daemon binaries from this package. If Agent later gets compiled artifacts, they must use Agent artifact names and remain separate from daemon ownership.
|
|
48
57
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.57",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Near-fork GoodVibes operator assistant with the GoodVibes TUI shell, renderer, input, fullscreen workspace, and daemon-connected Agent product brain.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"!src/test",
|
|
19
19
|
"!src/**/*.test.ts",
|
|
20
20
|
"!src/**/__tests__",
|
|
21
|
-
"!src/daemon/**",
|
|
22
21
|
"!src/panels/diff-panel.ts",
|
|
23
22
|
"!src/panels/file-explorer-panel.ts",
|
|
24
23
|
"!src/panels/file-preview-panel.ts",
|
|
@@ -92,7 +91,6 @@
|
|
|
92
91
|
"access": "public"
|
|
93
92
|
},
|
|
94
93
|
"engines": {
|
|
95
|
-
"node": ">=20",
|
|
96
94
|
"bun": ">=1.3.10"
|
|
97
95
|
},
|
|
98
96
|
"dependencies": {
|
package/scripts/check-bun.sh
CHANGED
|
@@ -5,9 +5,13 @@ if ! command -v bun >/dev/null 2>&1; then
|
|
|
5
5
|
cat >&2 <<'EOF'
|
|
6
6
|
goodvibes-agent requires Bun.
|
|
7
7
|
|
|
8
|
-
Install Bun first, then install GoodVibes Agent
|
|
8
|
+
Install Bun first, then install GoodVibes Agent with:
|
|
9
9
|
|
|
10
10
|
bun add -g @pellux/goodvibes-agent
|
|
11
|
+
|
|
12
|
+
If the installed command is not found, add Bun's global bin directory to PATH:
|
|
13
|
+
|
|
14
|
+
export PATH="$(bun pm bin -g):$PATH"
|
|
11
15
|
EOF
|
|
12
16
|
exit 1
|
|
13
17
|
fi
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ParsedRoutineSchedulePromotionArgs,
|
|
3
|
+
RoutineScheduleDeliverySurfaceKind,
|
|
4
|
+
RoutineScheduleDeliveryTargetSpec,
|
|
5
|
+
} from './routine-schedule-promotion.ts';
|
|
6
|
+
|
|
7
|
+
const DELIVERY_SURFACE_KINDS: readonly RoutineScheduleDeliverySurfaceKind[] = [
|
|
8
|
+
'tui',
|
|
9
|
+
'web',
|
|
10
|
+
'slack',
|
|
11
|
+
'discord',
|
|
12
|
+
'ntfy',
|
|
13
|
+
'webhook',
|
|
14
|
+
'telegram',
|
|
15
|
+
'google-chat',
|
|
16
|
+
'signal',
|
|
17
|
+
'whatsapp',
|
|
18
|
+
'imessage',
|
|
19
|
+
'msteams',
|
|
20
|
+
'bluebubbles',
|
|
21
|
+
'mattermost',
|
|
22
|
+
'matrix',
|
|
23
|
+
'service',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
function optionValue(args: readonly string[], index: number, inlineValue: string | undefined): {
|
|
27
|
+
readonly value: string | undefined;
|
|
28
|
+
readonly nextIndex: number;
|
|
29
|
+
} {
|
|
30
|
+
if (inlineValue !== undefined) return { value: inlineValue, nextIndex: index };
|
|
31
|
+
const next = args[index + 1];
|
|
32
|
+
if (next === undefined || next.startsWith('--')) return { value: undefined, nextIndex: index };
|
|
33
|
+
return { value: next, nextIndex: index + 1 };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function isRoutineScheduleDeliverySurfaceKind(value: string): value is RoutineScheduleDeliverySurfaceKind {
|
|
37
|
+
return DELIVERY_SURFACE_KINDS.includes(value as RoutineScheduleDeliverySurfaceKind);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseSurfaceDeliveryTarget(raw: string): RoutineScheduleDeliveryTargetSpec | string {
|
|
41
|
+
const [surfaceKind = '', routeId, label] = raw.split(':');
|
|
42
|
+
if (!isRoutineScheduleDeliverySurfaceKind(surfaceKind)) {
|
|
43
|
+
return `Unsupported delivery surface "${surfaceKind}".`;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
kind: 'surface',
|
|
47
|
+
surfaceKind,
|
|
48
|
+
routeId: routeId?.trim() || undefined,
|
|
49
|
+
label: label?.trim() || undefined,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function parseRouteDeliveryTarget(raw: string): RoutineScheduleDeliveryTargetSpec | string {
|
|
54
|
+
const [routeId = '', label] = raw.split(':');
|
|
55
|
+
const normalizedRouteId = routeId.trim();
|
|
56
|
+
if (!normalizedRouteId) return '--delivery-route requires a route id.';
|
|
57
|
+
return {
|
|
58
|
+
kind: 'surface',
|
|
59
|
+
routeId: normalizedRouteId,
|
|
60
|
+
label: label?.trim() || undefined,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function parseWebhookDeliveryTarget(raw: string): RoutineScheduleDeliveryTargetSpec | string {
|
|
65
|
+
const normalized = raw.trim();
|
|
66
|
+
if (!normalized) return '--delivery-webhook requires a URL.';
|
|
67
|
+
try {
|
|
68
|
+
const url = new URL(normalized);
|
|
69
|
+
if (url.protocol !== 'https:' && url.protocol !== 'http:') return '--delivery-webhook must be an http(s) URL.';
|
|
70
|
+
} catch {
|
|
71
|
+
return '--delivery-webhook must be a valid URL.';
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
kind: 'webhook',
|
|
75
|
+
address: normalized,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function parseLinkDeliveryTarget(raw: string): RoutineScheduleDeliveryTargetSpec | string {
|
|
80
|
+
const normalized = raw.trim();
|
|
81
|
+
if (!normalized) return '--delivery-link requires a URL or label.';
|
|
82
|
+
return {
|
|
83
|
+
kind: 'link',
|
|
84
|
+
address: normalized,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function validateDeliveryTargets(targets: readonly RoutineScheduleDeliveryTargetSpec[]): string | null {
|
|
89
|
+
const kinds = new Set(targets.map((target) => target.kind));
|
|
90
|
+
return kinds.size > 1 ? 'Use one delivery target kind per routine promotion command.' : null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function parseRoutineSchedulePromotionArgs(args: readonly string[]): ParsedRoutineSchedulePromotionArgs {
|
|
94
|
+
let routineId: string | null = null;
|
|
95
|
+
let schedule: ParsedRoutineSchedulePromotionArgs['schedule'] = null;
|
|
96
|
+
const deliveryTargets: RoutineScheduleDeliveryTargetSpec[] = [];
|
|
97
|
+
let name: string | undefined;
|
|
98
|
+
let timezone: string | undefined;
|
|
99
|
+
let provider: string | undefined;
|
|
100
|
+
let model: string | undefined;
|
|
101
|
+
let enabled = true;
|
|
102
|
+
let yes = false;
|
|
103
|
+
const errors: string[] = [];
|
|
104
|
+
|
|
105
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
106
|
+
const raw = args[index] ?? '';
|
|
107
|
+
const equals = raw.indexOf('=');
|
|
108
|
+
const optionName = equals >= 0 ? raw.slice(0, equals) : raw;
|
|
109
|
+
const inlineValue = equals >= 0 ? raw.slice(equals + 1) : undefined;
|
|
110
|
+
|
|
111
|
+
if (raw === '--yes') {
|
|
112
|
+
yes = true;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (raw === '--disabled') {
|
|
116
|
+
enabled = false;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (optionName === '--name' || optionName === '--timezone' || optionName === '--provider' || optionName === '--model') {
|
|
120
|
+
const consumed = optionValue(args, index, inlineValue);
|
|
121
|
+
index = consumed.nextIndex;
|
|
122
|
+
const value = consumed.value?.trim();
|
|
123
|
+
if (!value) {
|
|
124
|
+
errors.push(`${optionName} requires a value.`);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (optionName === '--name') name = value;
|
|
128
|
+
if (optionName === '--timezone') timezone = value;
|
|
129
|
+
if (optionName === '--provider') provider = value;
|
|
130
|
+
if (optionName === '--model') model = value;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (optionName === '--cron' || optionName === '--every' || optionName === '--at') {
|
|
134
|
+
const consumed = optionValue(args, index, inlineValue);
|
|
135
|
+
index = consumed.nextIndex;
|
|
136
|
+
const value = consumed.value?.trim();
|
|
137
|
+
if (!value) {
|
|
138
|
+
errors.push(`${optionName} requires a value.`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (schedule) {
|
|
142
|
+
errors.push('Choose exactly one schedule selector: --cron, --every, or --at.');
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
schedule = {
|
|
146
|
+
kind: optionName === '--cron' ? 'cron' : optionName === '--every' ? 'every' : 'at',
|
|
147
|
+
value,
|
|
148
|
+
};
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (optionName === '--delivery-surface' || optionName === '--deliver-surface') {
|
|
152
|
+
const consumed = optionValue(args, index, inlineValue);
|
|
153
|
+
index = consumed.nextIndex;
|
|
154
|
+
const value = consumed.value?.trim();
|
|
155
|
+
if (!value) {
|
|
156
|
+
errors.push(`${optionName} requires a value.`);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const target = parseSurfaceDeliveryTarget(value);
|
|
160
|
+
if (typeof target === 'string') errors.push(target);
|
|
161
|
+
else deliveryTargets.push(target);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (optionName === '--delivery-route' || optionName === '--deliver-route') {
|
|
165
|
+
const consumed = optionValue(args, index, inlineValue);
|
|
166
|
+
index = consumed.nextIndex;
|
|
167
|
+
const value = consumed.value?.trim();
|
|
168
|
+
if (!value) {
|
|
169
|
+
errors.push(`${optionName} requires a value.`);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const target = parseRouteDeliveryTarget(value);
|
|
173
|
+
if (typeof target === 'string') errors.push(target);
|
|
174
|
+
else deliveryTargets.push(target);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (optionName === '--delivery-webhook' || optionName === '--deliver-webhook') {
|
|
178
|
+
const consumed = optionValue(args, index, inlineValue);
|
|
179
|
+
index = consumed.nextIndex;
|
|
180
|
+
const value = consumed.value?.trim();
|
|
181
|
+
if (!value) {
|
|
182
|
+
errors.push(`${optionName} requires a value.`);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const target = parseWebhookDeliveryTarget(value);
|
|
186
|
+
if (typeof target === 'string') errors.push(target);
|
|
187
|
+
else deliveryTargets.push(target);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (optionName === '--delivery-link' || optionName === '--deliver-link') {
|
|
191
|
+
const consumed = optionValue(args, index, inlineValue);
|
|
192
|
+
index = consumed.nextIndex;
|
|
193
|
+
const value = consumed.value?.trim();
|
|
194
|
+
if (!value) {
|
|
195
|
+
errors.push(`${optionName} requires a value.`);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const target = parseLinkDeliveryTarget(value);
|
|
199
|
+
if (typeof target === 'string') errors.push(target);
|
|
200
|
+
else deliveryTargets.push(target);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (raw.startsWith('--')) {
|
|
204
|
+
errors.push(`Unknown option: ${raw}`);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (!routineId) {
|
|
208
|
+
routineId = raw;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
errors.push(`Unexpected argument: ${raw}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (!routineId) errors.push('Routine id or name is required.');
|
|
215
|
+
if (!schedule) errors.push('Schedule is required: use --cron <expr>, --every <interval>, or --at <iso-time>.');
|
|
216
|
+
const deliveryError = validateDeliveryTargets(deliveryTargets);
|
|
217
|
+
if (deliveryError) errors.push(deliveryError);
|
|
218
|
+
return { routineId, schedule, deliveryTargets, name, timezone, provider, model, enabled, yes, errors };
|
|
219
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ROUTINE_SCHEDULE_LIST_METHOD,
|
|
3
|
+
ROUTINE_SCHEDULE_METHOD,
|
|
4
|
+
type RoutineScheduleCorrelationResult,
|
|
5
|
+
type RoutineSchedulePromotionFailure,
|
|
6
|
+
type RoutineSchedulePromotionPreview,
|
|
7
|
+
type RoutineSchedulePromotionSuccess,
|
|
8
|
+
type RoutineScheduleReceipt,
|
|
9
|
+
type RoutineScheduleReceiptSnapshot,
|
|
10
|
+
} from './routine-schedule-promotion.ts';
|
|
11
|
+
|
|
12
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
13
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function readString(record: Record<string, unknown>, key: string): string | null {
|
|
17
|
+
const value = record[key];
|
|
18
|
+
return typeof value === 'string' ? value : null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function formatRoutineSchedulePreview(preview: RoutineSchedulePromotionPreview): string {
|
|
22
|
+
const schedule = preview.payload.kind === 'cron'
|
|
23
|
+
? `${preview.payload.cron}${preview.payload.timezone ? ` [${preview.payload.timezone}]` : ''}`
|
|
24
|
+
: preview.payload.kind === 'every'
|
|
25
|
+
? String(preview.payload.every)
|
|
26
|
+
: String(preview.payload.at);
|
|
27
|
+
const delivery = preview.payload.delivery;
|
|
28
|
+
const deliveryTargetCount = delivery?.targets.length ?? 0;
|
|
29
|
+
return [
|
|
30
|
+
'Daemon schedule preview for Agent routine',
|
|
31
|
+
` routine: ${preview.routineName} (${preview.routineId})`,
|
|
32
|
+
` route: ${preview.method} ${preview.route}`,
|
|
33
|
+
` name: ${String(preview.payload.name ?? '(daemon default)')}`,
|
|
34
|
+
` schedule: ${preview.payload.kind} ${schedule}`,
|
|
35
|
+
` enabled: ${preview.payload.enabled === false ? 'no' : 'yes'}`,
|
|
36
|
+
` delivery: ${delivery?.mode ?? 'none'}${deliveryTargetCount > 0 ? ` (${deliveryTargetCount} target${deliveryTargetCount === 1 ? '' : 's'})` : ''}`,
|
|
37
|
+
' target: external daemon service/main conversation route',
|
|
38
|
+
' policy: isolated Agent Knowledge only; no default wiki/non-Agent fallback; no WRFC unless explicitly delegated',
|
|
39
|
+
' next: rerun with --yes to create this daemon schedule',
|
|
40
|
+
].join('\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function formatRoutineScheduleSuccess(result: RoutineSchedulePromotionSuccess): string {
|
|
44
|
+
const record: Record<string, unknown> = isRecord(result.schedule) ? result.schedule : {};
|
|
45
|
+
const id = readString(record, 'id') ?? '(unknown)';
|
|
46
|
+
const status = readString(record, 'status') ?? (record.enabled === false ? 'paused' : 'enabled');
|
|
47
|
+
return [
|
|
48
|
+
'Created daemon schedule for Agent routine',
|
|
49
|
+
` routine: ${result.routineName} (${result.routineId})`,
|
|
50
|
+
` schedule: ${id}`,
|
|
51
|
+
` status: ${status}`,
|
|
52
|
+
` route: ${result.kind} ${result.route}`,
|
|
53
|
+
' next: inspect with /schedule list or daemon schedule observability',
|
|
54
|
+
].join('\n');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function formatRoutineScheduleReceipts(snapshot: RoutineScheduleReceiptSnapshot, limit = 10): string {
|
|
58
|
+
const receipts = snapshot.receipts.slice(0, Math.max(1, limit));
|
|
59
|
+
if (snapshot.receipts.length === 0) {
|
|
60
|
+
return [
|
|
61
|
+
'Agent routine schedule receipts',
|
|
62
|
+
` store: ${snapshot.path}`,
|
|
63
|
+
' No routine schedule promotions have been recorded yet.',
|
|
64
|
+
' Create one with /schedule promote-routine <routine-id> --cron <expr> --yes.',
|
|
65
|
+
].join('\n');
|
|
66
|
+
}
|
|
67
|
+
return [
|
|
68
|
+
`Agent routine schedule receipts (${snapshot.receipts.length})`,
|
|
69
|
+
` store: ${snapshot.path}`,
|
|
70
|
+
...receipts.map((receipt) => {
|
|
71
|
+
const schedule = receipt.scheduleId ? ` schedule=${receipt.scheduleId}` : '';
|
|
72
|
+
const failure = receipt.status === 'failed' && receipt.failureKind ? ` failure=${receipt.failureKind}` : '';
|
|
73
|
+
return ` ${receipt.id} ${receipt.status} ${receipt.scheduleKind} ${receipt.scheduleValue} routine=${receipt.routineId}${schedule}${failure}`;
|
|
74
|
+
}),
|
|
75
|
+
snapshot.receipts.length > receipts.length ? ` ...${snapshot.receipts.length - receipts.length} more` : '',
|
|
76
|
+
].filter((line): line is string => Boolean(line)).join('\n');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function formatRoutineScheduleReceipt(receipt: RoutineScheduleReceipt): string {
|
|
80
|
+
return [
|
|
81
|
+
`Agent routine schedule receipt ${receipt.id}`,
|
|
82
|
+
` created: ${receipt.createdAt}`,
|
|
83
|
+
` status: ${receipt.status}`,
|
|
84
|
+
` routine: ${receipt.routineName} (${receipt.routineId})`,
|
|
85
|
+
` route: ${receipt.method} ${receipt.route}`,
|
|
86
|
+
` daemon: ${receipt.daemonBaseUrl}`,
|
|
87
|
+
` schedule: ${receipt.scheduleName}${receipt.scheduleId ? ` (${receipt.scheduleId})` : ''}`,
|
|
88
|
+
receipt.scheduleStatus ? ` schedule status: ${receipt.scheduleStatus}` : '',
|
|
89
|
+
` cadence: ${receipt.scheduleKind} ${receipt.scheduleValue}${receipt.timezone ? ` [${receipt.timezone}]` : ''}`,
|
|
90
|
+
` enabled: ${receipt.enabled ? 'yes' : 'no'}`,
|
|
91
|
+
receipt.provider ? ` provider: ${receipt.provider}` : '',
|
|
92
|
+
receipt.model ? ` model: ${receipt.model}` : '',
|
|
93
|
+
` target: ${receipt.target.kind ?? 'unknown'}${receipt.target.surfaceKind ? `/${receipt.target.surfaceKind}` : ''}`,
|
|
94
|
+
receipt.deliveryMode ? ` delivery: ${receipt.deliveryMode}` : '',
|
|
95
|
+
...(receipt.deliveryTargets ?? []).map((target) => ` delivery target: ${target.kind}${target.surfaceKind ? `/${target.surfaceKind}` : ''}${target.routeId ? ` route=${target.routeId}` : ''}${target.address ? ` address=${target.address}` : ''}${target.label ? ` label=${target.label}` : ''}`),
|
|
96
|
+
receipt.failureKind ? ` failure: ${receipt.failureKind}` : '',
|
|
97
|
+
receipt.failureError ? ` error: ${receipt.failureError}` : '',
|
|
98
|
+
].filter((line): line is string => Boolean(line)).join('\n');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function formatRoutineScheduleCorrelation(result: RoutineScheduleCorrelationResult, limit = 10): string {
|
|
102
|
+
if (!result.ok) {
|
|
103
|
+
return [
|
|
104
|
+
`Daemon schedule reconciliation error: ${result.kind}`,
|
|
105
|
+
` ${result.error}`,
|
|
106
|
+
result.baseUrl ? ` daemon: ${result.baseUrl}` : null,
|
|
107
|
+
` route: ${ROUTINE_SCHEDULE_LIST_METHOD} ${result.route}`,
|
|
108
|
+
result.kind === 'auth_required'
|
|
109
|
+
? ' next: pair/authenticate with the externally managed GoodVibes daemon, then retry.'
|
|
110
|
+
: null,
|
|
111
|
+
result.kind === 'daemon_unavailable'
|
|
112
|
+
? ' next: start/restart the external GoodVibes daemon from TUI or daemon host tooling; Agent does not own daemon lifecycle.'
|
|
113
|
+
: null,
|
|
114
|
+
result.kind === 'version_mismatch' || result.kind === 'daemon_route_unavailable'
|
|
115
|
+
? ' next: update/restart the external GoodVibes daemon so public schedules.list is available.'
|
|
116
|
+
: null,
|
|
117
|
+
].filter((line): line is string => Boolean(line)).join('\n');
|
|
118
|
+
}
|
|
119
|
+
const correlations = result.correlations.slice(0, Math.max(1, limit));
|
|
120
|
+
if (result.receiptCount === 0) {
|
|
121
|
+
return [
|
|
122
|
+
'Agent routine schedule reconciliation',
|
|
123
|
+
` daemon: ${result.baseUrl}`,
|
|
124
|
+
` route: ${result.kind} ${result.route}`,
|
|
125
|
+
` live schedules: ${result.scheduleCount}`,
|
|
126
|
+
' No local routine promotion receipts exist yet.',
|
|
127
|
+
' Create one with /schedule promote-routine <routine-id> --cron <expr> --yes.',
|
|
128
|
+
].join('\n');
|
|
129
|
+
}
|
|
130
|
+
const matched = result.correlations.filter((entry) => entry.liveStatus === 'matched').length;
|
|
131
|
+
const missing = result.correlations.filter((entry) => entry.liveStatus === 'missing').length;
|
|
132
|
+
const failed = result.correlations.filter((entry) => entry.liveStatus === 'failed-receipt').length;
|
|
133
|
+
return [
|
|
134
|
+
'Agent routine schedule reconciliation',
|
|
135
|
+
` daemon: ${result.baseUrl}`,
|
|
136
|
+
` route: ${result.kind} ${result.route}`,
|
|
137
|
+
` receipts: ${result.receiptCount}; live schedules: ${result.scheduleCount}; matched: ${matched}; missing: ${missing}; failed receipts: ${failed}`,
|
|
138
|
+
...correlations.map((entry) => {
|
|
139
|
+
const receipt = entry.receipt;
|
|
140
|
+
const schedule = entry.schedule;
|
|
141
|
+
const live = schedule
|
|
142
|
+
? ` live=${schedule.id} status=${schedule.status ?? (schedule.enabled === false ? 'paused' : 'enabled')}`
|
|
143
|
+
: '';
|
|
144
|
+
const runs = schedule && schedule.runCount !== undefined
|
|
145
|
+
? ` runs=${schedule.runCount}/${schedule.successCount ?? 0}/${schedule.failureCount ?? 0}`
|
|
146
|
+
: '';
|
|
147
|
+
const next = schedule?.nextRunAt ? ` next=${new Date(schedule.nextRunAt).toISOString()}` : '';
|
|
148
|
+
return ` ${receipt.id} ${entry.liveStatus} reason=${entry.matchReason} routine=${receipt.routineId} receiptSchedule=${receipt.scheduleId ?? '(none)'}${live}${runs}${next}`;
|
|
149
|
+
}),
|
|
150
|
+
result.correlations.length > correlations.length ? ` ...${result.correlations.length - correlations.length} more` : '',
|
|
151
|
+
].filter((line): line is string => Boolean(line)).join('\n');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function formatRoutineScheduleFailure(failure: RoutineSchedulePromotionFailure): string {
|
|
155
|
+
return [
|
|
156
|
+
`Daemon schedule error: ${failure.kind}`,
|
|
157
|
+
` ${failure.error}`,
|
|
158
|
+
failure.baseUrl ? ` daemon: ${failure.baseUrl}` : null,
|
|
159
|
+
` route: ${ROUTINE_SCHEDULE_METHOD} ${failure.route}`,
|
|
160
|
+
failure.kind === 'version_mismatch' && failure.daemonVersion && failure.expectedSdkVersion
|
|
161
|
+
? ` versions: daemon=${failure.daemonVersion} expected=${failure.expectedSdkVersion}`
|
|
162
|
+
: null,
|
|
163
|
+
failure.kind === 'auth_required'
|
|
164
|
+
? ' next: pair/authenticate with the externally managed GoodVibes daemon, then retry with --yes.'
|
|
165
|
+
: null,
|
|
166
|
+
failure.kind === 'daemon_unavailable'
|
|
167
|
+
? ' next: start/restart the external GoodVibes daemon from TUI or daemon host tooling; Agent does not own daemon lifecycle.'
|
|
168
|
+
: null,
|
|
169
|
+
failure.kind === 'version_mismatch' || failure.kind === 'daemon_route_unavailable'
|
|
170
|
+
? ' next: update/restart the external GoodVibes daemon so public schedules.create is available.'
|
|
171
|
+
: null,
|
|
172
|
+
].filter((line): line is string => Boolean(line)).join('\n');
|
|
173
|
+
}
|