@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.
Files changed (85) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/dist/package/{ast-grep-napi.linux-x64-gnu-swtppvy9.node → ast-grep-napi.linux-x64-gnu-mkk8xwww.node} +0 -0
  3. package/dist/package/{ast-grep-napi.linux-x64-musl-ttfcdtap.node → ast-grep-napi.linux-x64-musl-ryqtgdv6.node} +0 -0
  4. package/dist/package/main.js +65740 -57156
  5. package/docs/README.md +3 -3
  6. package/docs/connected-host.md +2 -2
  7. package/docs/getting-started.md +11 -9
  8. package/docs/tools-and-commands.md +12 -10
  9. package/docs/voice-and-live-tts.md +2 -2
  10. package/package.json +1 -1
  11. package/release/release-notes.md +15 -144
  12. package/release/release-readiness.json +36 -36
  13. package/src/agent/competitive-feature-inventory.ts +42 -44
  14. package/src/agent/setup-wizard-artifact-receipts.ts +366 -0
  15. package/src/agent/setup-wizard.ts +267 -24
  16. package/src/cli/tui-startup.ts +2 -2
  17. package/src/input/agent-workspace-activation.ts +2 -2
  18. package/src/input/agent-workspace-categories.ts +2 -2
  19. package/src/input/agent-workspace-onboarding-categories.ts +4 -4
  20. package/src/input/agent-workspace-onboarding-finish.ts +21 -0
  21. package/src/input/agent-workspace-settings.ts +47 -1
  22. package/src/input/agent-workspace-setup-snapshot.ts +17 -6
  23. package/src/input/agent-workspace-setup.ts +20 -26
  24. package/src/input/agent-workspace-snapshot.ts +16 -3
  25. package/src/input/agent-workspace-types.ts +5 -2
  26. package/src/input/agent-workspace.ts +21 -6
  27. package/src/input/handler.ts +67 -5
  28. package/src/input/setup-wizard-live-receipts.ts +76 -0
  29. package/src/renderer/agent-workspace-context-lines.ts +17 -33
  30. package/src/renderer/agent-workspace.ts +434 -21
  31. package/src/runtime/tool-permission-safety.ts +1 -1
  32. package/src/tools/agent-harness-agent-orchestration-policy.ts +75 -0
  33. package/src/tools/agent-harness-agent-orchestration.ts +216 -128
  34. package/src/tools/agent-harness-autonomy-live-records.ts +154 -0
  35. package/src/tools/agent-harness-autonomy-queue-types.ts +1 -1
  36. package/src/tools/agent-harness-autonomy-queue.ts +19 -8
  37. package/src/tools/agent-harness-autonomy-watcher-read-models.ts +509 -0
  38. package/src/tools/agent-harness-background-processes.ts +8 -4
  39. package/src/tools/agent-harness-browser-cockpit-route.ts +188 -34
  40. package/src/tools/agent-harness-browser-control.ts +12 -4
  41. package/src/tools/agent-harness-browser-pwa-read-models.ts +622 -0
  42. package/src/tools/agent-harness-device-live-read-models.ts +366 -0
  43. package/src/tools/agent-harness-execution-posture.ts +3 -0
  44. package/src/tools/agent-harness-interactive-runtime-records.ts +421 -0
  45. package/src/tools/agent-harness-local-model-benchmarks.ts +71 -1
  46. package/src/tools/agent-harness-local-model-endpoints.ts +469 -354
  47. package/src/tools/agent-harness-local-model-smoke.ts +277 -0
  48. package/src/tools/agent-harness-local-model-url.ts +78 -0
  49. package/src/tools/agent-harness-media-posture.ts +27 -12
  50. package/src/tools/agent-harness-memory-external-providers.ts +796 -0
  51. package/src/tools/agent-harness-memory-posture.ts +253 -137
  52. package/src/tools/agent-harness-memory-provider-certification.ts +219 -0
  53. package/src/tools/agent-harness-memory-refinement.ts +340 -0
  54. package/src/tools/agent-harness-mode-catalog.ts +4 -2
  55. package/src/tools/agent-harness-model-provider-health.ts +139 -42
  56. package/src/tools/agent-harness-model-readiness.ts +31 -5
  57. package/src/tools/agent-harness-model-routing-types.ts +61 -0
  58. package/src/tools/agent-harness-model-routing.ts +31 -6
  59. package/src/tools/agent-harness-pairing-posture.ts +30 -9
  60. package/src/tools/agent-harness-personal-ops-certification.ts +116 -0
  61. package/src/tools/agent-harness-personal-ops-lanes.ts +81 -15
  62. package/src/tools/agent-harness-personal-ops-operations.ts +225 -0
  63. package/src/tools/agent-harness-personal-ops-provider-records.ts +358 -0
  64. package/src/tools/agent-harness-personal-ops-provider-task-records.ts +321 -0
  65. package/src/tools/agent-harness-personal-ops-records.ts +176 -224
  66. package/src/tools/agent-harness-personal-ops-types.ts +19 -1
  67. package/src/tools/agent-harness-personal-ops.ts +18 -11
  68. package/src/tools/agent-harness-remote-read-models.ts +541 -0
  69. package/src/tools/agent-harness-research-briefing.ts +26 -7
  70. package/src/tools/agent-harness-research-live-read-models.ts +500 -0
  71. package/src/tools/agent-harness-research-runs.ts +15 -3
  72. package/src/tools/agent-harness-research-workflow.ts +92 -19
  73. package/src/tools/agent-harness-setup-model-helpers.ts +1 -0
  74. package/src/tools/agent-harness-setup-posture.ts +7 -7
  75. package/src/tools/agent-harness-setup-smoke.ts +26 -1
  76. package/src/tools/agent-harness-tool-schema.ts +23 -1
  77. package/src/tools/agent-harness-tool-types.ts +5 -0
  78. package/src/tools/agent-harness-tool.ts +9 -1
  79. package/src/tools/agent-harness-workspace-actions.ts +1 -1
  80. package/src/tools/agent-memory-tool.ts +40 -1
  81. package/src/tools/agent-model-compare-run.ts +13 -0
  82. package/src/tools/agent-research-runner.ts +367 -0
  83. package/src/tools/agent-research-tool.ts +7 -179
  84. package/src/tools/agent-route-planner-candidates-surfaces.ts +1 -1
  85. package/src/version.ts +1 -1
@@ -0,0 +1,219 @@
1
+ import { previewHarnessText } from './agent-harness-text.ts';
2
+ import { readRecord, readString } from './agent-harness-model-routing-utils.ts';
3
+
4
+ export interface MemoryExternalProviderCertification {
5
+ readonly schemaStatus: 'certified' | 'legacy';
6
+ readonly schemaVersion?: string;
7
+ readonly publicationGuarantee?: string;
8
+ readonly publisher?: string;
9
+ readonly provenance?: readonly string[];
10
+ readonly receiptId?: string;
11
+ readonly receiptStatus?: string;
12
+ readonly receiptRoute?: string;
13
+ readonly receiptIds?: readonly string[];
14
+ readonly receiptStreamStatus?: string;
15
+ readonly missingSignals: readonly string[];
16
+ readonly policy: string;
17
+ }
18
+
19
+ const MEMORY_CERT_SECRET_PATTERNS: readonly [RegExp, string][] = [
20
+ [/secret:\/\/[^\s,'"}]+/gi, 'secret://<redacted>'],
21
+ [/("?\b(?:api[-_]?key|apikey|token|secret|password|passwd|credential|authorization)\b"?\s*:\s*)("[^"]*"|'[^']*'|[^\s,}]+)/gi, '$1"<redacted>"'],
22
+ [/\b([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTHORIZATION|BEARER)[A-Z0-9_]*)=("[^"]*"|'[^']*'|[^\s]+)/gi, '$1=<redacted>'],
23
+ [/(\b(?:token|secret|password|passwd|api[-_]?key|apikey|authorization|credential)\s*[:=]\s*)("[^"]*"|'[^']*'|[^\s,}]+)/gi, '$1<redacted>'],
24
+ [/(Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+/gi, '$1<redacted>'],
25
+ ];
26
+
27
+ function redactedPreview(value: unknown, limit = 180): string {
28
+ const raw = readString(value);
29
+ const redacted = MEMORY_CERT_SECRET_PATTERNS.reduce((text, [pattern, replacement]) => text.replace(pattern, replacement), raw);
30
+ return previewHarnessText(redacted, limit);
31
+ }
32
+
33
+ function firstString(record: Readonly<Record<string, unknown>>, keys: readonly string[]): string {
34
+ for (const key of keys) {
35
+ const value = readString(record[key]);
36
+ if (value) return value;
37
+ }
38
+ return '';
39
+ }
40
+
41
+ function readStringArray(value: unknown): readonly string[] {
42
+ if (Array.isArray(value)) {
43
+ return [...new Set(value.map((entry) => readString(entry)).filter(Boolean))].slice(0, 12);
44
+ }
45
+ const text = readString(value);
46
+ return text ? text.split(',').map((entry) => entry.trim()).filter(Boolean).slice(0, 12) : [];
47
+ }
48
+
49
+ function recordsForCertification(record: Readonly<Record<string, unknown>>): readonly Readonly<Record<string, unknown>>[] {
50
+ return [
51
+ record,
52
+ readRecord(record.schema),
53
+ readRecord(record.contract),
54
+ readRecord(record.providerContract),
55
+ readRecord(record.memoryProviderContract),
56
+ readRecord(record.receipt),
57
+ readRecord(record.receiptContract),
58
+ readRecord(record.publication),
59
+ readRecord(record.certification),
60
+ ];
61
+ }
62
+
63
+ function firstAcross(records: readonly Readonly<Record<string, unknown>>[], keys: readonly string[]): string {
64
+ for (const record of records) {
65
+ const value = firstString(record, keys);
66
+ if (value) return value;
67
+ }
68
+ return '';
69
+ }
70
+
71
+ function normalizeSchemaStatus(records: readonly Readonly<Record<string, unknown>>[]): MemoryExternalProviderCertification['schemaStatus'] {
72
+ const explicit = firstAcross(records, ['schemaStatus', 'receiptSchemaStatus', 'certificationStatus'])
73
+ .toLowerCase()
74
+ .replace(/[_\s]+/g, '-');
75
+ if (['certified', 'valid', 'verified', 'schema-certified'].includes(explicit)) return 'certified';
76
+ const schemaVersion = firstAcross(records, ['schemaVersion', 'receiptSchemaVersion', 'contractVersion']);
77
+ const publicationGuarantee = firstAcross(records, ['publicationGuarantee', 'hostPublicationGuarantee', 'providerPublicationGuarantee', 'memoryPublicationGuarantee']);
78
+ const proof = firstAcross(records, ['methodId', 'sourceTool', 'actionId', 'publisher', 'publisherId', 'daemonId', 'hostId']);
79
+ return schemaVersion && publicationGuarantee && proof ? 'certified' : 'legacy';
80
+ }
81
+
82
+ function receiptIds(record: Readonly<Record<string, unknown>>, records: readonly Readonly<Record<string, unknown>>[], extraIds: readonly string[]): readonly string[] {
83
+ const explicit = [
84
+ ...extraIds,
85
+ ...readStringArray(record.receiptIds),
86
+ ...readStringArray(record.effectReceiptIds),
87
+ ...readStringArray(record.providerReceiptIds),
88
+ ...readStringArray(record.syncReceiptIds),
89
+ firstAcross(records, ['receiptId', 'effectReceiptId', 'readReceiptId', 'writeReceiptId', 'syncReceiptId', 'forgetReceiptId', 'operationReceiptId']),
90
+ ].filter(Boolean);
91
+ return [...new Set(explicit.map((entry) => redactedPreview(entry, 96)))].slice(0, 12);
92
+ }
93
+
94
+ function provenance(record: Readonly<Record<string, unknown>>, records: readonly Readonly<Record<string, unknown>>[], sourcePath: string): readonly string[] {
95
+ const values = [
96
+ ...readStringArray(record.provenance),
97
+ sourcePath ? `source ${sourcePath}` : '',
98
+ firstAcross(records, ['methodId']) ? `method ${firstAcross(records, ['methodId'])}` : '',
99
+ firstAcross(records, ['actionId']) ? `action ${firstAcross(records, ['actionId'])}` : '',
100
+ firstAcross(records, ['sourceTool']) ? `sourceTool ${firstAcross(records, ['sourceTool'])}` : '',
101
+ ];
102
+ return [...new Set(values.map((entry) => redactedPreview(entry, 180)).filter(Boolean))].slice(0, 8);
103
+ }
104
+
105
+ function certifiedBase(input: {
106
+ readonly record: Readonly<Record<string, unknown>>;
107
+ readonly sourcePath: string;
108
+ readonly receiptIds?: readonly string[];
109
+ }): Omit<MemoryExternalProviderCertification, 'missingSignals' | 'policy'> & { readonly rawPublicationGuarantee: string; readonly rawPublisher: string; readonly rawReceiptRoute: string; readonly rawReceiptStreamStatus: string; readonly rawReceiptStatus: string; readonly rawSchemaVersion: string; readonly receiptIdsValue: readonly string[]; readonly schemaStatusValue: MemoryExternalProviderCertification['schemaStatus'] } {
110
+ const records = recordsForCertification(input.record);
111
+ const schemaStatus = normalizeSchemaStatus(records);
112
+ const schemaVersion = firstAcross(records, ['schemaVersion', 'receiptSchemaVersion', 'contractVersion']);
113
+ const publicationGuarantee = firstAcross(records, ['publicationGuarantee', 'hostPublicationGuarantee', 'providerPublicationGuarantee', 'memoryPublicationGuarantee']);
114
+ const publisher = firstAcross(records, ['publisher', 'publisherId', 'daemonId', 'hostId']);
115
+ const ids = receiptIds(input.record, records, input.receiptIds ?? []);
116
+ const receiptStatus = firstAcross(records, ['receiptStatus', 'receiptOutcome', 'operationStatus', 'status']);
117
+ const receiptRoute = firstAcross(records, ['receiptRoute', 'inspectReceiptRoute', 'artifactRoute']);
118
+ const receiptStreamStatus = firstAcross(records, ['receiptStreamStatus', 'receiptPublicationStatus', 'receiptsStatus', 'streamStatus']);
119
+ const proof = provenance(input.record, records, input.sourcePath);
120
+ return {
121
+ schemaStatus,
122
+ ...(schemaVersion ? { schemaVersion: redactedPreview(schemaVersion, 80) } : {}),
123
+ ...(publicationGuarantee ? { publicationGuarantee: redactedPreview(publicationGuarantee, 220) } : {}),
124
+ ...(publisher ? { publisher: redactedPreview(publisher, 80) } : {}),
125
+ ...(proof.length > 0 ? { provenance: proof } : {}),
126
+ ...(ids[0] ? { receiptId: ids[0] } : {}),
127
+ ...(receiptStatus ? { receiptStatus: redactedPreview(receiptStatus, 80) } : {}),
128
+ ...(receiptRoute ? { receiptRoute: redactedPreview(receiptRoute, 180) } : {}),
129
+ ...(ids.length > 0 ? { receiptIds: ids } : {}),
130
+ ...(receiptStreamStatus ? { receiptStreamStatus: redactedPreview(receiptStreamStatus, 80) } : {}),
131
+ rawPublicationGuarantee: publicationGuarantee,
132
+ rawPublisher: publisher,
133
+ rawReceiptRoute: receiptRoute,
134
+ rawReceiptStreamStatus: receiptStreamStatus,
135
+ rawReceiptStatus: receiptStatus,
136
+ rawSchemaVersion: schemaVersion,
137
+ receiptIdsValue: ids,
138
+ schemaStatusValue: schemaStatus,
139
+ };
140
+ }
141
+
142
+ export function memoryExternalProviderLiveCertification(input: {
143
+ readonly record: Readonly<Record<string, unknown>>;
144
+ readonly sourcePath: string;
145
+ readonly providerId: string;
146
+ readonly readContractPublished: boolean;
147
+ readonly writeContractPublished: boolean;
148
+ readonly syncContractPublished: boolean;
149
+ readonly forgetContractPublished: boolean;
150
+ readonly receiptIds: readonly string[];
151
+ readonly receiptRoute: string | null;
152
+ }): MemoryExternalProviderCertification {
153
+ const base = certifiedBase({ record: input.record, sourcePath: input.sourcePath, receiptIds: input.receiptIds });
154
+ const {
155
+ rawPublicationGuarantee,
156
+ rawPublisher,
157
+ rawReceiptRoute,
158
+ rawReceiptStreamStatus,
159
+ rawReceiptStatus,
160
+ rawSchemaVersion,
161
+ receiptIdsValue,
162
+ schemaStatusValue,
163
+ ...certification
164
+ } = base;
165
+ const receiptPublished = base.receiptIdsValue.length > 0 || Boolean(input.receiptRoute) || Boolean(base.rawReceiptRoute) || Boolean(base.rawReceiptStreamStatus);
166
+ const missingSignals = [
167
+ ...(schemaStatusValue === 'certified' ? [] : ['Certified external memory provider schema is not published.']),
168
+ ...(input.providerId ? [] : ['Durable external memory provider id is not published.']),
169
+ ...(rawPublicationGuarantee ? [] : ['Provider-side external memory publication guarantee is not published.']),
170
+ ...(rawPublisher ? [] : ['Provider-side external memory publisher is not published.']),
171
+ ...(certification.provenance?.length ? [] : ['Provider-side external memory provenance is not published.']),
172
+ ...(input.readContractPublished ? [] : ['Bounded read/search contract is not published.']),
173
+ ...(input.writeContractPublished ? [] : ['Confirmed write/upsert contract is not published.']),
174
+ ...(input.syncContractPublished ? [] : ['Confirmed sync/import/export contract is not published.']),
175
+ ...(input.forgetContractPublished ? [] : ['Forget/delete contract or explicit not-supported contract is not published.']),
176
+ ...(receiptPublished ? [] : ['External memory provider receipt stream or receipt ids are not published.']),
177
+ ];
178
+ return {
179
+ ...certification,
180
+ ...(input.receiptRoute && !certification.receiptRoute ? { receiptRoute: redactedPreview(input.receiptRoute, 180) } : {}),
181
+ missingSignals,
182
+ policy: 'External memory provider records certify release readiness only when the host or SDK publishes schema, durable provider id, publication guarantee, publisher/provenance, bounded read, confirmed write/sync, forget or explicit not-supported, and receipt stream evidence without raw secrets or memory bodies.',
183
+ };
184
+ }
185
+
186
+ export function memoryExternalProviderReceiptCertification(input: {
187
+ readonly metadata: Readonly<Record<string, unknown>>;
188
+ readonly sourcePath: string;
189
+ readonly providerId: string;
190
+ readonly artifactId: string;
191
+ }): MemoryExternalProviderCertification {
192
+ const base = certifiedBase({ record: input.metadata, sourcePath: input.sourcePath });
193
+ const {
194
+ rawPublicationGuarantee,
195
+ rawPublisher,
196
+ rawReceiptRoute,
197
+ rawReceiptStreamStatus,
198
+ rawReceiptStatus,
199
+ rawSchemaVersion,
200
+ receiptIdsValue,
201
+ schemaStatusValue,
202
+ ...certification
203
+ } = base;
204
+ const missingSignals = [
205
+ ...(schemaStatusValue === 'certified' ? [] : ['Certified external memory receipt schema is not published.']),
206
+ ...(input.providerId ? [] : ['Durable external memory provider id is not published.']),
207
+ ...(input.artifactId || receiptIdsValue.length > 0 ? [] : ['Durable external memory receipt id is not published.']),
208
+ ...(rawPublicationGuarantee ? [] : ['Provider-side external memory receipt publication guarantee is not published.']),
209
+ ...(rawPublisher ? [] : ['Provider-side external memory receipt publisher is not published.']),
210
+ ...(certification.provenance?.length ? [] : ['Provider-side external memory receipt provenance is not published.']),
211
+ ...(receiptIdsValue.length > 0 ? [] : ['Confirmed external memory operation receipt id is not published.']),
212
+ ];
213
+ return {
214
+ ...certification,
215
+ ...(certification.receiptId ? {} : { receiptId: redactedPreview(input.artifactId, 96), receiptIds: [redactedPreview(input.artifactId, 96)] }),
216
+ missingSignals,
217
+ policy: 'External memory receipt artifacts certify release evidence only when they include schema, durable provider and receipt ids, publication guarantee, publisher/provenance, status, redaction posture, and inspectable follow-up route metadata.',
218
+ };
219
+ }
@@ -0,0 +1,340 @@
1
+ import type {
2
+ KnowledgeRefinementTaskRecord,
3
+ KnowledgeSemanticSelfImproveResult,
4
+ } from '@pellux/goodvibes-sdk/platform/knowledge';
5
+ import type { CommandContext } from '../input/command-registry.ts';
6
+ import { previewHarnessText } from './agent-harness-text.ts';
7
+
8
+ interface AgentHarnessMemoryRefinementArgs {
9
+ readonly query?: unknown;
10
+ readonly target?: unknown;
11
+ readonly knowledgeSpaceId?: unknown;
12
+ readonly sourceIds?: unknown;
13
+ readonly gapIds?: unknown;
14
+ readonly limit?: unknown;
15
+ readonly maxRunMs?: unknown;
16
+ readonly timeoutMs?: unknown;
17
+ readonly force?: unknown;
18
+ readonly includeParameters?: unknown;
19
+ }
20
+
21
+ interface KnowledgeRefinementService {
22
+ listRefinementTasks?: (
23
+ limit?: number,
24
+ input?: {
25
+ readonly spaceId?: string;
26
+ readonly state?: string;
27
+ readonly subjectKind?: string;
28
+ readonly subjectId?: string;
29
+ readonly gapId?: string;
30
+ },
31
+ ) => readonly KnowledgeRefinementTaskRecord[];
32
+ getRefinementTask?: (id: string) => KnowledgeRefinementTaskRecord | null;
33
+ runRefinement?: (input?: {
34
+ readonly knowledgeSpaceId?: string;
35
+ readonly sourceIds?: readonly string[];
36
+ readonly gapIds?: readonly string[];
37
+ readonly limit?: number;
38
+ readonly maxRunMs?: number;
39
+ readonly force?: boolean;
40
+ }) => Promise<KnowledgeSemanticSelfImproveResult>;
41
+ listJobs?: () => readonly {
42
+ readonly id: string;
43
+ readonly kind: string;
44
+ readonly title: string;
45
+ readonly description: string;
46
+ readonly defaultMode: string;
47
+ }[];
48
+ listJobRuns?: (limit?: number, jobId?: string) => readonly {
49
+ readonly id: string;
50
+ readonly jobId: string;
51
+ readonly status: string;
52
+ readonly mode: string;
53
+ readonly requestedAt: number;
54
+ readonly completedAt?: number;
55
+ readonly error?: string;
56
+ }[];
57
+ }
58
+
59
+ const ACTIVE_STATES = new Set(['detected', 'queued', 'searching', 'evaluating', 'extracting', 'applying', 'verified']);
60
+ const ATTENTION_STATES = new Set(['blocked', 'needs_review', 'failed']);
61
+
62
+ function readString(value: unknown): string {
63
+ return typeof value === 'string' ? value.trim() : '';
64
+ }
65
+
66
+ function readStringArray(value: unknown): readonly string[] {
67
+ if (Array.isArray(value)) return value.filter((entry): entry is string => typeof entry === 'string').map((entry) => entry.trim()).filter(Boolean);
68
+ const text = readString(value);
69
+ if (!text) return [];
70
+ return text.split(',').map((entry) => entry.trim()).filter(Boolean);
71
+ }
72
+
73
+ function readLimit(value: unknown, fallback: number, max = 100): number {
74
+ const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
75
+ if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
76
+ return Math.max(1, Math.min(max, Math.trunc(parsed)));
77
+ }
78
+
79
+ function readRunBudgetMs(value: unknown): number | undefined {
80
+ const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
81
+ if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return undefined;
82
+ return Math.max(5_000, Math.min(60_000, Math.trunc(parsed)));
83
+ }
84
+
85
+ function knowledgeService(context: CommandContext): KnowledgeRefinementService | null {
86
+ const service = context.extensions?.agentKnowledgeService;
87
+ return service && typeof service === 'object' ? service as KnowledgeRefinementService : null;
88
+ }
89
+
90
+ function iso(value: number | undefined): string | null {
91
+ return typeof value === 'number' && Number.isFinite(value) ? new Date(value).toISOString() : null;
92
+ }
93
+
94
+ function routeValue(value: string): string {
95
+ return JSON.stringify(value);
96
+ }
97
+
98
+ function taskSearchText(task: KnowledgeRefinementTaskRecord): string {
99
+ return [
100
+ task.id,
101
+ task.spaceId,
102
+ task.state,
103
+ task.priority,
104
+ task.trigger,
105
+ task.subjectTitle ?? '',
106
+ task.subjectId ?? '',
107
+ task.subjectType ?? '',
108
+ task.gapId ?? '',
109
+ task.issueId ?? '',
110
+ task.blockedReason ?? '',
111
+ readString(task.metadata.gapTitle),
112
+ readString(task.metadata.gapKind),
113
+ ].join('\n').toLowerCase();
114
+ }
115
+
116
+ function compactTask(task: KnowledgeRefinementTaskRecord, includeParameters: boolean): Record<string, unknown> {
117
+ const latestTrace = task.trace.at(-1);
118
+ const accepted = task.acceptedSourceIds ?? [];
119
+ const ingested = task.ingestedSourceIds ?? [];
120
+ return {
121
+ taskId: task.id,
122
+ spaceId: task.spaceId,
123
+ state: task.state,
124
+ priority: task.priority,
125
+ trigger: task.trigger,
126
+ ...(task.subjectTitle ? { subject: previewHarnessText(task.subjectTitle, includeParameters ? 140 : 80) } : {}),
127
+ ...(task.subjectId ? { subjectId: task.subjectId } : {}),
128
+ ...(task.gapId ? { gapId: task.gapId } : {}),
129
+ attemptCount: task.attemptCount,
130
+ ...(task.blockedReason ? { blockedReason: previewHarnessText(task.blockedReason, includeParameters ? 180 : 96) } : {}),
131
+ acceptedSourceCount: accepted.length,
132
+ ingestedSourceCount: ingested.length,
133
+ promotedFactCount: task.promotedFactCount ?? 0,
134
+ updatedAt: iso(task.updatedAt),
135
+ inspectRoute: `memory action:"refinement" query:${routeValue(task.id)} includeParameters:true`,
136
+ rerunRoute: task.gapId
137
+ ? `memory action:"run_refinement" gapIds:[${routeValue(task.gapId)}] confirm:true explicitUserRequest:"..."`
138
+ : `memory action:"run_refinement" knowledgeSpaceId:${routeValue(task.spaceId)} limit:1 confirm:true explicitUserRequest:"..."`,
139
+ ...(latestTrace ? {
140
+ latestTrace: {
141
+ at: iso(latestTrace.at),
142
+ state: latestTrace.state,
143
+ message: previewHarnessText(latestTrace.message, includeParameters ? 180 : 96),
144
+ },
145
+ } : {}),
146
+ ...(includeParameters ? {
147
+ budget: task.budget,
148
+ acceptedSourceIds: accepted,
149
+ ingestedSourceIds: ingested,
150
+ rejectedSourceUrls: task.rejectedSourceUrls ?? [],
151
+ sourceAssessments: (task.sourceAssessments ?? []).slice(0, 5).map((entry) => ({
152
+ url: previewHarnessText(entry.url, 120),
153
+ accepted: entry.accepted,
154
+ confidence: entry.confidence,
155
+ reasons: entry.reasons.slice(0, 3),
156
+ })),
157
+ } : {}),
158
+ };
159
+ }
160
+
161
+ function taskCounts(tasks: readonly KnowledgeRefinementTaskRecord[]): Record<string, number> {
162
+ const counts: Record<string, number> = {
163
+ total: tasks.length,
164
+ active: tasks.filter((task) => ACTIVE_STATES.has(task.state)).length,
165
+ attention: tasks.filter((task) => ATTENTION_STATES.has(task.state)).length,
166
+ closed: tasks.filter((task) => task.state === 'closed').length,
167
+ suppressed: tasks.filter((task) => task.state === 'suppressed').length,
168
+ cancelled: tasks.filter((task) => task.state === 'cancelled').length,
169
+ };
170
+ for (const task of tasks) counts[task.state] = (counts[task.state] ?? 0) + 1;
171
+ return counts;
172
+ }
173
+
174
+ function semanticJob(service: KnowledgeRefinementService): ReturnType<NonNullable<KnowledgeRefinementService['listJobs']>>[number] | null {
175
+ return service.listJobs?.().find((job) => job.kind === 'semantic-self-improvement' || job.id === 'knowledge-semantic-self-improvement') ?? null;
176
+ }
177
+
178
+ export function memoryRefinementCatalogStatus(context: CommandContext): Record<string, unknown> {
179
+ const service = knowledgeService(context);
180
+ const tasks = service?.listRefinementTasks?.(1_000) ?? [];
181
+ const counts = taskCounts(tasks);
182
+ return {
183
+ modes: ['memory_refinement', 'run_memory_refinement'],
184
+ status: !service?.listRefinementTasks && !service?.runRefinement
185
+ ? 'unavailable'
186
+ : counts.attention > 0
187
+ ? 'attention'
188
+ : counts.active > 0
189
+ ? 'active'
190
+ : counts.total > 0
191
+ ? 'ready'
192
+ : 'empty',
193
+ serviceAvailable: Boolean(service),
194
+ taskCounts: counts,
195
+ semanticJobPublished: Boolean(service ? semanticJob(service) : null),
196
+ readOnlyRoute: 'memory action:"refinement"',
197
+ confirmedRunRoute: 'memory action:"run_refinement" confirm:true explicitUserRequest:"..."',
198
+ };
199
+ }
200
+
201
+ export function memoryRefinementSummary(context: CommandContext, args: AgentHarnessMemoryRefinementArgs): Record<string, unknown> {
202
+ const includeParameters = args.includeParameters === true;
203
+ const service = knowledgeService(context);
204
+ if (!service?.listRefinementTasks && !service?.runRefinement) {
205
+ return {
206
+ status: 'unavailable',
207
+ summary: 'Agent Knowledge semantic refinement is not available in this runtime.',
208
+ requiredService: 'extensions.agentKnowledgeService.listRefinementTasks and runRefinement',
209
+ routes: {
210
+ knowledgeStatus: 'agent_knowledge action:"status"',
211
+ memoryCurator: 'memory action:"curator" includeParameters:true',
212
+ },
213
+ policy: 'No refinement mutation is attempted from posture inspection.',
214
+ };
215
+ }
216
+
217
+ const query = (readString(args.query) || readString(args.target)).toLowerCase();
218
+ const limit = readLimit(args.limit, 25, 100);
219
+ const spaceId = readString(args.knowledgeSpaceId);
220
+ const allTasks = service.listRefinementTasks?.(1_000, spaceId ? { spaceId } : undefined) ?? [];
221
+ const filtered = allTasks.filter((task) => !query || taskSearchText(task).includes(query));
222
+ const counts = taskCounts(allTasks);
223
+ const job = semanticJob(service);
224
+ const latestRun = job ? service.listJobRuns?.(1, job.id)?.[0] : null;
225
+
226
+ return {
227
+ status: counts.attention > 0 ? 'attention' : counts.active > 0 ? 'active' : counts.total > 0 ? 'ready' : 'empty',
228
+ userOutcome: 'Semantic self-improvement is a supervised Agent Knowledge refinement lane: gaps and repair tasks stay inspectable before any source search, ingest, or prompt expansion.',
229
+ taskCounts: counts,
230
+ tasks: filtered.slice(0, limit).map((task) => compactTask(task, includeParameters)),
231
+ returned: Math.min(filtered.length, limit),
232
+ total: filtered.length,
233
+ semanticSelfImprovementJob: job ? {
234
+ id: job.id,
235
+ title: job.title,
236
+ defaultMode: job.defaultMode,
237
+ description: previewHarnessText(job.description, includeParameters ? 180 : 96),
238
+ runRoute: 'memory action:"run_refinement" confirm:true explicitUserRequest:"..."',
239
+ ...(latestRun ? {
240
+ latestRun: {
241
+ id: latestRun.id,
242
+ status: latestRun.status,
243
+ mode: latestRun.mode,
244
+ requestedAt: iso(latestRun.requestedAt),
245
+ completedAt: iso(latestRun.completedAt),
246
+ ...(latestRun.error ? { error: previewHarnessText(latestRun.error, 120) } : {}),
247
+ },
248
+ } : {}),
249
+ } : {
250
+ status: 'not-published',
251
+ description: 'KnowledgeService.runRefinement is available, but the scheduled semantic-self-improvement job is not listed.',
252
+ },
253
+ routes: {
254
+ inspect: 'memory action:"refinement" includeParameters:true',
255
+ inspectTask: 'memory action:"refinement" query:"<taskId>" includeParameters:true',
256
+ runManual: 'memory action:"run_refinement" limit:12 confirm:true explicitUserRequest:"..."',
257
+ runScopedSpace: 'memory action:"run_refinement" knowledgeSpaceId:"<spaceId>" limit:12 confirm:true explicitUserRequest:"..."',
258
+ runScopedGaps: 'memory action:"run_refinement" gapIds:["<gapId>"] confirm:true explicitUserRequest:"..."',
259
+ knowledgeStatus: 'agent_knowledge action:"status"',
260
+ memoryCurator: 'memory action:"curator" includeParameters:true',
261
+ },
262
+ nextActions: [
263
+ counts.attention > 0 ? 'Inspect blocked or failed refinement tasks before running a broader semantic self-improvement pass.' : '',
264
+ counts.active > 0 ? 'Let active refinement tasks finish or inspect their trace before starting another broad run.' : '',
265
+ counts.total === 0 ? 'Run a small confirmed manual refinement after useful Agent Knowledge sources exist.' : '',
266
+ 'Keep reviewed Agent-local memory as the active prompt path until refined Knowledge evidence is inspected and promoted through existing confirmed routes.',
267
+ ].filter(Boolean),
268
+ policy: 'Read-only refinement inspection never searches, ingests, writes prompt memory, or mutates Knowledge. Manual refinement runs require confirm:true and explicitUserRequest.',
269
+ };
270
+ }
271
+
272
+ export async function runMemoryRefinement(context: CommandContext, args: AgentHarnessMemoryRefinementArgs): Promise<Record<string, unknown>> {
273
+ const service = knowledgeService(context);
274
+ if (!service?.runRefinement) {
275
+ return {
276
+ status: 'unavailable',
277
+ error: 'Agent Knowledge semantic refinement runner is not available in this runtime.',
278
+ inspectRoute: 'memory action:"refinement" includeParameters:true',
279
+ };
280
+ }
281
+ const sourceIds = readStringArray(args.sourceIds);
282
+ const gapIds = readStringArray(args.gapIds);
283
+ const knowledgeSpaceId = readString(args.knowledgeSpaceId);
284
+ const limit = readLimit(args.limit, 12, 24);
285
+ const maxRunMs = readRunBudgetMs(args.maxRunMs) ?? readRunBudgetMs(args.timeoutMs);
286
+ const run = await service.runRefinement({
287
+ ...(knowledgeSpaceId ? { knowledgeSpaceId } : {}),
288
+ ...(sourceIds.length > 0 ? { sourceIds } : {}),
289
+ ...(gapIds.length > 0 ? { gapIds } : {}),
290
+ limit,
291
+ ...(maxRunMs ? { maxRunMs } : {}),
292
+ ...(args.force === true ? { force: true } : {}),
293
+ });
294
+ return {
295
+ status: run.errors.length > 0 || run.blockedGaps > 0 ? 'completed-with-attention' : 'completed',
296
+ result: {
297
+ scannedGaps: run.scannedGaps,
298
+ candidateGaps: run.candidateGaps ?? 0,
299
+ processedGaps: run.processedGaps ?? 0,
300
+ createdGaps: run.createdGaps,
301
+ repairableGaps: run.repairableGaps,
302
+ suppressedGaps: run.suppressedGaps,
303
+ skippedGaps: run.skippedGaps,
304
+ searched: run.searched,
305
+ ingestedSources: run.ingestedSources,
306
+ linkedRepairs: run.linkedRepairs,
307
+ blockedGaps: run.blockedGaps,
308
+ closedGaps: run.closedGaps,
309
+ queuedTasks: run.queuedTasks,
310
+ requestedLimit: run.requestedLimit ?? limit,
311
+ effectiveLimit: run.effectiveLimit ?? 0,
312
+ truncated: Boolean(run.truncated),
313
+ budgetExhausted: Boolean(run.budgetExhausted),
314
+ taskIds: run.taskIds,
315
+ acceptedSourceIds: run.acceptedSourceIds ?? [],
316
+ ingestedSourceIds: run.ingestedSourceIds,
317
+ promotedFactCount: run.promotedFactCount ?? 0,
318
+ ...(run.nextRepairAttemptAt ? { nextRepairAttemptAt: iso(run.nextRepairAttemptAt) } : {}),
319
+ errors: run.errors.map((entry) => ({
320
+ gapId: entry.gapId,
321
+ error: previewHarnessText(entry.error, 160),
322
+ })),
323
+ },
324
+ scope: {
325
+ ...(knowledgeSpaceId ? { knowledgeSpaceId } : {}),
326
+ ...(sourceIds.length > 0 ? { sourceIds } : {}),
327
+ ...(gapIds.length > 0 ? { gapIds } : {}),
328
+ limit,
329
+ ...(maxRunMs ? { maxRunMs } : {}),
330
+ force: args.force === true,
331
+ },
332
+ nextRoutes: {
333
+ refinement: 'memory action:"refinement" includeParameters:true',
334
+ curator: 'memory action:"curator" includeParameters:true',
335
+ tasks: run.taskIds.map((taskId) => `memory action:"refinement" query:${routeValue(taskId)} includeParameters:true`).slice(0, 8),
336
+ knowledgeStatus: 'agent_knowledge action:"status"',
337
+ },
338
+ policy: 'Confirmed semantic refinement updates only Agent Knowledge semantic gaps/refinement tasks and source-backed repair evidence through KnowledgeService.runRefinement. It does not write Agent-local prompt memory, external memory providers, channel messages, or reports.',
339
+ };
340
+ }
@@ -72,8 +72,8 @@ export const HARNESS_MODE_DESCRIPTORS: readonly HarnessModeDescriptor[] = [
72
72
  { id: 'project_context', kind: 'discover', family: 'context', summary: 'List AGENTS, HERMES, CLAUDE, SOUL, and Cursor context files.', next: 'Prefer context action:"files|file".', keywords: ['agents.md', 'hermes.md', '.hermes.md', 'claude.md', 'soul.md', '.cursorrules', '.cursor/rules', 'project instructions'], parameters: ['target', 'query', 'includeParameters'] },
73
73
  { id: 'project_context_file', kind: 'inspect', family: 'context', summary: 'Inspect one project context file body, source, or blocked reason.', next: 'Prefer context action:"file".', keywords: ['agents.md', 'hermes.md', '.hermes.md', 'claude.md', 'soul.md', '.cursorrules', '.cursor/rules', 'project instructions'], parameters: ['contextFileId', 'target', 'query', 'includeParameters'] },
74
74
  { id: 'prompt_context', kind: 'inspect', family: 'context', summary: 'Inspect prompt context, receipt outcomes, and token budget.', next: 'Prefer context action:"prompt|receipts|receipt".', keywords: ['prompt context', 'system prompt', 'why assistant acts', 'selected memory', 'active persona', 'suppressed context', 'token budget', 'receipt id', 'turn outcome', 'prompt receipt filters'], parameters: ['receiptId', 'turnId', 'outcomeStatus', 'limit', 'includeParameters'] },
75
- { id: 'agent_orchestration', kind: 'discover', family: 'execution', summary: 'Inspect managed plan cards, closeout evidence, and dispatch routes.', next: 'Inspect one agent; dispatch approved plan items via agent_work_plan.', keywords: ['subagent', 'subagents', 'agent spawn', 'batch-spawn', 'dispatch agents', 'work plan dispatch', 'dispatch receipts', 'closeout evidence', 'multi-agent', 'multi-runner', 'managed plan', 'milestone', 'remote runner', 'artifact trail', 'visible agents', 'cancellable agents', 'wrfc', 'cohort'], parameters: ['query', 'limit', 'includeParameters'] },
76
- { id: 'agent_orchestration_agent', kind: 'inspect', family: 'execution', summary: 'Inspect one visible Agent record with plan card and safe controls.', keywords: ['subagent', 'subagents', 'agent status', 'agent cancel', 'agent wait', 'agent message', 'batch-spawn', 'dispatch receipts', 'closeout evidence', 'multi-agent', 'multi-runner', 'managed plan', 'milestone', 'remote runner', 'artifact trail', 'visible agents', 'cancellable agents', 'wrfc', 'cohort'], parameters: ['agentId', 'target', 'query', 'includeParameters'] },
75
+ { id: 'agent_orchestration', kind: 'discover', family: 'execution', summary: 'Inspect plan cards, closeout, live remote outcomes, and dispatch.', next: 'Inspect one agent; dispatch approved plan items via agent_work_plan.', keywords: ['subagent', 'subagents', 'agent spawn', 'batch-spawn', 'dispatch agents', 'work plan dispatch', 'dispatch receipts', 'closeout evidence', 'remote read model', 'capture outcome', 'workspace isolation', 'worktree evidence', 'multi-agent', 'multi-runner', 'managed plan', 'milestone', 'remote runner', 'artifact trail', 'visible agents', 'cancellable agents', 'wrfc', 'cohort'], parameters: ['query', 'limit', 'includeParameters'] },
76
+ { id: 'agent_orchestration_agent', kind: 'inspect', family: 'execution', summary: 'Inspect one visible Agent plan card with remote evidence.', keywords: ['subagent', 'subagents', 'agent status', 'agent cancel', 'agent wait', 'agent message', 'batch-spawn', 'dispatch receipts', 'closeout evidence', 'remote read model', 'capture outcome', 'workspace isolation', 'worktree evidence', 'multi-agent', 'multi-runner', 'managed plan', 'milestone', 'remote runner', 'artifact trail', 'visible agents', 'cancellable agents', 'wrfc', 'cohort'], parameters: ['agentId', 'target', 'query', 'includeParameters'] },
77
77
  { id: 'model_routing', kind: 'discover', family: 'providers', summary: 'List model routes, readiness scores, local cookbook, and pins.', next: 'Prefer models action:"status|local|route|smoke".', parameters: ['query', 'limit', 'includeParameters'] },
78
78
  { id: 'model_route', kind: 'inspect', family: 'providers', summary: 'Inspect one model route, local endpoint, fit score, or picker path.', parameters: ['modelRouteId', 'target', 'query'] },
79
79
  { id: 'run_local_model_smoke', kind: 'effect', family: 'providers', summary: 'Run confirmed read-only model-list smoke checks for local endpoints.', requiresConfirmation: true, keywords: ['local model smoke', 'check local servers', 'ollama models', 'local endpoint probe'], parameters: ['modelRouteId', 'target', 'query', 'limit', 'timeoutMs', 'confirm', 'explicitUserRequest'] },
@@ -95,6 +95,8 @@ export const HARNESS_MODE_DESCRIPTORS: readonly HarnessModeDescriptor[] = [
95
95
  { id: 'run_personal_ops_read', kind: 'effect', family: 'personal-ops', summary: 'Run one confirmed read-only inbox/calendar MCP operation.', next: 'Prefer personal_ops action:"read" for user-facing calls.', requiresConfirmation: true, keywords: ['email triage', 'inbox read', 'calendar read', 'agenda read', 'mcp call tool'], parameters: ['laneId', 'recordId', 'target', 'query', 'fields', 'includeParameters', 'confirm', 'explicitUserRequest'] },
96
96
  { id: 'memory_posture', kind: 'discover', family: 'personal-ops', summary: 'Inspect Agent-local memory, vector recall, and provider posture.', next: 'Prefer memory action:"status"; use action:"provider" for one.', keywords: ['semantic recall', 'external memory', 'memory provider', 'honcho', 'openviking', 'mem0', 'hindsight', 'holographic', 'retaindb', 'byterover', 'supermemory'], parameters: ['query', 'limit', 'includeParameters'] },
97
97
  { id: 'memory_provider', kind: 'inspect', family: 'personal-ops', summary: 'Inspect one memory embedding or external-memory provider record.', keywords: ['semantic recall', 'external memory', 'embedding provider', 'memory provider', 'honcho', 'openviking', 'mem0', 'hindsight', 'holographic', 'retaindb', 'byterover', 'supermemory'], parameters: ['providerId', 'target', 'query', 'includeParameters'] },
98
+ { id: 'memory_refinement', kind: 'discover', family: 'personal-ops', summary: 'Inspect Knowledge semantic self-improvement tasks and routes.', next: 'Prefer memory action:"refinement".', keywords: ['semantic self improvement', 'semantic refinement', 'refinement tasks', 'closed learning loop', 'knowledge gaps', 'memory learning loop'], parameters: ['query', 'target', 'knowledgeSpaceId', 'sourceIds', 'gapIds', 'limit', 'includeParameters'] },
99
+ { id: 'run_memory_refinement', kind: 'effect', family: 'personal-ops', summary: 'Run bounded Agent Knowledge semantic self-improvement.', next: 'Prefer memory action:"run_refinement".', requiresConfirmation: true, keywords: ['run semantic self improvement', 'run semantic refinement', 'repair knowledge gaps', 'closed learning loop', 'knowledge gap repair'], parameters: ['knowledgeSpaceId', 'sourceIds', 'gapIds', 'limit', 'maxRunMs', 'force', 'confirm', 'explicitUserRequest'] },
98
100
  { id: 'autonomy_intake', kind: 'discover', family: 'personal-ops', summary: 'Route ongoing work with schedule and watcher trigger posture.', next: 'Prefer autonomy action:"intake"; use returned route or action:"queue".', keywords: ['incoming webhook', 'webhook watcher', 'watcher trigger', 'event trigger', 'gmail trigger', 'cron wakeup'], parameters: ['query', 'target', 'includeParameters'] },
99
101
  { id: 'autonomy_queue', kind: 'discover', family: 'personal-ops', summary: 'List autonomy work with live records, tails, and controls.', next: 'Prefer autonomy action:"queue"; inspect one with action:"item".', parameters: ['query', 'limit', 'includeParameters'] },
100
102
  { id: 'autonomy_queue_item', kind: 'inspect', family: 'personal-ops', summary: 'Inspect one autonomy card, live records, tails, and routes.', next: 'Prefer autonomy action:"item".', parameters: ['queueItemId', 'target', 'query'] },