@pellux/goodvibes-agent 1.1.7 → 1.3.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.
- package/CHANGELOG.md +329 -0
- package/README.md +46 -30
- package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
- package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
- package/dist/package/main.js +138903 -91477
- package/docs/README.md +14 -7
- package/docs/channels-remote-and-api.md +8 -5
- package/docs/connected-host.md +14 -12
- package/docs/getting-started.md +58 -30
- package/docs/knowledge-artifacts-and-multimodal.md +7 -5
- package/docs/project-planning.md +2 -2
- package/docs/providers-and-routing.md +11 -3
- package/docs/tools-and-commands.md +116 -45
- package/docs/voice-and-live-tts.md +3 -1
- package/package.json +3 -2
- package/release/release-notes.md +142 -5
- package/release/release-readiness.json +124 -94
- package/src/agent/assistant-cockpit.ts +247 -0
- package/src/agent/autonomy-schedule-format.ts +96 -0
- package/src/agent/autonomy-schedule.ts +514 -0
- package/src/agent/channel-delivery-receipts.ts +292 -0
- package/src/agent/competitive-feature-inventory.ts +294 -0
- package/src/agent/document-registry-types.ts +106 -0
- package/src/agent/document-registry.ts +734 -0
- package/src/agent/harness-control.ts +2 -2
- package/src/agent/memory-prompt.ts +2 -2
- package/src/agent/operator-actions.ts +50 -6
- package/src/agent/persona-registry.ts +8 -0
- package/src/agent/project-context-files.ts +273 -0
- package/src/agent/prompt-context-receipts.ts +502 -0
- package/src/agent/reminder-schedule-format.ts +16 -2
- package/src/agent/research-run-registry.ts +582 -0
- package/src/agent/research-source-registry.ts +441 -0
- package/src/agent/routine-registry.ts +19 -3
- package/src/agent/routine-schedule-format.ts +27 -2
- package/src/agent/runtime-profile-starters.ts +7 -0
- package/src/agent/runtime-profile.ts +106 -4
- package/src/agent/schedule-edit-format.ts +129 -0
- package/src/agent/schedule-edit.ts +496 -0
- package/src/agent/schedule-next-routes.ts +42 -0
- package/src/agent/setup-wizard-artifact-receipts.ts +366 -0
- package/src/agent/setup-wizard-checkpoint.ts +140 -0
- package/src/agent/setup-wizard.ts +683 -0
- package/src/agent/skill-registry-types.ts +102 -0
- package/src/agent/skill-registry.ts +81 -107
- package/src/agent/vibe-confirmation-routes.ts +62 -0
- package/src/agent/vibe-file.ts +285 -0
- package/src/cli/agent-knowledge-command.ts +45 -2
- package/src/cli/help.ts +3 -0
- package/src/cli/profiles-command.ts +25 -11
- package/src/config/agent-settings-policy.ts +1 -18
- package/src/input/agent-workspace-activation.ts +53 -0
- package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
- package/src/input/agent-workspace-artifact-metadata.ts +17 -0
- package/src/input/agent-workspace-basic-command-editors.ts +5 -1
- package/src/input/agent-workspace-categories.ts +153 -155
- package/src/input/agent-workspace-channel-triage.ts +481 -0
- package/src/input/agent-workspace-channels.ts +263 -0
- package/src/input/agent-workspace-command-editor.ts +152 -0
- package/src/input/agent-workspace-context-snapshot.ts +349 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
- package/src/input/agent-workspace-document-editor.ts +502 -0
- package/src/input/agent-workspace-document-ops-editor.ts +523 -0
- package/src/input/agent-workspace-host-category.ts +1 -1
- package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
- package/src/input/agent-workspace-model-compare-editor.ts +376 -0
- package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
- package/src/input/agent-workspace-model-compare-types.ts +82 -0
- package/src/input/agent-workspace-model-compare-utils.ts +35 -0
- package/src/input/agent-workspace-onboarding-categories.ts +141 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
- package/src/input/agent-workspace-operations-command-editors.ts +22 -0
- package/src/input/agent-workspace-research-report-editor.ts +212 -0
- package/src/input/agent-workspace-research-run-editor.ts +144 -0
- package/src/input/agent-workspace-research-source-editor.ts +167 -0
- package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
- package/src/input/agent-workspace-review-packet-utils.ts +265 -0
- package/src/input/agent-workspace-settings.ts +313 -30
- package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
- package/src/input/agent-workspace-setup-snapshot.ts +217 -0
- package/src/input/agent-workspace-setup.ts +61 -1
- package/src/input/agent-workspace-snapshot.ts +184 -149
- package/src/input/agent-workspace-types.ts +287 -2
- package/src/input/agent-workspace.ts +23 -1
- package/src/input/command-registry.ts +9 -2
- package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
- package/src/input/commands/channels-runtime.ts +102 -114
- package/src/input/commands/delegation-runtime.ts +87 -24
- package/src/input/commands/knowledge-browser-flags.ts +12 -0
- package/src/input/commands/knowledge.ts +28 -14
- package/src/input/commands/operator-actions-runtime.ts +6 -3
- package/src/input/commands/schedule-runtime.ts +71 -14
- package/src/input/commands/session-content.ts +2 -2
- package/src/input/commands/shell-core.ts +2 -0
- package/src/input/commands/vibe-runtime.ts +140 -0
- package/src/input/commands.ts +2 -0
- package/src/input/connected-host-routes.ts +123 -0
- package/src/input/settings-modal-types.ts +14 -0
- package/src/input/setup-wizard-live-receipts.ts +76 -0
- package/src/main.ts +15 -15
- package/src/panels/qr-panel.ts +2 -2
- package/src/renderer/agent-workspace-context-lines.ts +701 -0
- package/src/renderer/agent-workspace.ts +68 -421
- package/src/renderer/settings-modal-helpers.ts +12 -0
- package/src/renderer/settings-modal.ts +12 -0
- package/src/runtime/bootstrap-command-context.ts +11 -1
- package/src/runtime/bootstrap-command-parts.ts +14 -3
- package/src/runtime/bootstrap-core.ts +39 -1
- package/src/runtime/bootstrap-shell.ts +6 -0
- package/src/runtime/bootstrap.ts +113 -30
- package/src/runtime/connected-host-auth.ts +3 -2
- package/src/runtime/execution-ledger.ts +231 -0
- package/src/runtime/services.ts +88 -10
- package/src/runtime/tool-permission-safety.ts +199 -5
- package/src/shell/session-continuity-hints.ts +39 -0
- package/src/tools/agent-artifacts-tool.ts +606 -0
- package/src/tools/agent-audit-tool.ts +155 -0
- package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
- package/src/tools/agent-autonomy-tool.ts +140 -0
- package/src/tools/agent-channel-send-tool.ts +24 -2
- package/src/tools/agent-channels-tool.ts +140 -0
- package/src/tools/agent-computer-tool.ts +168 -0
- package/src/tools/agent-context-policy.ts +137 -7
- package/src/tools/agent-context-tool.ts +143 -0
- package/src/tools/agent-delegation-tool.ts +128 -0
- package/src/tools/agent-device-tool.ts +240 -0
- package/src/tools/agent-documents-tool.ts +684 -0
- package/src/tools/agent-execution-tool.ts +230 -0
- package/src/tools/agent-harness-agent-orchestration-policy.ts +75 -0
- package/src/tools/agent-harness-agent-orchestration.ts +791 -0
- package/src/tools/agent-harness-autonomy-intake.ts +785 -0
- package/src/tools/agent-harness-autonomy-live-records.ts +742 -0
- package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
- package/src/tools/agent-harness-autonomy-queue.ts +571 -0
- package/src/tools/agent-harness-autonomy-watcher-read-models.ts +509 -0
- package/src/tools/agent-harness-background-processes-types.ts +35 -0
- package/src/tools/agent-harness-background-processes.ts +798 -0
- package/src/tools/agent-harness-browser-cockpit-route.ts +373 -0
- package/src/tools/agent-harness-browser-control.ts +346 -0
- package/src/tools/agent-harness-browser-pwa-read-models.ts +622 -0
- package/src/tools/agent-harness-channel-metadata.ts +168 -10
- package/src/tools/agent-harness-cli-command-policy.ts +110 -0
- package/src/tools/agent-harness-command-catalog.ts +4 -2
- package/src/tools/agent-harness-command-runner.ts +42 -0
- package/src/tools/agent-harness-connected-host-status.ts +7 -4
- package/src/tools/agent-harness-delegation-posture.ts +234 -19
- package/src/tools/agent-harness-device-live-read-models.ts +366 -0
- package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
- package/src/tools/agent-harness-document-ops-types.ts +72 -0
- package/src/tools/agent-harness-document-ops.ts +671 -0
- package/src/tools/agent-harness-execution-history.ts +489 -0
- package/src/tools/agent-harness-execution-posture.ts +385 -0
- package/src/tools/agent-harness-file-recovery.ts +135 -0
- package/src/tools/agent-harness-interactive-runtime-records.ts +421 -0
- package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
- package/src/tools/agent-harness-learning-curator-common.ts +102 -0
- package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
- package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
- package/src/tools/agent-harness-learning-curator-types.ts +151 -0
- package/src/tools/agent-harness-learning-curator.ts +417 -0
- package/src/tools/agent-harness-local-model-benchmarks.ts +269 -0
- package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
- package/src/tools/agent-harness-local-model-endpoints.ts +788 -0
- package/src/tools/agent-harness-local-model-smoke.ts +277 -0
- package/src/tools/agent-harness-local-model-url.ts +78 -0
- package/src/tools/agent-harness-media-posture.ts +223 -2
- package/src/tools/agent-harness-memory-external-providers.ts +796 -0
- package/src/tools/agent-harness-memory-posture.ts +672 -0
- package/src/tools/agent-harness-memory-provider-certification.ts +219 -0
- package/src/tools/agent-harness-memory-refinement.ts +340 -0
- package/src/tools/agent-harness-metadata.ts +100 -168
- package/src/tools/agent-harness-mode-catalog.ts +86 -33
- package/src/tools/agent-harness-model-catalog.ts +162 -0
- package/src/tools/agent-harness-model-provider-health.ts +283 -0
- package/src/tools/agent-harness-model-readiness.ts +432 -0
- package/src/tools/agent-harness-model-routing-types.ts +327 -0
- package/src/tools/agent-harness-model-routing-utils.ts +30 -0
- package/src/tools/agent-harness-model-routing.ts +165 -193
- package/src/tools/agent-harness-operator-methods.ts +115 -133
- package/src/tools/agent-harness-pairing-posture.ts +452 -18
- package/src/tools/agent-harness-personal-ops-certification.ts +116 -0
- package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
- package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
- package/src/tools/agent-harness-personal-ops-lanes.ts +270 -0
- package/src/tools/agent-harness-personal-ops-operations.ts +225 -0
- package/src/tools/agent-harness-personal-ops-provider-records.ts +358 -0
- package/src/tools/agent-harness-personal-ops-provider-task-records.ts +321 -0
- package/src/tools/agent-harness-personal-ops-records.ts +684 -0
- package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
- package/src/tools/agent-harness-personal-ops-types.ts +240 -0
- package/src/tools/agent-harness-personal-ops.ts +613 -0
- package/src/tools/agent-harness-project-context.ts +144 -0
- package/src/tools/agent-harness-prompt-context.ts +589 -0
- package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
- package/src/tools/agent-harness-release-evidence.ts +9 -7
- package/src/tools/agent-harness-release-readiness.ts +9 -7
- package/src/tools/agent-harness-remote-read-models.ts +541 -0
- package/src/tools/agent-harness-research-briefing.ts +446 -0
- package/src/tools/agent-harness-research-live-read-models.ts +500 -0
- package/src/tools/agent-harness-research-queue.ts +250 -0
- package/src/tools/agent-harness-research-runs.ts +307 -0
- package/src/tools/agent-harness-research-workflow.ts +395 -0
- package/src/tools/agent-harness-security-posture.ts +2 -2
- package/src/tools/agent-harness-service-posture.ts +9 -9
- package/src/tools/agent-harness-session-metadata.ts +3 -3
- package/src/tools/agent-harness-setup-connected-host.ts +501 -0
- package/src/tools/agent-harness-setup-describe.ts +557 -0
- package/src/tools/agent-harness-setup-handoffs.ts +502 -0
- package/src/tools/agent-harness-setup-model-helpers.ts +102 -0
- package/src/tools/agent-harness-setup-plan.ts +253 -0
- package/src/tools/agent-harness-setup-posture-types.ts +218 -0
- package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
- package/src/tools/agent-harness-setup-posture.ts +449 -221
- package/src/tools/agent-harness-setup-smoke.ts +533 -0
- package/src/tools/agent-harness-sudo-posture.ts +114 -0
- package/src/tools/agent-harness-tool-schema.ts +142 -7
- package/src/tools/agent-harness-tool-types.ts +83 -0
- package/src/tools/agent-harness-tool-utils.ts +43 -0
- package/src/tools/agent-harness-tool.ts +319 -370
- package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
- package/src/tools/agent-harness-ui-surface-types.ts +46 -0
- package/src/tools/agent-harness-vibe-health.ts +105 -0
- package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
- package/src/tools/agent-harness-workspace-actions.ts +114 -8
- package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
- package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
- package/src/tools/agent-host-tool.ts +159 -0
- package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
- package/src/tools/agent-learning-consolidation-core.ts +327 -0
- package/src/tools/agent-learning-consolidation-tool.ts +758 -0
- package/src/tools/agent-memory-tool.ts +253 -0
- package/src/tools/agent-model-compare-export.ts +315 -0
- package/src/tools/agent-model-compare-handoff.ts +592 -0
- package/src/tools/agent-model-compare-judgment.ts +633 -0
- package/src/tools/agent-model-compare-run.ts +735 -0
- package/src/tools/agent-model-compare-tool.ts +698 -0
- package/src/tools/agent-model-compare-types.ts +191 -0
- package/src/tools/agent-model-compare-utils.ts +93 -0
- package/src/tools/agent-models-tool.ts +208 -0
- package/src/tools/agent-operator-action-tool.ts +1 -1
- package/src/tools/agent-operator-method-tool.ts +643 -0
- package/src/tools/agent-personal-ops-tool.ts +197 -0
- package/src/tools/agent-policy-explanation.ts +415 -0
- package/src/tools/agent-research-report-tool.ts +608 -0
- package/src/tools/agent-research-runner.ts +367 -0
- package/src/tools/agent-research-runs-tool.ts +434 -0
- package/src/tools/agent-research-sources-tool.ts +443 -0
- package/src/tools/agent-research-tool.ts +515 -0
- package/src/tools/agent-review-packet-presets-core.ts +757 -0
- package/src/tools/agent-review-packet-presets-tool.ts +466 -0
- package/src/tools/agent-review-packet-share-tool.ts +305 -0
- package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
- package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
- package/src/tools/agent-route-planner-candidates-work.ts +251 -0
- package/src/tools/agent-route-planner-helpers.ts +667 -0
- package/src/tools/agent-route-planner.ts +185 -0
- package/src/tools/agent-route-tool.ts +105 -0
- package/src/tools/agent-schedule-edit-tool.ts +210 -0
- package/src/tools/agent-schedule-tool.ts +282 -0
- package/src/tools/agent-security-tool.ts +145 -0
- package/src/tools/agent-sessions-tool.ts +122 -0
- package/src/tools/agent-settings-import-tool.ts +104 -0
- package/src/tools/agent-settings-tool.ts +176 -0
- package/src/tools/agent-setup-tool.ts +226 -0
- package/src/tools/agent-support-tool.ts +122 -0
- package/src/tools/agent-terminal-process-tools.ts +167 -0
- package/src/tools/agent-tool-policy-guard-types.ts +77 -0
- package/src/tools/agent-tool-policy-guard.ts +106 -85
- package/src/tools/agent-vibe-tool.ts +297 -0
- package/src/tools/agent-work-plan-tool.ts +265 -6
- package/src/tools/agent-workspace-tool.ts +305 -0
- package/src/tools/artifact-archive.ts +169 -0
- package/src/tools/tool-definition-compaction.ts +36 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname } 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 AgentResearchSourceStatus = 'candidate' | 'reviewed' | 'rejected' | 'used';
|
|
8
|
+
export type AgentResearchSourceCredibility = 'unreviewed' | 'low' | 'medium' | 'high' | 'mixed';
|
|
9
|
+
|
|
10
|
+
export interface AgentResearchSourceRecord {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly question: string;
|
|
13
|
+
readonly title: string;
|
|
14
|
+
readonly url?: string;
|
|
15
|
+
readonly publisher?: string;
|
|
16
|
+
readonly publishedAt?: string;
|
|
17
|
+
readonly accessedAt?: string;
|
|
18
|
+
readonly summary: string;
|
|
19
|
+
readonly evidence?: string;
|
|
20
|
+
readonly credibility: AgentResearchSourceCredibility;
|
|
21
|
+
readonly score: number;
|
|
22
|
+
readonly status: AgentResearchSourceStatus;
|
|
23
|
+
readonly tags: readonly string[];
|
|
24
|
+
readonly note?: string;
|
|
25
|
+
readonly usedInReportArtifactId?: string;
|
|
26
|
+
readonly provenance: string;
|
|
27
|
+
readonly createdAt: string;
|
|
28
|
+
readonly updatedAt: string;
|
|
29
|
+
readonly reviewedAt?: string;
|
|
30
|
+
readonly rejectedAt?: string;
|
|
31
|
+
readonly usedAt?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface AgentResearchSourceCreateInput {
|
|
35
|
+
readonly question: string;
|
|
36
|
+
readonly title: string;
|
|
37
|
+
readonly url?: string;
|
|
38
|
+
readonly publisher?: string;
|
|
39
|
+
readonly publishedAt?: string;
|
|
40
|
+
readonly accessedAt?: string;
|
|
41
|
+
readonly summary: string;
|
|
42
|
+
readonly evidence?: string;
|
|
43
|
+
readonly credibility?: AgentResearchSourceCredibility;
|
|
44
|
+
readonly score?: number;
|
|
45
|
+
readonly tags?: readonly string[];
|
|
46
|
+
readonly note?: string;
|
|
47
|
+
readonly provenance?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface AgentResearchSourceReviewInput {
|
|
51
|
+
readonly credibility?: AgentResearchSourceCredibility;
|
|
52
|
+
readonly score?: number;
|
|
53
|
+
readonly note?: string;
|
|
54
|
+
readonly summary?: string;
|
|
55
|
+
readonly evidence?: string;
|
|
56
|
+
readonly tags?: readonly string[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface AgentResearchSourceUseInput {
|
|
60
|
+
readonly reportArtifactId?: string;
|
|
61
|
+
readonly note?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface AgentResearchSourceSnapshot {
|
|
65
|
+
readonly path: string;
|
|
66
|
+
readonly sources: readonly AgentResearchSourceRecord[];
|
|
67
|
+
readonly candidates: readonly AgentResearchSourceRecord[];
|
|
68
|
+
readonly reviewed: readonly AgentResearchSourceRecord[];
|
|
69
|
+
readonly rejected: readonly AgentResearchSourceRecord[];
|
|
70
|
+
readonly used: readonly AgentResearchSourceRecord[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface ResearchSourceStoreFile {
|
|
74
|
+
readonly version: 1;
|
|
75
|
+
readonly sources: readonly AgentResearchSourceRecord[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type AgentResearchSourceStorePaths = Pick<ShellPathService, 'resolveProjectPath'>;
|
|
79
|
+
|
|
80
|
+
const STORE_VERSION = 1;
|
|
81
|
+
const SECRETISH = /token|secret|password|authorization|credential|api[-_]?key/i;
|
|
82
|
+
|
|
83
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
84
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function readString(value: unknown, fallback = ''): string {
|
|
88
|
+
return typeof value === 'string' ? value : fallback;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function readStringArray(value: unknown): string[] {
|
|
92
|
+
if (!Array.isArray(value)) return [];
|
|
93
|
+
return value.filter((entry): entry is string => typeof entry === 'string').map((entry) => entry.trim()).filter(Boolean);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function normalizeText(value: string): string {
|
|
97
|
+
return value.trim().replace(/\s+/g, ' ');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function normalizeList(values: readonly string[] | undefined): string[] {
|
|
101
|
+
const seen = new Set<string>();
|
|
102
|
+
const result: string[] = [];
|
|
103
|
+
for (const value of values ?? []) {
|
|
104
|
+
const trimmed = value.trim();
|
|
105
|
+
if (!trimmed) continue;
|
|
106
|
+
const key = trimmed.toLowerCase();
|
|
107
|
+
if (seen.has(key)) continue;
|
|
108
|
+
seen.add(key);
|
|
109
|
+
result.push(trimmed);
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function slugify(value: string): string {
|
|
115
|
+
const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
116
|
+
return slug || 'source';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function nowIso(): string {
|
|
120
|
+
return new Date().toISOString();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function credibility(value: unknown): AgentResearchSourceCredibility {
|
|
124
|
+
if (value === 'low' || value === 'medium' || value === 'high' || value === 'mixed') return value;
|
|
125
|
+
return 'unreviewed';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function status(value: unknown): AgentResearchSourceStatus {
|
|
129
|
+
if (value === 'reviewed' || value === 'rejected' || value === 'used') return value;
|
|
130
|
+
return 'candidate';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function boundedScore(value: unknown, fallback = 50): number {
|
|
134
|
+
const parsed = typeof value === 'number' ? value : typeof value === 'string' && value.trim() ? Number(value) : fallback;
|
|
135
|
+
if (!Number.isFinite(parsed)) return fallback;
|
|
136
|
+
return Math.max(0, Math.min(100, Math.round(parsed)));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function sanitizeResearchSourceUrl(value: string): string {
|
|
140
|
+
try {
|
|
141
|
+
const url = new URL(value);
|
|
142
|
+
for (const key of [...url.searchParams.keys()]) {
|
|
143
|
+
if (SECRETISH.test(key)) url.searchParams.set(key, '<redacted>');
|
|
144
|
+
}
|
|
145
|
+
return url.toString();
|
|
146
|
+
} catch {
|
|
147
|
+
return value.replace(/([?&\s](?:token|secret|password|authorization|credential|api[-_]?key)=)[^\s&]+/gi, '$1<redacted>');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function parseSource(value: unknown): AgentResearchSourceRecord | null {
|
|
152
|
+
if (!isRecord(value)) return null;
|
|
153
|
+
const id = readString(value.id).trim();
|
|
154
|
+
const question = normalizeText(readString(value.question));
|
|
155
|
+
const title = normalizeText(readString(value.title));
|
|
156
|
+
const summary = readString(value.summary).trim();
|
|
157
|
+
if (!id || !question || !title || !summary) return null;
|
|
158
|
+
const createdAt = readString(value.createdAt, nowIso());
|
|
159
|
+
const url = readString(value.url).trim();
|
|
160
|
+
const publisher = readString(value.publisher).trim();
|
|
161
|
+
const publishedAt = readString(value.publishedAt).trim();
|
|
162
|
+
const accessedAt = readString(value.accessedAt).trim();
|
|
163
|
+
const evidence = readString(value.evidence).trim();
|
|
164
|
+
const note = readString(value.note).trim();
|
|
165
|
+
const reviewedAt = readString(value.reviewedAt).trim();
|
|
166
|
+
const rejectedAt = readString(value.rejectedAt).trim();
|
|
167
|
+
const usedAt = readString(value.usedAt).trim();
|
|
168
|
+
const usedInReportArtifactId = readString(value.usedInReportArtifactId).trim();
|
|
169
|
+
return {
|
|
170
|
+
id,
|
|
171
|
+
question,
|
|
172
|
+
title,
|
|
173
|
+
...(url ? { url: sanitizeResearchSourceUrl(url) } : {}),
|
|
174
|
+
...(publisher ? { publisher } : {}),
|
|
175
|
+
...(publishedAt ? { publishedAt } : {}),
|
|
176
|
+
...(accessedAt ? { accessedAt } : {}),
|
|
177
|
+
summary,
|
|
178
|
+
...(evidence ? { evidence } : {}),
|
|
179
|
+
credibility: credibility(value.credibility),
|
|
180
|
+
score: boundedScore(value.score),
|
|
181
|
+
status: status(value.status),
|
|
182
|
+
tags: readStringArray(value.tags),
|
|
183
|
+
...(note ? { note } : {}),
|
|
184
|
+
...(usedInReportArtifactId ? { usedInReportArtifactId } : {}),
|
|
185
|
+
provenance: readString(value.provenance, 'agent-research-sources').trim() || 'agent-research-sources',
|
|
186
|
+
createdAt,
|
|
187
|
+
updatedAt: readString(value.updatedAt, createdAt),
|
|
188
|
+
...(reviewedAt ? { reviewedAt } : {}),
|
|
189
|
+
...(rejectedAt ? { rejectedAt } : {}),
|
|
190
|
+
...(usedAt ? { usedAt } : {}),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function parseStore(raw: string): ResearchSourceStoreFile {
|
|
195
|
+
const parsed: unknown = JSON.parse(raw);
|
|
196
|
+
if (!isRecord(parsed)) return { version: STORE_VERSION, sources: [] };
|
|
197
|
+
return {
|
|
198
|
+
version: STORE_VERSION,
|
|
199
|
+
sources: Array.isArray(parsed.sources)
|
|
200
|
+
? parsed.sources.map(parseSource).filter((entry): entry is AgentResearchSourceRecord => entry !== null)
|
|
201
|
+
: [],
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function formatStore(store: ResearchSourceStoreFile): string {
|
|
206
|
+
return `${JSON.stringify(store, null, 2)}\n`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function assertSourceContentSafe(fields: readonly string[]): void {
|
|
210
|
+
assertNoSecretLikeText(fields, 'Research source queue');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function researchSourceStorePath(shellPaths: AgentResearchSourceStorePaths): string {
|
|
214
|
+
return shellPaths.resolveProjectPath(GOODVIBES_AGENT_SURFACE_ROOT, 'research', 'sources.json');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function researchSourceReportLine(source: AgentResearchSourceRecord): string {
|
|
218
|
+
const url = source.url ?? '';
|
|
219
|
+
const note = [source.publisher, source.note, source.summary].filter(Boolean).join(' ');
|
|
220
|
+
return [source.title, url, source.credibility, note].filter(Boolean).join(' | ');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export class AgentResearchSourceRegistry {
|
|
224
|
+
public constructor(private readonly storePath: string) {}
|
|
225
|
+
|
|
226
|
+
public static fromShellPaths(shellPaths: AgentResearchSourceStorePaths): AgentResearchSourceRegistry {
|
|
227
|
+
return new AgentResearchSourceRegistry(researchSourceStorePath(shellPaths));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
public snapshot(): AgentResearchSourceSnapshot {
|
|
231
|
+
const sources = [...this.readStore().sources].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
232
|
+
return {
|
|
233
|
+
path: this.storePath,
|
|
234
|
+
sources,
|
|
235
|
+
candidates: sources.filter((source) => source.status === 'candidate'),
|
|
236
|
+
reviewed: sources.filter((source) => source.status === 'reviewed'),
|
|
237
|
+
rejected: sources.filter((source) => source.status === 'rejected'),
|
|
238
|
+
used: sources.filter((source) => source.status === 'used'),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
public list(statusFilter?: AgentResearchSourceStatus): readonly AgentResearchSourceRecord[] {
|
|
243
|
+
const sources = this.snapshot().sources;
|
|
244
|
+
return statusFilter ? sources.filter((source) => source.status === statusFilter) : sources;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
public search(query: string): readonly AgentResearchSourceRecord[] {
|
|
248
|
+
const normalized = query.trim().toLowerCase();
|
|
249
|
+
if (!normalized) return this.list();
|
|
250
|
+
return this.list().filter((source) => [
|
|
251
|
+
source.id,
|
|
252
|
+
source.question,
|
|
253
|
+
source.title,
|
|
254
|
+
source.url ?? '',
|
|
255
|
+
source.publisher ?? '',
|
|
256
|
+
source.summary,
|
|
257
|
+
source.evidence ?? '',
|
|
258
|
+
source.credibility,
|
|
259
|
+
source.status,
|
|
260
|
+
source.note ?? '',
|
|
261
|
+
...source.tags,
|
|
262
|
+
].some((field) => field.toLowerCase().includes(normalized)));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public get(idOrTitle: string): AgentResearchSourceRecord | null {
|
|
266
|
+
const lookup = idOrTitle.trim().toLowerCase();
|
|
267
|
+
if (!lookup) return null;
|
|
268
|
+
return this.list().find((source) => (
|
|
269
|
+
source.id.toLowerCase() === lookup
|
|
270
|
+
|| source.title.toLowerCase() === lookup
|
|
271
|
+
|| source.url?.toLowerCase() === lookup
|
|
272
|
+
)) ?? null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
public create(input: AgentResearchSourceCreateInput): AgentResearchSourceRecord {
|
|
276
|
+
const store = this.readStore();
|
|
277
|
+
const question = normalizeText(input.question);
|
|
278
|
+
const title = normalizeText(input.title);
|
|
279
|
+
const summary = input.summary.trim();
|
|
280
|
+
if (!question) throw new Error('question is required.');
|
|
281
|
+
if (!title) throw new Error('title is required.');
|
|
282
|
+
if (!summary) throw new Error('summary is required.');
|
|
283
|
+
const url = input.url?.trim() ? sanitizeResearchSourceUrl(input.url.trim()) : undefined;
|
|
284
|
+
const publisher = input.publisher?.trim() || undefined;
|
|
285
|
+
const publishedAt = input.publishedAt?.trim() || undefined;
|
|
286
|
+
const accessedAt = input.accessedAt?.trim() || nowIso();
|
|
287
|
+
const evidence = input.evidence?.trim() || undefined;
|
|
288
|
+
const note = input.note?.trim() || undefined;
|
|
289
|
+
const tags = normalizeList(input.tags);
|
|
290
|
+
assertSourceContentSafe([question, title, publisher ?? '', summary, evidence ?? '', note ?? '', ...tags]);
|
|
291
|
+
const duplicate = store.sources.find((source) => (
|
|
292
|
+
(url && source.url?.toLowerCase() === url.toLowerCase())
|
|
293
|
+
|| (!url && source.title.toLowerCase() === title.toLowerCase() && source.question.toLowerCase() === question.toLowerCase())
|
|
294
|
+
));
|
|
295
|
+
if (duplicate) throw new Error(`Research source already exists ${duplicate.id}.`);
|
|
296
|
+
const timestamp = nowIso();
|
|
297
|
+
const source: AgentResearchSourceRecord = {
|
|
298
|
+
id: this.nextId(title, store.sources),
|
|
299
|
+
question,
|
|
300
|
+
title,
|
|
301
|
+
...(url ? { url } : {}),
|
|
302
|
+
...(publisher ? { publisher } : {}),
|
|
303
|
+
...(publishedAt ? { publishedAt } : {}),
|
|
304
|
+
accessedAt,
|
|
305
|
+
summary,
|
|
306
|
+
...(evidence ? { evidence } : {}),
|
|
307
|
+
credibility: input.credibility ?? 'unreviewed',
|
|
308
|
+
score: boundedScore(input.score, input.credibility === 'high' ? 80 : input.credibility === 'medium' ? 60 : 50),
|
|
309
|
+
status: input.credibility && input.credibility !== 'unreviewed' ? 'reviewed' : 'candidate',
|
|
310
|
+
tags,
|
|
311
|
+
...(note ? { note } : {}),
|
|
312
|
+
provenance: input.provenance?.trim() || 'agent-research-sources',
|
|
313
|
+
createdAt: timestamp,
|
|
314
|
+
updatedAt: timestamp,
|
|
315
|
+
...(input.credibility && input.credibility !== 'unreviewed' ? { reviewedAt: timestamp } : {}),
|
|
316
|
+
};
|
|
317
|
+
this.writeStore({ ...store, sources: [...store.sources, source] });
|
|
318
|
+
return source;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
public review(idOrTitle: string, input: AgentResearchSourceReviewInput): AgentResearchSourceRecord {
|
|
322
|
+
const store = this.readStore();
|
|
323
|
+
const existing = this.findInStore(store, idOrTitle);
|
|
324
|
+
if (!existing) throw new Error(`Unknown research source ${idOrTitle}.`);
|
|
325
|
+
const tags = input.tags === undefined ? existing.tags : normalizeList(input.tags);
|
|
326
|
+
const note = input.note === undefined ? existing.note : input.note.trim() || undefined;
|
|
327
|
+
const summary = input.summary === undefined ? existing.summary : input.summary.trim();
|
|
328
|
+
if (!summary) throw new Error('summary is required.');
|
|
329
|
+
const evidence = input.evidence === undefined ? existing.evidence : input.evidence.trim() || undefined;
|
|
330
|
+
assertSourceContentSafe([summary, evidence ?? '', note ?? '', ...tags]);
|
|
331
|
+
const credibilityValue = input.credibility ?? (existing.credibility === 'unreviewed' ? 'medium' : existing.credibility);
|
|
332
|
+
const timestamp = nowIso();
|
|
333
|
+
const { evidence: _oldEvidence, note: _oldNote, rejectedAt: _oldRejectedAt, ...base } = existing;
|
|
334
|
+
const reviewed: AgentResearchSourceRecord = {
|
|
335
|
+
...base,
|
|
336
|
+
summary,
|
|
337
|
+
...(evidence ? { evidence } : {}),
|
|
338
|
+
credibility: credibilityValue,
|
|
339
|
+
score: boundedScore(input.score, existing.score),
|
|
340
|
+
status: 'reviewed',
|
|
341
|
+
tags,
|
|
342
|
+
...(note ? { note } : {}),
|
|
343
|
+
reviewedAt: timestamp,
|
|
344
|
+
updatedAt: timestamp,
|
|
345
|
+
};
|
|
346
|
+
this.writeStore({
|
|
347
|
+
...store,
|
|
348
|
+
sources: store.sources.map((source) => source.id === existing.id ? reviewed : source),
|
|
349
|
+
});
|
|
350
|
+
return reviewed;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
public reject(idOrTitle: string, reason: string): AgentResearchSourceRecord {
|
|
354
|
+
const store = this.readStore();
|
|
355
|
+
const existing = this.findInStore(store, idOrTitle);
|
|
356
|
+
if (!existing) throw new Error(`Unknown research source ${idOrTitle}.`);
|
|
357
|
+
const note = reason.trim() || 'Rejected during source review.';
|
|
358
|
+
assertSourceContentSafe([note]);
|
|
359
|
+
const timestamp = nowIso();
|
|
360
|
+
const rejected: AgentResearchSourceRecord = {
|
|
361
|
+
...existing,
|
|
362
|
+
note,
|
|
363
|
+
status: 'rejected',
|
|
364
|
+
rejectedAt: timestamp,
|
|
365
|
+
updatedAt: timestamp,
|
|
366
|
+
};
|
|
367
|
+
this.writeStore({
|
|
368
|
+
...store,
|
|
369
|
+
sources: store.sources.map((source) => source.id === existing.id ? rejected : source),
|
|
370
|
+
});
|
|
371
|
+
return rejected;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
public markUsed(idOrTitle: string, input: AgentResearchSourceUseInput = {}): AgentResearchSourceRecord {
|
|
375
|
+
const store = this.readStore();
|
|
376
|
+
const existing = this.findInStore(store, idOrTitle);
|
|
377
|
+
if (!existing) throw new Error(`Unknown research source ${idOrTitle}.`);
|
|
378
|
+
const reportArtifactId = input.reportArtifactId?.trim() || existing.usedInReportArtifactId;
|
|
379
|
+
const note = input.note === undefined ? existing.note : input.note.trim() || undefined;
|
|
380
|
+
assertSourceContentSafe([reportArtifactId ?? '', note ?? '']);
|
|
381
|
+
const timestamp = nowIso();
|
|
382
|
+
const { note: _oldNote, usedInReportArtifactId: _oldArtifactId, ...base } = existing;
|
|
383
|
+
const used: AgentResearchSourceRecord = {
|
|
384
|
+
...base,
|
|
385
|
+
...(note ? { note } : {}),
|
|
386
|
+
...(reportArtifactId ? { usedInReportArtifactId: reportArtifactId } : {}),
|
|
387
|
+
status: 'used',
|
|
388
|
+
usedAt: timestamp,
|
|
389
|
+
updatedAt: timestamp,
|
|
390
|
+
};
|
|
391
|
+
this.writeStore({
|
|
392
|
+
...store,
|
|
393
|
+
sources: store.sources.map((source) => source.id === existing.id ? used : source),
|
|
394
|
+
});
|
|
395
|
+
return used;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
public delete(idOrTitle: string): AgentResearchSourceRecord {
|
|
399
|
+
const store = this.readStore();
|
|
400
|
+
const existing = this.findInStore(store, idOrTitle);
|
|
401
|
+
if (!existing) throw new Error(`Unknown research source ${idOrTitle}.`);
|
|
402
|
+
this.writeStore({
|
|
403
|
+
...store,
|
|
404
|
+
sources: store.sources.filter((source) => source.id !== existing.id),
|
|
405
|
+
});
|
|
406
|
+
return existing;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private readStore(): ResearchSourceStoreFile {
|
|
410
|
+
if (!existsSync(this.storePath)) return { version: STORE_VERSION, sources: [] };
|
|
411
|
+
return parseStore(readFileSync(this.storePath, 'utf-8'));
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
private writeStore(store: ResearchSourceStoreFile): void {
|
|
415
|
+
mkdirSync(dirname(this.storePath), { recursive: true });
|
|
416
|
+
const tempPath = `${this.storePath}.tmp`;
|
|
417
|
+
writeFileSync(tempPath, formatStore(store), 'utf-8');
|
|
418
|
+
renameSync(tempPath, this.storePath);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private nextId(title: string, sources: readonly AgentResearchSourceRecord[]): string {
|
|
422
|
+
const base = slugify(title);
|
|
423
|
+
const existing = new Set(sources.map((source) => source.id));
|
|
424
|
+
if (!existing.has(base)) return base;
|
|
425
|
+
for (let index = 2; index < 10_000; index += 1) {
|
|
426
|
+
const candidate = `${base}-${index}`;
|
|
427
|
+
if (!existing.has(candidate)) return candidate;
|
|
428
|
+
}
|
|
429
|
+
throw new Error('Unable to allocate a unique research source id.');
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
private findInStore(store: ResearchSourceStoreFile, idOrTitle: string): AgentResearchSourceRecord | null {
|
|
433
|
+
const lookup = idOrTitle.trim().toLowerCase();
|
|
434
|
+
if (!lookup) return null;
|
|
435
|
+
return store.sources.find((source) => (
|
|
436
|
+
source.id.toLowerCase() === lookup
|
|
437
|
+
|| source.title.toLowerCase() === lookup
|
|
438
|
+
|| source.url?.toLowerCase() === lookup
|
|
439
|
+
)) ?? null;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
@@ -410,11 +410,21 @@ export function evaluateAgentRoutineReadiness(
|
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
export function buildEnabledRoutinesPrompt(shellPaths: ShellPathService): string | null {
|
|
413
|
-
const
|
|
414
|
-
|
|
413
|
+
const enabledRecords = AgentRoutineRegistry.fromShellPaths(shellPaths).snapshot().enabledRoutines;
|
|
414
|
+
const enabled = enabledRecords.filter((routine) => routine.reviewState === 'reviewed' && evaluateAgentRoutineReadiness(routine).ready);
|
|
415
|
+
const suppressed = enabledRecords
|
|
416
|
+
.filter((routine) => !enabled.some((activeRoutine) => activeRoutine.id === routine.id))
|
|
417
|
+
.slice(0, 8)
|
|
418
|
+
.map((routine) => {
|
|
419
|
+
const readiness = evaluateAgentRoutineReadiness(routine);
|
|
420
|
+
const review = routine.reviewState === 'reviewed' ? '' : `review=${formatAgentRecordReviewState(routine.reviewState)}`;
|
|
421
|
+
const setup = readiness.ready ? '' : `missing=${readiness.missing.map(formatAgentSkillRequirement).join(', ')}`;
|
|
422
|
+
return `- ${routine.name}: ${[review, setup].filter(Boolean).join('; ')}`;
|
|
423
|
+
});
|
|
424
|
+
if (enabled.length === 0 && suppressed.length === 0) return null;
|
|
415
425
|
return [
|
|
416
426
|
'## Enabled GoodVibes Agent Routines',
|
|
417
|
-
'Use
|
|
427
|
+
'Use only reviewed, setup-ready local reusable routines inside the same serial assistant conversation when they fit the user request. Do not start hidden background jobs because a routine matches.',
|
|
418
428
|
'',
|
|
419
429
|
...enabled.slice(0, 8).flatMap((routine) => [
|
|
420
430
|
`### ${routine.name}`,
|
|
@@ -425,5 +435,11 @@ export function buildEnabledRoutinesPrompt(shellPaths: ShellPathService): string
|
|
|
425
435
|
routine.steps,
|
|
426
436
|
'',
|
|
427
437
|
]),
|
|
438
|
+
...(suppressed.length > 0 ? [
|
|
439
|
+
'### Suppressed Routines Pending Review Or Setup',
|
|
440
|
+
'Do not apply these routines until the user reviews them or resolves setup through the learning curator.',
|
|
441
|
+
...suppressed,
|
|
442
|
+
'',
|
|
443
|
+
] : []),
|
|
428
444
|
].join('\n').trim();
|
|
429
445
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type RoutineScheduleReceipt,
|
|
9
9
|
type RoutineScheduleReceiptSnapshot,
|
|
10
10
|
} from './routine-schedule-promotion.ts';
|
|
11
|
+
import { scheduleConfirmationRouteLines, scheduleNextRouteLines, scheduleRouteArg } from './schedule-next-routes.ts';
|
|
11
12
|
|
|
12
13
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
13
14
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -47,6 +48,27 @@ function formatRoutineScheduleFailureKind(kind: string): string {
|
|
|
47
48
|
return kind.replace(/[_-]+/g, ' ');
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
function routineScheduleSelector(preview: RoutineSchedulePromotionPreview): { readonly flag: string; readonly value: string } {
|
|
52
|
+
if (preview.payload.kind === 'cron') return { flag: '--cron', value: String(preview.payload.cron ?? '') };
|
|
53
|
+
if (preview.payload.kind === 'every') return { flag: '--every', value: String(preview.payload.every ?? '') };
|
|
54
|
+
return { flag: '--at', value: String(preview.payload.at ?? '') };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function routineScheduleConfirmCommand(preview: RoutineSchedulePromotionPreview): string {
|
|
58
|
+
const selector = routineScheduleSelector(preview);
|
|
59
|
+
const args = [
|
|
60
|
+
'/schedule promote-routine',
|
|
61
|
+
scheduleRouteArg(preview.routineId),
|
|
62
|
+
selector.flag,
|
|
63
|
+
scheduleRouteArg(selector.value),
|
|
64
|
+
];
|
|
65
|
+
if (typeof preview.payload.timezone === 'string' && preview.payload.timezone) {
|
|
66
|
+
args.push('--timezone', scheduleRouteArg(preview.payload.timezone));
|
|
67
|
+
}
|
|
68
|
+
args.push('--yes');
|
|
69
|
+
return args.join(' ');
|
|
70
|
+
}
|
|
71
|
+
|
|
50
72
|
export function formatRoutineSchedulePreview(preview: RoutineSchedulePromotionPreview): string {
|
|
51
73
|
const schedule = preview.payload.kind === 'cron'
|
|
52
74
|
? `${preview.payload.cron}${preview.payload.timezone ? ` [${preview.payload.timezone}]` : ''}`
|
|
@@ -65,7 +87,10 @@ export function formatRoutineSchedulePreview(preview: RoutineSchedulePromotionPr
|
|
|
65
87
|
` delivery: ${delivery?.mode ?? 'none'}${deliveryTargetCount > 0 ? ` (${deliveryTargetCount} target${deliveryTargetCount === 1 ? '' : 's'})` : ''}`,
|
|
66
88
|
' target connected GoodVibes host/main conversation route',
|
|
67
89
|
' policy isolated Agent Knowledge only; no default knowledge/non-Agent fallback; no delegated review unless explicitly requested',
|
|
68
|
-
|
|
90
|
+
...scheduleConfirmationRouteLines({
|
|
91
|
+
workspace: 'workspace action:"run" actionId:"schedule-promote-routine" confirm:true explicitUserRequest:"..."',
|
|
92
|
+
cli: routineScheduleConfirmCommand(preview),
|
|
93
|
+
}),
|
|
69
94
|
].join('\n');
|
|
70
95
|
}
|
|
71
96
|
|
|
@@ -79,7 +104,7 @@ export function formatRoutineScheduleSuccess(result: RoutineSchedulePromotionSuc
|
|
|
79
104
|
` schedule ${id}`,
|
|
80
105
|
` status ${status}`,
|
|
81
106
|
` route ${result.kind} ${result.route}`,
|
|
82
|
-
|
|
107
|
+
...scheduleNextRouteLines(id),
|
|
83
108
|
].join('\n');
|
|
84
109
|
}
|
|
85
110
|
|
|
@@ -22,6 +22,13 @@ export interface AgentRuntimeProfileStarterTemplate extends AgentRuntimeProfileT
|
|
|
22
22
|
readonly triggers: readonly string[];
|
|
23
23
|
readonly tags: readonly string[];
|
|
24
24
|
}[];
|
|
25
|
+
readonly vibe?: {
|
|
26
|
+
readonly body: string;
|
|
27
|
+
readonly source: 'discovered' | 'template';
|
|
28
|
+
readonly appliedAs: 'global';
|
|
29
|
+
readonly sourcePaths: readonly string[];
|
|
30
|
+
readonly truncated: number;
|
|
31
|
+
};
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
export interface AgentRuntimeProfileStarterTemplateFile {
|