kiokuko-dsh 0.2.27 → 0.2.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.
Files changed (66) hide show
  1. package/dist/dsh/agenticreplay-host.d.ts.map +1 -1
  2. package/dist/dsh/agenticreplay-host.js +5 -1
  3. package/dist/dsh/agenticreplay-host.js.map +1 -1
  4. package/dist/dsh/agenticreplay-libraries.d.ts +1 -0
  5. package/dist/dsh/agenticreplay-libraries.d.ts.map +1 -1
  6. package/dist/dsh/agenticreplay-libraries.js.map +1 -1
  7. package/dist/dsh/agenticreplay-recorder.d.ts.map +1 -1
  8. package/dist/dsh/agenticreplay-recorder.js +22 -10
  9. package/dist/dsh/agenticreplay-recorder.js.map +1 -1
  10. package/dist/dsh/agenticreplay-security.d.ts.map +1 -1
  11. package/dist/dsh/agenticreplay-security.js +40 -6
  12. package/dist/dsh/agenticreplay-security.js.map +1 -1
  13. package/dist/dsh/agenticreplay-types.d.ts +3 -0
  14. package/dist/dsh/agenticreplay-types.d.ts.map +1 -1
  15. package/dist/dsh/agenticreplay-types.js.map +1 -1
  16. package/dist/dsh/coding-workflow/host.d.ts +1 -0
  17. package/dist/dsh/coding-workflow/host.d.ts.map +1 -1
  18. package/dist/dsh/coding-workflow/host.js +10 -0
  19. package/dist/dsh/coding-workflow/host.js.map +1 -1
  20. package/dist/dsh/coding-workflow/service.d.ts +6 -2
  21. package/dist/dsh/coding-workflow/service.d.ts.map +1 -1
  22. package/dist/dsh/coding-workflow/service.js +6 -5
  23. package/dist/dsh/coding-workflow/service.js.map +1 -1
  24. package/dist/dsh/core/host.d.ts.map +1 -1
  25. package/dist/dsh/core/host.js +10 -1
  26. package/dist/dsh/core/host.js.map +1 -1
  27. package/dist/dsh/execution-support.d.ts.map +1 -1
  28. package/dist/dsh/execution-support.js +2 -0
  29. package/dist/dsh/execution-support.js.map +1 -1
  30. package/dist/dsh/lifecycle-memory.d.ts +1 -0
  31. package/dist/dsh/lifecycle-memory.d.ts.map +1 -1
  32. package/dist/dsh/lifecycle-memory.js +7 -0
  33. package/dist/dsh/lifecycle-memory.js.map +1 -1
  34. package/dist/dsh/memory-application.d.ts +9 -9
  35. package/dist/dsh/memory-application.d.ts.map +1 -1
  36. package/dist/dsh/memory-application.js +448 -147
  37. package/dist/dsh/memory-application.js.map +1 -1
  38. package/dist/dsh/on-demand-intake.d.ts +13 -0
  39. package/dist/dsh/on-demand-intake.d.ts.map +1 -1
  40. package/dist/dsh/on-demand-intake.js +30 -7
  41. package/dist/dsh/on-demand-intake.js.map +1 -1
  42. package/dist/dsh/repository-learning-reflector.d.ts +58 -0
  43. package/dist/dsh/repository-learning-reflector.d.ts.map +1 -0
  44. package/dist/dsh/repository-learning-reflector.js +230 -0
  45. package/dist/dsh/repository-learning-reflector.js.map +1 -0
  46. package/dist/dsh/repository-learning.d.ts +34 -0
  47. package/dist/dsh/repository-learning.d.ts.map +1 -0
  48. package/dist/dsh/repository-learning.js +512 -0
  49. package/dist/dsh/repository-learning.js.map +1 -0
  50. package/dist/locale/en.json +1 -1
  51. package/dist/locale/ja.json +1 -1
  52. package/dist/locale/ko.json +1 -1
  53. package/dist/locale/zh-CN.json +1 -1
  54. package/dist/memory/forget.d.ts +2 -2
  55. package/dist/memory/forget.d.ts.map +1 -1
  56. package/dist/memory/forget.js +175 -74
  57. package/dist/memory/forget.js.map +1 -1
  58. package/dist/memory/repository-learning.d.ts +106 -0
  59. package/dist/memory/repository-learning.d.ts.map +1 -0
  60. package/dist/memory/repository-learning.js +348 -0
  61. package/dist/memory/repository-learning.js.map +1 -0
  62. package/docs/agenticreplay-recording.md +20 -2
  63. package/docs/on-demand-intake.md +8 -2
  64. package/docs/repository-learning.md +109 -0
  65. package/migrations/048_repository_learning.sql +65 -0
  66. package/package.json +5 -1
@@ -1,62 +1,123 @@
1
- import { forgetMemory } from '../memory/forget.js';
2
- import { explainMemory, renderMemoryExplanation } from '../memory/explain.js';
3
- import { z } from 'zod';
4
- import { realpathSync } from 'node:fs';
5
- import { resolve } from 'node:path';
6
- import { beginMemoryExecution, completeMemoryExecution, memoryApplicationReviewSchema, memoryApplicationStatus } from '../memory/application.js';
7
- import { autoGlobalizationStatus } from '../memory/auto-globalization.js';
8
- import { MemoryTimeConstraint } from '../memory/retrieval-contracts.js';
9
- import { isOwnedExecutionCall } from './owned-execution.js';
10
- import { authorizeTaskLease } from './task-state.js';
11
- import { captureExecutionTaskLease } from './task-authority-context.js';
12
- import { withImmediateTransaction } from '../db/transaction.js';
13
- import { correctionDecisionSchema, checkCorrectionDecision, literalVersionGate, recordCorrectionObservation } from './correction-decision.js';
14
- import { canonicalContentHash } from '../serialization/validate.js';
15
- import { KiokukoError } from '../errors.js';
16
- const inputSchema = z.discriminatedUnion('action', [
17
- z.object({ action: z.literal('status') }).strict(),
18
- z.object({ action: z.literal('review'), review: memoryApplicationReviewSchema }).strict(),
19
- z.object({ action: z.literal('review_batch'), reviews: z.array(memoryApplicationReviewSchema).min(1).max(32) }).strict(),
20
- z.object({ action: z.literal('refresh'), query: z.string().trim().min(1).max(4000), timeConstraint: MemoryTimeConstraint.optional() }).strict(),
1
+ import { detectRepositoryRoot } from "../repository/detect-root.js";
2
+ import { readRepositoryLearning, resetRepositoryLearning, } from "../memory/repository-learning.js";
3
+ import { forgetMemory } from "../memory/forget.js";
4
+ import { explainMemory, renderMemoryExplanation } from "../memory/explain.js";
5
+ import { z } from "zod";
6
+ import { realpathSync } from "node:fs";
7
+ import { resolve } from "node:path";
8
+ import { beginMemoryExecution, completeMemoryExecution, memoryApplicationReviewSchema, memoryApplicationStatus, } from "../memory/application.js";
9
+ import { autoGlobalizationStatus } from "../memory/auto-globalization.js";
10
+ import { MemoryTimeConstraint } from "../memory/retrieval-contracts.js";
11
+ import { isOwnedExecutionCall } from "./owned-execution.js";
12
+ import { authorizeTaskLease, } from "./task-state.js";
13
+ import { captureExecutionTaskLease } from "./task-authority-context.js";
14
+ import { withImmediateTransaction } from "../db/transaction.js";
15
+ import { correctionDecisionSchema, checkCorrectionDecision, literalVersionGate, recordCorrectionObservation, } from "./correction-decision.js";
16
+ import { canonicalContentHash } from "../serialization/validate.js";
17
+ import { KiokukoError } from "../errors.js";
18
+ const inputSchema = z.discriminatedUnion("action", [
19
+ z.object({ action: z.literal("status") }).strict(),
20
+ z
21
+ .object({
22
+ action: z.literal("review"),
23
+ review: memoryApplicationReviewSchema,
24
+ })
25
+ .strict(),
26
+ z
27
+ .object({
28
+ action: z.literal("review_batch"),
29
+ reviews: z.array(memoryApplicationReviewSchema).min(1).max(32),
30
+ })
31
+ .strict(),
32
+ z
33
+ .object({
34
+ action: z.literal("refresh"),
35
+ query: z.string().trim().min(1).max(4000),
36
+ timeConstraint: MemoryTimeConstraint.optional(),
37
+ })
38
+ .strict(),
21
39
  ]);
22
40
  // Model providers require an object at the root of every tool schema. Keep
23
41
  // action-specific validation in inputSchema after the native tool call arrives.
24
- const transportSchema = z.object({
25
- action: z.enum(['status', 'review', 'review_batch', 'refresh']),
42
+ const transportSchema = z
43
+ .object({
44
+ action: z.enum(["status", "review", "review_batch", "refresh"]),
26
45
  review: memoryApplicationReviewSchema.optional(),
27
46
  reviews: z.array(memoryApplicationReviewSchema).min(1).max(32).optional(),
28
47
  query: z.string().trim().min(1).max(4000).optional(),
29
48
  timeConstraint: MemoryTimeConstraint.optional(),
30
- }).strict();
31
- export const MEMORY_APPLICATION_GUIDANCE = 'Memory references and past application status are optional advisory data. Missing, stale or failed memory evidence never blocks tools or task completion. Native permissions, explicit Stop and actual task verification remain authoritative. correction_check checks compiler compatibility and completion judgments against host-delivered corrections and actual verification; self-reported use is not proof. A supported literal conflicting version-only write asks a scoped native question. New memory saving happens only after task completion, permission to organize, and approval of the exact shown revision.';
49
+ })
50
+ .strict();
51
+ export const MEMORY_APPLICATION_GUIDANCE = "Memory references and past application status are optional advisory data. Missing, stale or failed memory evidence never blocks tools or task completion. Native permissions, explicit Stop and actual task verification remain authoritative. correction_check checks compiler compatibility and completion judgments against host-delivered corrections and actual verification; self-reported use is not proof. A supported literal conflicting version-only write asks a scoped native question. New memory saving happens only after task completion, permission to organize, and approval of the exact shown revision.";
32
52
  // Exact native read tools only; never classify arbitrary shell strings as read-only.
33
- const READ_TOOLS = new Set(['Read', 'Glob', 'Grep', 'LS', 'Skill', 'read', 'read_file', 'glob', 'grep', 'skill', 'observation_read', 'memory_explain', 'lisp_status', 'lisp_hot_status']);
34
- const CONTROL_TOOLS = new Set(['correction_check', 'task_memory_review', 'task_completion', 'memory_checkpoint', 'curator_check', 'enno_finish', 'enno_work_report', 'enno_plan_review', 'enno_plan_submit', 'enno_ideal_submit', 'enno_meditation_submit']);
53
+ const READ_TOOLS = new Set([
54
+ "Read",
55
+ "Glob",
56
+ "Grep",
57
+ "LS",
58
+ "Skill",
59
+ "read",
60
+ "read_file",
61
+ "glob",
62
+ "grep",
63
+ "skill",
64
+ "observation_read",
65
+ "memory_explain",
66
+ "lisp_status",
67
+ "lisp_hot_status",
68
+ ]);
69
+ const CONTROL_TOOLS = new Set([
70
+ "correction_check",
71
+ "task_memory_review",
72
+ "task_completion",
73
+ "memory_checkpoint",
74
+ "curator_check",
75
+ "enno_finish",
76
+ "enno_work_report",
77
+ "enno_plan_review",
78
+ "enno_plan_submit",
79
+ "enno_ideal_submit",
80
+ "enno_meditation_submit",
81
+ ]);
35
82
  /** Only an exact foreground native Bash invocation at the bound repository root is proof-eligible. */
36
83
  export function foregroundNativeCommand(execution, repositoryRoot) {
37
84
  const args = execution.arguments;
38
- if (execution.parent !== undefined || !['Bash', 'bash'].includes(execution.name)
39
- || typeof args?.command !== 'string' || args.background === true || args.run_in_background === true)
85
+ if (execution.parent !== undefined ||
86
+ !["Bash", "bash"].includes(execution.name) ||
87
+ typeof args?.command !== "string" ||
88
+ args.background === true ||
89
+ args.run_in_background === true)
40
90
  return null;
41
91
  try {
42
- const directories = ['cwd', 'workdir', 'workingDirectory', 'working_directory']
43
- .filter(key => args[key] !== undefined).map(key => args[key]);
44
- return directories.every(directory => typeof directory === 'string'
45
- && realpathSync(resolve(repositoryRoot, directory)) === repositoryRoot) ? args.command : null;
92
+ const directories = [
93
+ "cwd",
94
+ "workdir",
95
+ "workingDirectory",
96
+ "working_directory",
97
+ ]
98
+ .filter((key) => args[key] !== undefined)
99
+ .map((key) => args[key]);
100
+ return directories.every((directory) => typeof directory === "string" &&
101
+ realpathSync(resolve(repositoryRoot, directory)) === repositoryRoot)
102
+ ? args.command
103
+ : null;
46
104
  }
47
105
  catch {
48
106
  return null;
49
107
  }
50
108
  }
51
109
  function isPtcSubcall(execution) {
52
- return execution.parent !== undefined && typeof execution.rootCallId === 'string'
53
- && execution.callId.startsWith(`${execution.rootCallId}:ptc:`)
54
- && /^[1-9]\d*$/u.test(execution.callId.slice(execution.rootCallId.length + 5));
110
+ return (execution.parent !== undefined &&
111
+ typeof execution.rootCallId === "string" &&
112
+ execution.callId.startsWith(`${execution.rootCallId}:ptc:`) &&
113
+ /^[1-9]\d*$/u.test(execution.callId.slice(execution.rootCallId.length + 5)));
55
114
  }
56
115
  /** Only saved-result paging is a read; ref inspection can run a live worker. */
57
116
  export function isSavedLispResultRead(execution) {
58
- return execution.name === 'lisp_inspect' && execution.parent === undefined
59
- && typeof execution.arguments?.resultOperationId === 'string' && execution.arguments.ref === undefined;
117
+ return (execution.name === "lisp_inspect" &&
118
+ execution.parent === undefined &&
119
+ typeof execution.arguments?.resultOperationId === "string" &&
120
+ execution.arguments.ref === undefined);
60
121
  }
61
122
  /** Mount on the actual DSH pre-execute/result path; it never grants native permission. */
62
123
  export function mountMemoryApplication(ctx, host) {
@@ -66,227 +127,467 @@ export function mountMemoryApplication(ctx, host) {
66
127
  const checkDecision = async (execution, decision) => {
67
128
  const identity = host.resolve(execution);
68
129
  if (!identity)
69
- throw new KiokukoError('CONFLICT', 'No exact native task for correction check');
130
+ throw new KiokukoError("CONFLICT", "No exact native task for correction check");
70
131
  const receipt = identity.corrections;
71
- if (receipt && (receipt.runId !== identity.runId || receipt.workspace !== identity.workspace || receipt.repositoryRoot !== realpathSync(identity.repositoryRoot)))
72
- throw new KiokukoError('CONFLICT', 'Correction receipt belongs to another native task');
73
- const operationDigest = canonicalContentHash({ name: execution.name, arguments: execution.arguments });
132
+ if (receipt &&
133
+ (receipt.runId !== identity.runId ||
134
+ receipt.workspace !== identity.workspace ||
135
+ receipt.repositoryRoot !== realpathSync(identity.repositoryRoot)))
136
+ throw new KiokukoError("CONFLICT", "Correction receipt belongs to another native task");
137
+ const operationDigest = canonicalContentHash({
138
+ name: execution.name,
139
+ arguments: execution.arguments,
140
+ });
74
141
  let verdict;
75
142
  try {
76
- verdict = await host.runtime.withDatabase(db => checkCorrectionDecision(db, receipt, decision));
143
+ verdict = await host.runtime.withDatabase((db) => checkCorrectionDecision(db, receipt, decision));
77
144
  }
78
145
  catch (error) {
79
146
  execution.signal.throwIfAborted();
80
- if (error instanceof KiokukoError && ['SECURITY_REJECTION', 'CONFLICT', 'VALIDATION_ERROR', 'INTEGRITY_ERROR'].includes(error.code))
147
+ if (error instanceof KiokukoError &&
148
+ [
149
+ "SECURITY_REJECTION",
150
+ "CONFLICT",
151
+ "VALIDATION_ERROR",
152
+ "INTEGRITY_ERROR",
153
+ ].includes(error.code))
81
154
  throw error;
82
- return { state: 'unavailable', reason: 'correction_observer_unavailable', retrieval: receipt?.retrieval ?? 'not_requested', delivery: receipt?.delivery ?? 'not_delivered', verification: 'unverified', allowed: true, authorizationGranted: false, recorded: false };
155
+ return {
156
+ state: "unavailable",
157
+ reason: "correction_observer_unavailable",
158
+ retrieval: receipt?.retrieval ?? "not_requested",
159
+ delivery: receipt?.delivery ?? "not_delivered",
160
+ verification: "unverified",
161
+ allowed: true,
162
+ authorizationGranted: false,
163
+ recorded: false,
164
+ };
83
165
  }
84
- const knownGate = decision.kind === 'compatibility' && decision.basis === 'version_only' && receipt?.sources.some(source => source.rule === 'capability_compatibility');
85
- const conflict = verdict.state === 'contradiction' || verdict.state === 'handoff_missing' && knownGate;
86
- let confirmation = 'not_needed';
166
+ const knownGate = decision.kind === "compatibility" &&
167
+ decision.basis === "version_only" &&
168
+ receipt?.sources.some((source) => source.rule === "capability_compatibility");
169
+ const conflict = verdict.state === "contradiction" ||
170
+ (verdict.state === "handoff_missing" && knownGate);
171
+ let confirmation = "not_needed";
87
172
  if (conflict) {
88
- const key = canonicalContentHash({ runId: identity.runId, request: receipt?.requestDigest, sources: receipt?.sources, decision });
173
+ const key = canonicalContentHash({
174
+ runId: identity.runId,
175
+ request: receipt?.requestDigest,
176
+ sources: receipt?.sources,
177
+ decision,
178
+ });
89
179
  const previous = answered.get(key);
90
- confirmation = previous ?? 'unavailable';
180
+ confirmation = previous ?? "unavailable";
91
181
  if (!previous && host.questions && execution.agent?.id) {
92
- const result = await host.questions.ask({ agent: execution.agent, signal: execution.signal, questions: [{ id: `correction-${key.slice(0, 24)}`, header: '訂正との矛盾',
93
- question: verdict.reason === 'verified_work_marked_incomplete_for_version'
94
- ? '対象の試験は成功しています。版数だけを理由に未完了とする判断を見直しますか?'
95
- : 'この操作は、能力で互換性を確認するという訂正と矛盾する完全一致チェックを含みます。どう扱いますか?',
182
+ const result = await host.questions.ask({
183
+ agent: execution.agent,
184
+ signal: execution.signal,
185
+ questions: [
186
+ {
187
+ id: `correction-${key.slice(0, 24)}`,
188
+ header: "訂正との矛盾",
189
+ question: verdict.reason === "verified_work_marked_incomplete_for_version"
190
+ ? "対象の試験は成功しています。版数だけを理由に未完了とする判断を見直しますか?"
191
+ : "この操作は、能力で互換性を確認するという訂正と矛盾する完全一致チェックを含みます。どう扱いますか?",
96
192
  detail: `対象: ${decision.target}`,
97
- options: [{ label: '見直す' }, { label: 'この操作だけ許可' }, { label: 'この操作を中止' }] }] });
193
+ options: [
194
+ { label: "見直す" },
195
+ { label: "この操作だけ許可" },
196
+ { label: "この操作を中止" },
197
+ ],
198
+ },
199
+ ],
200
+ });
98
201
  execution.signal.throwIfAborted();
99
202
  const current = host.resolve(execution);
100
- if (current?.runId !== identity.runId || canonicalContentHash(current.corrections ?? null) !== canonicalContentHash(receipt ?? null))
101
- throw new KiokukoError('CONFLICT', 'Correction request changed during confirmation');
102
- if (canonicalContentHash({ name: execution.name, arguments: execution.arguments }) !== operationDigest)
103
- throw new KiokukoError('CONFLICT', 'Correction operation changed during confirmation');
104
- const fresh = await host.runtime.withDatabase(db => checkCorrectionDecision(db, receipt, decision));
105
- if (fresh.state === 'stale')
106
- throw new KiokukoError('CONFLICT', 'Correction source changed during confirmation');
107
- if (fresh.targetDigest !== verdict.targetDigest || fresh.state !== verdict.state || fresh.verification !== verdict.verification)
108
- throw new KiokukoError('CONFLICT', 'Correction target or verification changed during confirmation');
109
- const answer = result.answers.find(answer => answer.id === `correction-${key.slice(0, 24)}`)?.selected[0];
110
- confirmation = answer === 'この操作だけ許可' ? 'approve' : answer === '見直す' ? 'revise' : 'cancel';
111
- if (confirmation !== 'approve') {
203
+ if (current?.runId !== identity.runId ||
204
+ canonicalContentHash(current.corrections ?? null) !==
205
+ canonicalContentHash(receipt ?? null))
206
+ throw new KiokukoError("CONFLICT", "Correction request changed during confirmation");
207
+ if (canonicalContentHash({
208
+ name: execution.name,
209
+ arguments: execution.arguments,
210
+ }) !== operationDigest)
211
+ throw new KiokukoError("CONFLICT", "Correction operation changed during confirmation");
212
+ const fresh = await host.runtime.withDatabase((db) => checkCorrectionDecision(db, receipt, decision));
213
+ if (fresh.state === "stale")
214
+ throw new KiokukoError("CONFLICT", "Correction source changed during confirmation");
215
+ if (fresh.targetDigest !== verdict.targetDigest ||
216
+ fresh.state !== verdict.state ||
217
+ fresh.verification !== verdict.verification)
218
+ throw new KiokukoError("CONFLICT", "Correction target or verification changed during confirmation");
219
+ const answer = result.answers.find((answer) => answer.id === `correction-${key.slice(0, 24)}`)?.selected[0];
220
+ confirmation =
221
+ answer === "この操作だけ許可"
222
+ ? "approve"
223
+ : answer === "見直す"
224
+ ? "revise"
225
+ : "cancel";
226
+ if (confirmation !== "approve") {
112
227
  if (answered.size >= 128)
113
228
  answered.delete(answered.keys().next().value);
114
229
  answered.set(key, confirmation);
115
230
  }
116
231
  }
117
232
  }
118
- const result = { ...verdict, allowed: !conflict || confirmation === 'approve', authorizationGranted: false, confirmation, operationDigest, decisionDigest: canonicalContentHash(decision) };
233
+ const result = {
234
+ ...verdict,
235
+ allowed: !conflict || confirmation === "approve",
236
+ authorizationGranted: false,
237
+ confirmation,
238
+ operationDigest,
239
+ decisionDigest: canonicalContentHash(decision),
240
+ };
119
241
  let recorded = false;
120
242
  if (receipt)
121
243
  try {
122
- recorded = await host.runtime.withDatabase(db => recordCorrectionObservation(db, receipt, { decision: decision.kind, target: decision.target, ...result }));
244
+ recorded = await host.runtime.withDatabase((db) => recordCorrectionObservation(db, receipt, {
245
+ decision: decision.kind,
246
+ target: decision.target,
247
+ ...result,
248
+ }));
123
249
  }
124
250
  catch {
125
251
  execution.signal.throwIfAborted();
126
252
  }
127
253
  return { ...result, recorded };
128
254
  };
129
- disposers.push(ctx.tools.register({ name: 'correction_check', modelFacing: true,
130
- description: 'Check a compiler compatibility or completion judgment against host-retrieved corrections and actual current verification. A model claim never proves application. Only a concrete conflicting operation asks a scoped native question.',
255
+ disposers.push(ctx.tools.register({
256
+ name: "correction_check",
257
+ modelFacing: true,
258
+ description: "Check a compiler compatibility or completion judgment against host-retrieved corrections and actual current verification. A model claim never proves application. Only a concrete conflicting operation asks a scoped native question.",
131
259
  parameters: JSON.parse(JSON.stringify(z.toJSONSchema(z.object({ decision: correctionDecisionSchema }).strict()))),
132
- output: { schema: {}, render: (_, value) => [{ type: 'text', text: JSON.stringify(value) }] },
260
+ output: {
261
+ schema: {},
262
+ render: (_, value) => [
263
+ { type: "text", text: JSON.stringify(value) },
264
+ ],
265
+ },
133
266
  execute: async (args, execution) => {
134
- if (execution.name !== 'correction_check' || execution.parent !== undefined)
135
- throw new KiokukoError('CONFLICT', 'Correction check requires a root native call');
136
- return checkDecision(execution, z.object({ decision: correctionDecisionSchema }).strict().parse(args).decision);
137
- } }));
267
+ if (execution.name !== "correction_check" ||
268
+ execution.parent !== undefined)
269
+ throw new KiokukoError("CONFLICT", "Correction check requires a root native call");
270
+ return checkDecision(execution, z.object({ decision: correctionDecisionSchema }).strict().parse(args)
271
+ .decision);
272
+ },
273
+ }));
138
274
  // Existing authorization hooks still own the operation. This guard never grants
139
275
  // permission, executes a verifier, or blocks unrelated/missing-memory work.
140
- disposers.push(ctx.on('tools/pre-execute', async (execution, next) => {
276
+ disposers.push(ctx.on("tools/pre-execute", async (execution, next) => {
141
277
  const identity = host.resolve(execution);
142
- if (!identity?.corrections?.sources.some(source => source.rule === 'capability_compatibility'))
278
+ if (!identity?.corrections?.sources.some((source) => source.rule === "capability_compatibility"))
143
279
  return next();
144
280
  const decision = literalVersionGate(execution.name, execution.arguments, identity.repositoryRoot);
145
281
  if (!decision)
146
282
  return next();
147
283
  const result = await checkDecision(execution, decision);
148
284
  if (!result.allowed)
149
- throw new KiokukoError('CONFLICT', `Correction conflict: ${result.reason}; only this operation is held`);
285
+ throw new KiokukoError("CONFLICT", `Correction conflict: ${result.reason}; only this operation is held`);
150
286
  return next();
151
287
  }, { prepend: true }));
152
288
  if (ctx.commands && host.session)
153
- disposers.push(ctx.commands.register({ name: 'kioku-memory-application',
154
- description: 'Show memory application and regression verification status for this native session.', input: { hint: 'status [--json]' },
289
+ disposers.push(ctx.commands.register({
290
+ name: "kioku-memory-application",
291
+ description: "Show memory application and regression verification status for this native session.",
292
+ input: { hint: "status [--json]" },
155
293
  handler: async (invocation) => {
156
294
  invocation.signal.throwIfAborted();
157
- if (!['', 'status', 'status --json'].includes(invocation.rawInput.trim()))
158
- return { kind: 'error', text: 'Use /kioku-memory-application status [--json].' };
295
+ if (!["", "status", "status --json"].includes(invocation.rawInput.trim()))
296
+ return {
297
+ kind: "error",
298
+ text: "Use /kioku-memory-application status [--json].",
299
+ };
159
300
  const session = host.session(invocation.agent);
160
301
  if (!session)
161
- return { kind: 'error', text: 'Native session identity is unavailable.' };
162
- const status = await host.runtime.withDatabase(db => {
163
- const row = db.prepare('SELECT run_id FROM task_memory_bindings WHERE session_id=? AND repository_root=? ORDER BY rowid DESC LIMIT 1')
302
+ return {
303
+ kind: "error",
304
+ text: "Native session identity is unavailable.",
305
+ };
306
+ const status = await host.runtime.withDatabase((db) => {
307
+ const row = db
308
+ .prepare("SELECT run_id FROM task_memory_bindings WHERE session_id=? AND repository_root=? ORDER BY rowid DESC LIMIT 1")
164
309
  .get(session.sessionId, session.repositoryRoot);
165
- const application = row ? memoryApplicationStatus(db, row.run_id) : { supported: false, ready: true, workMayContinue: true, verification: 'unobserved' };
166
- const globalization = application.supported && 'items' in application
167
- ? application.items.map(item => ({ entryId: item.entryId, revision: item.revision,
168
- ...autoGlobalizationStatus(db, item.entryId, item.revision) })) : [];
169
- return { integration: 'native_active', ...application, globalization };
310
+ const application = row
311
+ ? memoryApplicationStatus(db, row.run_id)
312
+ : {
313
+ supported: false,
314
+ ready: true,
315
+ workMayContinue: true,
316
+ verification: "unobserved",
317
+ };
318
+ const globalization = application.supported && "items" in application
319
+ ? application.items.map((item) => ({
320
+ entryId: item.entryId,
321
+ revision: item.revision,
322
+ ...autoGlobalizationStatus(db, item.entryId, item.revision),
323
+ }))
324
+ : [];
325
+ return {
326
+ integration: "native_active",
327
+ ...application,
328
+ globalization,
329
+ };
170
330
  });
171
- if (invocation.rawInput.includes('--json'))
172
- return { kind: 'success', text: JSON.stringify(status, null, 2) };
173
- return { kind: 'success', text: !status.supported ? '記憶適用の連携は稼働中です。この会話で準備済みの依頼はありません。'
174
- : `記憶適用: ${status.ready ? '未処理なし' : '確認が必要'}\n取得: ${'retrieval' in status ? status.retrieval : 'unavailable'}\n検証: ${status.verification}\n未処理: ${'pending' in status ? status.pending.length : 0}\n実行中・終了未確認: ${'running' in status ? status.running : 0}\n自動Global化: ${status.globalization.map(item => `${item.entryId}@${item.revision}: ${'successfulRuns' in item ? item.successfulRuns : 0}/3, ${'reason' in item ? item.reason ?? item.state : '未対応'}, ${'globalEntryId' in item ? item.globalEntryId ?? '未生成' : '未生成'}`).join(' / ') || '対象なし'}\n詳細は status --json で確認できます。` };
175
- } }));
176
- disposers.push(ctx.tools.register({ name: 'memory_explain', modelFacing: true,
177
- description: 'Inspect stored memory claims, source excerpts, revision history and current eligibility. Source attachment does not prove truth.',
178
- parameters: JSON.parse(JSON.stringify(z.toJSONSchema(z.object({ entryId: z.string().min(1).max(256), revision: z.number().int().positive().optional() }).strict()))),
179
- output: { schema: {}, render: (_, value) => [{ type: 'text', text: JSON.stringify(value) }] },
331
+ if (invocation.rawInput.includes("--json"))
332
+ return { kind: "success", text: JSON.stringify(status, null, 2) };
333
+ return {
334
+ kind: "success",
335
+ text: !status.supported
336
+ ? "記憶適用の連携は稼働中です。この会話で準備済みの依頼はありません。"
337
+ : `記憶適用: ${status.ready ? "未処理なし" : "確認が必要"}\n取得: ${"retrieval" in status ? status.retrieval : "unavailable"}\n検証: ${status.verification}\n未処理: ${"pending" in status ? status.pending.length : 0}\n実行中・終了未確認: ${"running" in status ? status.running : 0}\n自動Global化: ${status.globalization.map((item) => `${item.entryId}@${item.revision}: ${"successfulRuns" in item ? item.successfulRuns : 0}/3, ${"reason" in item ? (item.reason ?? item.state) : "未対応"}, ${"globalEntryId" in item ? (item.globalEntryId ?? "未生成") : "未生成"}`).join(" / ") || "対象なし"}\n詳細は status --json で確認できます。`,
338
+ };
339
+ },
340
+ }));
341
+ disposers.push(ctx.tools.register({
342
+ name: "memory_explain",
343
+ modelFacing: true,
344
+ description: "Inspect stored memory claims, source excerpts, revision history and current eligibility. Source attachment does not prove truth.",
345
+ parameters: JSON.parse(JSON.stringify(z.toJSONSchema(z
346
+ .object({
347
+ entryId: z.string().min(1).max(256),
348
+ revision: z.number().int().positive().optional(),
349
+ })
350
+ .strict()))),
351
+ output: {
352
+ schema: {},
353
+ render: (_, value) => [
354
+ { type: "text", text: JSON.stringify(value) },
355
+ ],
356
+ },
180
357
  execute: async (args, execution) => {
181
358
  const identity = host.resolve(execution);
182
- if (!identity || execution.parent !== undefined || execution.name !== 'memory_explain')
183
- throw new Error('No active native task');
184
- const input = z.object({ entryId: z.string().min(1).max(256), revision: z.number().int().positive().optional() }).strict().parse(args);
359
+ if (!identity ||
360
+ execution.parent !== undefined ||
361
+ execution.name !== "memory_explain")
362
+ throw new Error("No active native task");
363
+ const input = z
364
+ .object({
365
+ entryId: z.string().min(1).max(256),
366
+ revision: z.number().int().positive().optional(),
367
+ })
368
+ .strict()
369
+ .parse(args);
185
370
  execution.signal.throwIfAborted();
186
- return host.runtime.withDatabase(db => {
371
+ return host.runtime.withDatabase((db) => {
187
372
  if (host.resolve(execution)?.runId !== identity.runId)
188
- throw new Error('Native task changed');
189
- const value = explainMemory(db, { workspace: identity.workspace, runId: identity.runId, ...input });
190
- db.prepare('INSERT OR IGNORE INTO memory_explain_receipts VALUES(?,?,?,?)').run(identity.sessionId, execution.callId, value.entryId, value.revision);
373
+ throw new Error("Native task changed");
374
+ const value = explainMemory(db, {
375
+ workspace: identity.workspace,
376
+ runId: identity.runId,
377
+ ...input,
378
+ });
379
+ db.prepare("INSERT OR IGNORE INTO memory_explain_receipts VALUES(?,?,?,?)").run(identity.sessionId, execution.callId, value.entryId, value.revision);
191
380
  return value;
192
381
  });
193
- }
382
+ },
194
383
  }));
195
384
  if (ctx.commands && host.session)
196
- disposers.push(ctx.commands.register({ name: 'kioku-memory', description: 'Explain memory evidence or forget all revisions and dependent memories. Native logs remain. explain ENTRY_ID [--revision N] [--json] | forget ENTRY_ID --revision N', input: { hint: 'explain ENTRY_ID [--revision N] [--json] | forget ENTRY_ID --revision N' },
385
+ disposers.push(ctx.commands.register({
386
+ name: "kioku-memory",
387
+ description: "Explain memory evidence or forget all revisions and dependent memories. Native logs remain. explain ENTRY_ID [--revision N] [--json] | forget ENTRY_ID --revision N | learning status | learning reset",
388
+ input: {
389
+ hint: "explain ENTRY_ID [--revision N] [--json] | forget ENTRY_ID --revision N | learning status | learning reset",
390
+ },
197
391
  handler: async (invocation) => {
198
392
  try {
199
393
  const session = host.session(invocation.agent);
200
394
  if (!session)
201
- throw new Error('Native session identity unavailable');
395
+ throw new Error("Native session identity unavailable");
202
396
  const args = invocation.rawInput.trim().split(/\s+/u);
203
- if (!['explain', 'forget'].includes(args[0]) || !args[1])
204
- throw new Error('Use explain ENTRY_ID [--revision N] [--json]');
397
+ if (args[0] === "learning") {
398
+ if (args.length !== 2 || !["status", "reset"].includes(args[1]))
399
+ throw new Error("Use /kioku-memory learning status | learning reset (current repository only).");
400
+ invocation.signal.throwIfAborted();
401
+ const value = await host.runtime.withDatabase((db) => {
402
+ invocation.signal.throwIfAborted();
403
+ const current = host.session(invocation.agent);
404
+ if (!current ||
405
+ current.sessionId !== session.sessionId ||
406
+ current.repositoryRoot !== session.repositoryRoot)
407
+ throw new Error("Native session identity changed");
408
+ const root = detectRepositoryRoot({
409
+ cwd: current.repositoryRoot,
410
+ allowDirectory: true,
411
+ }).root;
412
+ if (args[1] === "reset")
413
+ return {
414
+ action: "reset",
415
+ ...resetRepositoryLearning(db, root),
416
+ };
417
+ const snapshot = readRepositoryLearning(db, root);
418
+ // No lesson text, model tags, source excerpts or filesystem paths in status.
419
+ return {
420
+ action: "status",
421
+ repositoryKey: snapshot.repositoryKey,
422
+ revision: snapshot.revision,
423
+ turnCount: snapshot.turnCount,
424
+ retainedPoints: snapshot.points.length,
425
+ outcomeCounts: snapshot.outcomeCounts,
426
+ assessment: snapshot.assessment,
427
+ };
428
+ });
429
+ return {
430
+ kind: "success",
431
+ text: JSON.stringify(value, null, 2) +
432
+ (args[1] === "reset"
433
+ ? "\nCurrent repository learning was reset; pending pre-reset writes are invalidated. Automatic learning remains enabled. Native logs, already-delivered context and backups are not erased."
434
+ : "\nCounts describe stored learning, not verified correctness or model use."),
435
+ };
436
+ }
437
+ if (!["explain", "forget"].includes(args[0]) || !args[1])
438
+ throw new Error("Use explain ENTRY_ID [--revision N] [--json]");
205
439
  let revision;
206
440
  for (let i = 2; i < args.length; i++) {
207
- if (args[i] === '--json')
441
+ if (args[i] === "--json")
208
442
  continue;
209
- if (args[i] === '--revision' && revision === undefined && /^[1-9]\d*$/.test(args[i + 1] ?? '')) {
443
+ if (args[i] === "--revision" &&
444
+ revision === undefined &&
445
+ /^[1-9]\d*$/.test(args[i + 1] ?? "")) {
210
446
  revision = Number(args[++i]);
211
447
  if (!Number.isSafeInteger(revision))
212
- throw new Error('Invalid revision');
448
+ throw new Error("Invalid revision");
213
449
  continue;
214
450
  }
215
- throw new Error('Invalid memory command arguments');
451
+ throw new Error("Invalid memory command arguments");
216
452
  }
217
- if (args[0] === 'forget' && revision === undefined)
218
- throw new Error('forget requires --revision N; it erases all revisions and dependent memories');
453
+ if (args[0] === "forget" && revision === undefined)
454
+ throw new Error("forget requires --revision N; it erases all revisions and dependent memories");
219
455
  invocation.signal.throwIfAborted();
220
- const value = await host.runtime.withDatabase(db => {
221
- const binding = db.prepare('SELECT workspace,run_id FROM task_memory_bindings WHERE session_id=? AND repository_root=? ORDER BY rowid DESC LIMIT 1').get(session.sessionId, session.repositoryRoot);
222
- const project = db.prepare('SELECT workspace FROM repository_locations JOIN repositories USING(repository_id) WHERE canonical_root=?').get(session.repositoryRoot);
456
+ const value = await host.runtime.withDatabase((db) => {
457
+ const binding = db
458
+ .prepare("SELECT workspace,run_id FROM task_memory_bindings WHERE session_id=? AND repository_root=? ORDER BY rowid DESC LIMIT 1")
459
+ .get(session.sessionId, session.repositoryRoot);
460
+ const project = db
461
+ .prepare("SELECT workspace FROM repository_locations JOIN repositories USING(repository_id) WHERE canonical_root=?")
462
+ .get(session.repositoryRoot);
223
463
  const workspace = binding?.workspace ?? project?.workspace;
224
464
  if (!workspace)
225
- throw new Error('Current native project is unavailable');
226
- return args[0] === 'forget' ? forgetMemory(db, { workspace, entryId: args[1], expectedRevision: revision, operationId: `forget:${session.sessionId}:${invocation.commandId ?? args[1] + ':' + revision}` }) : explainMemory(db, { workspace, entryId: args[1], revision, ...(binding ? { runId: binding.run_id } : {}) });
465
+ throw new Error("Current native project is unavailable");
466
+ return args[0] === "forget"
467
+ ? forgetMemory(db, {
468
+ workspace,
469
+ entryId: args[1],
470
+ expectedRevision: revision,
471
+ operationId: `forget:${session.sessionId}:${invocation.commandId ?? args[1] + ":" + revision}`,
472
+ })
473
+ : explainMemory(db, {
474
+ workspace,
475
+ entryId: args[1],
476
+ revision,
477
+ ...(binding ? { runId: binding.run_id } : {}),
478
+ });
227
479
  });
228
- return { kind: 'success', text: args.includes('--json') ? JSON.stringify(value, null, 2) : args[0] === 'forget' ? `記憶 ${args[1]} と依存する記憶を忘却しました。native会話ログ、外部への送信済み情報、バックアップは対象外です。` : renderMemoryExplanation(value) };
480
+ return {
481
+ kind: "success",
482
+ text: args.includes("--json")
483
+ ? JSON.stringify(value, null, 2)
484
+ : args[0] === "forget"
485
+ ? `記憶 ${args[1]} と依存する記憶を忘却しました。native会話ログ、外部への送信済み情報、バックアップは対象外です。`
486
+ : renderMemoryExplanation(value),
487
+ };
229
488
  }
230
489
  catch (error) {
231
- return { kind: 'error', text: error instanceof Error ? error.message : 'Memory inspection failed' };
490
+ return {
491
+ kind: "error",
492
+ text: error instanceof Error
493
+ ? error.message
494
+ : "Memory inspection failed",
495
+ };
232
496
  }
233
- }
497
+ },
234
498
  }));
235
- disposers.push(ctx.tools.register({ name: 'task_memory_review', modelFacing: true,
499
+ disposers.push(ctx.tools.register({
500
+ name: "task_memory_review",
501
+ modelFacing: true,
236
502
  description: MEMORY_APPLICATION_GUIDANCE,
237
503
  // Zod attaches non-enumerable ~standard metadata; DSH requires plain JSON.
238
- parameters: JSON.parse(JSON.stringify(z.toJSONSchema(transportSchema))), output: { schema: {}, render: (_, value) => [{ type: 'text', text: JSON.stringify(value) }] },
504
+ parameters: JSON.parse(JSON.stringify(z.toJSONSchema(transportSchema))),
505
+ output: {
506
+ schema: {},
507
+ render: (_, value) => [
508
+ { type: "text", text: JSON.stringify(value) },
509
+ ],
510
+ },
239
511
  execute: async (args, execution) => {
240
512
  const identity = host.resolve(execution);
241
- if (!identity || execution.parent !== undefined && !isPtcSubcall(execution) || execution.name !== 'task_memory_review')
242
- throw new Error('No active native task for memory application');
513
+ if (!identity ||
514
+ (execution.parent !== undefined && !isPtcSubcall(execution)) ||
515
+ execution.name !== "task_memory_review")
516
+ throw new Error("No active native task for memory application");
243
517
  execution.signal.throwIfAborted();
244
518
  const input = inputSchema.parse(args);
245
- if (input.action !== 'status')
246
- return { recorded: false, workMayContinue: true, reason: 'post_task_memory_review_required' };
247
- return host.runtime.withDatabase(db => {
519
+ if (input.action !== "status")
520
+ return {
521
+ recorded: false,
522
+ workMayContinue: true,
523
+ reason: "post_task_memory_review_required",
524
+ };
525
+ return host.runtime.withDatabase((db) => {
248
526
  execution.signal.throwIfAborted();
249
527
  if (host.resolve(execution)?.runId !== identity.runId)
250
- throw new Error('Native task changed');
528
+ throw new Error("Native task changed");
251
529
  return memoryApplicationStatus(db, identity.runId);
252
530
  });
253
- } }));
254
- disposers.push(ctx.on('tools/pre-execute', async (execution, next) => {
531
+ },
532
+ }));
533
+ disposers.push(ctx.on("tools/pre-execute", async (execution, next) => {
255
534
  const identity = host.resolve(execution);
256
- if (!identity || isOwnedExecutionCall(execution) || READ_TOOLS.has(execution.name) || CONTROL_TOOLS.has(execution.name) || isSavedLispResultRead(execution) || host.preparationOnly?.(execution) === true)
535
+ if (!identity ||
536
+ isOwnedExecutionCall(execution) ||
537
+ READ_TOOLS.has(execution.name) ||
538
+ CONTROL_TOOLS.has(execution.name) ||
539
+ isSavedLispResultRead(execution) ||
540
+ host.preparationOnly?.(execution) === true)
257
541
  return next();
258
542
  // A child without its own admitted binding cannot borrow its parent's proof.
259
543
  const command = foregroundNativeCommand(execution, identity.repositoryRoot);
260
- const tracked = await host.runtime.withDatabase(db => {
544
+ const tracked = await host.runtime
545
+ .withDatabase((db) => {
261
546
  // Empty memory applications remain observational and take no writer lock.
262
547
  if (!memoryApplicationStatus(db, identity.runId).items?.length)
263
548
  return undefined;
264
549
  return withImmediateTransaction(db, () => {
265
550
  execution.signal.throwIfAborted();
266
551
  if (host.resolve(execution)?.runId !== identity.runId)
267
- throw new Error('Native task changed');
268
- const lease = captureExecutionTaskLease(db, { taskId: identity.runId, sessionId: identity.sessionId, repositoryRoot: identity.repositoryRoot }, execution);
269
- return beginMemoryExecution(db, identity, execution.callId, command) ? lease : undefined;
552
+ throw new Error("Native task changed");
553
+ const lease = captureExecutionTaskLease(db, {
554
+ taskId: identity.runId,
555
+ sessionId: identity.sessionId,
556
+ repositoryRoot: identity.repositoryRoot,
557
+ }, execution);
558
+ return beginMemoryExecution(db, identity, execution.callId, command)
559
+ ? lease
560
+ : undefined;
270
561
  });
271
- }).catch(() => undefined);
562
+ })
563
+ .catch(() => undefined);
272
564
  if (tracked)
273
- pending.set(execution, { identity: Object.freeze({ ...identity }), lease: tracked });
565
+ pending.set(execution, {
566
+ identity: Object.freeze({ ...identity }),
567
+ lease: tracked,
568
+ });
274
569
  return next();
275
570
  }, { prepend: true }));
276
- disposers.push(ctx.on('tools/result', (execution, result) => {
571
+ disposers.push(ctx.on("tools/result", (execution, result) => {
277
572
  const tracked = pending.get(execution);
278
573
  if (!tracked)
279
574
  return;
280
575
  const { identity, lease } = tracked;
281
576
  pending.delete(execution);
282
- return host.runtime.withDatabase(db => withImmediateTransaction(db, () => {
577
+ return host.runtime
578
+ .withDatabase((db) => withImmediateTransaction(db, () => {
283
579
  if (host.resolve(execution)?.runId !== identity.runId)
284
580
  return;
285
581
  authorizeTaskLease(db, lease);
286
582
  completeMemoryExecution(db, identity, execution.callId, result);
287
- })).catch(() => { });
583
+ }))
584
+ .catch(() => {
585
+ /* Stale completion cannot adopt evidence into a resumed task. */
586
+ });
288
587
  }));
289
- return () => { for (const dispose of disposers.reverse())
290
- dispose(); };
588
+ return () => {
589
+ for (const dispose of disposers.reverse())
590
+ dispose();
591
+ };
291
592
  }
292
593
  //# sourceMappingURL=memory-application.js.map