@pellux/goodvibes-agent 1.2.0 → 1.4.1
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 +194 -0
- package/dist/package/{ast-grep-napi.linux-x64-gnu-swtppvy9.node → ast-grep-napi.linux-x64-gnu-mkk8xwww.node} +0 -0
- package/dist/package/{ast-grep-napi.linux-x64-musl-ttfcdtap.node → ast-grep-napi.linux-x64-musl-ryqtgdv6.node} +0 -0
- package/dist/package/main.js +65740 -57156
- package/docs/README.md +3 -3
- package/docs/connected-host.md +2 -2
- package/docs/getting-started.md +11 -9
- package/docs/tools-and-commands.md +12 -10
- package/docs/voice-and-live-tts.md +2 -2
- package/package.json +1 -1
- package/release/release-notes.md +15 -144
- package/release/release-readiness.json +36 -36
- package/src/agent/competitive-feature-inventory.ts +42 -44
- package/src/agent/setup-wizard-artifact-receipts.ts +366 -0
- package/src/agent/setup-wizard.ts +267 -24
- package/src/cli/tui-startup.ts +2 -2
- package/src/input/agent-workspace-activation.ts +2 -2
- package/src/input/agent-workspace-categories.ts +2 -2
- package/src/input/agent-workspace-onboarding-categories.ts +4 -4
- package/src/input/agent-workspace-onboarding-finish.ts +21 -0
- package/src/input/agent-workspace-settings.ts +47 -1
- package/src/input/agent-workspace-setup-snapshot.ts +17 -6
- package/src/input/agent-workspace-setup.ts +20 -26
- package/src/input/agent-workspace-snapshot.ts +16 -3
- package/src/input/agent-workspace-types.ts +5 -2
- package/src/input/agent-workspace.ts +21 -6
- package/src/input/handler.ts +67 -5
- package/src/input/setup-wizard-live-receipts.ts +76 -0
- package/src/renderer/agent-workspace-context-lines.ts +17 -33
- package/src/renderer/agent-workspace.ts +434 -21
- package/src/runtime/tool-permission-safety.ts +1 -1
- package/src/tools/agent-harness-agent-orchestration-policy.ts +75 -0
- package/src/tools/agent-harness-agent-orchestration.ts +216 -128
- package/src/tools/agent-harness-autonomy-live-records.ts +154 -0
- package/src/tools/agent-harness-autonomy-queue-types.ts +1 -1
- package/src/tools/agent-harness-autonomy-queue.ts +19 -8
- package/src/tools/agent-harness-autonomy-watcher-read-models.ts +509 -0
- package/src/tools/agent-harness-background-processes.ts +8 -4
- package/src/tools/agent-harness-browser-cockpit-route.ts +188 -34
- package/src/tools/agent-harness-browser-control.ts +12 -4
- package/src/tools/agent-harness-browser-pwa-read-models.ts +622 -0
- package/src/tools/agent-harness-device-live-read-models.ts +366 -0
- package/src/tools/agent-harness-execution-posture.ts +3 -0
- package/src/tools/agent-harness-interactive-runtime-records.ts +421 -0
- package/src/tools/agent-harness-local-model-benchmarks.ts +71 -1
- package/src/tools/agent-harness-local-model-endpoints.ts +469 -354
- 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 +27 -12
- package/src/tools/agent-harness-memory-external-providers.ts +796 -0
- package/src/tools/agent-harness-memory-posture.ts +253 -137
- 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-mode-catalog.ts +4 -2
- package/src/tools/agent-harness-model-provider-health.ts +139 -42
- package/src/tools/agent-harness-model-readiness.ts +31 -5
- package/src/tools/agent-harness-model-routing-types.ts +61 -0
- package/src/tools/agent-harness-model-routing.ts +31 -6
- package/src/tools/agent-harness-pairing-posture.ts +30 -9
- package/src/tools/agent-harness-personal-ops-certification.ts +116 -0
- package/src/tools/agent-harness-personal-ops-lanes.ts +81 -15
- 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 +176 -224
- package/src/tools/agent-harness-personal-ops-types.ts +19 -1
- package/src/tools/agent-harness-personal-ops.ts +18 -11
- package/src/tools/agent-harness-remote-read-models.ts +541 -0
- package/src/tools/agent-harness-research-briefing.ts +26 -7
- package/src/tools/agent-harness-research-live-read-models.ts +500 -0
- package/src/tools/agent-harness-research-runs.ts +15 -3
- package/src/tools/agent-harness-research-workflow.ts +92 -19
- package/src/tools/agent-harness-setup-model-helpers.ts +1 -0
- package/src/tools/agent-harness-setup-posture.ts +7 -7
- package/src/tools/agent-harness-setup-smoke.ts +26 -1
- package/src/tools/agent-harness-tool-schema.ts +23 -1
- package/src/tools/agent-harness-tool-types.ts +5 -0
- package/src/tools/agent-harness-tool.ts +9 -1
- package/src/tools/agent-harness-workspace-actions.ts +1 -1
- package/src/tools/agent-memory-tool.ts +40 -1
- package/src/tools/agent-model-compare-run.ts +13 -0
- package/src/tools/agent-research-runner.ts +367 -0
- package/src/tools/agent-research-tool.ts +7 -179
- package/src/tools/agent-route-planner-candidates-surfaces.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CommandContext } from '../input/command-registry.ts';
|
|
2
|
+
import type { ArtifactDescriptor } from '@pellux/goodvibes-sdk/platform/artifacts';
|
|
2
3
|
import { buildAgentWorkspaceRuntimeSnapshot } from '../input/agent-workspace-snapshot.ts';
|
|
3
4
|
import { previewHarnessText } from './agent-harness-text.ts';
|
|
4
5
|
import type { UiAutomationSnapshot, UiTasksSnapshot } from '../runtime/ui-read-models.ts';
|
|
@@ -22,6 +23,10 @@ function formatTimeFragment(label: string, value: number | undefined): string {
|
|
|
22
23
|
return formatted ? `${label} ${formatted}` : '';
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
function readString(value: unknown): string {
|
|
27
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
const SENSITIVE_TEXT_PATTERNS: readonly [RegExp, string][] = [
|
|
26
31
|
[/("?\b(?:api[-_]?key|apikey|token|secret|password|passwd|credential|authorization)\b"?\s*:\s*)("[^"]*"|'[^']*'|[^\s,}]+)/gi, '$1"<redacted>"'],
|
|
27
32
|
[/\b([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTHORIZATION|BEARER)[A-Z0-9_]*)=("[^"]*"|'[^']*'|[^\s]+)/gi, '$1=<redacted>'],
|
|
@@ -30,6 +35,20 @@ const SENSITIVE_TEXT_PATTERNS: readonly [RegExp, string][] = [
|
|
|
30
35
|
[/(\s--(?:token|password|secret|api-key|api_key)\s+)("[^"]*"|'[^']*'|[^\s]+)/gi, '$1<redacted>'],
|
|
31
36
|
];
|
|
32
37
|
|
|
38
|
+
const WATCHER_RECEIPT_PURPOSES = new Set([
|
|
39
|
+
'watcher-receipt',
|
|
40
|
+
'watcher-run-receipt',
|
|
41
|
+
'automation-watcher-receipt',
|
|
42
|
+
'automation-run-history-receipt',
|
|
43
|
+
'durable-run-history-receipt',
|
|
44
|
+
'agent-watcher-receipt',
|
|
45
|
+
'agent-watcher-run-receipt',
|
|
46
|
+
'connected-host-watcher-receipt',
|
|
47
|
+
'connected-host-watcher-run-receipt',
|
|
48
|
+
'connected-host-automation-run-history-receipt',
|
|
49
|
+
'provider-source-record-receipt',
|
|
50
|
+
]);
|
|
51
|
+
|
|
33
52
|
function redactHarnessOutputText(value: string): string {
|
|
34
53
|
return SENSITIVE_TEXT_PATTERNS.reduce((text, [pattern, replacement]) => text.replace(pattern, replacement), value);
|
|
35
54
|
}
|
|
@@ -45,6 +64,64 @@ function compactUnknown(value: unknown): string {
|
|
|
45
64
|
}
|
|
46
65
|
}
|
|
47
66
|
|
|
67
|
+
function artifactMetadata(artifact: ArtifactDescriptor): Readonly<Record<string, unknown>> {
|
|
68
|
+
return artifact.metadata && typeof artifact.metadata === 'object'
|
|
69
|
+
? artifact.metadata as Readonly<Record<string, unknown>>
|
|
70
|
+
: {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function artifactMetadataString(artifact: ArtifactDescriptor, key: string): string {
|
|
74
|
+
return readString(artifactMetadata(artifact)[key]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function artifactMetadataBoolean(artifact: ArtifactDescriptor, key: string): boolean | null {
|
|
78
|
+
const value = artifactMetadata(artifact)[key];
|
|
79
|
+
if (typeof value === 'boolean') return value;
|
|
80
|
+
if (typeof value === 'string') {
|
|
81
|
+
const normalized = value.trim().toLowerCase();
|
|
82
|
+
if (normalized === 'true') return true;
|
|
83
|
+
if (normalized === 'false') return false;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function artifactTimestamp(artifact: ArtifactDescriptor): number {
|
|
89
|
+
const explicit = artifactMetadataString(artifact, 'createdAt')
|
|
90
|
+
|| artifactMetadataString(artifact, 'recordedAt')
|
|
91
|
+
|| artifactMetadataString(artifact, 'completedAt')
|
|
92
|
+
|| artifactMetadataString(artifact, 'timestamp');
|
|
93
|
+
if (explicit) {
|
|
94
|
+
const parsed = Date.parse(explicit);
|
|
95
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
96
|
+
}
|
|
97
|
+
return typeof artifact.createdAt === 'number' && Number.isFinite(artifact.createdAt) ? artifact.createdAt : 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function normalizedReceiptStatus(artifact: ArtifactDescriptor): string {
|
|
101
|
+
const raw = (artifactMetadataString(artifact, 'status')
|
|
102
|
+
|| artifactMetadataString(artifact, 'outcome')
|
|
103
|
+
|| artifactMetadataString(artifact, 'result')).toLowerCase();
|
|
104
|
+
if (!raw) return 'unknown';
|
|
105
|
+
if (['ok', 'ready', 'success', 'succeeded', 'complete', 'completed', 'delivered', 'captured', 'recorded'].includes(raw)) return 'succeeded';
|
|
106
|
+
if (['queued', 'scheduled', 'running', 'pending', 'in-progress', 'in_progress'].includes(raw)) return raw.replace('_', '-');
|
|
107
|
+
if (['blocked', 'needs-review', 'needs_setup', 'needs-setup'].includes(raw)) return 'blocked';
|
|
108
|
+
if (['fail', 'failed', 'error', 'errored'].includes(raw)) return 'failed';
|
|
109
|
+
return raw;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function watcherReceiptArtifacts(context: CommandContext): readonly ArtifactDescriptor[] {
|
|
113
|
+
const store = context.platform.artifactStore;
|
|
114
|
+
if (!store?.list) return [];
|
|
115
|
+
try {
|
|
116
|
+
return store.list(100)
|
|
117
|
+
.filter((artifact) => WATCHER_RECEIPT_PURPOSES.has(artifactMetadataString(artifact, 'purpose')))
|
|
118
|
+
.sort((left, right) => artifactTimestamp(right) - artifactTimestamp(left))
|
|
119
|
+
.slice(0, 20);
|
|
120
|
+
} catch {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
48
125
|
function formatIntervalMs(value: number): string {
|
|
49
126
|
if (!Number.isFinite(value) || value <= 0) return `${value}ms`;
|
|
50
127
|
const units: ReadonlyArray<readonly [number, string]> = [
|
|
@@ -462,6 +539,83 @@ export function automationRunLiveRecords(context: CommandContext): readonly Auto
|
|
|
462
539
|
});
|
|
463
540
|
}
|
|
464
541
|
|
|
542
|
+
export function watcherReceiptLiveRecords(context: CommandContext): readonly AutonomyQueueLiveRecord[] {
|
|
543
|
+
return watcherReceiptArtifacts(context).map((artifact) => {
|
|
544
|
+
const purpose = artifactMetadataString(artifact, 'purpose');
|
|
545
|
+
const operation = artifactMetadataString(artifact, 'operation')
|
|
546
|
+
|| artifactMetadataString(artifact, 'action')
|
|
547
|
+
|| artifactMetadataString(artifact, 'event')
|
|
548
|
+
|| 'watcher-run';
|
|
549
|
+
const status = normalizedReceiptStatus(artifact);
|
|
550
|
+
const watcherId = artifactMetadataString(artifact, 'watcherId')
|
|
551
|
+
|| artifactMetadataString(artifact, 'sourceId')
|
|
552
|
+
|| artifactMetadataString(artifact, 'providerSourceId');
|
|
553
|
+
const runId = artifactMetadataString(artifact, 'runId')
|
|
554
|
+
|| artifactMetadataString(artifact, 'jobRunId')
|
|
555
|
+
|| artifactMetadataString(artifact, 'automationRunId');
|
|
556
|
+
const provider = artifactMetadataString(artifact, 'providerId')
|
|
557
|
+
|| artifactMetadataString(artifact, 'provider')
|
|
558
|
+
|| artifactMetadataString(artifact, 'sourceProvider');
|
|
559
|
+
const trigger = artifactMetadataString(artifact, 'trigger')
|
|
560
|
+
|| artifactMetadataString(artifact, 'triggerKind')
|
|
561
|
+
|| artifactMetadataString(artifact, 'eventKind');
|
|
562
|
+
const correlationId = artifactMetadataString(artifact, 'correlationId')
|
|
563
|
+
|| artifactMetadataString(artifact, 'turnId')
|
|
564
|
+
|| artifactMetadataString(artifact, 'sessionId');
|
|
565
|
+
const redaction = artifactMetadataString(artifact, 'redaction')
|
|
566
|
+
|| artifactMetadataString(artifact, 'redactionPolicy')
|
|
567
|
+
|| 'metadata-only';
|
|
568
|
+
const failureReason = artifactMetadataString(artifact, 'failureReason')
|
|
569
|
+
|| artifactMetadataString(artifact, 'error');
|
|
570
|
+
const sourceTool = artifactMetadataString(artifact, 'sourceTool')
|
|
571
|
+
|| artifactMetadataString(artifact, 'qualifiedName');
|
|
572
|
+
const payloadRedacted = artifactMetadataBoolean(artifact, 'payloadRedacted');
|
|
573
|
+
const artifactRoute = `agent_artifacts show artifactId:"${artifact.id}" includeContent:false`;
|
|
574
|
+
const queueRoute = 'autonomy action:"item" queueItemId:"automation-runs" includeParameters:true';
|
|
575
|
+
return {
|
|
576
|
+
id: `watcher-receipt:${artifact.id}`,
|
|
577
|
+
label: `Watcher receipt: ${operation.replace(/[-_]+/g, ' ')}`,
|
|
578
|
+
status,
|
|
579
|
+
phase: trigger || operation,
|
|
580
|
+
updatedAt: formatEpochMs(artifactTimestamp(artifact)),
|
|
581
|
+
summary: [
|
|
582
|
+
`Durable watcher/run receipt ${artifact.id} reports ${operation} ${status}.`,
|
|
583
|
+
`Redaction ${redaction}.`,
|
|
584
|
+
payloadRedacted === true ? 'Payload redacted.' : payloadRedacted === false ? 'Payload redaction not asserted.' : '',
|
|
585
|
+
provider ? `Provider ${provider}.` : '',
|
|
586
|
+
watcherId ? `Watcher ${compactUnknown(watcherId)}.` : '',
|
|
587
|
+
runId ? `Run ${compactUnknown(runId)}.` : '',
|
|
588
|
+
trigger ? `Trigger ${compactUnknown(trigger)}.` : '',
|
|
589
|
+
failureReason ? `Failure ${compactUnknown(failureReason)}.` : '',
|
|
590
|
+
sourceTool ? `Source ${sourceTool}.` : '',
|
|
591
|
+
].filter(Boolean).join(' '),
|
|
592
|
+
inspectRoute: artifactRoute,
|
|
593
|
+
nextSteps: [
|
|
594
|
+
artifactRoute,
|
|
595
|
+
queueRoute,
|
|
596
|
+
],
|
|
597
|
+
sourceIds: [
|
|
598
|
+
watcherId,
|
|
599
|
+
runId,
|
|
600
|
+
provider,
|
|
601
|
+
trigger,
|
|
602
|
+
correlationId,
|
|
603
|
+
].filter((value): value is string => typeof value === 'string' && value.length > 0),
|
|
604
|
+
diagnostics: [
|
|
605
|
+
`purpose ${purpose}`,
|
|
606
|
+
`receipt artifact ${artifact.id}`,
|
|
607
|
+
`redaction ${redaction}`,
|
|
608
|
+
failureReason ? `failure ${compactUnknown(failureReason)}` : '',
|
|
609
|
+
].filter((value): value is string => value.length > 0),
|
|
610
|
+
...(failureReason ? { logTail: [compactUnknown(failureReason)] } : {}),
|
|
611
|
+
controls: [
|
|
612
|
+
availableControl('inspect', 'Inspect watcher receipt', 'read-only', artifactRoute),
|
|
613
|
+
availableControl('queue', 'Inspect automation queue', 'read-only', queueRoute),
|
|
614
|
+
],
|
|
615
|
+
};
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
|
|
465
619
|
export function scheduleLiveRecords(context: CommandContext): readonly AutonomyQueueLiveRecord[] {
|
|
466
620
|
const snapshot = readSnapshot(context.platform.readModels?.automation);
|
|
467
621
|
return [...(snapshot?.jobs ?? [])]
|
|
@@ -63,7 +63,7 @@ export interface AutonomyQueueLiveRecord {
|
|
|
63
63
|
export interface AutonomyQueueRecordOutput {
|
|
64
64
|
readonly status: 'preview' | 'route-only';
|
|
65
65
|
readonly route: string;
|
|
66
|
-
readonly source: 'runtime-task-result' | 'runtime-task-error' | 'not-published';
|
|
66
|
+
readonly source: 'runtime-task-result' | 'runtime-task-error' | 'host-output-chunk' | 'provider-source-preview' | 'not-published';
|
|
67
67
|
readonly preview?: string;
|
|
68
68
|
readonly policy: string;
|
|
69
69
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { getOperatorContract } from '@pellux/goodvibes-sdk/contracts';
|
|
2
2
|
import type { CommandContext } from '../input/command-registry.ts';
|
|
3
3
|
import { buildAgentWorkspaceRuntimeSnapshot } from '../input/agent-workspace-snapshot.ts';
|
|
4
|
-
import { automationRunLiveRecords, approvalLiveRecords, controlAvailable, firstAvailableControlRoute, researchRunLiveRecords, scheduleLiveRecords, taskLiveRecords } from './agent-harness-autonomy-live-records.ts';
|
|
4
|
+
import { automationRunLiveRecords, approvalLiveRecords, controlAvailable, firstAvailableControlRoute, researchRunLiveRecords, scheduleLiveRecords, taskLiveRecords, watcherReceiptLiveRecords } from './agent-harness-autonomy-live-records.ts';
|
|
5
|
+
import { watcherReadModelLiveRecords } from './agent-harness-autonomy-watcher-read-models.ts';
|
|
5
6
|
import type { AgentHarnessAutonomyQueueArgs, AutonomyQueueItem, AutonomyQueueLiveRecord, AutonomyQueueRecordControl, AutonomyQueueRecordOutput, AutonomyQueueResolution, AutonomyQueueStatus, OperatorContractMethod } from './agent-harness-autonomy-queue-types.ts';
|
|
6
7
|
export type { AutonomyQueueResolution } from './agent-harness-autonomy-queue-types.ts';
|
|
7
8
|
import { previewHarnessText } from './agent-harness-text.ts';
|
|
@@ -196,7 +197,10 @@ function buildQueueItems(context: CommandContext): readonly AutonomyQueueItem[]
|
|
|
196
197
|
const researchRuns = researchRunLiveRecords(snapshot);
|
|
197
198
|
const taskRecords = taskLiveRecords(context);
|
|
198
199
|
const approvalRecords = approvalLiveRecords(context);
|
|
199
|
-
const
|
|
200
|
+
const automationReadModelRecords = automationRunLiveRecords(context);
|
|
201
|
+
const watcherReadModelRecords = watcherReadModelLiveRecords(context);
|
|
202
|
+
const watcherReceiptRecords = watcherReceiptLiveRecords(context);
|
|
203
|
+
const automationRecords = [...automationReadModelRecords, ...watcherReadModelRecords, ...watcherReceiptRecords];
|
|
200
204
|
const scheduleRecords = scheduleLiveRecords(context);
|
|
201
205
|
const latestResearchRun = researchRuns[0];
|
|
202
206
|
const taskCancelRoute = firstAvailableControlRoute(taskRecords, 'cancel');
|
|
@@ -212,11 +216,12 @@ function buildQueueItems(context: CommandContext): readonly AutonomyQueueItem[]
|
|
|
212
216
|
: approvalMethods.length > 0
|
|
213
217
|
? 'ready'
|
|
214
218
|
: 'needs-setup';
|
|
215
|
-
const automationStatus: AutonomyQueueStatus = automationRecords.some((record) => record.status === 'failed')
|
|
219
|
+
const automationStatus: AutonomyQueueStatus = automationRecords.some((record) => record.status === 'failed' || record.status === 'blocked')
|
|
216
220
|
? 'attention'
|
|
217
|
-
:
|
|
221
|
+
: automationReadModelRecords.some((record) => record.status === 'queued' || record.status === 'running')
|
|
222
|
+
|| watcherReadModelRecords.some((record) => record.status === 'queued' || record.status === 'running')
|
|
218
223
|
? 'active'
|
|
219
|
-
: automationMethods.length > 0
|
|
224
|
+
: automationMethods.length > 0 || watcherReadModelRecords.length > 0 || watcherReceiptRecords.length > 0
|
|
220
225
|
? 'ready'
|
|
221
226
|
: 'needs-setup';
|
|
222
227
|
const scheduleStatus: AutonomyQueueStatus = scheduleRecords.some((record) => record.status === 'error')
|
|
@@ -345,13 +350,19 @@ function buildQueueItems(context: CommandContext): readonly AutonomyQueueItem[]
|
|
|
345
350
|
cancellable: true,
|
|
346
351
|
count: automationRecords.length > 0 ? automationRecords.length : automationMethods.length,
|
|
347
352
|
current: automationRecords.length > 0
|
|
348
|
-
? `${
|
|
353
|
+
? `${automationReadModelRecords.length} recent automation run record(s), ${watcherReadModelRecords.length} live watcher run/source record(s), ${watcherReceiptRecords.length} durable watcher/run receipt(s); active, failed, and retryable live runs expose exact control routes while receipt records stay read-only.`
|
|
349
354
|
: `${automationMethods.length} automation daemon method(s) are present; run, pause, resume, cancel, and retry actions are confirmed forms.`,
|
|
350
355
|
next: automationRecords.some((record) => record.status === 'failed')
|
|
351
356
|
? 'Inspect failed automation runs, then retry or leave them alone only through exact confirmed run routes.'
|
|
352
|
-
:
|
|
357
|
+
: automationReadModelRecords.some((record) => record.status === 'queued' || record.status === 'running')
|
|
353
358
|
? 'Inspect active automation runs and cancel only the exact run id the user authorizes.'
|
|
354
|
-
:
|
|
359
|
+
: watcherReadModelRecords.some((record) => record.status === 'queued' || record.status === 'running')
|
|
360
|
+
? 'Inspect live watcher/source records and use exact published watcher controls only for the run id the user authorizes.'
|
|
361
|
+
: watcherReadModelRecords.length > 0
|
|
362
|
+
? 'Review live watcher/source read models and durable receipts; mutate only through exact confirmed routes published by the host.'
|
|
363
|
+
: watcherReceiptRecords.length > 0
|
|
364
|
+
? 'Review durable watcher/run receipts, then wait for live SDK/daemon run records before controlling any run.'
|
|
365
|
+
: 'Inspect automation posture first. Use exact run/job ids for confirmed run control.',
|
|
355
366
|
inspectRoute: 'host action:"methods" query:"automation"',
|
|
356
367
|
modelRoute: 'workspace action:"actions" categoryId:"automation"',
|
|
357
368
|
cancelRoute: 'workspace action:"run" actionId:"automation-run-cancel" confirm:true explicitUserRequest:"..."',
|