forgeos 0.1.0-alpha.12 → 0.1.0-alpha.13
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/AGENTS.md +1 -1
- package/CHANGELOG.md +11 -0
- package/package.json +1 -1
- package/src/forge/_generated/actionSubscriptions.json +1 -1
- package/src/forge/_generated/actionSubscriptions.ts +3 -3
- package/src/forge/_generated/agentAdapterManifest.json +1 -1
- package/src/forge/_generated/agentAdapterManifest.ts +3 -3
- package/src/forge/_generated/agentContract.json +1 -1
- package/src/forge/_generated/agentContract.ts +2 -2
- package/src/forge/_generated/agentQuickstart.md +1 -1
- package/src/forge/_generated/agentTools.json +1 -1
- package/src/forge/_generated/agentTools.md +1 -1
- package/src/forge/_generated/agentTools.ts +2 -2
- package/src/forge/_generated/aiContext.ts +1 -1
- package/src/forge/_generated/aiModels.ts +1 -1
- package/src/forge/_generated/aiProviders.ts +1 -1
- package/src/forge/_generated/aiRegistry.json +1 -1
- package/src/forge/_generated/aiRegistry.ts +3 -3
- package/src/forge/_generated/api.json +1 -1
- package/src/forge/_generated/api.ts +1 -1
- package/src/forge/_generated/appGraph.json +1 -1
- package/src/forge/_generated/appGraph.ts +288 -19
- package/src/forge/_generated/appMap.md +1 -1
- package/src/forge/_generated/artifactManifest.json +1 -1
- package/src/forge/_generated/artifactManifest.ts +2 -2
- package/src/forge/_generated/authClaims.ts +1 -1
- package/src/forge/_generated/authConfig.ts +1 -1
- package/src/forge/_generated/authContext.ts +1 -1
- package/src/forge/_generated/authRegistry.ts +1 -1
- package/src/forge/_generated/buildInfo.json +1 -1
- package/src/forge/_generated/buildInfo.ts +4 -4
- package/src/forge/_generated/capabilityMap.json +1 -1
- package/src/forge/_generated/capabilityMap.md +1 -1
- package/src/forge/_generated/capabilityMap.ts +2 -2
- package/src/forge/_generated/client.ts +1 -1
- package/src/forge/_generated/clientApi.ts +1 -1
- package/src/forge/_generated/clientManifest.json +1 -1
- package/src/forge/_generated/clientManifest.ts +3 -3
- package/src/forge/_generated/clientTypes.ts +1 -1
- package/src/forge/_generated/configRegistry.ts +1 -1
- package/src/forge/_generated/dataGraph.json +1 -1
- package/src/forge/_generated/dataGraph.ts +3 -3
- package/src/forge/_generated/db.ts +1 -1
- package/src/forge/_generated/dbSecurityManifest.ts +1 -1
- package/src/forge/_generated/dbSessionContext.ts +1 -1
- package/src/forge/_generated/deployManifest.json +1 -1
- package/src/forge/_generated/deployManifest.ts +7 -7
- package/src/forge/_generated/devManifest.json +1 -1
- package/src/forge/_generated/devManifest.ts +3 -3
- package/src/forge/_generated/envSchema.ts +1 -1
- package/src/forge/_generated/externalServices.ts +1 -1
- package/src/forge/_generated/frontendGraph.ts +1 -1
- package/src/forge/_generated/importGuards.ts +1 -1
- package/src/forge/_generated/index.ts +1 -1
- package/src/forge/_generated/liveProductionManifest.ts +1 -1
- package/src/forge/_generated/liveProtocol.ts +1 -1
- package/src/forge/_generated/liveQueryRegistry.json +1 -1
- package/src/forge/_generated/liveQueryRegistry.ts +3 -3
- package/src/forge/_generated/liveTransportConfig.ts +1 -1
- package/src/forge/_generated/makeRegistry.json +1 -1
- package/src/forge/_generated/makeRegistry.ts +2 -2
- package/src/forge/_generated/makeTemplates.ts +1 -1
- package/src/forge/_generated/mockMap.ts +1 -1
- package/src/forge/_generated/operationPlaybooks.md +1 -1
- package/src/forge/_generated/packageGraph.json +1 -1
- package/src/forge/_generated/packageGraph.ts +2 -2
- package/src/forge/_generated/packageUpgradeRegistry.json +1 -1
- package/src/forge/_generated/packageUpgradeRegistry.ts +2 -2
- package/src/forge/_generated/permissionMatrix.json +1 -1
- package/src/forge/_generated/permissionMatrix.ts +3 -3
- package/src/forge/_generated/policyRegistry.json +1 -1
- package/src/forge/_generated/policyRegistry.ts +3 -3
- package/src/forge/_generated/queryRegistry.json +1 -1
- package/src/forge/_generated/queryRegistry.ts +3 -3
- package/src/forge/_generated/react.d.ts +1 -1
- package/src/forge/_generated/react.ts +1 -1
- package/src/forge/_generated/reactManifest.json +1 -1
- package/src/forge/_generated/reactManifest.ts +3 -3
- package/src/forge/_generated/releaseManifest.json +1 -1
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/_generated/rlsPolicies.sql +1 -1
- package/src/forge/_generated/rlsPolicies.ts +1 -1
- package/src/forge/_generated/runtimeGraph.json +1 -1
- package/src/forge/_generated/runtimeGraph.ts +3 -3
- package/src/forge/_generated/runtimeMatrix.ts +1 -1
- package/src/forge/_generated/runtimeRegistry.ts +1 -1
- package/src/forge/_generated/runtimeRules.md +1 -1
- package/src/forge/_generated/secretRegistry.ts +1 -1
- package/src/forge/_generated/secretsContext.ts +1 -1
- package/src/forge/_generated/serverApi.ts +1 -1
- package/src/forge/_generated/sourceMapManifest.json +1 -1
- package/src/forge/_generated/sourceMapManifest.ts +2 -2
- package/src/forge/_generated/sqlPlan.ts +1 -1
- package/src/forge/_generated/subscriptionManifest.json +1 -1
- package/src/forge/_generated/subscriptionManifest.ts +3 -3
- package/src/forge/_generated/symbolicationManifest.json +1 -1
- package/src/forge/_generated/symbolicationManifest.ts +2 -2
- package/src/forge/_generated/telemetryRegistry.json +1 -1
- package/src/forge/_generated/telemetryRegistry.ts +3 -3
- package/src/forge/_generated/telemetrySinks.json +1 -1
- package/src/forge/_generated/telemetrySinks.ts +2 -2
- package/src/forge/_generated/tenantScope.json +1 -1
- package/src/forge/_generated/tenantScope.ts +3 -3
- package/src/forge/_generated/testGraph.json +1 -1
- package/src/forge/_generated/testGraph.ts +21 -3
- package/src/forge/_generated/testPlanRegistry.json +1 -1
- package/src/forge/_generated/testPlanRegistry.ts +2 -2
- package/src/forge/_generated/uiRoutes.ts +1 -1
- package/src/forge/_generated/uiScenarios.ts +1 -1
- package/src/forge/_generated/uiTestManifest.json +1 -1
- package/src/forge/_generated/uiTestManifest.ts +2 -2
- package/src/forge/_generated/workflowRegistry.json +1 -1
- package/src/forge/_generated/workflowRegistry.ts +3 -3
- package/src/forge/_generated/workflowSubscriptions.json +1 -1
- package/src/forge/_generated/workflowSubscriptions.ts +3 -3
- package/src/forge/agent-adapters/index.ts +36 -2
- package/src/forge/agent-adapters/types.ts +10 -1
- package/src/forge/agent-memory/bridge.ts +228 -0
- package/src/forge/agent-memory/context-pack.ts +104 -0
- package/src/forge/agent-memory/mcp.ts +224 -0
- package/src/forge/agent-memory/normalize.ts +249 -0
- package/src/forge/agent-memory/redaction.ts +94 -0
- package/src/forge/agent-memory/sources/claude-code.ts +51 -0
- package/src/forge/agent-memory/sources/codex.ts +58 -0
- package/src/forge/agent-memory/sources/cursor.ts +35 -0
- package/src/forge/agent-memory/types.ts +112 -0
- package/src/forge/cli/build.ts +19 -3
- package/src/forge/cli/commands.ts +4 -0
- package/src/forge/cli/main.ts +2 -0
- package/src/forge/cli/parse.ts +47 -2
- package/src/forge/delta/ids.ts +2 -0
- package/src/forge/delta/schema.ts +38 -1
- package/src/forge/delta/store.ts +235 -2
- package/src/forge/version.ts +1 -1
package/src/forge/cli/parse.ts
CHANGED
|
@@ -164,6 +164,7 @@ export type ForgeCommand =
|
|
|
164
164
|
| { kind: "do"; options: ForgeDoOptions }
|
|
165
165
|
| { kind: "bench"; options: BenchCommandOptions }
|
|
166
166
|
| { kind: "agent"; options: AgentCommandOptions }
|
|
167
|
+
| { kind: "mcp"; subcommand: "serve"; workspaceRoot: string }
|
|
167
168
|
| { kind: "review"; options: ReviewCommandOptions }
|
|
168
169
|
| { kind: "ui"; options: UiCommandOptions }
|
|
169
170
|
| { kind: "manifest"; subcommand: "validate" | "import"; path: string; json: boolean; workspaceRoot: string }
|
|
@@ -336,6 +337,7 @@ export const TOP_LEVEL_COMMANDS = [
|
|
|
336
337
|
"self-host",
|
|
337
338
|
"agent-contract",
|
|
338
339
|
"agent",
|
|
340
|
+
"mcp",
|
|
339
341
|
"review",
|
|
340
342
|
"ui",
|
|
341
343
|
"doctor",
|
|
@@ -533,6 +535,10 @@ const AGENT_SUBCOMMANDS: AgentSubcommand[] = [
|
|
|
533
535
|
"doctor",
|
|
534
536
|
"print-context",
|
|
535
537
|
"clean",
|
|
538
|
+
"install",
|
|
539
|
+
"ingest",
|
|
540
|
+
"context",
|
|
541
|
+
"memory",
|
|
536
542
|
];
|
|
537
543
|
const REVIEW_SUBCOMMANDS: ReviewSubcommand[] = ["inspect", "list", "explain"];
|
|
538
544
|
const REVIEW_MODES: ReviewMode[] = ["quick", "standard", "strict"];
|
|
@@ -890,12 +896,27 @@ export function parseCli(argv: string[]): ParsedCli {
|
|
|
890
896
|
case "agent": {
|
|
891
897
|
const subcommand = rest[0] as AgentSubcommand | undefined;
|
|
892
898
|
if (!subcommand || !AGENT_SUBCOMMANDS.includes(subcommand)) {
|
|
893
|
-
errors.push("forge agent requires subcommand: list-targets, export, check, doctor, print-context, or
|
|
899
|
+
errors.push("forge agent requires subcommand: list-targets, export, check, doctor, print-context, clean, install, ingest, context, or memory");
|
|
894
900
|
return { command: null, workspaceRoot, errors };
|
|
895
901
|
}
|
|
902
|
+
const inputRaw = parseOptionValue(argv, "--input");
|
|
903
|
+
let input: unknown;
|
|
904
|
+
if (inputRaw !== undefined) {
|
|
905
|
+
try {
|
|
906
|
+
input = JSON.parse(inputRaw);
|
|
907
|
+
} catch {
|
|
908
|
+
errors.push("--input must be valid JSON");
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
const limitRaw = parseOptionValue(argv, "--limit");
|
|
912
|
+
const limit = limitRaw ? Number(limitRaw) : undefined;
|
|
913
|
+
if (limitRaw !== undefined && (!Number.isFinite(limit) || limit! < 1)) {
|
|
914
|
+
errors.push("--limit must be a number >= 1");
|
|
915
|
+
}
|
|
896
916
|
const target =
|
|
897
917
|
(parseOptionValue(argv, "--target") as AgentAdapterTarget | undefined) ??
|
|
898
|
-
(subcommand === "
|
|
918
|
+
(subcommand === "install" || subcommand === "ingest" ? rest[1] : undefined) ??
|
|
919
|
+
"generic";
|
|
899
920
|
return {
|
|
900
921
|
command: {
|
|
901
922
|
kind: "agent",
|
|
@@ -909,12 +930,33 @@ export function parseCli(argv: string[]): ParsedCli {
|
|
|
909
930
|
preserveUserSections: !parseFlag(argv, "--no-preserve-user-sections"),
|
|
910
931
|
skills: !parseFlag(argv, "--no-skills"),
|
|
911
932
|
rules: !parseFlag(argv, "--no-rules"),
|
|
933
|
+
eventName: parseOptionValue(argv, "--event"),
|
|
934
|
+
input,
|
|
935
|
+
entry: parseOptionValue(argv, "--entry") ?? (subcommand === "context" && rest[1] !== "--current" ? rest[1] : undefined),
|
|
936
|
+
current: parseFlag(argv, "--current"),
|
|
937
|
+
limit: limit ? Math.floor(limit) : undefined,
|
|
912
938
|
},
|
|
913
939
|
},
|
|
914
940
|
workspaceRoot,
|
|
915
941
|
errors,
|
|
916
942
|
};
|
|
917
943
|
}
|
|
944
|
+
case "mcp": {
|
|
945
|
+
const subcommand = rest[0];
|
|
946
|
+
if (subcommand !== "serve") {
|
|
947
|
+
errors.push("forge mcp requires subcommand: serve");
|
|
948
|
+
return { command: null, workspaceRoot, errors };
|
|
949
|
+
}
|
|
950
|
+
return {
|
|
951
|
+
command: {
|
|
952
|
+
kind: "mcp",
|
|
953
|
+
subcommand,
|
|
954
|
+
workspaceRoot,
|
|
955
|
+
},
|
|
956
|
+
workspaceRoot,
|
|
957
|
+
errors,
|
|
958
|
+
};
|
|
959
|
+
}
|
|
918
960
|
case "review": {
|
|
919
961
|
const requested = rest[0] as ReviewSubcommand | undefined;
|
|
920
962
|
const subcommand =
|
|
@@ -2304,6 +2346,8 @@ export function hasUnknownOption(argv: string[]): string | null {
|
|
|
2304
2346
|
"--policy",
|
|
2305
2347
|
"--emit",
|
|
2306
2348
|
"--event",
|
|
2349
|
+
"--entry",
|
|
2350
|
+
"--current",
|
|
2307
2351
|
"--trigger",
|
|
2308
2352
|
"--component",
|
|
2309
2353
|
"--framework",
|
|
@@ -2442,6 +2486,7 @@ export function hasUnknownOption(argv: string[]): string | null {
|
|
|
2442
2486
|
arg === "--policy" ||
|
|
2443
2487
|
arg === "--emit" ||
|
|
2444
2488
|
arg === "--event" ||
|
|
2489
|
+
arg === "--entry" ||
|
|
2445
2490
|
arg === "--trigger" ||
|
|
2446
2491
|
arg === "--component" ||
|
|
2447
2492
|
arg === "--package" ||
|
package/src/forge/delta/ids.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const DELTA_SCHEMA_VERSION = "0.
|
|
1
|
+
export const DELTA_SCHEMA_VERSION = "0.3.0";
|
|
2
2
|
|
|
3
3
|
export const DELTA_SCHEMA_SQL = [
|
|
4
4
|
`CREATE TABLE IF NOT EXISTS delta_meta (
|
|
@@ -179,6 +179,38 @@ export const DELTA_SCHEMA_SQL = [
|
|
|
179
179
|
projection_version text,
|
|
180
180
|
graph_hash text
|
|
181
181
|
)`,
|
|
182
|
+
`CREATE TABLE IF NOT EXISTS agent_event_sources (
|
|
183
|
+
id text PRIMARY KEY,
|
|
184
|
+
source_name text NOT NULL,
|
|
185
|
+
source_kind text NOT NULL,
|
|
186
|
+
integration_kind text NOT NULL,
|
|
187
|
+
trust_level text NOT NULL,
|
|
188
|
+
config_json text,
|
|
189
|
+
created_at text NOT NULL
|
|
190
|
+
)`,
|
|
191
|
+
`CREATE TABLE IF NOT EXISTS external_agent_events (
|
|
192
|
+
id text PRIMARY KEY,
|
|
193
|
+
source_id text NOT NULL,
|
|
194
|
+
external_session_id text,
|
|
195
|
+
external_turn_id text,
|
|
196
|
+
event_kind text NOT NULL,
|
|
197
|
+
captured_at text NOT NULL,
|
|
198
|
+
payload_redacted_json text NOT NULL,
|
|
199
|
+
payload_hash text,
|
|
200
|
+
raw_stored integer DEFAULT 0,
|
|
201
|
+
normalization_status text NOT NULL
|
|
202
|
+
)`,
|
|
203
|
+
`CREATE TABLE IF NOT EXISTS agent_memory_events (
|
|
204
|
+
id text PRIMARY KEY,
|
|
205
|
+
external_event_id text,
|
|
206
|
+
forge_session_id text,
|
|
207
|
+
forge_change_id text,
|
|
208
|
+
operation_id text,
|
|
209
|
+
normalized_kind text NOT NULL,
|
|
210
|
+
summary text,
|
|
211
|
+
confidence real NOT NULL,
|
|
212
|
+
data_json text NOT NULL
|
|
213
|
+
)`,
|
|
182
214
|
`CREATE INDEX IF NOT EXISTS operations_timestamp_idx ON operations(timestamp)`,
|
|
183
215
|
`CREATE INDEX IF NOT EXISTS operations_kind_idx ON operations(kind)`,
|
|
184
216
|
`CREATE INDEX IF NOT EXISTS operations_session_idx ON operations(session_id)`,
|
|
@@ -198,4 +230,9 @@ export const DELTA_SCHEMA_SQL = [
|
|
|
198
230
|
`CREATE INDEX IF NOT EXISTS timeline_entities_event_idx ON timeline_entities(timeline_event_id)`,
|
|
199
231
|
`CREATE INDEX IF NOT EXISTS timeline_edges_from_idx ON timeline_edges(from_event_id)`,
|
|
200
232
|
`CREATE INDEX IF NOT EXISTS timeline_edges_to_idx ON timeline_edges(to_event_id)`,
|
|
233
|
+
`CREATE INDEX IF NOT EXISTS agent_event_sources_name_idx ON agent_event_sources(source_name, integration_kind)`,
|
|
234
|
+
`CREATE INDEX IF NOT EXISTS external_agent_events_source_idx ON external_agent_events(source_id, captured_at)`,
|
|
235
|
+
`CREATE INDEX IF NOT EXISTS external_agent_events_kind_idx ON external_agent_events(event_kind)`,
|
|
236
|
+
`CREATE INDEX IF NOT EXISTS agent_memory_events_kind_idx ON agent_memory_events(normalized_kind)`,
|
|
237
|
+
`CREATE INDEX IF NOT EXISTS agent_memory_events_operation_idx ON agent_memory_events(operation_id)`,
|
|
201
238
|
];
|
package/src/forge/delta/store.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { createDeltaId } from "./ids.ts";
|
|
|
9
9
|
import { redactDeltaPayload } from "./redaction.ts";
|
|
10
10
|
import { classifyArtifactKind, classifyDeltaPath, type DeltaSemanticHint } from "./classifier.ts";
|
|
11
11
|
import { readDeltaGitSnapshot, type DeltaGitSnapshot } from "./git-observer.ts";
|
|
12
|
+
import type { AgentEventEnvelope, AgentMemoryEventRecord } from "../agent-memory/types.ts";
|
|
12
13
|
|
|
13
14
|
export type DeltaActorKind = "human" | "agent" | "forge" | "ci" | "git" | "unknown";
|
|
14
15
|
export type DeltaSessionSource = "forge-dev" | "forge-command" | "agent-adapter" | "git" | "auto";
|
|
@@ -88,6 +89,20 @@ export interface DeltaAppendInput {
|
|
|
88
89
|
git?: { commitSha?: string; branch?: string; confidence?: number; metadata?: Record<string, unknown> };
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
export interface DeltaAgentMemoryEventInput {
|
|
93
|
+
envelope: AgentEventEnvelope;
|
|
94
|
+
summary?: string;
|
|
95
|
+
bindings?: {
|
|
96
|
+
toolName?: string;
|
|
97
|
+
command?: string;
|
|
98
|
+
exitCode?: number;
|
|
99
|
+
files?: string[];
|
|
100
|
+
entries?: string[];
|
|
101
|
+
proofs?: string[];
|
|
102
|
+
status?: string;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
91
106
|
export interface DeltaTimelineFilter {
|
|
92
107
|
target?: string;
|
|
93
108
|
kind?: string;
|
|
@@ -394,6 +409,191 @@ export class DeltaStore {
|
|
|
394
409
|
return operationId;
|
|
395
410
|
}
|
|
396
411
|
|
|
412
|
+
async recordAgentMemoryEvent(input: DeltaAgentMemoryEventInput): Promise<AgentMemoryEventRecord> {
|
|
413
|
+
const envelope = input.envelope;
|
|
414
|
+
const timestamp = envelope.event.timestamp || new Date().toISOString();
|
|
415
|
+
const sourceId = deterministicTimelineId("agsrc", [
|
|
416
|
+
String(envelope.source.agent),
|
|
417
|
+
String(envelope.source.integration),
|
|
418
|
+
String(envelope.capture.trustLevel),
|
|
419
|
+
]);
|
|
420
|
+
await this.adapter.query(
|
|
421
|
+
`INSERT INTO agent_event_sources (id, source_name, source_kind, integration_kind, trust_level, config_json, created_at)
|
|
422
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
423
|
+
ON CONFLICT (id) DO UPDATE
|
|
424
|
+
SET source_name = EXCLUDED.source_name,
|
|
425
|
+
source_kind = EXCLUDED.source_kind,
|
|
426
|
+
integration_kind = EXCLUDED.integration_kind,
|
|
427
|
+
trust_level = EXCLUDED.trust_level,
|
|
428
|
+
config_json = EXCLUDED.config_json`,
|
|
429
|
+
[
|
|
430
|
+
sourceId,
|
|
431
|
+
String(envelope.source.agent),
|
|
432
|
+
"external-agent",
|
|
433
|
+
String(envelope.source.integration),
|
|
434
|
+
envelope.capture.trustLevel,
|
|
435
|
+
JSON.stringify({ version: envelope.source.version }),
|
|
436
|
+
timestamp,
|
|
437
|
+
],
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
const actorId = await this.ensureActor("agent", envelope.actor.name, {
|
|
441
|
+
source: envelope.source.agent,
|
|
442
|
+
model: envelope.actor.model,
|
|
443
|
+
integration: envelope.source.integration,
|
|
444
|
+
});
|
|
445
|
+
const forgeSessionId = envelope.session.forgeSessionId ?? await this.createSession({
|
|
446
|
+
source: "agent-adapter",
|
|
447
|
+
summary: `${envelope.source.agent} ${envelope.event.kind}`,
|
|
448
|
+
metadata: {
|
|
449
|
+
externalSessionId: envelope.session.externalSessionId,
|
|
450
|
+
source: envelope.source,
|
|
451
|
+
},
|
|
452
|
+
git: { branch: envelope.workspace.gitBranch, head: envelope.workspace.gitHead },
|
|
453
|
+
});
|
|
454
|
+
const bindings = input.bindings ?? {};
|
|
455
|
+
const operationId = await this.appendOperation({
|
|
456
|
+
sessionId: forgeSessionId,
|
|
457
|
+
actorId,
|
|
458
|
+
kind: envelope.event.kind,
|
|
459
|
+
summary: input.summary,
|
|
460
|
+
data: {
|
|
461
|
+
source: envelope.source,
|
|
462
|
+
session: envelope.session,
|
|
463
|
+
capture: envelope.capture,
|
|
464
|
+
privacy: envelope.privacy,
|
|
465
|
+
payload: envelope.payload,
|
|
466
|
+
toolName: bindings.toolName,
|
|
467
|
+
status: bindings.status,
|
|
468
|
+
entries: bindings.entries,
|
|
469
|
+
files: bindings.files,
|
|
470
|
+
proofs: bindings.proofs,
|
|
471
|
+
},
|
|
472
|
+
commandRun: bindings.command
|
|
473
|
+
? {
|
|
474
|
+
commandName: bindings.command,
|
|
475
|
+
argv: [bindings.command],
|
|
476
|
+
exitCode: bindings.exitCode,
|
|
477
|
+
}
|
|
478
|
+
: undefined,
|
|
479
|
+
fileChanges: bindings.files?.map((path) => ({
|
|
480
|
+
path,
|
|
481
|
+
changeType: envelope.event.kind === "agent.file.changed" ? "modified" : "modified",
|
|
482
|
+
semanticHints: classifyDeltaPath(path),
|
|
483
|
+
})),
|
|
484
|
+
proof: bindings.proofs?.[0]
|
|
485
|
+
? {
|
|
486
|
+
proofKind: bindings.proofs[0],
|
|
487
|
+
command: bindings.command,
|
|
488
|
+
result: bindings.status === "failed" ? "failed" : "passed",
|
|
489
|
+
}
|
|
490
|
+
: undefined,
|
|
491
|
+
git: envelope.workspace.gitHead || envelope.workspace.gitBranch
|
|
492
|
+
? {
|
|
493
|
+
commitSha: envelope.workspace.gitHead,
|
|
494
|
+
branch: envelope.workspace.gitBranch,
|
|
495
|
+
confidence: envelope.capture.confidence,
|
|
496
|
+
metadata: { source: envelope.source.agent },
|
|
497
|
+
}
|
|
498
|
+
: undefined,
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
const externalEventId = createDeltaId("aevt");
|
|
502
|
+
const payloadJson = JSON.stringify(envelope.payload);
|
|
503
|
+
await this.adapter.query(
|
|
504
|
+
`INSERT INTO external_agent_events
|
|
505
|
+
(id, source_id, external_session_id, external_turn_id, event_kind, captured_at, payload_redacted_json, payload_hash, raw_stored, normalization_status)
|
|
506
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 0, 'normalized')`,
|
|
507
|
+
[
|
|
508
|
+
externalEventId,
|
|
509
|
+
sourceId,
|
|
510
|
+
envelope.session.externalSessionId ?? null,
|
|
511
|
+
envelope.session.turnId ?? null,
|
|
512
|
+
envelope.event.kind,
|
|
513
|
+
timestamp,
|
|
514
|
+
payloadJson,
|
|
515
|
+
hashStable(payloadJson),
|
|
516
|
+
],
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
const memoryId = createDeltaId("amem");
|
|
520
|
+
const data = {
|
|
521
|
+
envelope,
|
|
522
|
+
bindings,
|
|
523
|
+
};
|
|
524
|
+
await this.adapter.query(
|
|
525
|
+
`INSERT INTO agent_memory_events
|
|
526
|
+
(id, external_event_id, forge_session_id, forge_change_id, operation_id, normalized_kind, summary, confidence, data_json)
|
|
527
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
|
528
|
+
[
|
|
529
|
+
memoryId,
|
|
530
|
+
externalEventId,
|
|
531
|
+
forgeSessionId,
|
|
532
|
+
null,
|
|
533
|
+
operationId,
|
|
534
|
+
envelope.event.kind,
|
|
535
|
+
input.summary ?? null,
|
|
536
|
+
envelope.capture.confidence,
|
|
537
|
+
JSON.stringify(data),
|
|
538
|
+
],
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
return {
|
|
542
|
+
id: memoryId,
|
|
543
|
+
externalEventId,
|
|
544
|
+
sourceName: String(envelope.source.agent),
|
|
545
|
+
integrationKind: String(envelope.source.integration),
|
|
546
|
+
trustLevel: envelope.capture.trustLevel,
|
|
547
|
+
externalSessionId: envelope.session.externalSessionId,
|
|
548
|
+
externalTurnId: envelope.session.turnId,
|
|
549
|
+
eventKind: envelope.event.kind,
|
|
550
|
+
normalizedKind: envelope.event.kind,
|
|
551
|
+
summary: input.summary,
|
|
552
|
+
confidence: envelope.capture.confidence,
|
|
553
|
+
capturedAt: timestamp,
|
|
554
|
+
operationId,
|
|
555
|
+
data,
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
async listAgentMemoryEvents(filter: { target?: string; limit?: number } = {}): Promise<AgentMemoryEventRecord[]> {
|
|
560
|
+
const limit = Math.max(1, Math.min(filter.limit ?? 50, 200));
|
|
561
|
+
const params: unknown[] = [];
|
|
562
|
+
const clauses: string[] = [];
|
|
563
|
+
if (filter.target) {
|
|
564
|
+
params.push(`%${filter.target}%`);
|
|
565
|
+
clauses.push(`(ame.summary ILIKE $${params.length} OR ame.data_json ILIKE $${params.length})`);
|
|
566
|
+
}
|
|
567
|
+
const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
568
|
+
const rows = await this.adapter.query(
|
|
569
|
+
`SELECT ame.*, e.external_session_id, e.external_turn_id, e.event_kind, e.captured_at,
|
|
570
|
+
s.source_name, s.integration_kind, s.trust_level
|
|
571
|
+
FROM agent_memory_events ame
|
|
572
|
+
JOIN external_agent_events e ON e.id = ame.external_event_id
|
|
573
|
+
JOIN agent_event_sources s ON s.id = e.source_id
|
|
574
|
+
${where}
|
|
575
|
+
ORDER BY e.captured_at DESC, ame.id DESC
|
|
576
|
+
LIMIT ${limit}`,
|
|
577
|
+
params,
|
|
578
|
+
);
|
|
579
|
+
return rows.rows.reverse().map((row) => ({
|
|
580
|
+
id: String(row.id),
|
|
581
|
+
externalEventId: String(row.external_event_id),
|
|
582
|
+
sourceName: String(row.source_name),
|
|
583
|
+
integrationKind: String(row.integration_kind),
|
|
584
|
+
trustLevel: String(row.trust_level),
|
|
585
|
+
externalSessionId: typeof row.external_session_id === "string" ? row.external_session_id : undefined,
|
|
586
|
+
externalTurnId: typeof row.external_turn_id === "string" ? row.external_turn_id : undefined,
|
|
587
|
+
eventKind: String(row.event_kind),
|
|
588
|
+
normalizedKind: String(row.normalized_kind),
|
|
589
|
+
summary: typeof row.summary === "string" ? row.summary : undefined,
|
|
590
|
+
confidence: Number(row.confidence ?? 0),
|
|
591
|
+
capturedAt: String(row.captured_at),
|
|
592
|
+
operationId: typeof row.operation_id === "string" ? row.operation_id : undefined,
|
|
593
|
+
data: parseJsonRecord(row.data_json),
|
|
594
|
+
}));
|
|
595
|
+
}
|
|
596
|
+
|
|
397
597
|
async status(): Promise<DeltaStatus> {
|
|
398
598
|
const sessionRows = await this.adapter.query(
|
|
399
599
|
`SELECT s.id, s.started_at, COUNT(o.id)::int AS operation_count
|
|
@@ -1093,6 +1293,7 @@ export class DeltaStore {
|
|
|
1093
1293
|
const commands = uniqueStrings([
|
|
1094
1294
|
...commandResult.rows.map((item) => item.command_name),
|
|
1095
1295
|
data.command,
|
|
1296
|
+
data.toolName,
|
|
1096
1297
|
]);
|
|
1097
1298
|
return {
|
|
1098
1299
|
id: String(row.id),
|
|
@@ -1674,6 +1875,9 @@ function semanticEventKindForOperation(
|
|
|
1674
1875
|
if (context.kind === "git.commit.detected" || context.kind === "git.mapping.detected") {
|
|
1675
1876
|
return "git.exported";
|
|
1676
1877
|
}
|
|
1878
|
+
if (context.kind.startsWith("agent.") || context.kind.startsWith("approval.")) {
|
|
1879
|
+
return context.kind;
|
|
1880
|
+
}
|
|
1677
1881
|
if (context.kind.startsWith("file.")) {
|
|
1678
1882
|
return context.fileClusters.includes("policy.change") ? "policy.changed" : "modified";
|
|
1679
1883
|
}
|
|
@@ -1721,14 +1925,26 @@ function semanticTitleForOperation(
|
|
|
1721
1925
|
if (eventKind === "git.exported") {
|
|
1722
1926
|
return "Exported to Git";
|
|
1723
1927
|
}
|
|
1928
|
+
if (eventKind === "agent.prompt.submitted") {
|
|
1929
|
+
return `${agentNameFromContext(context) ?? "Agent"} submitted a prompt`;
|
|
1930
|
+
}
|
|
1931
|
+
if (eventKind.startsWith("agent.tool")) {
|
|
1932
|
+
return `${agentNameFromContext(context) ?? "Agent"} ${String(context.data.toolName ?? context.commands[0] ?? "tool")} ${eventKind.split(".").pop()}`;
|
|
1933
|
+
}
|
|
1934
|
+
if (eventKind.startsWith("approval.")) {
|
|
1935
|
+
return `${agentNameFromContext(context) ?? "Agent"} approval ${eventKind.split(".").pop()}`;
|
|
1936
|
+
}
|
|
1937
|
+
if (eventKind.startsWith("agent.")) {
|
|
1938
|
+
return `${agentNameFromContext(context) ?? "Agent"} ${eventKind.replace(/^agent\./, "").replace(/\./g, " ")}`;
|
|
1939
|
+
}
|
|
1724
1940
|
return context.summary ?? context.kind;
|
|
1725
1941
|
}
|
|
1726
1942
|
|
|
1727
1943
|
function semanticSeverity(eventKind: string): string {
|
|
1728
|
-
if (eventKind === "failed" || eventKind === "denied" || eventKind === "proof.failed") {
|
|
1944
|
+
if (eventKind === "failed" || eventKind === "denied" || eventKind === "proof.failed" || eventKind.endsWith(".failed") || eventKind.endsWith(".denied")) {
|
|
1729
1945
|
return "error";
|
|
1730
1946
|
}
|
|
1731
|
-
if (eventKind === "proof.passed" || eventKind === "executed") {
|
|
1947
|
+
if (eventKind === "proof.passed" || eventKind === "executed" || eventKind.endsWith(".completed")) {
|
|
1732
1948
|
return "success";
|
|
1733
1949
|
}
|
|
1734
1950
|
if (eventKind === "policy.changed" || eventKind === "dependency.added" || eventKind === "dependency.upgraded") {
|
|
@@ -1744,6 +1960,12 @@ function confidenceForSemanticEvent(context: DeltaOperationContext, eventKind: s
|
|
|
1744
1960
|
if (eventKind === "policy.changed" && !context.data.policy) {
|
|
1745
1961
|
return 0.78;
|
|
1746
1962
|
}
|
|
1963
|
+
if (context.kind.startsWith("agent.") || context.kind.startsWith("approval.")) {
|
|
1964
|
+
const capture = context.data.capture && typeof context.data.capture === "object"
|
|
1965
|
+
? context.data.capture as Record<string, unknown>
|
|
1966
|
+
: {};
|
|
1967
|
+
return typeof capture.confidence === "number" ? capture.confidence : 0.86;
|
|
1968
|
+
}
|
|
1747
1969
|
return 0.95;
|
|
1748
1970
|
}
|
|
1749
1971
|
|
|
@@ -1769,6 +1991,8 @@ function timelineEntitiesFromContext(
|
|
|
1769
1991
|
add("runtime-entry", entry, eventKind === "executed" || eventKind === "denied" || eventKind === "failed" ? "primary" : "affected", 0.95);
|
|
1770
1992
|
add("agent-tool", entry, "affected", 0.7);
|
|
1771
1993
|
}
|
|
1994
|
+
add("agent", agentNameFromContext(context), "source", 0.95);
|
|
1995
|
+
add("agent-tool", context.data.toolName, eventKind.startsWith("agent.tool") ? "primary" : "affected", 0.95);
|
|
1772
1996
|
for (const service of context.services) {
|
|
1773
1997
|
add("external-service", service, eventKind === "imported" ? "primary" : "source", 0.88);
|
|
1774
1998
|
}
|
|
@@ -1818,6 +2042,15 @@ function timelineEntitiesFromContext(
|
|
|
1818
2042
|
: [{ kind: "session", name: context.sessionId ?? context.id, role: "source", confidence: 0.5 }];
|
|
1819
2043
|
}
|
|
1820
2044
|
|
|
2045
|
+
function agentNameFromContext(context: DeltaOperationContext): string | undefined {
|
|
2046
|
+
const source = context.data.source;
|
|
2047
|
+
if (source && typeof source === "object" && !Array.isArray(source)) {
|
|
2048
|
+
const agent = (source as Record<string, unknown>).agent;
|
|
2049
|
+
return typeof agent === "string" && agent.length > 0 ? agent : undefined;
|
|
2050
|
+
}
|
|
2051
|
+
return undefined;
|
|
2052
|
+
}
|
|
2053
|
+
|
|
1821
2054
|
function parseTimelineEntityTarget(target: string | undefined): DeltaTimelineEntityRef | undefined {
|
|
1822
2055
|
if (!target) {
|
|
1823
2056
|
return undefined;
|
package/src/forge/version.ts
CHANGED