@webpresso/agent-kit 3.1.26 → 3.1.28
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/catalog/AGENTS.md.tpl +6 -10
- package/catalog/agent/commands/verify.md +2 -2
- package/catalog/agent/rules/changeset-release.md +4 -2
- package/catalog/agent/rules/workflow-skills-routing.md +6 -3
- package/catalog/agent/skills/autopilot/SKILL.md +48 -11
- package/catalog/agent/skills/claude/SKILL.md +7 -0
- package/catalog/agent/skills/codex/SKILL.md +7 -0
- package/catalog/agent/skills/fix/SKILL.md +33 -8
- package/catalog/agent/skills/grok/SKILL.md +7 -0
- package/catalog/agent/skills/investigate/SKILL.md +12 -1
- package/catalog/agent/skills/pll/SKILL.md +53 -48
- package/catalog/agent/skills/team/SKILL.md +26 -9
- package/catalog/agent/skills/ultragoal/SKILL.md +147 -19
- package/catalog/agent/skills/verify/SKILL.md +71 -51
- package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +8 -0
- package/dist/esm/audit/blueprint-lifecycle-sql.js +25 -1
- package/dist/esm/ci/native-session-memory-cache.d.ts +9 -1
- package/dist/esm/ci/native-session-memory-cache.js +9 -1
- package/dist/esm/ci/vitest-ci-shards.d.ts +6 -4
- package/dist/esm/ci/vitest-ci-shards.js +6 -4
- package/dist/esm/cli/auto-update/guard-tombstone.d.ts +25 -0
- package/dist/esm/cli/auto-update/guard-tombstone.js +67 -0
- package/dist/esm/cli/auto-update/installer.d.ts +4 -17
- package/dist/esm/cli/auto-update/installer.js +6 -57
- package/dist/esm/cli/auto-update/self-invocation.d.ts +37 -0
- package/dist/esm/cli/auto-update/self-invocation.js +62 -0
- package/dist/esm/cli/commands/audit.js +1 -0
- package/dist/esm/cli/commands/dash/index.js +3 -3
- package/dist/esm/cli/commands/dash/plan-once-attention.d.ts +32 -0
- package/dist/esm/cli/commands/dash/plan-once-attention.js +50 -0
- package/dist/esm/cli/commands/dash/plan-once-schema.d.ts +73 -0
- package/dist/esm/cli/commands/dash/plan-once-schema.js +119 -0
- package/dist/esm/cli/commands/dash/plan-once.d.ts +122 -0
- package/dist/esm/cli/commands/dash/plan-once.js +224 -0
- package/dist/esm/cli/commands/dash/tui/ipc-protocol.d.ts +87 -0
- package/dist/esm/cli/commands/dash/tui/ipc-protocol.js +128 -0
- package/dist/esm/cli/commands/dash/tui/native-host.d.ts +34 -0
- package/dist/esm/cli/commands/dash/tui/native-host.js +256 -0
- package/dist/esm/cli/commands/dash/tui/native-path.d.ts +11 -0
- package/dist/esm/cli/commands/dash/tui/native-path.js +41 -0
- package/dist/esm/cli/commands/dash/tui/runtime.js +72 -0
- package/dist/esm/cli/commands/init/scaffolders/agent-kit-global/index.js +1 -1
- package/dist/esm/cli/commands/package-manager.js +2 -1
- package/dist/esm/cli/commands/self-install-guard.d.ts +14 -32
- package/dist/esm/cli/commands/self-install-guard.js +17 -63
- package/dist/esm/hooks/guard-switch/index.js +8 -4
- package/dist/esm/hooks/post-tool/lint-after-edit.js +6 -4
- package/dist/esm/hooks/precompact/index.js +5 -3
- package/dist/esm/hooks/sessionstart/index.d.ts +10 -0
- package/dist/esm/hooks/sessionstart/index.js +61 -4
- package/dist/esm/hooks/shared/types.d.ts +11 -0
- package/dist/esm/hooks/shared/types.js +21 -0
- package/dist/esm/paths/state-root.js +6 -0
- package/dist/esm/session-memory/current-session.js +2 -0
- package/dist/esm/session-memory/native-runtime.js +5 -3
- package/dist/esm/session-memory/native-warm-markers.d.ts +18 -0
- package/dist/esm/session-memory/native-warm-markers.js +22 -0
- package/dist/esm/session-memory/sync/types.d.ts +4 -0
- package/dist/esm/session-memory/types.d.ts +3 -1
- package/dist/esm/session-memory/types.js +2 -0
- package/dist/esm/ultragoal/runtime.js +44 -2
- package/package.json +15 -12
|
@@ -5,11 +5,11 @@ import { tmpdir } from "node:os";
|
|
|
5
5
|
import { runHook } from "#hooks/shared/hook-bootstrap";
|
|
6
6
|
import { resolveHookProjectDir } from "#hooks/shared/project-dir.js";
|
|
7
7
|
import { createManagedHookExecutionContext, reportSessionMemoryHookDegradation, sessionMemoryHookStoreOptions, } from "#hooks/shared/session-memory-deadline.js";
|
|
8
|
-
import { getCommand, getContent, getFilePath, isBashInput, isFileEditInput, isFileReadInput, isFileWriteInput, } from "#hooks/shared/types";
|
|
8
|
+
import { getCommand, getContent, getFilePath, isBashInput, isFileEditInput, isFileReadInput, isFileWriteInput, resolveHookSessionId, } from "#hooks/shared/types";
|
|
9
9
|
import { isDirectEntrypoint } from "#hooks/shared/direct-entrypoint";
|
|
10
10
|
import { getSurfacePath, NotInGitRepoError } from "#paths/state-root.js";
|
|
11
11
|
import { buildContinuityEvent } from "#session-memory/hook-capture.js";
|
|
12
|
-
import { repoHashFromRoot } from "#session-memory/repo-hash.js";
|
|
12
|
+
import { computeRepoHash, repoHashFromRoot } from "#session-memory/repo-hash.js";
|
|
13
13
|
import { SessionMemorySessionStore, } from "#session-memory/session.js";
|
|
14
14
|
export const LINTABLE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".json", ".css"];
|
|
15
15
|
export const DEFAULT_MAX_CAPTURE_BYTES = 2048;
|
|
@@ -116,7 +116,8 @@ export function capturePostToolUse(input, projectDir, env = process.env, deps =
|
|
|
116
116
|
const store = deps.createStore?.(dbPath, deps.storeOptions) ??
|
|
117
117
|
new SessionMemorySessionStore(dbPath, deps.storeOptions);
|
|
118
118
|
try {
|
|
119
|
-
|
|
119
|
+
// Match readCurrentSessionId hashing (computeRepoHash), not path-only.
|
|
120
|
+
const repoHash = deps.repoHash?.(projectDir) ?? computeRepoHash(projectDir);
|
|
120
121
|
const event = buildContinuityEvent({
|
|
121
122
|
eventType,
|
|
122
123
|
toolName: input.tool_name ?? "PostToolUse",
|
|
@@ -131,10 +132,11 @@ export function capturePostToolUse(input, projectDir, env = process.env, deps =
|
|
|
131
132
|
},
|
|
132
133
|
maxContentBytes: DEFAULT_MAX_CAPTURE_BYTES,
|
|
133
134
|
});
|
|
135
|
+
const sessionId = resolveHookSessionId(input, env);
|
|
134
136
|
store.captureEvent({
|
|
135
137
|
repoHash,
|
|
136
138
|
agentId: input.tool_name ?? "default",
|
|
137
|
-
...(
|
|
139
|
+
...(sessionId === undefined ? {} : { sessionId }),
|
|
138
140
|
event: { ...event, ts: (deps.now?.() ?? new Date()).toISOString() },
|
|
139
141
|
});
|
|
140
142
|
return true;
|
|
@@ -6,9 +6,10 @@ import { isDirectEntrypoint } from "#hooks/shared/direct-entrypoint";
|
|
|
6
6
|
import { runHook } from "#hooks/shared/hook-bootstrap";
|
|
7
7
|
import { resolveHookProjectDir } from "#hooks/shared/project-dir.js";
|
|
8
8
|
import { createManagedHookExecutionContext, reportSessionMemoryHookDegradation, sessionMemoryHookStoreOptions, } from "#hooks/shared/session-memory-deadline.js";
|
|
9
|
+
import { resolveHookSessionId } from "#hooks/shared/types.js";
|
|
9
10
|
import { getSurfacePath, NotInGitRepoError } from "#paths/state-root.js";
|
|
10
11
|
import { buildContinuityEvent } from "#session-memory/hook-capture.js";
|
|
11
|
-
import { repoHashFromRoot } from "#session-memory/repo-hash.js";
|
|
12
|
+
import { computeRepoHash, repoHashFromRoot } from "#session-memory/repo-hash.js";
|
|
12
13
|
import { SessionMemorySessionStore, } from "#session-memory/session.js";
|
|
13
14
|
export const DEFAULT_MAX_SNAPSHOT_BYTES = 32 * 1024;
|
|
14
15
|
export const DEFAULT_MAX_EVENT_BYTES = 2 * 1024;
|
|
@@ -61,14 +62,15 @@ export function buildOutput(inputValue, cwd, env, deps = {}) {
|
|
|
61
62
|
try {
|
|
62
63
|
const input = normalizeInput(inputValue);
|
|
63
64
|
const projectDir = resolveHookProjectDir(input, cwd, env);
|
|
64
|
-
|
|
65
|
+
// Match readCurrentSessionId hashing (computeRepoHash), not path-only.
|
|
66
|
+
const repoHash = deps.repoHash?.(projectDir) ?? computeRepoHash(projectDir);
|
|
65
67
|
const dbPath = deps.dbPath ?? resolveSessionMemoryDbPath(projectDir, env);
|
|
66
68
|
mkdirSync(dirname(dbPath), { recursive: true });
|
|
67
69
|
const store = deps.createStore?.(dbPath, deps.storeOptions) ??
|
|
68
70
|
new SessionMemorySessionStore(dbPath, deps.storeOptions);
|
|
69
71
|
try {
|
|
70
72
|
const agentId = input.agent_id ?? input.agent_type ?? "default";
|
|
71
|
-
const sessionId = input
|
|
73
|
+
const sessionId = resolveHookSessionId(input, env);
|
|
72
74
|
const timestamp = (deps.now?.() ?? new Date()).toISOString();
|
|
73
75
|
const boundary = buildContinuityEvent({
|
|
74
76
|
eventType: "compaction_boundary",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { Database } from "#db/sqlite.js";
|
|
3
|
+
import { SessionMemorySessionStore } from "#session-memory/session.js";
|
|
3
4
|
export declare const MAX_BYTES: number;
|
|
4
5
|
export declare const TRUNCATION_NOTICE = "\n\n[truncated: file exceeded 200KB limit]";
|
|
5
6
|
export declare const RESUME_MAX_EVENT_BYTES: number;
|
|
@@ -10,10 +11,19 @@ type StartInput = Record<string, unknown>;
|
|
|
10
11
|
type EnvLike = Record<string, string | undefined>;
|
|
11
12
|
export interface SessionStartDeps {
|
|
12
13
|
readonly createDatabase?: (dbPath: string) => Pick<Database, "prepare" | "close">;
|
|
14
|
+
readonly createStore?: (dbPath: string) => Pick<SessionMemorySessionStore, "captureEvent" | "close">;
|
|
13
15
|
readonly dbPath?: string;
|
|
14
16
|
readonly repoHash?: (projectDir: string) => string;
|
|
17
|
+
readonly now?: () => Date;
|
|
18
|
+
readonly onStorageError?: (error: unknown) => void;
|
|
15
19
|
}
|
|
16
20
|
export declare function resolveSessionMemoryDbPath(projectDir: string, env: EnvLike): string;
|
|
21
|
+
/**
|
|
22
|
+
* Seed session-memory with a real host session id so `wp session-info` works
|
|
23
|
+
* under Grok (and similar hosts) before any Edit/Write tool capture. Fail-open:
|
|
24
|
+
* storage errors never break SessionStart stdout.
|
|
25
|
+
*/
|
|
26
|
+
export declare function seedSessionIdentityCapture(input: StartInput, projectDir: string, env: EnvLike, deps?: SessionStartDeps): void;
|
|
17
27
|
/**
|
|
18
28
|
* Pure function: given a parsed input payload, a working directory, and
|
|
19
29
|
* environment variables, produce the JSON string that the hook should write
|
|
@@ -18,20 +18,23 @@
|
|
|
18
18
|
* Always emits valid JSON; `additionalContext` is empty when there is no
|
|
19
19
|
* `.agent/routing.md`, continuity, or update banner to surface.
|
|
20
20
|
*/
|
|
21
|
-
import { readFileSync, statSync } from "node:fs";
|
|
21
|
+
import { mkdirSync, readFileSync, statSync } from "node:fs";
|
|
22
22
|
import { tmpdir } from "node:os";
|
|
23
23
|
import { performance } from "node:perf_hooks";
|
|
24
|
-
import { join } from "node:path";
|
|
24
|
+
import { dirname, join } from "node:path";
|
|
25
25
|
import { renderSessionStartInstructionContext } from "#hooks/shared/instruction-surfaces";
|
|
26
26
|
import { writeHookOutput } from "#hooks/shared/hook-bootstrap";
|
|
27
27
|
import { rememberHookStdin } from "#hooks/logs/store.js";
|
|
28
28
|
import { resolveHookProjectDir } from "#hooks/shared/project-dir.js";
|
|
29
|
+
import { resolveHookSessionId } from "#hooks/shared/types.js";
|
|
29
30
|
import { getSurfacePath, NotInGitRepoError } from "#paths/state-root.js";
|
|
30
31
|
import { WP_AGENT_LAUNCHED_VIA_WP_ENV, WP_AGENT_LAUNCHED_VIA_WP_VALUE, } from "#runtime/agent-launch-marker.js";
|
|
31
32
|
import { Database } from "#db/sqlite.js";
|
|
32
33
|
import { readUpdateBanner } from "./update-banner.js";
|
|
33
34
|
import { isDirectEntrypoint } from "#hooks/shared/direct-entrypoint";
|
|
34
|
-
import {
|
|
35
|
+
import { buildContinuityEvent } from "#session-memory/hook-capture.js";
|
|
36
|
+
import { computeRepoHash, repoHashFromRoot } from "#session-memory/repo-hash.js";
|
|
37
|
+
import { SessionMemorySessionStore } from "#session-memory/session.js";
|
|
35
38
|
export const MAX_BYTES = 200 * 1024;
|
|
36
39
|
export const TRUNCATION_NOTICE = "\n\n[truncated: file exceeded 200KB limit]";
|
|
37
40
|
export const RESUME_MAX_EVENT_BYTES = 2 * 1024;
|
|
@@ -223,7 +226,8 @@ function buildResumeContext(input, projectDir, env, deps) {
|
|
|
223
226
|
const rows = readRecentContinuityEvents({
|
|
224
227
|
db,
|
|
225
228
|
repoHash,
|
|
226
|
-
|
|
229
|
+
// Prefer stdin session id; fall back to GROK_SESSION_ID for Grok hooks.
|
|
230
|
+
sessionId: resolveHookSessionId(input, env),
|
|
227
231
|
minPriority: parsePositiveInt(env.WP_SESSIONSTART_RESUME_MIN_PRIORITY, RESUME_MIN_PRIORITY),
|
|
228
232
|
limit: parsePositiveInt(env.WP_SESSIONSTART_RESUME_MAX_EVENTS, 16),
|
|
229
233
|
});
|
|
@@ -267,6 +271,56 @@ function buildDirectLaunchWarning(input, env) {
|
|
|
267
271
|
"</wp_launch_warning>",
|
|
268
272
|
].join("\n");
|
|
269
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* Seed session-memory with a real host session id so `wp session-info` works
|
|
276
|
+
* under Grok (and similar hosts) before any Edit/Write tool capture. Fail-open:
|
|
277
|
+
* storage errors never break SessionStart stdout.
|
|
278
|
+
*/
|
|
279
|
+
export function seedSessionIdentityCapture(input, projectDir, env, deps = {}) {
|
|
280
|
+
const sessionId = resolveHookSessionId(input, env);
|
|
281
|
+
if (!sessionId)
|
|
282
|
+
return;
|
|
283
|
+
try {
|
|
284
|
+
const dbPath = deps.dbPath ?? resolveSessionMemoryDbPath(projectDir, env);
|
|
285
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
286
|
+
const store = deps.createStore?.(dbPath) ?? new SessionMemorySessionStore(dbPath);
|
|
287
|
+
try {
|
|
288
|
+
// Match `readCurrentSessionId` (computeRepoHash), not path-only hashing.
|
|
289
|
+
const repoHash = deps.repoHash?.(projectDir) ?? computeRepoHash(projectDir);
|
|
290
|
+
const event = buildContinuityEvent({
|
|
291
|
+
eventType: "session_identity",
|
|
292
|
+
toolName: "SessionStart",
|
|
293
|
+
content: `Session identity: ${sessionId}`,
|
|
294
|
+
summary: "Session identity for PR disclosure",
|
|
295
|
+
// Below RESUME_MIN_PRIORITY (50): kept for `wp session-info`, not resume inject.
|
|
296
|
+
priority: 40,
|
|
297
|
+
metadata: {
|
|
298
|
+
source: "sessionstart-hook",
|
|
299
|
+
hookEventName: "SessionStart",
|
|
300
|
+
sessionStartSource: sessionStartSource(input),
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
store.captureEvent({
|
|
304
|
+
repoHash,
|
|
305
|
+
agentId: "SessionStart",
|
|
306
|
+
sessionId,
|
|
307
|
+
event: {
|
|
308
|
+
...event,
|
|
309
|
+
ts: (deps.now?.() ?? new Date()).toISOString(),
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
finally {
|
|
314
|
+
store.close();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
deps.onStorageError?.(error);
|
|
319
|
+
if (env.WP_SESSIONSTART_DEBUG === "1") {
|
|
320
|
+
process.stderr.write(`wp-sessionstart-identity: ${error.message}\n`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
270
324
|
/**
|
|
271
325
|
* Pure function: given a parsed input payload, a working directory, and
|
|
272
326
|
* environment variables, produce the JSON string that the hook should write
|
|
@@ -277,6 +331,9 @@ function buildDirectLaunchWarning(input, env) {
|
|
|
277
331
|
*/
|
|
278
332
|
export function buildOutput(input, cwd, env, deps = {}) {
|
|
279
333
|
const projectDir = resolveHookProjectDir(input, cwd, env);
|
|
334
|
+
// Capture before resume read so this SessionStart can seed disclosure even
|
|
335
|
+
// when no prior events exist (Grok option-3 path).
|
|
336
|
+
seedSessionIdentityCapture(input, projectDir, env, deps);
|
|
280
337
|
const target = join(projectDir, ".agent", "routing.md");
|
|
281
338
|
let routingMd = null;
|
|
282
339
|
try {
|
|
@@ -29,6 +29,16 @@ export type UpdatedInputEnvelope = {
|
|
|
29
29
|
*/
|
|
30
30
|
export declare function normalizeHookToolInput(raw: Record<string, unknown>): ToolInput;
|
|
31
31
|
export declare function parseToolInput(json: string): ToolInput;
|
|
32
|
+
type EnvLike = Record<string, string | undefined>;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a real host session id for session-memory capture / PR disclosure.
|
|
35
|
+
* Prefer stdin session fields (snake_case Claude/Codex or camelCase Grok), then
|
|
36
|
+
* Grok hook env `GROK_SESSION_ID` (documented for every Grok hook process).
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveHookSessionId(input: {
|
|
39
|
+
readonly session_id?: unknown;
|
|
40
|
+
readonly sessionId?: unknown;
|
|
41
|
+
}, env?: EnvLike): string | undefined;
|
|
32
42
|
export declare function isBashInput(input: ToolInput): boolean;
|
|
33
43
|
export declare function isFileEditInput(input: ToolInput): boolean;
|
|
34
44
|
export declare function isFileWriteInput(input: ToolInput): boolean;
|
|
@@ -72,3 +82,4 @@ export type DenyEnvelope = ClaudeCodexDenyEnvelope | GrokDualDenyEnvelope;
|
|
|
72
82
|
export declare function buildDenyEnvelope(options: {
|
|
73
83
|
readonly reason: string;
|
|
74
84
|
}, env?: NodeJS.ProcessEnv): DenyEnvelope;
|
|
85
|
+
export {};
|
|
@@ -55,6 +55,27 @@ export function parseToolInput(json) {
|
|
|
55
55
|
}
|
|
56
56
|
return normalizeHookToolInput(parsed);
|
|
57
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve a real host session id for session-memory capture / PR disclosure.
|
|
60
|
+
* Prefer stdin session fields (snake_case Claude/Codex or camelCase Grok), then
|
|
61
|
+
* Grok hook env `GROK_SESSION_ID` (documented for every Grok hook process).
|
|
62
|
+
*/
|
|
63
|
+
export function resolveHookSessionId(input, env = process.env) {
|
|
64
|
+
const pick = (value) => {
|
|
65
|
+
if (typeof value !== "string")
|
|
66
|
+
return undefined;
|
|
67
|
+
const trimmed = value.trim();
|
|
68
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
69
|
+
};
|
|
70
|
+
// Prefer snake_case when both present (Claude/Codex contract).
|
|
71
|
+
const fromInput = pick(input.session_id) ?? pick(input.sessionId);
|
|
72
|
+
if (fromInput)
|
|
73
|
+
return fromInput;
|
|
74
|
+
const fromEnv = env.GROK_SESSION_ID?.trim();
|
|
75
|
+
if (fromEnv)
|
|
76
|
+
return fromEnv;
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
58
79
|
export function isBashInput(input) {
|
|
59
80
|
return "command" in (input.tool_input || {});
|
|
60
81
|
}
|
|
@@ -72,6 +72,12 @@ function sha256Hex(value) {
|
|
|
72
72
|
* Probe whether a directory can hold state files.
|
|
73
73
|
* Used so quality CLIs (wp audit/test/…) keep working in sandboxes that
|
|
74
74
|
* deny writes under Application Support (e.g. Codex outside-voice).
|
|
75
|
+
*
|
|
76
|
+
* Any probe failure means the root is not usable (permission, ENOSPC, bad
|
|
77
|
+
* path, …). That is intentionally broader than `createCliLogSink`, which only
|
|
78
|
+
* remaps EPERM/EACCES/EROFS so unexpected IO errors stay loud at the log layer.
|
|
79
|
+
* A failed preferred env-paths root falls back once and is memoized for the
|
|
80
|
+
* process; set `WP_STATE_ROOT` to pin an explicit location instead.
|
|
75
81
|
*/
|
|
76
82
|
function canWriteStateRoot(root) {
|
|
77
83
|
try {
|
|
@@ -23,6 +23,8 @@ const LIVE_SESSION_ENV_KEYS = [
|
|
|
23
23
|
"CLAUDE_SESSION_ID",
|
|
24
24
|
"CLAUDE_CODE_SESSION_ID",
|
|
25
25
|
"OPENCODE_SESSION_ID",
|
|
26
|
+
// Grok Build: hook processes always get this; tool children may in future builds.
|
|
27
|
+
"GROK_SESSION_ID",
|
|
26
28
|
"RUNTIME_SESSION_ID",
|
|
27
29
|
];
|
|
28
30
|
export function readLiveSessionIdFromEnv(env) {
|
|
@@ -9,6 +9,7 @@ import envPaths from "env-paths";
|
|
|
9
9
|
import lockfile from "proper-lockfile";
|
|
10
10
|
import { resolveAgentKitPackageRoot } from "#cli/commands/init/package-root.js";
|
|
11
11
|
import { SESSION_MEMORY_NATIVE_ADDON_FILENAME, resolveSessionMemoryNativeTarget, } from "./native-targets.js";
|
|
12
|
+
import { NATIVE_WARM_LOG_CORRUPT_REBUILD, NATIVE_WARM_LOG_HIT, NATIVE_WARM_LOG_REBUILD, } from "./native-warm-markers.js";
|
|
12
13
|
const requireFromHere = createRequire(import.meta.url);
|
|
13
14
|
const NATIVE_WORKSPACE_DIRNAME = join("native", "session-memory-engine");
|
|
14
15
|
const BUILD_PACKAGE = "session-memory-napi";
|
|
@@ -240,12 +241,12 @@ function ensureNativeModuleBuilt(options = {}) {
|
|
|
240
241
|
const nodePath = compiledNodePath();
|
|
241
242
|
const force = options.force === true;
|
|
242
243
|
if (!force && !shouldRebuildNativeSessionMemoryNode(nodePath, workspaceRoot)) {
|
|
243
|
-
console.log(`[native-session-memory]
|
|
244
|
+
console.log(`[native-session-memory] ${NATIVE_WARM_LOG_HIT}${nodePath} trust=${trustCachedNativeNode() ? "1" : "0"}`);
|
|
244
245
|
return nodePath;
|
|
245
246
|
}
|
|
246
247
|
return withNativeBuildLock(sessionMemoryNativeCacheRoot(), () => {
|
|
247
248
|
if (!force && !shouldRebuildNativeSessionMemoryNode(nodePath, workspaceRoot)) {
|
|
248
|
-
console.log(`[native-session-memory]
|
|
249
|
+
console.log(`[native-session-memory] ${NATIVE_WARM_LOG_HIT}${nodePath} trust=${trustCachedNativeNode() ? "1" : "0"}`);
|
|
249
250
|
return nodePath;
|
|
250
251
|
}
|
|
251
252
|
if (force && existsSync(nodePath)) {
|
|
@@ -256,7 +257,8 @@ function ensureNativeModuleBuilt(options = {}) {
|
|
|
256
257
|
// Best-effort: cargo rebuild overwrites via copyFileSync below.
|
|
257
258
|
}
|
|
258
259
|
}
|
|
259
|
-
|
|
260
|
+
const warmMarker = force ? NATIVE_WARM_LOG_CORRUPT_REBUILD : NATIVE_WARM_LOG_REBUILD;
|
|
261
|
+
console.log(`[native-session-memory] ${warmMarker}${nodePath} trust=${trustCachedNativeNode() ? "1" : "0"}`);
|
|
260
262
|
const targetDir = cargoTargetDir();
|
|
261
263
|
mkdirSync(targetDir, { recursive: true });
|
|
262
264
|
try {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grep-stable warm-path log markers for the session-memory native warm step.
|
|
3
|
+
*
|
|
4
|
+
* Emitted by `native-runtime` and classified by the Test job E1 summary greps
|
|
5
|
+
* in `.github/workflows/ci.agent-kit.yml`. YAML cannot import TS — contract
|
|
6
|
+
* tests in `src/ci/native-session-memory-cache.test.ts` pin that the workflow
|
|
7
|
+
* greps these exact substrings.
|
|
8
|
+
*
|
|
9
|
+
* Rename only with a coordinated workflow + contract-test update.
|
|
10
|
+
*/
|
|
11
|
+
/** Exact-hit warm log marker (`grep -q` target + runtime emit prefix). */
|
|
12
|
+
export declare const NATIVE_WARM_LOG_HIT = "warm=hit path=";
|
|
13
|
+
/** Source/mtime rebuild warm log marker. */
|
|
14
|
+
export declare const NATIVE_WARM_LOG_REBUILD = "warm=rebuild path=";
|
|
15
|
+
/** Forced corrupt-node rebuild warm log marker. */
|
|
16
|
+
export declare const NATIVE_WARM_LOG_CORRUPT_REBUILD = "warm=corrupt-rebuild path=";
|
|
17
|
+
/** All E1-classified warm markers (corrupt-rebuild → hit → rebuild order matches workflow). */
|
|
18
|
+
export declare const NATIVE_WARM_LOG_MARKERS: readonly ["warm=corrupt-rebuild path=", "warm=hit path=", "warm=rebuild path="];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grep-stable warm-path log markers for the session-memory native warm step.
|
|
3
|
+
*
|
|
4
|
+
* Emitted by `native-runtime` and classified by the Test job E1 summary greps
|
|
5
|
+
* in `.github/workflows/ci.agent-kit.yml`. YAML cannot import TS — contract
|
|
6
|
+
* tests in `src/ci/native-session-memory-cache.test.ts` pin that the workflow
|
|
7
|
+
* greps these exact substrings.
|
|
8
|
+
*
|
|
9
|
+
* Rename only with a coordinated workflow + contract-test update.
|
|
10
|
+
*/
|
|
11
|
+
/** Exact-hit warm log marker (`grep -q` target + runtime emit prefix). */
|
|
12
|
+
export const NATIVE_WARM_LOG_HIT = "warm=hit path=";
|
|
13
|
+
/** Source/mtime rebuild warm log marker. */
|
|
14
|
+
export const NATIVE_WARM_LOG_REBUILD = "warm=rebuild path=";
|
|
15
|
+
/** Forced corrupt-node rebuild warm log marker. */
|
|
16
|
+
export const NATIVE_WARM_LOG_CORRUPT_REBUILD = "warm=corrupt-rebuild path=";
|
|
17
|
+
/** All E1-classified warm markers (corrupt-rebuild → hit → rebuild order matches workflow). */
|
|
18
|
+
export const NATIVE_WARM_LOG_MARKERS = [
|
|
19
|
+
NATIVE_WARM_LOG_CORRUPT_REBUILD,
|
|
20
|
+
NATIVE_WARM_LOG_HIT,
|
|
21
|
+
NATIVE_WARM_LOG_REBUILD,
|
|
22
|
+
];
|
|
@@ -48,6 +48,7 @@ export declare const shareContinuityEventV1: z.ZodObject<{
|
|
|
48
48
|
helper_waiting: "helper_waiting";
|
|
49
49
|
rejected_approach: "rejected_approach";
|
|
50
50
|
rule_snapshot: "rule_snapshot";
|
|
51
|
+
session_identity: "session_identity";
|
|
51
52
|
tool_command: "tool_command";
|
|
52
53
|
tool_edit: "tool_edit";
|
|
53
54
|
tool_read: "tool_read";
|
|
@@ -81,6 +82,7 @@ export declare const shareAgentRunDeltaV1: z.ZodObject<{
|
|
|
81
82
|
helper_waiting: "helper_waiting";
|
|
82
83
|
rejected_approach: "rejected_approach";
|
|
83
84
|
rule_snapshot: "rule_snapshot";
|
|
85
|
+
session_identity: "session_identity";
|
|
84
86
|
tool_command: "tool_command";
|
|
85
87
|
tool_edit: "tool_edit";
|
|
86
88
|
tool_read: "tool_read";
|
|
@@ -119,6 +121,7 @@ export declare const localAgentRunDeltaEnvelopeV1: z.ZodObject<{
|
|
|
119
121
|
helper_waiting: "helper_waiting";
|
|
120
122
|
rejected_approach: "rejected_approach";
|
|
121
123
|
rule_snapshot: "rule_snapshot";
|
|
124
|
+
session_identity: "session_identity";
|
|
122
125
|
tool_command: "tool_command";
|
|
123
126
|
tool_edit: "tool_edit";
|
|
124
127
|
tool_read: "tool_read";
|
|
@@ -155,6 +158,7 @@ export declare const sessionShareEnvelopeV1: z.ZodObject<{
|
|
|
155
158
|
helper_waiting: "helper_waiting";
|
|
156
159
|
rejected_approach: "rejected_approach";
|
|
157
160
|
rule_snapshot: "rule_snapshot";
|
|
161
|
+
session_identity: "session_identity";
|
|
158
162
|
tool_command: "tool_command";
|
|
159
163
|
tool_edit: "tool_edit";
|
|
160
164
|
tool_read: "tool_read";
|
|
@@ -23,7 +23,9 @@ export interface SessionMemorySearchResult extends IndexedSessionMemoryChunk {
|
|
|
23
23
|
score: number;
|
|
24
24
|
tier: "porter" | "trigram" | "levenshtein";
|
|
25
25
|
}
|
|
26
|
-
export declare const SESSION_CONTINUITY_EVENT_TYPES: readonly ["user_prompt", "decision", "constraint", "tool_read", "tool_edit", "tool_command", "failure", "rejected_approach", "assistant_turn_summary", "compaction_boundary", "rule_snapshot",
|
|
26
|
+
export declare const SESSION_CONTINUITY_EVENT_TYPES: readonly ["user_prompt", "decision", "constraint", "tool_read", "tool_edit", "tool_command", "failure", "rejected_approach", "assistant_turn_summary", "compaction_boundary", "rule_snapshot",
|
|
27
|
+
/** SessionStart seed so `wp session-info` can resolve a real host session id. */
|
|
28
|
+
"session_identity", "helper_selected", "helper_started", "helper_waiting", "helper_completed", "helper_failed", "helper_returned"];
|
|
27
29
|
export type SessionContinuityEventType = (typeof SESSION_CONTINUITY_EVENT_TYPES)[number];
|
|
28
30
|
/**
|
|
29
31
|
* Optional dashboard identity carried in continuity-event metadata. It keeps
|
|
@@ -10,6 +10,8 @@ export const SESSION_CONTINUITY_EVENT_TYPES = [
|
|
|
10
10
|
"assistant_turn_summary",
|
|
11
11
|
"compaction_boundary",
|
|
12
12
|
"rule_snapshot",
|
|
13
|
+
/** SessionStart seed so `wp session-info` can resolve a real host session id. */
|
|
14
|
+
"session_identity",
|
|
13
15
|
"helper_selected",
|
|
14
16
|
"helper_started",
|
|
15
17
|
"helper_waiting",
|
|
@@ -2,8 +2,9 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { runQaCommand } from "#cli/commands/qa.js";
|
|
5
|
-
import { validateTrackedReviewProvenance } from "#lifecycle/review-provenance.js";
|
|
5
|
+
import { collectV2ReviewProvenance, validateTrackedReviewProvenance, } from "#lifecycle/review-provenance.js";
|
|
6
6
|
import { evaluateRequiredChecks } from "#mcp/tools/_shared/required-checks.js";
|
|
7
|
+
import { createDeliverySubjectAtRef, createPlanSubjectAtRef } from "#review/subject.js";
|
|
7
8
|
import { scanBlueprintDirectory } from "#service/scanner.js";
|
|
8
9
|
import { resolveBlueprintRoot } from "#utils/blueprint-root.js";
|
|
9
10
|
import matter from "gray-matter";
|
|
@@ -105,6 +106,11 @@ async function collectPrProbe(cwd) {
|
|
|
105
106
|
function hasRequiredGreenChecks(checks) {
|
|
106
107
|
return evaluateRequiredChecks(checks).green;
|
|
107
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Validation needs two distinct reviewers bound to the current ultragoal source
|
|
111
|
+
* snapshot. Prefer legacy frontmatter+reviews.md; fall back to current v2 plan +
|
|
112
|
+
* delivery authorities (distinct lanes) when their subjects still match HEAD.
|
|
113
|
+
*/
|
|
108
114
|
function collectValidationEvidence(cwd, blueprintSlugs, sourceSnapshot) {
|
|
109
115
|
const entries = scanBlueprintDirectory({
|
|
110
116
|
baseDir: resolveBlueprintRoot(cwd),
|
|
@@ -115,7 +121,43 @@ function collectValidationEvidence(cwd, blueprintSlugs, sourceSnapshot) {
|
|
|
115
121
|
if (!entry)
|
|
116
122
|
return undefined;
|
|
117
123
|
const approvals = matter(readFileSync(entry.path, "utf8")).data.approvals;
|
|
118
|
-
|
|
124
|
+
const legacy = validateTrackedReviewProvenance(entry.path, approvals, { sourceSnapshot });
|
|
125
|
+
if (legacy.valid)
|
|
126
|
+
return legacy;
|
|
127
|
+
const stableSlug = slug.includes("/") ? (slug.split("/").pop() ?? slug) : slug;
|
|
128
|
+
let deliveryDigest;
|
|
129
|
+
let planDigest;
|
|
130
|
+
try {
|
|
131
|
+
deliveryDigest = createDeliverySubjectAtRef(cwd, "HEAD", stableSlug).digest;
|
|
132
|
+
planDigest = createPlanSubjectAtRef(cwd, "HEAD", stableSlug).digest;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
const bind = (records) => records.map((record) => ({
|
|
138
|
+
reviewer: record.reviewer,
|
|
139
|
+
artifact: record.artifact,
|
|
140
|
+
sourceSnapshot,
|
|
141
|
+
targetHash: record.targetHash,
|
|
142
|
+
}));
|
|
143
|
+
const delivery = bind(collectV2ReviewProvenance(entry.path, "delivery", "HEAD").filter((record) => record.targetHash === deliveryDigest));
|
|
144
|
+
const plan = bind(collectV2ReviewProvenance(entry.path, "plan", "HEAD").filter((record) => record.targetHash === planDigest));
|
|
145
|
+
// Prefer delivery as code-review lane; plan as verify/architecture lane.
|
|
146
|
+
const byReviewer = new Map();
|
|
147
|
+
for (const record of [...plan, ...delivery]) {
|
|
148
|
+
byReviewer.set(record.reviewer, record);
|
|
149
|
+
}
|
|
150
|
+
const v2Records = [...byReviewer.values()];
|
|
151
|
+
const distinctReviewers = [...new Set(v2Records.map((record) => record.reviewer))];
|
|
152
|
+
const distinctArtifacts = [...new Set(v2Records.map((record) => record.artifact))];
|
|
153
|
+
return {
|
|
154
|
+
distinctArtifacts,
|
|
155
|
+
distinctReviewers,
|
|
156
|
+
records: v2Records,
|
|
157
|
+
valid: v2Records.length >= 2 &&
|
|
158
|
+
distinctReviewers.length === v2Records.length &&
|
|
159
|
+
distinctArtifacts.length === v2Records.length,
|
|
160
|
+
};
|
|
119
161
|
});
|
|
120
162
|
if (evaluations.some((evaluation) => evaluation?.valid !== true))
|
|
121
163
|
return undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpresso/agent-kit",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.28",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "TypeScript-first agent harness for guarded develop/deploy workflows: wp CLI gates, MCP tools, hooks, memory, worktrees, secrets, audits, and evidence checks.",
|
|
6
6
|
"keywords": [
|
|
@@ -399,6 +399,9 @@
|
|
|
399
399
|
"prepare": "husky",
|
|
400
400
|
"mutation": "./bin/wp test --mutation",
|
|
401
401
|
"e2e": "./bin/wp e2e --config playwright.config.ts",
|
|
402
|
+
"native:dash-tui:build": "cargo build --manifest-path native/dash-tui/Cargo.toml --release",
|
|
403
|
+
"native:dash-tui:test": "cargo test --manifest-path native/dash-tui/Cargo.toml",
|
|
404
|
+
"native:dash-tui:smoke": "cargo run --manifest-path native/dash-tui/Cargo.toml --release -- --smoke",
|
|
402
405
|
"native:session-memory:build": "cargo build --manifest-path native/session-memory-engine/Cargo.toml --package session-memory-napi --release --locked",
|
|
403
406
|
"native:session-memory:fmt": "cargo fmt --manifest-path native/session-memory-engine/Cargo.toml --all -- --check",
|
|
404
407
|
"native:session-memory:clippy": "cargo clippy --manifest-path native/session-memory-engine/Cargo.toml --all-targets --all-features -- -D warnings",
|
|
@@ -499,16 +502,16 @@
|
|
|
499
502
|
"setupWpActionRef": "c2c71a7a4be446fc6858e6b57bf55a11ccfa2d88"
|
|
500
503
|
},
|
|
501
504
|
"optionalDependencies": {
|
|
502
|
-
"@webpresso/agent-kit-runtime-darwin-arm64": "3.1.
|
|
503
|
-
"@webpresso/agent-kit-runtime-darwin-x64": "3.1.
|
|
504
|
-
"@webpresso/agent-kit-runtime-linux-x64": "3.1.
|
|
505
|
-
"@webpresso/agent-kit-runtime-linux-arm64": "3.1.
|
|
506
|
-
"@webpresso/agent-kit-runtime-windows-x64": "3.1.
|
|
507
|
-
"@webpresso/agent-kit-session-memory-darwin-x64": "3.1.
|
|
508
|
-
"@webpresso/agent-kit-session-memory-darwin-arm64": "3.1.
|
|
509
|
-
"@webpresso/agent-kit-session-memory-linux-x64": "3.1.
|
|
510
|
-
"@webpresso/agent-kit-session-memory-linux-arm64": "3.1.
|
|
511
|
-
"@webpresso/agent-kit-session-memory-win32-x64": "3.1.
|
|
512
|
-
"@webpresso/agent-kit-session-memory-win32-arm64": "3.1.
|
|
505
|
+
"@webpresso/agent-kit-runtime-darwin-arm64": "3.1.28",
|
|
506
|
+
"@webpresso/agent-kit-runtime-darwin-x64": "3.1.28",
|
|
507
|
+
"@webpresso/agent-kit-runtime-linux-x64": "3.1.28",
|
|
508
|
+
"@webpresso/agent-kit-runtime-linux-arm64": "3.1.28",
|
|
509
|
+
"@webpresso/agent-kit-runtime-windows-x64": "3.1.28",
|
|
510
|
+
"@webpresso/agent-kit-session-memory-darwin-x64": "3.1.28",
|
|
511
|
+
"@webpresso/agent-kit-session-memory-darwin-arm64": "3.1.28",
|
|
512
|
+
"@webpresso/agent-kit-session-memory-linux-x64": "3.1.28",
|
|
513
|
+
"@webpresso/agent-kit-session-memory-linux-arm64": "3.1.28",
|
|
514
|
+
"@webpresso/agent-kit-session-memory-win32-x64": "3.1.28",
|
|
515
|
+
"@webpresso/agent-kit-session-memory-win32-arm64": "3.1.28"
|
|
513
516
|
}
|
|
514
517
|
}
|