akm-cli 0.9.0-beta.47 → 0.9.0-beta.49
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/dist/commands/agent/agent-dispatch.js +2 -2
- package/dist/commands/agent/agent-support.js +0 -7
- package/dist/commands/agent/contribute-cli.js +1 -1
- package/dist/commands/proposal/propose.js +2 -2
- package/dist/commands/tasks/tasks.js +1 -1
- package/dist/core/common.js +0 -5
- package/dist/core/config/config-schema.js +55 -69
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/state-db.js +59 -11
- package/dist/integrations/agent/config.js +6 -53
- package/dist/integrations/agent/index.js +2 -18
- package/dist/integrations/agent/prompts.js +0 -8
- package/dist/integrations/harnesses/index.js +2 -3
- package/dist/integrations/harnesses/opencode-sdk/index.js +2 -2
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -2
- package/dist/output/context.js +5 -5
- package/dist/scripts/migrate-storage.js +79 -79
- package/dist/sources/wiki-fetchers/youtube.js +58 -4
- package/dist/tasks/backends/cron.js +1 -1
- package/dist/tasks/backends/launchd.js +1 -1
- package/dist/tasks/backends/schtasks.js +1 -1
- package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
- package/package.json +1 -1
- package/dist/commands/improve/related-sessions.js +0 -120
- package/dist/commands/lint.js +0 -4
|
@@ -18,7 +18,7 @@ import { parseAssetRef } from "../../core/asset/asset-ref.js";
|
|
|
18
18
|
import { NotFoundError, UsageError } from "../../core/errors.js";
|
|
19
19
|
import { requireAgentProfile } from "../../integrations/agent/config.js";
|
|
20
20
|
import { runAgent } from "../../integrations/agent/spawn.js";
|
|
21
|
-
import {
|
|
21
|
+
import { runOpencodeSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
|
|
22
22
|
/**
|
|
23
23
|
* Fill `{{0}}`, `{{1}}`, ... placeholders in `template` with the
|
|
24
24
|
* corresponding entries in `args`. Any placeholder index that exceeds the
|
|
@@ -93,7 +93,7 @@ export async function akmAgentDispatch(options) {
|
|
|
93
93
|
...(dispatchRequest !== undefined ? { dispatch: dispatchRequest } : {}),
|
|
94
94
|
};
|
|
95
95
|
const result = profile.sdkMode
|
|
96
|
-
? await
|
|
96
|
+
? await runOpencodeSdk(profile, prompt ?? "", runOptions, options.llmConfig)
|
|
97
97
|
: await runAgent(profile, prompt, runOptions);
|
|
98
98
|
return {
|
|
99
99
|
schemaVersion: 1,
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
/**
|
|
5
|
-
* Shared helpers for agent-based commands (reflect, propose, etc.).
|
|
6
|
-
*
|
|
7
|
-
* Consolidates utility functions that were duplicated byte-for-byte across
|
|
8
|
-
* `reflect.ts` and `propose.ts`. Any command that shells out to an agent
|
|
9
|
-
* profile can import from here rather than copy-pasting.
|
|
10
|
-
*/
|
|
11
4
|
import { loadConfig } from "../../core/config/config.js";
|
|
12
5
|
import { requireAgentProfile, } from "../../integrations/agent/index.js";
|
|
13
6
|
// ── Config helpers ───────────────────────────────────────────────────────────
|
|
@@ -29,7 +29,7 @@ import { assertFlatAssetName, combineCreatePath, normalizeCreateSubPath } from "
|
|
|
29
29
|
import { loadConfig } from "../../core/config/config.js";
|
|
30
30
|
import { UsageError } from "../../core/errors.js";
|
|
31
31
|
import { getHyphenatedArg } from "../../output/context.js";
|
|
32
|
-
import { akmLint } from "../lint.js";
|
|
32
|
+
import { akmLint } from "../lint/index.js";
|
|
33
33
|
import { akmPropose } from "../proposal/propose.js";
|
|
34
34
|
import { akmAgentDispatch } from "./agent-dispatch.js";
|
|
35
35
|
const EXIT_GENERAL = EXIT_CODES.GENERAL;
|
|
@@ -22,7 +22,7 @@ import { resolveStandardsContext } from "../../core/standards/resolve-standards-
|
|
|
22
22
|
import { runAgent, } from "../../integrations/agent/index.js";
|
|
23
23
|
import { resolveProcessAgentProfile } from "../../integrations/agent/config.js";
|
|
24
24
|
import { buildProposePrompt, parseAgentProposalPayload } from "../../integrations/agent/prompts.js";
|
|
25
|
-
import {
|
|
25
|
+
import { runOpencodeSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
|
|
26
26
|
import { baseFailureFields, enoentHintMessage, isEnoentFailure, loadAgentConfigFromDisk, resolveAgentProfile, } from "../agent/agent-support.js";
|
|
27
27
|
import { createProposal, isProposalSkipped, } from "./validators/proposals.js";
|
|
28
28
|
function failureEnvelope(result, type, name, fallbackReason = "non_zero_exit") {
|
|
@@ -128,7 +128,7 @@ export async function akmPropose(options) {
|
|
|
128
128
|
...(resolvedTimeoutMs !== undefined ? { timeoutMs: resolvedTimeoutMs } : {}),
|
|
129
129
|
};
|
|
130
130
|
result = profile.sdkMode
|
|
131
|
-
? await
|
|
131
|
+
? await runOpencodeSdk(profile, prompt ?? "", runOptions)
|
|
132
132
|
: await runAgent(profile, prompt, runOptions);
|
|
133
133
|
}
|
|
134
134
|
if (!result.ok) {
|
|
@@ -20,7 +20,7 @@ import { listAgentProfileNames } from "../../integrations/agent/index.js";
|
|
|
20
20
|
import { resolveAssetPath } from "../../sources/resolve.js";
|
|
21
21
|
import { backendNameForPlatform, selectBackend } from "../../tasks/backends/index.js";
|
|
22
22
|
import { parseTaskDocument } from "../../tasks/parser.js";
|
|
23
|
-
import { resolveAkmInvocation } from "../../tasks/
|
|
23
|
+
import { resolveAkmInvocation } from "../../tasks/resolve-akm-bin.js";
|
|
24
24
|
import { exitCodeForStatus, readTaskHistory, runTask } from "../../tasks/runner.js";
|
|
25
25
|
import { parseSchedule, SCHEDULE_SUPPORTED_SUBSET_HINT, translateToCron } from "../../tasks/schedule.js";
|
|
26
26
|
import { validateTaskDocument } from "../../tasks/validator.js";
|
package/dist/core/common.js
CHANGED
|
@@ -44,11 +44,6 @@ export function isRemoteUrl(value) {
|
|
|
44
44
|
value.startsWith("ssh://") ||
|
|
45
45
|
value.startsWith("git://"));
|
|
46
46
|
}
|
|
47
|
-
export function filterNonEmptyStrings(value) {
|
|
48
|
-
if (!Array.isArray(value))
|
|
49
|
-
return undefined;
|
|
50
|
-
return value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
51
|
-
}
|
|
52
47
|
// ── Validators ──────────────────────────────────────────────────────────────
|
|
53
48
|
/**
|
|
54
49
|
* Returns true if `type` is a known asset type — either a built-in from
|
|
@@ -22,8 +22,14 @@
|
|
|
22
22
|
* - Two exceptions (hard-rejected): openviking source type and legacy
|
|
23
23
|
* `stashes[]` key. Both have explicit migration paths; silently dropping
|
|
24
24
|
* would mask user data loss.
|
|
25
|
-
* -
|
|
26
|
-
*
|
|
25
|
+
* - UNKNOWN-KEY POLICY: object schemas use passthrough (unknown keys are
|
|
26
|
+
* preserved and ignored, NOT rejected). akm runs across multiple installed
|
|
27
|
+
* versions sharing one config.json; a newer version writes keys an older
|
|
28
|
+
* version's schema doesn't know yet, so hard-rejecting unknown keys turned
|
|
29
|
+
* benign version skew into `INVALID_CONFIG_FILE` failures. Known keys are
|
|
30
|
+
* still type-checked; passthrough preserves unknown keys across a
|
|
31
|
+
* load→save round trip so an older reader never strips a newer writer's
|
|
32
|
+
* settings. (Replaced the prior strict-mode object walls.)
|
|
27
33
|
* - `defaultWriteTarget` resolution and similar cross-field invariants are
|
|
28
34
|
* enforced at save time via `superRefine` on the top-level schema.
|
|
29
35
|
*/
|
|
@@ -50,7 +56,7 @@ const LlmCapabilitiesSchema = z
|
|
|
50
56
|
.object({
|
|
51
57
|
structuredOutput: z.boolean().optional(),
|
|
52
58
|
})
|
|
53
|
-
.
|
|
59
|
+
.passthrough();
|
|
54
60
|
/**
|
|
55
61
|
* Connection config used for both top-level `llm` (after migration) and
|
|
56
62
|
* `profiles.llm[*]`. `model` is required at schema level — partial entries
|
|
@@ -75,15 +81,15 @@ export const LlmConnectionConfigSchema = z
|
|
|
75
81
|
judgeModel: z.string().min(1).optional(),
|
|
76
82
|
enableThinking: z.boolean().optional(),
|
|
77
83
|
})
|
|
78
|
-
.
|
|
84
|
+
.passthrough();
|
|
79
85
|
export const LlmProfileConfigSchema = LlmConnectionConfigSchema.extend({
|
|
80
86
|
supportsJsonSchema: z.boolean().optional(),
|
|
81
|
-
}).
|
|
87
|
+
}).passthrough();
|
|
82
88
|
const EmbeddingOllamaOptionsSchema = z
|
|
83
89
|
.object({
|
|
84
90
|
num_ctx: positiveInt.optional(),
|
|
85
91
|
})
|
|
86
|
-
.
|
|
92
|
+
.passthrough();
|
|
87
93
|
/**
|
|
88
94
|
* Embedding connection config. Both `endpoint` and `model` are optional:
|
|
89
95
|
* - Remote: provide `endpoint` (http/https URL) + `model`.
|
|
@@ -107,7 +113,7 @@ export const EmbeddingConnectionConfigSchema = z
|
|
|
107
113
|
contextLength: positiveInt.optional(),
|
|
108
114
|
ollamaOptions: EmbeddingOllamaOptionsSchema.optional(),
|
|
109
115
|
})
|
|
110
|
-
.
|
|
116
|
+
.passthrough();
|
|
111
117
|
// ── Agent profiles ──────────────────────────────────────────────────────────
|
|
112
118
|
// Derives from the canonical VALID_HARNESS_IDS (#565) so the Zod gate cannot
|
|
113
119
|
// drift from the TS union / parse check / setup detection.
|
|
@@ -120,7 +126,7 @@ export const AgentProfileConfigSchema = z
|
|
|
120
126
|
workspace: z.string().min(1).optional(),
|
|
121
127
|
model: z.string().min(1).optional(),
|
|
122
128
|
})
|
|
123
|
-
.
|
|
129
|
+
.passthrough();
|
|
124
130
|
// ── Improve profile / process ──────────────────────────────────────────────
|
|
125
131
|
export const ImproveProcessConfigSchema = z
|
|
126
132
|
.object({
|
|
@@ -151,7 +157,7 @@ export const ImproveProcessConfigSchema = z
|
|
|
151
157
|
// with care — cost is O(n²).
|
|
152
158
|
cosineCandidateLimit: z.number().int().positive().optional(),
|
|
153
159
|
})
|
|
154
|
-
.
|
|
160
|
+
.passthrough()
|
|
155
161
|
.optional(),
|
|
156
162
|
// Consolidate process: judged-state cache (#581). When enabled, a memory
|
|
157
163
|
// whose current content hash equals its cached judged hash is SKIPPED from
|
|
@@ -160,9 +166,9 @@ export const ImproveProcessConfigSchema = z
|
|
|
160
166
|
// time-window slice. Default OFF — when absent the consolidate pass behaves
|
|
161
167
|
// byte-identically to today (the incrementalSince path is unaffected). Only
|
|
162
168
|
// meaningful on the `consolidate` process.
|
|
163
|
-
judgedCache: z.object({ enabled: z.boolean().optional() }).
|
|
164
|
-
qualityGate: z.object({ enabled: z.boolean().optional() }).
|
|
165
|
-
contradictionDetection: z.object({ enabled: z.boolean().optional() }).
|
|
169
|
+
judgedCache: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
|
|
170
|
+
qualityGate: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
|
|
171
|
+
contradictionDetection: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
|
|
166
172
|
// Extract process config (only meaningful for extract process)
|
|
167
173
|
defaultSince: z.string().min(1).optional(),
|
|
168
174
|
maxTotalChars: positiveInt.optional(),
|
|
@@ -236,7 +242,7 @@ export const ImproveProcessConfigSchema = z
|
|
|
236
242
|
// Demotion factor: multiply retrievalSalience by this when stale (default 0.5).
|
|
237
243
|
demotionFactor: z.number().min(0).max(1).optional(),
|
|
238
244
|
})
|
|
239
|
-
.
|
|
245
|
+
.passthrough()
|
|
240
246
|
.optional(),
|
|
241
247
|
// WS-3b: Schema-similarity gate (step 0b). At intake, if a new candidate's
|
|
242
248
|
// body embedding is within epsilon of an existing derived-layer lesson/knowledge
|
|
@@ -253,7 +259,7 @@ export const ImproveProcessConfigSchema = z
|
|
|
253
259
|
// to pass the quality gate and create redundant stash entries.
|
|
254
260
|
confidencePenalty: z.number().min(0).max(1).optional(),
|
|
255
261
|
})
|
|
256
|
-
.
|
|
262
|
+
.passthrough()
|
|
257
263
|
.optional(),
|
|
258
264
|
// WS-3b: Hot-probation intake buffer (step 0c, #604). New system-generated
|
|
259
265
|
// extractions enter captureMode: hot-probation and spend ONE consolidation
|
|
@@ -263,7 +269,7 @@ export const ImproveProcessConfigSchema = z
|
|
|
263
269
|
.object({
|
|
264
270
|
enabled: z.boolean().optional(),
|
|
265
271
|
})
|
|
266
|
-
.
|
|
272
|
+
.passthrough()
|
|
267
273
|
.optional(),
|
|
268
274
|
// WS-3b: Anti-collapse guards (step 8). Prevents the consolidation pipeline
|
|
269
275
|
// from collapsing too aggressively and losing diversity.
|
|
@@ -278,7 +284,7 @@ export const ImproveProcessConfigSchema = z
|
|
|
278
284
|
lexicalDiversityCheck: z.boolean().optional(),
|
|
279
285
|
randomClusterFraction: z.number().min(0).max(1).optional(),
|
|
280
286
|
})
|
|
281
|
-
.
|
|
287
|
+
.passthrough()
|
|
282
288
|
.optional(),
|
|
283
289
|
// WS-3b: CLS (Complementary Learning System) interleaving (step 9).
|
|
284
290
|
// distill/memoryInference prompts include embedding-retrieved existing adjacent
|
|
@@ -290,7 +296,7 @@ export const ImproveProcessConfigSchema = z
|
|
|
290
296
|
// Number of adjacent lessons/knowledge to include in prompts (default 3).
|
|
291
297
|
adjacentCount: z.number().int().min(1).optional(),
|
|
292
298
|
})
|
|
293
|
-
.
|
|
299
|
+
.passthrough()
|
|
294
300
|
.optional(),
|
|
295
301
|
// WS-3b: Distill→source fidelity check (step 10). After a distill proposal,
|
|
296
302
|
// check it against its cited source memories; a contradiction flag forces
|
|
@@ -299,7 +305,7 @@ export const ImproveProcessConfigSchema = z
|
|
|
299
305
|
.object({
|
|
300
306
|
enabled: z.boolean().optional(),
|
|
301
307
|
})
|
|
302
|
-
.
|
|
308
|
+
.passthrough()
|
|
303
309
|
.optional(),
|
|
304
310
|
// #609 — recombine process: minimum related-memory cluster size before an
|
|
305
311
|
// LLM generalization call. Default 3. Only meaningful on `recombine`.
|
|
@@ -342,7 +348,7 @@ export const ImproveProcessConfigSchema = z
|
|
|
342
348
|
// enabled, proposals classified as "low-value" by the deterministic noise
|
|
343
349
|
// gate are deferred. DEFAULT OFF (absent / { enabled: false } = pre-#639
|
|
344
350
|
// byte-identical behaviour). Only meaningful on the `reflect` process.
|
|
345
|
-
lowValueFilter: z.object({ enabled: z.boolean().optional() }).
|
|
351
|
+
lowValueFilter: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
|
|
346
352
|
// #641 — procedural-aware floor for the `extract` process triage gate.
|
|
347
353
|
// When true, a session must have markers>=1 OR editCommit>=0.5 to pass, even
|
|
348
354
|
// if score>=minScore. DEFAULT OFF (absent/false = pre-#641 byte-identical).
|
|
@@ -360,10 +366,10 @@ export const ImproveProcessConfigSchema = z
|
|
|
360
366
|
profile: z.string().min(1).optional(),
|
|
361
367
|
timeoutMs: z.union([positiveInt, z.null()]).optional(),
|
|
362
368
|
})
|
|
363
|
-
.
|
|
369
|
+
.passthrough()
|
|
364
370
|
.optional(),
|
|
365
371
|
})
|
|
366
|
-
.
|
|
372
|
+
.passthrough();
|
|
367
373
|
const ImproveProfileProcessesSchema = z
|
|
368
374
|
.object({
|
|
369
375
|
reflect: ImproveProcessConfigSchema.optional(),
|
|
@@ -380,37 +386,17 @@ const ImproveProfileProcessesSchema = z
|
|
|
380
386
|
.passthrough()
|
|
381
387
|
.superRefine((val, ctx) => {
|
|
382
388
|
// 0.8.0 removed the duplicated `feedbackDistillation` process key — it was
|
|
383
|
-
// a thin wrapper around `processes.distill.enabled`.
|
|
384
|
-
|
|
385
|
-
|
|
389
|
+
// a thin wrapper around `processes.distill.enabled`. Keep the migration
|
|
390
|
+
// hint so a stale config gets an actionable message rather than silently
|
|
391
|
+
// doing nothing. All OTHER unknown process keys are tolerated (passthrough)
|
|
392
|
+
// — see the unknown-key policy in this file's header. Hard-rejecting them
|
|
393
|
+
// turned benign cross-version skew into INVALID_CONFIG_FILE failures.
|
|
394
|
+
if ("feedbackDistillation" in val) {
|
|
386
395
|
ctx.addIssue({
|
|
387
396
|
code: z.ZodIssueCode.custom,
|
|
388
397
|
message: "feedbackDistillation was removed in 0.8.0 — use processes.distill.enabled instead. " +
|
|
389
398
|
"It now controls both the orchestration gate and the LLM-call gate.",
|
|
390
399
|
});
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
const allowed = new Set([
|
|
394
|
-
"reflect",
|
|
395
|
-
"distill",
|
|
396
|
-
"consolidate",
|
|
397
|
-
"memoryInference",
|
|
398
|
-
"graphExtraction",
|
|
399
|
-
"validation",
|
|
400
|
-
"extract",
|
|
401
|
-
"triage",
|
|
402
|
-
"proactiveMaintenance",
|
|
403
|
-
"recombine",
|
|
404
|
-
"procedural",
|
|
405
|
-
]);
|
|
406
|
-
for (const k of Object.keys(raw)) {
|
|
407
|
-
if (!allowed.has(k)) {
|
|
408
|
-
ctx.addIssue({
|
|
409
|
-
code: z.ZodIssueCode.unrecognized_keys,
|
|
410
|
-
keys: [k],
|
|
411
|
-
message: `Unrecognized improve process key: "${k}".`,
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
400
|
}
|
|
415
401
|
});
|
|
416
402
|
export const ImproveProfileConfigSchema = z
|
|
@@ -435,10 +421,10 @@ export const ImproveProfileConfigSchema = z
|
|
|
435
421
|
push: z.boolean().optional(),
|
|
436
422
|
message: z.string().min(1).optional(),
|
|
437
423
|
})
|
|
438
|
-
.
|
|
424
|
+
.passthrough()
|
|
439
425
|
.optional(),
|
|
440
426
|
})
|
|
441
|
-
.
|
|
427
|
+
.passthrough();
|
|
442
428
|
// ── Profiles / defaults ────────────────────────────────────────────────────
|
|
443
429
|
export const ProfilesSchema = z
|
|
444
430
|
.object({
|
|
@@ -446,14 +432,14 @@ export const ProfilesSchema = z
|
|
|
446
432
|
agent: z.record(z.string(), AgentProfileConfigSchema).optional(),
|
|
447
433
|
improve: z.record(z.string(), ImproveProfileConfigSchema).optional(),
|
|
448
434
|
})
|
|
449
|
-
.
|
|
435
|
+
.passthrough();
|
|
450
436
|
export const DefaultsSchema = z
|
|
451
437
|
.object({
|
|
452
438
|
llm: z.string().min(1).optional(),
|
|
453
439
|
agent: z.string().min(1).optional(),
|
|
454
440
|
improve: z.string().min(1).optional(),
|
|
455
441
|
})
|
|
456
|
-
.
|
|
442
|
+
.passthrough();
|
|
457
443
|
// ── Sources / registries / installed ────────────────────────────────────────
|
|
458
444
|
const SourceConfigEntryOptionsSchema = z
|
|
459
445
|
.object({
|
|
@@ -477,7 +463,7 @@ export const SourceConfigEntrySchema = z
|
|
|
477
463
|
options: SourceConfigEntryOptionsSchema.optional(),
|
|
478
464
|
wikiName: z.string().min(1).optional(),
|
|
479
465
|
})
|
|
480
|
-
.
|
|
466
|
+
.passthrough()
|
|
481
467
|
.superRefine((entry, ctx) => {
|
|
482
468
|
if (entry.writable === true && (entry.type === "website" || entry.type === "npm")) {
|
|
483
469
|
ctx.addIssue({
|
|
@@ -496,7 +482,7 @@ export const RegistryConfigEntrySchema = z
|
|
|
496
482
|
provider: z.string().min(1).optional(),
|
|
497
483
|
options: z.record(z.unknown()).optional(),
|
|
498
484
|
})
|
|
499
|
-
.
|
|
485
|
+
.passthrough();
|
|
500
486
|
const KitSourceSchema = z.enum(["filesystem", "git", "npm", "github", "website", "local"]);
|
|
501
487
|
export const InstalledStashEntrySchema = z
|
|
502
488
|
.object({
|
|
@@ -512,7 +498,7 @@ export const InstalledStashEntrySchema = z
|
|
|
512
498
|
resolvedRevision: z.string().min(1).optional(),
|
|
513
499
|
wikiName: z.string().min(1).optional(),
|
|
514
500
|
})
|
|
515
|
-
.
|
|
501
|
+
.passthrough()
|
|
516
502
|
.superRefine((entry, ctx) => {
|
|
517
503
|
if (entry.writable === true && entry.source !== "git" && entry.source !== "filesystem") {
|
|
518
504
|
ctx.addIssue({
|
|
@@ -527,7 +513,7 @@ export const OutputConfigSchema = z
|
|
|
527
513
|
format: z.enum(["json", "yaml", "text"]).optional(),
|
|
528
514
|
detail: z.enum(["brief", "normal", "full"]).optional(),
|
|
529
515
|
})
|
|
530
|
-
.
|
|
516
|
+
.passthrough();
|
|
531
517
|
// ── Search ──────────────────────────────────────────────────────────────────
|
|
532
518
|
const SearchGraphBoostSchema = z
|
|
533
519
|
.object({
|
|
@@ -541,29 +527,29 @@ const SearchGraphBoostSchema = z
|
|
|
541
527
|
/** Range [0, 1]; values > 1 hard-error (no silent clamp). */
|
|
542
528
|
confidenceWeight: z.number().finite().min(0).max(1).default(0.2).optional(),
|
|
543
529
|
})
|
|
544
|
-
.
|
|
530
|
+
.passthrough();
|
|
545
531
|
export const SearchConfigSchema = z
|
|
546
532
|
.object({
|
|
547
533
|
minScore: nonNegativeNumber.optional(),
|
|
548
534
|
defaultExcludeTypes: z.array(nonEmptyString).optional(),
|
|
549
|
-
curateRerank: z.object({ enabled: z.boolean().optional() }).
|
|
535
|
+
curateRerank: z.object({ enabled: z.boolean().optional() }).passthrough().optional(),
|
|
550
536
|
graphBoost: SearchGraphBoostSchema.optional(),
|
|
551
537
|
})
|
|
552
|
-
.
|
|
538
|
+
.passthrough();
|
|
553
539
|
// ── Feedback ────────────────────────────────────────────────────────────────
|
|
554
540
|
export const FeedbackConfigSchema = z
|
|
555
541
|
.object({
|
|
556
542
|
requireReason: z.boolean().optional(),
|
|
557
543
|
allowedFailureModes: z.array(nonEmptyString).optional(),
|
|
558
544
|
})
|
|
559
|
-
.
|
|
545
|
+
.passthrough();
|
|
560
546
|
// ── Improve top-level (utility decay, event retention) ─────────────────────
|
|
561
547
|
const ImproveUtilityDecaySchema = z
|
|
562
548
|
.object({
|
|
563
549
|
halfLifeDays: z.number().finite().min(0.1).optional(),
|
|
564
550
|
feedbackStabilityBoost: z.number().finite().min(1).optional(),
|
|
565
551
|
})
|
|
566
|
-
.
|
|
552
|
+
.passthrough();
|
|
567
553
|
// #612 / WS-4 — auto-accept gate calibration + bounded, opt-in per-phase
|
|
568
554
|
// threshold auto-tune. DEFAULT OFF: when absent (or `autoTune: false`) no
|
|
569
555
|
// tuning occurs, so the gate behaves byte-identically to today.
|
|
@@ -586,7 +572,7 @@ const ImproveCalibrationSchema = z
|
|
|
586
572
|
/** Target realized accept rate in [0, 1]. Default 0.9. */
|
|
587
573
|
targetAcceptRate: z.number().finite().min(0).max(1).optional(),
|
|
588
574
|
})
|
|
589
|
-
.
|
|
575
|
+
.passthrough();
|
|
590
576
|
// WS-4 — exploration budget: a fixed fraction of proposals accepted per run
|
|
591
577
|
// regardless of confidence. DEFAULT OFF.
|
|
592
578
|
const ImproveExplorationSchema = z
|
|
@@ -602,7 +588,7 @@ const ImproveExplorationSchema = z
|
|
|
602
588
|
*/
|
|
603
589
|
budgetFraction: z.number().finite().min(0).max(1).optional(),
|
|
604
590
|
})
|
|
605
|
-
.
|
|
591
|
+
.passthrough();
|
|
606
592
|
const ImproveSalienceSchema = z
|
|
607
593
|
.object({
|
|
608
594
|
/**
|
|
@@ -624,7 +610,7 @@ const ImproveSalienceSchema = z
|
|
|
624
610
|
*/
|
|
625
611
|
replayBudget: z.number().int().min(0).optional(),
|
|
626
612
|
})
|
|
627
|
-
.
|
|
613
|
+
.passthrough();
|
|
628
614
|
export const ImproveConfigSchema = z
|
|
629
615
|
.object({
|
|
630
616
|
utilityDecay: ImproveUtilityDecaySchema.optional(),
|
|
@@ -633,7 +619,7 @@ export const ImproveConfigSchema = z
|
|
|
633
619
|
exploration: ImproveExplorationSchema.optional(),
|
|
634
620
|
salience: ImproveSalienceSchema.optional(),
|
|
635
621
|
})
|
|
636
|
-
.
|
|
622
|
+
.passthrough();
|
|
637
623
|
// ── Index / per-pass ────────────────────────────────────────────────────────
|
|
638
624
|
const GRAPH_EXTRACTION_INCLUDE_TYPES_ALLOWED = [
|
|
639
625
|
"memory",
|
|
@@ -712,13 +698,13 @@ export const IndexPassConfigSchema = z.preprocess((raw, ctx) => {
|
|
|
712
698
|
lazyGraphExtraction: z.boolean().optional(),
|
|
713
699
|
})
|
|
714
700
|
.passthrough());
|
|
715
|
-
const MetadataEnhanceSchema = z.object({ enabled: z.boolean().optional() }).
|
|
701
|
+
const MetadataEnhanceSchema = z.object({ enabled: z.boolean().optional() }).passthrough();
|
|
716
702
|
const StalenessDetectionSchema = z
|
|
717
703
|
.object({
|
|
718
704
|
enabled: z.boolean().optional(),
|
|
719
705
|
thresholdDays: positiveInt.optional(),
|
|
720
706
|
})
|
|
721
|
-
.
|
|
707
|
+
.passthrough();
|
|
722
708
|
/**
|
|
723
709
|
* Index config is a union of reserved feature sections and per-pass entries.
|
|
724
710
|
* Passthrough so per-pass entries (keyed by arbitrary pass names like `graph`,
|
|
@@ -791,12 +777,12 @@ export const SetupTaskSchedulesSchema = z
|
|
|
791
777
|
improve: z.string().min(1).optional(),
|
|
792
778
|
index: z.string().min(1).optional(),
|
|
793
779
|
})
|
|
794
|
-
.
|
|
780
|
+
.passthrough();
|
|
795
781
|
export const SetupConfigSchema = z
|
|
796
782
|
.object({
|
|
797
783
|
taskSchedules: SetupTaskSchedulesSchema.optional(),
|
|
798
784
|
})
|
|
799
|
-
.
|
|
785
|
+
.passthrough();
|
|
800
786
|
// ── Top-level AkmConfig ────────────────────────────────────────────────────
|
|
801
787
|
/**
|
|
802
788
|
* Base object schema used both as the top-level shape and as the source of
|
|
@@ -828,7 +814,7 @@ export const AkmConfigShape = {
|
|
|
828
814
|
improve: ImproveConfigSchema.optional(),
|
|
829
815
|
setup: SetupConfigSchema.optional(),
|
|
830
816
|
};
|
|
831
|
-
export const AkmConfigBaseSchema = z.object(AkmConfigShape).
|
|
817
|
+
export const AkmConfigBaseSchema = z.object(AkmConfigShape).passthrough();
|
|
832
818
|
export const AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
|
|
833
819
|
// #464.a: defaultWriteTarget must name a configured source when sources
|
|
834
820
|
// are present. With no sources configured, error out instead of silently
|
|
@@ -9,8 +9,8 @@ import { VALID_HARNESS_IDS } from "../../integrations/harnesses/index.js";
|
|
|
9
9
|
/**
|
|
10
10
|
* Canonical list of valid agent harness / platform ids. Re-exported from the
|
|
11
11
|
* unified harness registry (#562) so the Zod `AgentPlatformSchema` enum, the
|
|
12
|
-
* `
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* `AgentProfileConfig` platform union, and setup's `DetectedHarness` union all
|
|
13
|
+
* derive from one place and cannot drift. Add a harness in
|
|
14
|
+
* `src/integrations/harnesses/index.ts`.
|
|
15
15
|
*/
|
|
16
16
|
export { VALID_HARNESS_IDS };
|
package/dist/core/state-db.js
CHANGED
|
@@ -469,22 +469,70 @@ export function insertProposalIfAbsent(db, proposal, stashDir) {
|
|
|
469
469
|
* need the write lock BEFORE those reads so concurrent processes serialize on
|
|
470
470
|
* the live queue state rather than clobbering each other.
|
|
471
471
|
*/
|
|
472
|
+
/**
|
|
473
|
+
* Errors `BEGIN IMMEDIATE` can throw under concurrent-writer contention that are
|
|
474
|
+
* transient (the statement did NOT start a usable transaction) and safe to
|
|
475
|
+
* retry after clearing any phantom transaction state:
|
|
476
|
+
* - "database is locked" / SQLITE_BUSY — another writer holds the lock.
|
|
477
|
+
* - "cannot start a transaction within a transaction" — bun:sqlite can leave
|
|
478
|
+
* the connection reporting an open transaction after a contended busy-wait
|
|
479
|
+
* on BEGIN IMMEDIATE (observed only under heavy parallel load, e.g. the
|
|
480
|
+
* proposal-queue worker race). A ROLLBACK clears that phantom state.
|
|
481
|
+
* These are start-of-transaction failures only; an error thrown by `fn` is a
|
|
482
|
+
* real failure and is NEVER retried.
|
|
483
|
+
*/
|
|
484
|
+
function isRetryableBeginError(err) {
|
|
485
|
+
const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
|
|
486
|
+
return (msg.includes("within a transaction") ||
|
|
487
|
+
msg.includes("database is locked") ||
|
|
488
|
+
msg.includes("database table is locked"));
|
|
489
|
+
}
|
|
490
|
+
const WITH_IMMEDIATE_TX_MAX_ATTEMPTS = 5;
|
|
491
|
+
/** Portable synchronous sleep (works under both Bun and Node). */
|
|
492
|
+
function sleepSyncMs(ms) {
|
|
493
|
+
if (ms <= 0)
|
|
494
|
+
return;
|
|
495
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
496
|
+
}
|
|
472
497
|
export function withImmediateTransaction(db, fn) {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
const result = fn();
|
|
476
|
-
db.exec("COMMIT");
|
|
477
|
-
return result;
|
|
478
|
-
}
|
|
479
|
-
catch (err) {
|
|
498
|
+
let lastBeginErr;
|
|
499
|
+
for (let attempt = 1; attempt <= WITH_IMMEDIATE_TX_MAX_ATTEMPTS; attempt++) {
|
|
480
500
|
try {
|
|
481
|
-
db.exec("
|
|
501
|
+
db.exec("BEGIN IMMEDIATE");
|
|
482
502
|
}
|
|
483
|
-
catch {
|
|
484
|
-
|
|
503
|
+
catch (err) {
|
|
504
|
+
lastBeginErr = err;
|
|
505
|
+
if (isRetryableBeginError(err) && attempt < WITH_IMMEDIATE_TX_MAX_ATTEMPTS) {
|
|
506
|
+
// Clear any phantom/stale transaction left by the contended BEGIN, then
|
|
507
|
+
// retry with a small backoff so concurrent writers serialize cleanly.
|
|
508
|
+
try {
|
|
509
|
+
db.exec("ROLLBACK");
|
|
510
|
+
}
|
|
511
|
+
catch {
|
|
512
|
+
// No active transaction to roll back — fine.
|
|
513
|
+
}
|
|
514
|
+
sleepSyncMs(2 ** (attempt - 1));
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
throw err;
|
|
518
|
+
}
|
|
519
|
+
try {
|
|
520
|
+
const result = fn();
|
|
521
|
+
db.exec("COMMIT");
|
|
522
|
+
return result;
|
|
523
|
+
}
|
|
524
|
+
catch (err) {
|
|
525
|
+
try {
|
|
526
|
+
db.exec("ROLLBACK");
|
|
527
|
+
}
|
|
528
|
+
catch {
|
|
529
|
+
// Ignore rollback failures so the original error is preserved.
|
|
530
|
+
}
|
|
531
|
+
throw err; // a real error inside the transaction body — never retried.
|
|
485
532
|
}
|
|
486
|
-
throw err;
|
|
487
533
|
}
|
|
534
|
+
// Exhausted retries on transient begin failures.
|
|
535
|
+
throw lastBeginErr;
|
|
488
536
|
}
|
|
489
537
|
// ── task_history table helpers ───────────────────────────────────────────────
|
|
490
538
|
/**
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { VALID_HARNESS_IDS } from "../../core/config/config.js";
|
|
5
4
|
import { ConfigError } from "../../core/errors.js";
|
|
6
|
-
import { warn } from "../../core/warn.js";
|
|
7
5
|
import { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles.js";
|
|
8
6
|
/**
|
|
9
7
|
* Default hard timeout for an agent CLI (60s — matches the value used in
|
|
@@ -41,7 +39,12 @@ export function resolveAgentProfile(name, overrides) {
|
|
|
41
39
|
stdio: base.stdio,
|
|
42
40
|
env: base.env,
|
|
43
41
|
envPassthrough: base.envPassthrough,
|
|
44
|
-
|
|
42
|
+
// Honor a user-configured `profiles.agent.<name>.timeoutMs` override; fall
|
|
43
|
+
// back to the built-in profile's value. (Previously always used base, so
|
|
44
|
+
// the documented config override was silently ignored — callers had to pass
|
|
45
|
+
// a CLI flag like `--timeout-ms`.) runAgent (spawn.ts) reads profile.timeoutMs
|
|
46
|
+
// when no per-call timeout is supplied, so this makes the config knob work.
|
|
47
|
+
timeoutMs: overrides.timeoutMs ?? base.timeoutMs,
|
|
45
48
|
parseOutput: base.parseOutput,
|
|
46
49
|
...(sdkMode ? { sdkMode: true } : {}),
|
|
47
50
|
model: overrides.model ?? base.model,
|
|
@@ -134,53 +137,3 @@ export function listResolvedAgentProfiles(config) {
|
|
|
134
137
|
}
|
|
135
138
|
return resolved;
|
|
136
139
|
}
|
|
137
|
-
/**
|
|
138
|
-
* Parse the v2 `profiles.agent` map (AgentProfileConfigV2 shape with required
|
|
139
|
-
* `platform` field). Returns a map of profile name → AgentProfileConfigV2.
|
|
140
|
-
*/
|
|
141
|
-
export function parseAgentProfilesMapV2(value) {
|
|
142
|
-
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
143
|
-
return undefined;
|
|
144
|
-
const out = {};
|
|
145
|
-
// Derives from the canonical harness-id source of truth (#565).
|
|
146
|
-
const VALID_PLATFORMS = VALID_HARNESS_IDS;
|
|
147
|
-
for (const [name, raw] of Object.entries(value)) {
|
|
148
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
149
|
-
warn(`[akm] Ignoring profiles.agent["${name}"]: expected an object.`);
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
const obj = raw;
|
|
153
|
-
if (!VALID_PLATFORMS.includes(obj.platform)) {
|
|
154
|
-
warn(`[akm] Ignoring profiles.agent["${name}"]: missing or invalid "platform" (must be one of: ${VALID_PLATFORMS.join(", ")}).`);
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
const profile = {
|
|
158
|
-
platform: obj.platform,
|
|
159
|
-
};
|
|
160
|
-
if (typeof obj.bin === "string" && obj.bin.trim())
|
|
161
|
-
profile.bin = obj.bin.trim();
|
|
162
|
-
if (Array.isArray(obj.args) && obj.args.every((a) => typeof a === "string")) {
|
|
163
|
-
profile.args = obj.args;
|
|
164
|
-
}
|
|
165
|
-
if (typeof obj.workspace === "string" && obj.workspace.trim())
|
|
166
|
-
profile.workspace = obj.workspace.trim();
|
|
167
|
-
if (typeof obj.model === "string" && obj.model.trim())
|
|
168
|
-
profile.model = obj.model.trim();
|
|
169
|
-
out[name] = profile;
|
|
170
|
-
}
|
|
171
|
-
return Object.keys(out).length > 0 ? out : undefined;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Stub kept for source-compat with callers that previously used the v1 agent
|
|
175
|
-
* config parser. After 0.8.0 there is no separate `agent` block to parse — the
|
|
176
|
-
* loaded `AkmConfig` already carries the agent data on `profiles.agent` and
|
|
177
|
-
* `defaults.agent`. This function is a no-op alias for those callers.
|
|
178
|
-
*
|
|
179
|
-
* @deprecated v0.8.0 — the unified `AkmConfig` IS the agent config. Use the
|
|
180
|
-
* profile/defaults accessors above instead.
|
|
181
|
-
*/
|
|
182
|
-
export function parseAgentConfig(_value) {
|
|
183
|
-
// No-op: there is no separate agent block in 0.8.0. Callers should pass
|
|
184
|
-
// their loaded `AkmConfig` directly to `requireAgentProfile` etc.
|
|
185
|
-
return undefined;
|
|
186
|
-
}
|