@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
|
@@ -3,6 +3,7 @@ export type AgentSetupWizardStatus = 'complete' | 'active' | 'blocked';
|
|
|
3
3
|
export type AgentSetupWizardStepStatus = 'done' | 'current' | 'pending' | 'blocked';
|
|
4
4
|
export type AgentSetupWizardCheckpointStatus = 'available' | 'none' | 'stale' | 'unavailable';
|
|
5
5
|
export type AgentSetupWizardCloseoutStatus = 'complete' | 'ready-to-finish' | 'needs-smoke-evidence' | 'blocked';
|
|
6
|
+
export type AgentSetupWizardReceiptSchemaStatus = 'certified' | 'legacy';
|
|
6
7
|
|
|
7
8
|
export interface AgentSetupWizardSourceItem {
|
|
8
9
|
readonly id: string;
|
|
@@ -25,6 +26,8 @@ export interface AgentSetupWizardSmokeHistory {
|
|
|
25
26
|
readonly trend: string;
|
|
26
27
|
readonly latestResult: string | null;
|
|
27
28
|
readonly previousResult: string | null;
|
|
29
|
+
readonly latestEvidenceId?: string | null;
|
|
30
|
+
readonly latestEvidenceAt?: string | null;
|
|
28
31
|
readonly resultCounts: Readonly<Record<string, number>>;
|
|
29
32
|
readonly blockedCheckFrequency: readonly AgentSetupWizardBlockedCheckFrequency[];
|
|
30
33
|
readonly inspectLatestRoute: string | null;
|
|
@@ -33,6 +36,26 @@ export interface AgentSetupWizardSmokeHistory {
|
|
|
33
36
|
readonly reason?: string;
|
|
34
37
|
}
|
|
35
38
|
|
|
39
|
+
export type AgentSetupWizardDurableReceiptStatus = 'ready' | 'blocked' | 'failed' | 'unknown';
|
|
40
|
+
|
|
41
|
+
export interface AgentSetupWizardDurableReceipt {
|
|
42
|
+
readonly stepId: string;
|
|
43
|
+
readonly stepLabel?: string;
|
|
44
|
+
readonly status: AgentSetupWizardDurableReceiptStatus;
|
|
45
|
+
readonly receiptId: string;
|
|
46
|
+
readonly recordedAt: string;
|
|
47
|
+
readonly summary: string;
|
|
48
|
+
readonly inspectRoute: string | null;
|
|
49
|
+
readonly source?: string;
|
|
50
|
+
readonly schemaStatus?: AgentSetupWizardReceiptSchemaStatus;
|
|
51
|
+
readonly schemaVersion?: string;
|
|
52
|
+
readonly provenance?: readonly string[];
|
|
53
|
+
readonly publicationGuarantee?: string;
|
|
54
|
+
readonly eventCursor?: string;
|
|
55
|
+
readonly eventSequence?: number;
|
|
56
|
+
readonly publisher?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
36
59
|
export interface AgentSetupWizardRepeatedBlocker {
|
|
37
60
|
readonly setupItemId: string;
|
|
38
61
|
readonly checkId: string;
|
|
@@ -52,6 +75,36 @@ export interface AgentSetupWizardStep {
|
|
|
52
75
|
readonly backtrackRoute: string | null;
|
|
53
76
|
}
|
|
54
77
|
|
|
78
|
+
export type AgentSetupWizardStepHistoryKind = 'checkpoint' | 'setup-smoke' | 'durable-receipt';
|
|
79
|
+
|
|
80
|
+
export interface AgentSetupWizardStepHistoryEntry {
|
|
81
|
+
readonly id: string;
|
|
82
|
+
readonly stepId: string;
|
|
83
|
+
readonly stepLabel: string;
|
|
84
|
+
readonly kind: AgentSetupWizardStepHistoryKind;
|
|
85
|
+
readonly receiptId: string;
|
|
86
|
+
readonly recordedAt: string;
|
|
87
|
+
readonly summary: string;
|
|
88
|
+
readonly inspectRoute: string | null;
|
|
89
|
+
readonly source?: string;
|
|
90
|
+
readonly receiptStatus?: string;
|
|
91
|
+
readonly satisfiesReceipt?: boolean;
|
|
92
|
+
readonly schemaStatus?: AgentSetupWizardReceiptSchemaStatus;
|
|
93
|
+
readonly schemaVersion?: string;
|
|
94
|
+
readonly provenance?: readonly string[];
|
|
95
|
+
readonly publicationGuarantee?: string;
|
|
96
|
+
readonly eventCursor?: string;
|
|
97
|
+
readonly eventSequence?: number;
|
|
98
|
+
readonly publisher?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface AgentSetupWizardReceiptGap {
|
|
102
|
+
readonly stepId: string;
|
|
103
|
+
readonly stepLabel: string;
|
|
104
|
+
readonly requiredReceipt: string;
|
|
105
|
+
readonly summary: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
55
108
|
export interface AgentSetupWizardCloseout {
|
|
56
109
|
readonly status: AgentSetupWizardCloseoutStatus;
|
|
57
110
|
readonly label: string;
|
|
@@ -95,6 +148,15 @@ export interface AgentSetupWizardCheckpointAutoAdvance {
|
|
|
95
148
|
readonly inspectRoute: string;
|
|
96
149
|
}
|
|
97
150
|
|
|
151
|
+
export interface AgentSetupWizardDiagnostic {
|
|
152
|
+
readonly repeatedBlocker: AgentSetupWizardRepeatedBlocker | null;
|
|
153
|
+
readonly smokeHistory: AgentSetupWizardSmokeHistory;
|
|
154
|
+
readonly stepHistory: readonly AgentSetupWizardStepHistoryEntry[];
|
|
155
|
+
readonly receiptGaps: readonly AgentSetupWizardReceiptGap[];
|
|
156
|
+
readonly closeout: AgentSetupWizardCloseout;
|
|
157
|
+
readonly checkpoint: AgentSetupWizardCheckpoint;
|
|
158
|
+
}
|
|
159
|
+
|
|
98
160
|
export interface AgentSetupWizard {
|
|
99
161
|
readonly available: true;
|
|
100
162
|
readonly status: AgentSetupWizardStatus;
|
|
@@ -105,11 +167,8 @@ export interface AgentSetupWizard {
|
|
|
105
167
|
readonly progressLabel: string;
|
|
106
168
|
readonly next: string;
|
|
107
169
|
readonly reviewRoute: string;
|
|
108
|
-
readonly repeatedBlocker: AgentSetupWizardRepeatedBlocker | null;
|
|
109
|
-
readonly smokeHistory: AgentSetupWizardSmokeHistory;
|
|
110
|
-
readonly closeout: AgentSetupWizardCloseout;
|
|
111
|
-
readonly checkpoint: AgentSetupWizardCheckpoint;
|
|
112
170
|
readonly steps: readonly AgentSetupWizardStep[];
|
|
171
|
+
readonly _diagnostic: AgentSetupWizardDiagnostic;
|
|
113
172
|
}
|
|
114
173
|
|
|
115
174
|
export interface BuildAgentSetupWizardInput {
|
|
@@ -120,6 +179,8 @@ export interface BuildAgentSetupWizardInput {
|
|
|
120
179
|
readonly setupMarkerExists?: boolean;
|
|
121
180
|
readonly finishRoute?: string;
|
|
122
181
|
readonly finishUserRoute?: string;
|
|
182
|
+
readonly receiptRequiredStepIds?: readonly string[];
|
|
183
|
+
readonly durableReceipts?: readonly AgentSetupWizardDurableReceipt[];
|
|
123
184
|
readonly repeatedBlockerAliases?: Readonly<Record<string, readonly string[]>>;
|
|
124
185
|
readonly reviewRoute?: string;
|
|
125
186
|
}
|
|
@@ -305,9 +366,168 @@ function buildStep(item: AgentSetupWizardSourceItem, currentId: string | null):
|
|
|
305
366
|
};
|
|
306
367
|
}
|
|
307
368
|
|
|
369
|
+
function validIso(value: string | null | undefined): string | null {
|
|
370
|
+
if (!value || Number.isNaN(Date.parse(value))) return null;
|
|
371
|
+
return new Date(value).toISOString();
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function setupReceiptKind(stepId: string): string {
|
|
375
|
+
if (stepId === 'runtime' || stepId === 'connected-host-readiness') return 'connected-host service status receipt';
|
|
376
|
+
if (stepId === 'connected-host-auth') return 'connected-host auth receipt';
|
|
377
|
+
if (stepId === 'install-smoke') return 'setup smoke evidence receipt';
|
|
378
|
+
if (stepId === 'browser-pwa') return 'connected-host browser/PWA first-run receipt';
|
|
379
|
+
return 'durable setup receipt';
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function setupStepAliases(stepId: string): readonly string[] {
|
|
383
|
+
if (stepId === 'runtime' || stepId === 'connected-host-readiness') return ['runtime', 'connected-host-readiness'];
|
|
384
|
+
return [stepId];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function setupStepMatches(left: string, right: string): boolean {
|
|
388
|
+
const leftAliases = new Set(setupStepAliases(left));
|
|
389
|
+
return setupStepAliases(right).some((alias) => leftAliases.has(alias));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function durableReceiptSatisfies(receipt: AgentSetupWizardDurableReceipt): boolean {
|
|
393
|
+
return receipt.status === 'ready' && Boolean(validIso(receipt.recordedAt)) && receipt.receiptId.trim().length > 0;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export function setupStepHasSatisfyingReceipt(
|
|
397
|
+
receipts: readonly AgentSetupWizardDurableReceipt[],
|
|
398
|
+
stepId: string,
|
|
399
|
+
): boolean {
|
|
400
|
+
return receipts.some((receipt) => durableReceiptSatisfies(receipt) && setupStepMatches(stepId, receipt.stepId));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function latestSatisfyingReceipt(
|
|
404
|
+
receipts: readonly AgentSetupWizardDurableReceipt[],
|
|
405
|
+
stepId: string,
|
|
406
|
+
): AgentSetupWizardDurableReceipt | null {
|
|
407
|
+
return receipts
|
|
408
|
+
.filter((receipt) => durableReceiptSatisfies(receipt) && setupStepMatches(stepId, receipt.stepId))
|
|
409
|
+
.sort((left, right) => Date.parse(right.recordedAt) - Date.parse(left.recordedAt) || left.receiptId.localeCompare(right.receiptId))[0] ?? null;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function applyDurableReceiptStatus(
|
|
413
|
+
items: readonly AgentSetupWizardSourceItem[],
|
|
414
|
+
receipts: readonly AgentSetupWizardDurableReceipt[],
|
|
415
|
+
): readonly AgentSetupWizardSourceItem[] {
|
|
416
|
+
if (receipts.length === 0) return items;
|
|
417
|
+
return items.map((item) => {
|
|
418
|
+
const receipt = latestSatisfyingReceipt(receipts, item.id);
|
|
419
|
+
if (!receipt) return item;
|
|
420
|
+
return {
|
|
421
|
+
...item,
|
|
422
|
+
status: 'ready',
|
|
423
|
+
detail: `${item.detail} Durable receipt ${receipt.receiptId}: ${receipt.summary}`,
|
|
424
|
+
};
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function buildStepHistory(input: {
|
|
429
|
+
readonly items: readonly AgentSetupWizardSourceItem[];
|
|
430
|
+
readonly smokeHistory: AgentSetupWizardSmokeHistory;
|
|
431
|
+
readonly checkpoint: AgentSetupWizardCheckpoint;
|
|
432
|
+
readonly durableReceipts: readonly AgentSetupWizardDurableReceipt[];
|
|
433
|
+
}): readonly AgentSetupWizardStepHistoryEntry[] {
|
|
434
|
+
const byId = new Map(input.items.map((item) => [item.id, item]));
|
|
435
|
+
const history: AgentSetupWizardStepHistoryEntry[] = [];
|
|
436
|
+
|
|
437
|
+
const checkpointAt = validIso(input.checkpoint.savedAt);
|
|
438
|
+
if (input.checkpoint.status === 'available' && input.checkpoint.currentStepId && checkpointAt) {
|
|
439
|
+
const item = byId.get(input.checkpoint.currentStepId);
|
|
440
|
+
const stepLabel = item?.label ?? input.checkpoint.currentStepLabel ?? input.checkpoint.currentStepId;
|
|
441
|
+
const receiptId = `setup-wizard-checkpoint:${input.checkpoint.currentStepId}:${checkpointAt}`;
|
|
442
|
+
history.push({
|
|
443
|
+
id: `setup-step-history:${input.checkpoint.currentStepId}:checkpoint:${checkpointAt}`,
|
|
444
|
+
stepId: input.checkpoint.currentStepId,
|
|
445
|
+
stepLabel,
|
|
446
|
+
kind: 'checkpoint',
|
|
447
|
+
receiptId,
|
|
448
|
+
recordedAt: checkpointAt,
|
|
449
|
+
summary: `Saved checkpoint for ${stepLabel}.`,
|
|
450
|
+
inspectRoute: input.checkpoint.inspectRoute,
|
|
451
|
+
source: input.checkpoint.source ?? undefined,
|
|
452
|
+
satisfiesReceipt: false,
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const smokeAt = validIso(input.smokeHistory.latestEvidenceAt);
|
|
457
|
+
if (input.smokeHistory.latestEvidenceId && smokeAt) {
|
|
458
|
+
const item = byId.get('install-smoke');
|
|
459
|
+
const result = input.smokeHistory.latestResult ?? 'unknown';
|
|
460
|
+
const ready = result === 'ready-for-user-run';
|
|
461
|
+
history.push({
|
|
462
|
+
id: `setup-step-history:install-smoke:setup-smoke:${input.smokeHistory.latestEvidenceId}`,
|
|
463
|
+
stepId: 'install-smoke',
|
|
464
|
+
stepLabel: item?.label ?? 'Install smoke',
|
|
465
|
+
kind: 'setup-smoke',
|
|
466
|
+
receiptId: input.smokeHistory.latestEvidenceId,
|
|
467
|
+
recordedAt: smokeAt,
|
|
468
|
+
summary: `Latest setup smoke evidence is ${result}.`,
|
|
469
|
+
inspectRoute: input.smokeHistory.inspectLatestRoute,
|
|
470
|
+
source: 'agent-setup-smoke-evidence',
|
|
471
|
+
receiptStatus: result,
|
|
472
|
+
satisfiesReceipt: ready,
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
for (const receipt of input.durableReceipts) {
|
|
477
|
+
const recordedAt = validIso(receipt.recordedAt);
|
|
478
|
+
if (!recordedAt || receipt.receiptId.trim().length === 0) continue;
|
|
479
|
+
const item = input.items.find((candidate) => setupStepMatches(candidate.id, receipt.stepId));
|
|
480
|
+
const stepLabel = receipt.stepLabel ?? item?.label ?? receipt.stepId;
|
|
481
|
+
history.push({
|
|
482
|
+
id: `setup-step-history:${receipt.stepId}:durable-receipt:${receipt.receiptId}`,
|
|
483
|
+
stepId: receipt.stepId,
|
|
484
|
+
stepLabel,
|
|
485
|
+
kind: 'durable-receipt',
|
|
486
|
+
receiptId: receipt.receiptId,
|
|
487
|
+
recordedAt,
|
|
488
|
+
summary: receipt.summary,
|
|
489
|
+
inspectRoute: receipt.inspectRoute,
|
|
490
|
+
source: receipt.source,
|
|
491
|
+
receiptStatus: receipt.status,
|
|
492
|
+
satisfiesReceipt: durableReceiptSatisfies(receipt),
|
|
493
|
+
schemaStatus: receipt.schemaStatus,
|
|
494
|
+
schemaVersion: receipt.schemaVersion,
|
|
495
|
+
provenance: receipt.provenance,
|
|
496
|
+
publicationGuarantee: receipt.publicationGuarantee,
|
|
497
|
+
eventCursor: receipt.eventCursor,
|
|
498
|
+
eventSequence: receipt.eventSequence,
|
|
499
|
+
publisher: receipt.publisher,
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return history.sort((left, right) => Date.parse(right.recordedAt) - Date.parse(left.recordedAt) || left.id.localeCompare(right.id));
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function buildReceiptGaps(input: {
|
|
507
|
+
readonly items: readonly AgentSetupWizardSourceItem[];
|
|
508
|
+
readonly stepHistory: readonly AgentSetupWizardStepHistoryEntry[];
|
|
509
|
+
readonly receiptRequiredStepIds: readonly string[];
|
|
510
|
+
}): readonly AgentSetupWizardReceiptGap[] {
|
|
511
|
+
return input.receiptRequiredStepIds
|
|
512
|
+
.filter((stepId) => !input.stepHistory.some((entry) => entry.satisfiesReceipt === true && setupStepMatches(stepId, entry.stepId)))
|
|
513
|
+
.map((stepId) => {
|
|
514
|
+
const item = input.items.find((candidate) => candidate.id === stepId);
|
|
515
|
+
const stepLabel = item?.label ?? stepId;
|
|
516
|
+
const requiredReceipt = setupReceiptKind(stepId);
|
|
517
|
+
return {
|
|
518
|
+
stepId,
|
|
519
|
+
stepLabel,
|
|
520
|
+
requiredReceipt,
|
|
521
|
+
summary: `${stepLabel} still needs a stable ${requiredReceipt} id and timestamp before release closeout can count it as durable setup evidence.`,
|
|
522
|
+
};
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
|
|
308
526
|
function buildCloseout(input: {
|
|
309
527
|
readonly items: readonly AgentSetupWizardSourceItem[];
|
|
310
528
|
readonly smokeHistory: AgentSetupWizardSmokeHistory;
|
|
529
|
+
readonly setupSmokeReceiptReady: boolean;
|
|
530
|
+
readonly stepHistory: readonly AgentSetupWizardStepHistoryEntry[];
|
|
311
531
|
readonly criticalStepIds: readonly string[];
|
|
312
532
|
readonly setupMarkerExists: boolean;
|
|
313
533
|
readonly reviewRoute: string;
|
|
@@ -318,14 +538,21 @@ function buildCloseout(input: {
|
|
|
318
538
|
const primaryBlocker = input.items.find((item) => (
|
|
319
539
|
critical.has(item.id) && item.status === 'blocked'
|
|
320
540
|
)) ?? null;
|
|
321
|
-
const smokeReady = input.
|
|
541
|
+
const smokeReady = input.setupSmokeReceiptReady
|
|
542
|
+
|| (input.smokeHistory.status === 'available' && input.smokeHistory.latestResult === 'ready-for-user-run');
|
|
322
543
|
const latestSmoke = input.smokeHistory.status === 'available'
|
|
323
544
|
? input.smokeHistory.latestResult ?? 'unknown'
|
|
324
|
-
: input.smokeHistory.status;
|
|
545
|
+
: input.setupSmokeReceiptReady ? 'durable receipt ready' : input.smokeHistory.status;
|
|
546
|
+
const satisfyingSetupReceipts = input.stepHistory.filter((entry) => entry.kind === 'durable-receipt' && entry.satisfiesReceipt === true);
|
|
547
|
+
const certifiedSetupReceipts = satisfyingSetupReceipts.filter((entry) => entry.schemaStatus === 'certified');
|
|
548
|
+
const eventStreamSetupReceipts = satisfyingSetupReceipts.filter((entry) => entry.eventCursor);
|
|
325
549
|
const evidence = [
|
|
326
550
|
`critical setup blockers: ${primaryBlocker ? `${primaryBlocker.label} (${primaryBlocker.status})` : 'none'}`,
|
|
327
551
|
`setup marker: ${input.setupMarkerExists ? 'present' : 'missing'}`,
|
|
328
552
|
`latest setup smoke: ${latestSmoke}`,
|
|
553
|
+
`setup smoke receipt: ${input.setupSmokeReceiptReady ? 'ready' : 'missing'}`,
|
|
554
|
+
`certified setup receipts: ${certifiedSetupReceipts.length}/${satisfyingSetupReceipts.length}`,
|
|
555
|
+
`setup receipt event streams: ${eventStreamSetupReceipts.length}`,
|
|
329
556
|
`setup smoke history: ${input.smokeHistory.status}; total ${input.smokeHistory.total}; trend ${input.smokeHistory.trend}`,
|
|
330
557
|
];
|
|
331
558
|
const policy = 'Setup closeout is advisory until a confirmed finish route writes the local onboarding marker. Optional setup recommendations do not block closeout, but unresolved critical blockers or missing ready setup smoke evidence do.';
|
|
@@ -401,14 +628,23 @@ function buildCloseout(input: {
|
|
|
401
628
|
export function buildAgentSetupWizard(input: BuildAgentSetupWizardInput): AgentSetupWizard {
|
|
402
629
|
const smokeHistory = input.smokeHistory ?? emptyAgentSetupSmokeHistory();
|
|
403
630
|
const inputCheckpoint = input.checkpoint ?? emptyAgentSetupWizardCheckpoint();
|
|
404
|
-
const
|
|
405
|
-
const
|
|
406
|
-
const
|
|
631
|
+
const durableReceipts = input.durableReceipts ?? [];
|
|
632
|
+
const items = applyDurableReceiptStatus(input.items, durableReceipts);
|
|
633
|
+
const repeated = itemFromRepeatedBlockers(items, smokeHistory, input.repeatedBlockerAliases ?? {});
|
|
634
|
+
const blocking = firstBlockingItem(items);
|
|
635
|
+
const rawCheckpointItem = itemFromCheckpoint(items, inputCheckpoint);
|
|
407
636
|
const checkpointItem = blocking && rawCheckpointItem?.id !== blocking.id ? null : rawCheckpointItem;
|
|
408
|
-
const checkpoint = buildCheckpoint(inputCheckpoint,
|
|
409
|
-
const current = repeated?.item ?? blocking ?? checkpointItem ?? firstAttentionItem(
|
|
637
|
+
const checkpoint = buildCheckpoint(inputCheckpoint, items, checkpointItem, blocking);
|
|
638
|
+
const current = repeated?.item ?? blocking ?? checkpointItem ?? firstAttentionItem(items);
|
|
410
639
|
const currentId = current?.id ?? null;
|
|
411
|
-
const steps =
|
|
640
|
+
const steps = items.map((item) => buildStep(item, currentId));
|
|
641
|
+
const stepHistory = buildStepHistory({ items, smokeHistory, checkpoint, durableReceipts });
|
|
642
|
+
const setupSmokeReceiptReady = stepHistory.some((entry) => entry.satisfiesReceipt === true && setupStepMatches('install-smoke', entry.stepId));
|
|
643
|
+
const receiptGaps = buildReceiptGaps({
|
|
644
|
+
items,
|
|
645
|
+
stepHistory,
|
|
646
|
+
receiptRequiredStepIds: input.receiptRequiredStepIds ?? [],
|
|
647
|
+
});
|
|
412
648
|
const completedSteps = steps.filter((step) => step.status === 'done').length;
|
|
413
649
|
const status: AgentSetupWizardStatus = completedSteps === steps.length
|
|
414
650
|
? 'complete'
|
|
@@ -420,6 +656,17 @@ export function buildAgentSetupWizard(input: BuildAgentSetupWizardInput): AgentS
|
|
|
420
656
|
? `${current.label}: ${repeated.blocker.summary} ${current.detail}`
|
|
421
657
|
: `${current.label}: ${current.detail}`
|
|
422
658
|
: 'Setup wizard is complete; rerun setup smoke if this machine was upgraded or moved.';
|
|
659
|
+
const closeout = buildCloseout({
|
|
660
|
+
items,
|
|
661
|
+
smokeHistory,
|
|
662
|
+
setupSmokeReceiptReady,
|
|
663
|
+
stepHistory,
|
|
664
|
+
criticalStepIds: input.closeoutCriticalStepIds ?? [],
|
|
665
|
+
setupMarkerExists: input.setupMarkerExists === true,
|
|
666
|
+
reviewRoute: input.reviewRoute ?? DEFAULT_AGENT_SETUP_WIZARD_REVIEW_ROUTE,
|
|
667
|
+
finishRoute: input.finishRoute ?? DEFAULT_AGENT_SETUP_WIZARD_FINISH_ROUTE,
|
|
668
|
+
finishUserRoute: input.finishUserRoute ?? DEFAULT_AGENT_SETUP_WIZARD_FINISH_USER_ROUTE,
|
|
669
|
+
});
|
|
423
670
|
return {
|
|
424
671
|
available: true,
|
|
425
672
|
status,
|
|
@@ -430,18 +677,14 @@ export function buildAgentSetupWizard(input: BuildAgentSetupWizardInput): AgentS
|
|
|
430
677
|
progressLabel: `${completedSteps}/${steps.length} setup step(s) ready`,
|
|
431
678
|
next,
|
|
432
679
|
reviewRoute: input.reviewRoute ?? DEFAULT_AGENT_SETUP_WIZARD_REVIEW_ROUTE,
|
|
433
|
-
repeatedBlocker: repeated?.blocker ?? null,
|
|
434
|
-
smokeHistory,
|
|
435
|
-
closeout: buildCloseout({
|
|
436
|
-
items: input.items,
|
|
437
|
-
smokeHistory,
|
|
438
|
-
criticalStepIds: input.closeoutCriticalStepIds ?? [],
|
|
439
|
-
setupMarkerExists: input.setupMarkerExists === true,
|
|
440
|
-
reviewRoute: input.reviewRoute ?? DEFAULT_AGENT_SETUP_WIZARD_REVIEW_ROUTE,
|
|
441
|
-
finishRoute: input.finishRoute ?? DEFAULT_AGENT_SETUP_WIZARD_FINISH_ROUTE,
|
|
442
|
-
finishUserRoute: input.finishUserRoute ?? DEFAULT_AGENT_SETUP_WIZARD_FINISH_USER_ROUTE,
|
|
443
|
-
}),
|
|
444
|
-
checkpoint,
|
|
445
680
|
steps,
|
|
681
|
+
_diagnostic: {
|
|
682
|
+
repeatedBlocker: repeated?.blocker ?? null,
|
|
683
|
+
smokeHistory,
|
|
684
|
+
stepHistory,
|
|
685
|
+
receiptGaps,
|
|
686
|
+
closeout,
|
|
687
|
+
checkpoint,
|
|
688
|
+
},
|
|
446
689
|
};
|
|
447
690
|
}
|
package/src/cli/tui-startup.ts
CHANGED
|
@@ -102,14 +102,14 @@ export function applyInitialTuiCliState(options: {
|
|
|
102
102
|
const onboardingCompletionMarker = readOnboardingCompletionMarker(shellPaths, 'user');
|
|
103
103
|
const seededPrompt = cli.flags.prompt ?? (cli.rawCommand === undefined && cli.positionals.length > 0 ? cli.positionals.join(' ') : undefined);
|
|
104
104
|
if (cli.command === 'onboarding') {
|
|
105
|
-
input.openAgentWorkspace(commandContext);
|
|
105
|
+
input.openAgentWorkspace(commandContext, undefined, 'ONBOARDING');
|
|
106
106
|
} else if (cli.command === 'sessions' && cli.commandArgs[0] === 'resume') {
|
|
107
107
|
const target = cli.commandArgs.slice(1).join(' ').trim();
|
|
108
108
|
if (target) {
|
|
109
109
|
void commandRegistry.execute('session', ['resume', target], commandContext).then(() => render());
|
|
110
110
|
}
|
|
111
111
|
} else if (!onboardingCompletionMarker.payload) {
|
|
112
|
-
input.openAgentWorkspace(commandContext, 'setup');
|
|
112
|
+
input.openAgentWorkspace(commandContext, 'setup', 'ONBOARDING');
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
if (seededPrompt) {
|
|
@@ -52,7 +52,7 @@ interface AgentWorkspaceActivationHost {
|
|
|
52
52
|
openSettingsModalAction(action: AgentWorkspaceCategory['actions'][number], requestRender?: () => void): void;
|
|
53
53
|
completeOnboarding(): void;
|
|
54
54
|
hasCommandDispatch(): boolean;
|
|
55
|
-
dispatchWorkspaceCommand:
|
|
55
|
+
dispatchWorkspaceCommand(command: string, behavior?: 'inline' | 'compose' | 'exit'): void;
|
|
56
56
|
commitActionSearchSelection(): boolean;
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -186,7 +186,7 @@ export function activateAgentWorkspaceSelection(
|
|
|
186
186
|
command: action.command,
|
|
187
187
|
safety: action.safety,
|
|
188
188
|
};
|
|
189
|
-
workspace.dispatchWorkspaceCommand(action.command);
|
|
189
|
+
workspace.dispatchWorkspaceCommand(action.command, action.commandBehavior);
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
export function createAgentWorkspaceEditor(
|
|
@@ -455,8 +455,8 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
455
455
|
detail: 'Voice, media, browser tools, and image-capable flows are first-class Agent tools. Connected-host administration stays outside Agent and side effects stay explicit.',
|
|
456
456
|
actions: [
|
|
457
457
|
{ id: 'voice-workflow-posture', label: 'Voice workflows', detail: 'Inspect push-to-talk, voice memo transcription, spoken responses, and wake-word readiness with device action:"voice".', kind: 'guidance', safety: 'read-only' },
|
|
458
|
-
{ id: 'device-capability-map', label: 'Device capability map', detail: 'Inspect pairing, mobile command routing, browser/PWA, notifications, browser/desktop control, and camera/location readiness with device action:"status" without claiming
|
|
459
|
-
{ id: 'browser-cockpit-readiness', label: 'Browser/PWA readiness', detail: 'Inspect the connected browser cockpit/PWA route, workspace category coverage, mobile controls, and first-run receipt
|
|
458
|
+
{ id: 'device-capability-map', label: 'Device capability map', detail: 'Inspect pairing, mobile command routing, browser/PWA, notifications, browser/desktop control, and certified camera/location readiness with device action:"status" without claiming uncertified contracts.', kind: 'guidance', safety: 'read-only' },
|
|
459
|
+
{ id: 'browser-cockpit-readiness', label: 'Browser/PWA readiness', detail: 'Inspect the connected browser cockpit/PWA route, certified workspace category coverage, mobile controls, and first-run receipt evidence with computer action:"browser" before opening a browser.', kind: 'guidance', safety: 'read-only' },
|
|
460
460
|
{ id: 'tts-config', label: 'Configure live TTS', detail: 'Open the settings workspace at the TTS group.', command: '/config tts', kind: 'command', safety: 'safe' },
|
|
461
461
|
{ id: 'tts-provider', label: 'Choose TTS provider', detail: 'Open provider/model routing for spoken responses through the settings flow.', command: '/config tts.provider', kind: 'command', safety: 'safe' },
|
|
462
462
|
{ id: 'voice-review', label: 'Voice review', detail: 'Inspect local voice posture before enabling spoken interaction.', command: '/voice review', kind: 'command', safety: 'read-only' },
|
|
@@ -103,10 +103,10 @@ export const AGENT_WORKSPACE_ONBOARDING_DETAIL_CATEGORIES: readonly AgentWorkspa
|
|
|
103
103
|
summary: 'Create/import memory, personas, skills, routines, notes, and Knowledge.',
|
|
104
104
|
detail: 'Use this page to seed the assistant with durable local context. These forms create Agent-owned records or ingest reviewed sources.',
|
|
105
105
|
actions: [
|
|
106
|
-
{ id: 'context-vibe-status', label: 'Inspect VIBE.md', detail: 'Show project/global VIBE.md personality files, blocked files, and init paths before relying on a custom assistant feel.',
|
|
107
|
-
{ id: 'context-project-files', label: 'Inspect project context', detail: 'List secret-scanned .hermes.md, HERMES.md, AGENTS.md, CLAUDE.md, SOUL.md, and Cursor context files with blocked/truncated status.',
|
|
108
|
-
{ id: 'context-project-file', label: 'Inspect one context file', detail: 'Inspect one loaded or blocked project context file by id, target, or query through the read-only context-file
|
|
109
|
-
{ id: 'context-prompt-context', label: 'Prompt context', detail: 'Inspect the applied prompt context order, selected memory/persona/skill/routine records, suppressed context, and approximate token budget.',
|
|
106
|
+
{ id: 'context-vibe-status', label: 'Inspect VIBE.md', detail: 'Show project/global VIBE.md personality files, blocked files, and init paths before relying on a custom assistant feel.', kind: 'guidance', safety: 'read-only' },
|
|
107
|
+
{ id: 'context-project-files', label: 'Inspect project context', detail: 'List secret-scanned .hermes.md, HERMES.md, AGENTS.md, CLAUDE.md, SOUL.md, and Cursor context files with blocked/truncated status.', kind: 'guidance', safety: 'read-only' },
|
|
108
|
+
{ id: 'context-project-file', label: 'Inspect one context file', detail: 'Inspect one loaded or blocked project context file by id, target, or query through the read-only context-file control.', kind: 'guidance', safety: 'read-only' },
|
|
109
|
+
{ id: 'context-prompt-context', label: 'Prompt context', detail: 'Inspect the applied prompt context order, selected memory/persona/skill/routine records, suppressed context, and approximate token budget.', kind: 'guidance', safety: 'read-only' },
|
|
110
110
|
{ id: 'context-profile-from-discovered', label: 'Profile from discovered files', detail: 'Create an isolated Agent profile from reviewed local persona, skill, and routine files.', editorKind: 'profile-from-discovered', kind: 'editor', safety: 'safe' },
|
|
111
111
|
{ id: 'context-persona-discovery', label: 'Import persona files', detail: 'Import discovered persona files into the Agent persona registry.', editorKind: 'persona-discovery-import', kind: 'editor', safety: 'safe' },
|
|
112
112
|
{ id: 'context-skill-discovery', label: 'Import skill files', detail: 'Import discovered skill files into the Agent skill registry.', editorKind: 'skill-discovery-import', kind: 'editor', safety: 'safe' },
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AgentWorkspaceAction, AgentWorkspaceCategory } from './agent-workspace-types.ts';
|
|
2
|
+
|
|
3
|
+
export const ONBOARDING_CRITICAL_STEP_IDS = ['runtime', 'connected-host-auth', 'provider-model'] as const;
|
|
4
|
+
|
|
5
|
+
export const ONBOARDING_COMPLETE_SYNTHETIC_ACTION: AgentWorkspaceAction = {
|
|
6
|
+
id: 'onboarding-apply-close',
|
|
7
|
+
label: 'Apply & close',
|
|
8
|
+
detail: 'Acknowledge onboarding as finished, persist the user completion marker, and close the fullscreen Agent workspace.',
|
|
9
|
+
kind: 'onboarding-complete',
|
|
10
|
+
safety: 'safe',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function shouldShowOnboardingFinishFooter(
|
|
14
|
+
category: AgentWorkspaceCategory,
|
|
15
|
+
baseActions: readonly AgentWorkspaceAction[],
|
|
16
|
+
): boolean {
|
|
17
|
+
return (
|
|
18
|
+
category.group === 'ONBOARDING'
|
|
19
|
+
&& baseActions.every((a) => a.kind !== 'onboarding-complete')
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -56,6 +56,12 @@ export interface TuiSettingsImportOutcome extends SettingMutationOutcome {
|
|
|
56
56
|
readonly runtimeSnapshot: AgentWorkspaceRuntimeSnapshot | null;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
export interface AgentWorkspaceSettingActionDisplay {
|
|
60
|
+
readonly setting: string;
|
|
61
|
+
readonly defaultValue: string;
|
|
62
|
+
readonly currentValue: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
59
65
|
type TuiImportStatus = 'would_import' | 'unchanged' | 'skipped';
|
|
60
66
|
|
|
61
67
|
interface TuiSettingsImportSource {
|
|
@@ -173,10 +179,31 @@ function valuesMatch(left: unknown, right: unknown): boolean {
|
|
|
173
179
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
174
180
|
}
|
|
175
181
|
|
|
182
|
+
function isSecretLikeSettingKey(key: string): boolean {
|
|
183
|
+
const normalized = key.replace(/([a-z0-9])([A-Z])/g, '$1.$2').toLowerCase();
|
|
184
|
+
if (normalized.endsWith('secret.policy')) return false;
|
|
185
|
+
return /(?:secret|token|password|api[-_.]?key|api\.key|signing)/i.test(normalized);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function compactSettingValue(key: string, value: unknown): string {
|
|
189
|
+
if (value === undefined || value === null) return '(unset)';
|
|
190
|
+
if (isSecretLikeSettingKey(key)) return value === '' ? '(empty)' : '(secret)';
|
|
191
|
+
if (typeof value === 'boolean') return value ? 'true' : 'false';
|
|
192
|
+
if (typeof value === 'number') return Number.isFinite(value) ? String(value) : '(invalid)';
|
|
193
|
+
if (typeof value === 'string') {
|
|
194
|
+
if (value.length === 0) return '(empty)';
|
|
195
|
+
if (value.startsWith('goodvibes://secrets/')) return '(secret)';
|
|
196
|
+
return value.length > 36 ? `${value.slice(0, 33)}...` : value;
|
|
197
|
+
}
|
|
198
|
+
if (Array.isArray(value)) return `[${value.length} item${value.length === 1 ? '' : 's'}]`;
|
|
199
|
+
if (isRecord(value)) return '{...}';
|
|
200
|
+
return String(value);
|
|
201
|
+
}
|
|
202
|
+
|
|
176
203
|
function redactImportValue(key: string, value: unknown): unknown {
|
|
177
204
|
if (typeof value !== 'string') return value;
|
|
178
205
|
if (!value) return value;
|
|
179
|
-
if (
|
|
206
|
+
if (isSecretLikeSettingKey(key)) {
|
|
180
207
|
return value.startsWith('goodvibes://secrets/') ? '<secret-ref>' : '<redacted>';
|
|
181
208
|
}
|
|
182
209
|
return value;
|
|
@@ -369,6 +396,25 @@ export function buildAgentWorkspaceSettingActionEffect(
|
|
|
369
396
|
};
|
|
370
397
|
}
|
|
371
398
|
|
|
399
|
+
export function buildAgentWorkspaceSettingActionDisplay(
|
|
400
|
+
context: CommandContext | null,
|
|
401
|
+
action: AgentWorkspaceAction,
|
|
402
|
+
): AgentWorkspaceSettingActionDisplay | null {
|
|
403
|
+
const settingKey = action.settingKey?.trim();
|
|
404
|
+
const configManager = context?.platform?.configManager;
|
|
405
|
+
if (!settingKey || !configManager) return null;
|
|
406
|
+
|
|
407
|
+
const setting = agentWorkspaceSettingSchema(context, settingKey);
|
|
408
|
+
if (!setting) return null;
|
|
409
|
+
const currentValue = configManager.get(settingKey as ConfigKey);
|
|
410
|
+
|
|
411
|
+
return {
|
|
412
|
+
setting: action.label || settingKey,
|
|
413
|
+
defaultValue: compactSettingValue(settingKey, setting.default),
|
|
414
|
+
currentValue: compactSettingValue(settingKey, currentValue),
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
372
418
|
export async function applyAgentWorkspaceSettingValue(
|
|
373
419
|
context: CommandContext | null,
|
|
374
420
|
setting: ConfigSetting,
|
|
@@ -2,7 +2,7 @@ import type { ArtifactDescriptor } from '@pellux/goodvibes-sdk/platform/artifact
|
|
|
2
2
|
import type { CommandContext } from './command-registry.ts';
|
|
3
3
|
import { readSetupWizardCheckpoint } from '../agent/setup-wizard-checkpoint.ts';
|
|
4
4
|
import { readOnboardingCompletionMarker } from '../runtime/onboarding/index.ts';
|
|
5
|
-
import { DEFAULT_AGENT_SETUP_WIZARD_CLEAR_CHECKPOINT_ROUTE, DEFAULT_AGENT_SETUP_WIZARD_INSPECT_CHECKPOINT_ROUTE, DEFAULT_AGENT_SETUP_WIZARD_MARK_CHECKPOINT_ROUTE, DEFAULT_AGENT_SETUP_WIZARD_RERUN_SMOKE_ROUTE, DEFAULT_AGENT_SETUP_WIZARD_SAVE_SMOKE_ROUTE, buildAgentSetupWizard, emptyAgentSetupSmokeHistory, emptyAgentSetupWizardCheckpoint, type AgentSetupWizard, type AgentSetupWizardBlockedCheckFrequency, type AgentSetupWizardCheckpoint, type AgentSetupWizardSmokeHistory, type AgentSetupWizardSourceItem } from '../agent/setup-wizard.ts';
|
|
5
|
+
import { DEFAULT_AGENT_SETUP_WIZARD_CLEAR_CHECKPOINT_ROUTE, DEFAULT_AGENT_SETUP_WIZARD_INSPECT_CHECKPOINT_ROUTE, DEFAULT_AGENT_SETUP_WIZARD_MARK_CHECKPOINT_ROUTE, DEFAULT_AGENT_SETUP_WIZARD_RERUN_SMOKE_ROUTE, DEFAULT_AGENT_SETUP_WIZARD_SAVE_SMOKE_ROUTE, buildAgentSetupWizard, emptyAgentSetupSmokeHistory, emptyAgentSetupWizardCheckpoint, type AgentSetupWizard, type AgentSetupWizardBlockedCheckFrequency, type AgentSetupWizardCheckpoint, type AgentSetupWizardDurableReceipt, type AgentSetupWizardSmokeHistory, type AgentSetupWizardSourceItem } from '../agent/setup-wizard.ts';
|
|
6
6
|
import type { AgentWorkspaceSetupChecklistItem } from './agent-workspace-setup.ts';
|
|
7
7
|
import { readArtifactMetadataString, readArtifactMetadataStringList } from './agent-workspace-artifact-metadata.ts';
|
|
8
8
|
|
|
@@ -30,6 +30,12 @@ function setupSmokeEvidenceTrend(artifacts: readonly ArtifactDescriptor[]): stri
|
|
|
30
30
|
return 'unchanged';
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
function artifactCreatedAtIso(artifact: ArtifactDescriptor): string | null {
|
|
34
|
+
const createdAt = artifact.createdAt;
|
|
35
|
+
if (typeof createdAt !== 'number' || !Number.isFinite(createdAt)) return null;
|
|
36
|
+
return new Date(createdAt).toISOString();
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
function setupSmokeBlockedCheckFrequency(artifacts: readonly ArtifactDescriptor[]): readonly AgentSetupWizardBlockedCheckFrequency[] {
|
|
34
40
|
const counts = new Map<string, number>();
|
|
35
41
|
for (const artifact of artifacts) {
|
|
@@ -67,6 +73,8 @@ export function buildSetupSmokeHistory(artifacts: readonly ArtifactDescriptor[],
|
|
|
67
73
|
trend: setupSmokeEvidenceTrend(setupSmokeArtifacts),
|
|
68
74
|
latestResult: readArtifactMetadataString(latest.metadata, 'result') || 'unknown',
|
|
69
75
|
previousResult: previous ? readArtifactMetadataString(previous.metadata, 'result') || 'unknown' : null,
|
|
76
|
+
latestEvidenceId: latest.id,
|
|
77
|
+
latestEvidenceAt: artifactCreatedAtIso(latest),
|
|
70
78
|
resultCounts,
|
|
71
79
|
blockedCheckFrequency: setupSmokeBlockedCheckFrequency(setupSmokeArtifacts),
|
|
72
80
|
inspectLatestRoute: `agent_artifacts show artifactId:"${latest.id}" includeContent:false`,
|
|
@@ -120,13 +128,12 @@ export function buildSetupWizardCheckpoint(context: CommandContext): AgentSetupW
|
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
function setupChecklistUserRoute(item: AgentWorkspaceSetupChecklistItem): string {
|
|
123
|
-
return item.
|
|
131
|
+
return item.breadcrumb ?? 'Start';
|
|
124
132
|
}
|
|
125
133
|
|
|
126
134
|
function setupChecklistModelRoute(item: AgentWorkspaceSetupChecklistItem): string {
|
|
127
135
|
if (item.id === 'runtime') return 'agent_harness mode:"setup_item" setupItemId:"connected-host-readiness"';
|
|
128
136
|
if (item.id === 'provider-model') return 'models action:"status"';
|
|
129
|
-
if (item.id === 'install-smoke') return DEFAULT_AGENT_SETUP_WIZARD_RERUN_SMOKE_ROUTE;
|
|
130
137
|
if (item.id === 'subscriptions') return 'models action:"providers"';
|
|
131
138
|
if (item.id === 'agent-knowledge') return 'agent_knowledge mode:"status"';
|
|
132
139
|
if (item.id === 'profile') return 'agent_harness mode:"workspace_action" actionId:"profile-template-show"';
|
|
@@ -154,12 +161,10 @@ function setupChecklistActionId(item: AgentWorkspaceSetupChecklistItem): string
|
|
|
154
161
|
}
|
|
155
162
|
|
|
156
163
|
const SETUP_WIZARD_SNAPSHOT_BLOCKER_ALIASES: Readonly<Record<string, readonly string[]>> = {
|
|
157
|
-
'agent-binary': ['runtime'
|
|
164
|
+
'agent-binary': ['runtime'],
|
|
158
165
|
'connected-host-status': ['runtime'],
|
|
159
166
|
'connected-host-auth': ['connected-host-auth'],
|
|
160
167
|
'provider-model': ['provider-model'],
|
|
161
|
-
'setup-posture': ['install-smoke'],
|
|
162
|
-
'first-assistant-turn': ['install-smoke'],
|
|
163
168
|
};
|
|
164
169
|
|
|
165
170
|
export function buildWorkspaceSetupWizard(
|
|
@@ -167,6 +172,7 @@ export function buildWorkspaceSetupWizard(
|
|
|
167
172
|
smokeHistory: AgentSetupWizardSmokeHistory,
|
|
168
173
|
checkpoint: AgentSetupWizardCheckpoint,
|
|
169
174
|
setupMarkerExists: boolean,
|
|
175
|
+
durableReceipts: readonly AgentSetupWizardDurableReceipt[] = [],
|
|
170
176
|
): AgentSetupWizard {
|
|
171
177
|
const items: AgentSetupWizardSourceItem[] = checklist.map((item) => ({
|
|
172
178
|
id: item.id,
|
|
@@ -182,6 +188,11 @@ export function buildWorkspaceSetupWizard(
|
|
|
182
188
|
smokeHistory,
|
|
183
189
|
checkpoint,
|
|
184
190
|
closeoutCriticalStepIds: ['runtime', 'connected-host-auth', 'provider-model'],
|
|
191
|
+
receiptRequiredStepIds: [
|
|
192
|
+
'runtime',
|
|
193
|
+
'connected-host-auth',
|
|
194
|
+
],
|
|
195
|
+
durableReceipts,
|
|
185
196
|
setupMarkerExists,
|
|
186
197
|
repeatedBlockerAliases: SETUP_WIZARD_SNAPSHOT_BLOCKER_ALIASES,
|
|
187
198
|
});
|