akm-cli 0.9.25-alpha.1 → 0.9.25-alpha.2

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 (56) hide show
  1. package/CHANGELOG.md +159 -280
  2. package/dist/cli.js +1 -1
  3. package/dist/commands/improve/consolidate/pair-pass.js +1 -0
  4. package/dist/commands/improve/consolidate.js +7 -2
  5. package/dist/commands/improve/execution.js +2 -3
  6. package/dist/commands/improve/extract.js +1 -0
  7. package/dist/commands/improve/improve-cli.js +33 -1
  8. package/dist/commands/improve/loop-stages.js +3 -0
  9. package/dist/commands/improve/reflect-noise.js +125 -0
  10. package/dist/commands/improve/reflect.js +13 -16
  11. package/dist/commands/improve/retrieval-gate.js +7 -2
  12. package/dist/commands/improve/stage.js +31 -39
  13. package/dist/commands/proposal/drain.js +4 -7
  14. package/dist/commands/proposal/propose.js +2 -11
  15. package/dist/commands/proposal/validators/proposal-quality-validators.js +4 -2
  16. package/dist/commands/read/search-cli.js +0 -38
  17. package/dist/core/config/schema/engines.js +15 -33
  18. package/dist/core/config/schema/improve-processes.js +16 -0
  19. package/dist/core/redaction.js +4 -0
  20. package/dist/core/spawn-env.js +25 -0
  21. package/dist/core/structured.js +1 -1
  22. package/dist/execution/source.js +8 -12
  23. package/dist/integrations/agent/config.js +1 -3
  24. package/dist/integrations/agent/engine-resolution.js +0 -3
  25. package/dist/integrations/agent/execution.js +14 -13
  26. package/dist/integrations/agent/index.js +1 -1
  27. package/dist/integrations/agent/model-map.js +15 -16
  28. package/dist/integrations/agent/profiles.js +2 -2
  29. package/dist/integrations/agent/prompts.js +3 -39
  30. package/dist/integrations/agent/request-lowering.js +9 -7
  31. package/dist/integrations/agent/runner-dispatch.js +25 -31
  32. package/dist/integrations/harnesses/aider/agent-builder.js +1 -2
  33. package/dist/integrations/harnesses/amazonq/agent-builder.js +1 -2
  34. package/dist/integrations/harnesses/claude/agent-builder.js +4 -16
  35. package/dist/integrations/harnesses/codex/agent-builder.js +1 -2
  36. package/dist/integrations/harnesses/ids.js +10 -16
  37. package/dist/integrations/harnesses/opencode/agent-builder.js +14 -24
  38. package/dist/integrations/harnesses/opencode/model-config.js +15 -62
  39. package/dist/integrations/harnesses/opencode/model-work-agent.js +71 -36
  40. package/dist/integrations/harnesses/opencode-sdk/harness.js +2 -6
  41. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +32 -90
  42. package/dist/integrations/harnesses/openhands/agent-builder.js +1 -2
  43. package/dist/integrations/harnesses/pi/agent-builder.js +1 -2
  44. package/dist/llm/feature-gate.js +2 -5
  45. package/dist/llm/index-passes.js +2 -2
  46. package/dist/llm/structured-call.js +5 -5
  47. package/dist/output/shapes/passthrough.js +1 -0
  48. package/dist/scripts/akm-migrate-node.js +170 -194
  49. package/dist/scripts/akm-migrate.js +170 -194
  50. package/dist/workflows/exec/unit-dispatch.js +4 -13
  51. package/docs/reference/cli.md +12 -7
  52. package/docs/reference/configuration.md +78 -82
  53. package/docs/reference/data-and-telemetry.md +2 -3
  54. package/docs/reference/workflow-schema.md +6 -9
  55. package/package.json +1 -1
  56. package/schemas/akm-config.json +108 -36
@@ -28364,6 +28364,7 @@ var PASSTHROUGH_COMMANDS = [
28364
28364
  "extract",
28365
28365
  "health",
28366
28366
  "improve",
28367
+ "improve-judge",
28367
28368
  "improve-report",
28368
28369
  "import",
28369
28370
  "index",
@@ -34782,25 +34783,21 @@ var coerce = {
34782
34783
  };
34783
34784
  var NEVER = INVALID;
34784
34785
  // src/integrations/harnesses/ids.ts
34785
- var OPENCODE_INFERENCE = ["temperature", "maxTokens", "contextLength", "enableThinking", "reasoningEffort"];
34786
34786
  var HARNESS_ID_TABLE = [
34787
- { id: "opencode", agentDispatch: true, enforcesModelWorkTools: true, inference: OPENCODE_INFERENCE },
34788
- { id: "claude", agentDispatch: true, enforcesModelWorkTools: true, inference: ["reasoningEffort"] },
34789
- { id: "opencode-sdk", agentDispatch: true, enforcesModelWorkTools: true, inference: OPENCODE_INFERENCE },
34790
- { id: "codex", agentDispatch: true, enforcesModelWorkTools: false, inference: [] },
34791
- { id: "copilot", agentDispatch: true, enforcesModelWorkTools: false, inference: [] },
34792
- { id: "pi", agentDispatch: true, enforcesModelWorkTools: false, inference: [] },
34793
- { id: "gemini", agentDispatch: true, enforcesModelWorkTools: false, inference: [] },
34794
- { id: "aider", agentDispatch: true, enforcesModelWorkTools: false, inference: [] },
34795
- { id: "amazonq", agentDispatch: true, enforcesModelWorkTools: false, inference: [] },
34796
- { id: "openhands", agentDispatch: true, enforcesModelWorkTools: false, inference: [] }
34787
+ { id: "opencode", agentDispatch: true, enforcesModelWorkTools: true },
34788
+ { id: "claude", agentDispatch: true, enforcesModelWorkTools: true },
34789
+ { id: "opencode-sdk", agentDispatch: true, enforcesModelWorkTools: true },
34790
+ { id: "codex", agentDispatch: true, enforcesModelWorkTools: false },
34791
+ { id: "copilot", agentDispatch: true, enforcesModelWorkTools: false },
34792
+ { id: "pi", agentDispatch: true, enforcesModelWorkTools: false },
34793
+ { id: "gemini", agentDispatch: true, enforcesModelWorkTools: false },
34794
+ { id: "aider", agentDispatch: true, enforcesModelWorkTools: false },
34795
+ { id: "amazonq", agentDispatch: true, enforcesModelWorkTools: false },
34796
+ { id: "openhands", agentDispatch: true, enforcesModelWorkTools: false }
34797
34797
  ];
34798
34798
  var VALID_HARNESS_IDS = Object.freeze(HARNESS_ID_TABLE.map((h) => h.id));
34799
34799
  var HARNESS_AGENT_DISPATCH_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.agentDispatch).map((h) => h.id));
34800
34800
  var HARNESS_MODEL_WORK_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.enforcesModelWorkTools).map((h) => h.id));
34801
- function harnessInferenceKeys(platform) {
34802
- return HARNESS_ID_TABLE.find((h) => h.id === platform)?.inference ?? [];
34803
- }
34804
34801
 
34805
34802
  // src/core/extra-params.ts
34806
34803
  var EXTRA_PARAMS_PROTECTED_TOP_LEVEL_KEYS = [
@@ -35105,13 +35102,6 @@ var LlmEngineSchema = exports_external.object({
35105
35102
  });
35106
35103
  }
35107
35104
  });
35108
- var AGENT_INFERENCE_KEYS = [
35109
- "temperature",
35110
- "maxTokens",
35111
- "contextLength",
35112
- "enableThinking",
35113
- "reasoningEffort"
35114
- ];
35115
35105
  var AgentEngineSchema = exports_external.object({
35116
35106
  kind: exports_external.literal("agent"),
35117
35107
  platform: AgentPlatformSchema.refine((platform) => HARNESS_AGENT_DISPATCH_IDS.has(platform), {
@@ -35122,27 +35112,25 @@ var AgentEngineSchema = exports_external.object({
35122
35112
  workspace: nonEmptyString.optional(),
35123
35113
  model: nonEmptyString.optional(),
35124
35114
  timeoutMs: timeoutMsField,
35125
- llmEngine: engineName.optional(),
35126
- temperature: exports_external.number().finite().optional(),
35127
- maxTokens: positiveInt.optional(),
35128
- contextLength: positiveInt.optional(),
35129
- enableThinking: exports_external.boolean().optional(),
35130
- reasoningEffort: nonEmptyString.optional()
35115
+ llmEngine: engineName.optional()
35131
35116
  }).passthrough().superRefine((value, ctx) => {
35132
- for (const key of ["provider", "endpoint", "apiKey", "apiKeyFile", "concurrency", "extraParams", "modelAliases"]) {
35117
+ for (const key of [
35118
+ "provider",
35119
+ "endpoint",
35120
+ "apiKey",
35121
+ "apiKeyFile",
35122
+ "temperature",
35123
+ "maxTokens",
35124
+ "concurrency",
35125
+ "extraParams",
35126
+ "contextLength",
35127
+ "enableThinking",
35128
+ "reasoningEffort",
35129
+ "modelAliases"
35130
+ ]) {
35133
35131
  if (key in value)
35134
35132
  ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: [key], message: `${key} is not valid on an agent engine` });
35135
35133
  }
35136
- const translated = harnessInferenceKeys(value.platform);
35137
- for (const key of AGENT_INFERENCE_KEYS) {
35138
- if (key in value && !translated.includes(key)) {
35139
- ctx.addIssue({
35140
- code: exports_external.ZodIssueCode.custom,
35141
- path: [key],
35142
- message: `${key} is not valid on a ${value.platform} engine: ${translated.length > 0 ? `the platform translates only ${translated.join(", ")}` : "the platform translates no inference fields"}`
35143
- });
35144
- }
35145
- }
35146
35134
  if (value.platform !== "opencode-sdk" && value.llmEngine !== undefined) {
35147
35135
  ctx.addIssue({
35148
35136
  code: exports_external.ZodIssueCode.custom,
@@ -35206,6 +35194,11 @@ var clsField = exports_external.object({
35206
35194
  }).passthrough().optional();
35207
35195
  var fidelityCheckField = exports_external.object({ enabled: exports_external.boolean().optional() }).passthrough().optional();
35208
35196
  var lowValueFilterField = exports_external.object({ enabled: exports_external.boolean().optional() }).passthrough().optional();
35197
+ var defectFilterField = exports_external.object({
35198
+ placeholders: exports_external.array(nonEmptyString).optional(),
35199
+ metaCommentary: exports_external.array(nonEmptyString).optional(),
35200
+ frontmatterKeys: exports_external.array(nonEmptyString).optional()
35201
+ }).passthrough().optional();
35209
35202
  var extractTriageGateField = exports_external.object({
35210
35203
  enabled: exports_external.boolean().optional(),
35211
35204
  minScore: exports_external.number().min(0).optional()
@@ -35228,7 +35221,8 @@ var REFLECT_PROCESS_FIELDS = {
35228
35221
  excludeRefPrefixes: excludeRefPrefixesField,
35229
35222
  limit: processLimitField,
35230
35223
  qualityGate: qualityGateField,
35231
- lowValueFilter: lowValueFilterField
35224
+ lowValueFilter: lowValueFilterField,
35225
+ defectFilter: defectFilterField
35232
35226
  };
35233
35227
  var DISTILL_PROCESS_FIELDS = {
35234
35228
  allowedTypes: allowedTypesField,
@@ -36950,6 +36944,10 @@ var ENV_PASSTHROUGH_REDACTION_POLICY = {
36950
36944
  OPENCODE_CONFIG: "path",
36951
36945
  CLAUDE_CONFIG: "path",
36952
36946
  CODEX_CONFIG: "path",
36947
+ XDG_CONFIG_HOME: "path",
36948
+ XDG_DATA_HOME: "path",
36949
+ XDG_CACHE_HOME: "path",
36950
+ XDG_STATE_HOME: "path",
36953
36951
  AWS_PROFILE: "identifier",
36954
36952
  AWS_REGION: "identifier",
36955
36953
  LLM_MODEL: "identifier",
@@ -39002,10 +39000,7 @@ import { createHash as createHash3 } from "crypto";
39002
39000
 
39003
39001
  // src/execution/source.ts
39004
39002
  var EXECUTION_SOURCE_SCHEMA_VERSION = 1;
39005
- var MODEL_WORK_TOOLS = Object.freeze(["read", "edit", "akm search", "akm show"]);
39006
- function isModelWorkTools(tools) {
39007
- return Array.isArray(tools) && tools.length === MODEL_WORK_TOOLS.length && tools.every((tool, index) => tool === MODEL_WORK_TOOLS[index]);
39008
- }
39003
+ var MODEL_WORK_POLICY_ID = "model-work";
39009
39004
  function requireRecord(value, path18) {
39010
39005
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
39011
39006
  throw new TypeError(`${path18} must be an object`);
@@ -51040,8 +51035,9 @@ function extensionFields(request) {
51040
51035
  ];
51041
51036
  }
51042
51037
  function createAgentRequestLowerer(options) {
51043
- return (profile, request) => {
51044
- const supportedInference = new Set(typeof options.inference === "function" ? options.inference(profile, request) : options.inference ?? []);
51038
+ const supportedInference = new Set(options.inference ?? []);
51039
+ return (_profile, request) => {
51040
+ const modelWork = request.authorization.policy?.id === MODEL_WORK_POLICY_ID;
51045
51041
  const notices = [];
51046
51042
  const skip = (field) => {
51047
51043
  notices.push(untranslated(options.adapter, field));
@@ -51082,18 +51078,18 @@ function createAgentRequestLowerer(options) {
51082
51078
  if (Object.hasOwn(request, "inference")) {
51083
51079
  dispatch.inference = request.inference ?? null;
51084
51080
  for (const key of Object.keys(request.inference ?? {}).sort()) {
51085
- if (!supportedInference.has(key))
51081
+ if (!(modelWork && supportedInference.has(key)))
51086
51082
  skip(`inference.${key}`);
51087
51083
  }
51088
51084
  }
51089
- if (isModelWorkTools(request.tools)) {
51090
- if (!options.modelWorkTools) {
51085
+ if (modelWork) {
51086
+ if (!HARNESS_MODEL_WORK_IDS.has(options.adapter)) {
51091
51087
  throw new ConfigError(`The ${options.adapter} transport cannot enforce the model-work tool policy.`, "INVALID_CONFIG_FILE");
51092
51088
  }
51093
51089
  if (dispatch.agent) {
51094
51090
  throw new ConfigError(`The ${options.adapter} transport cannot run native agent ${JSON.stringify(dispatch.agent)} under the model-work tool policy.`, "INVALID_CONFIG_FILE");
51095
51091
  }
51096
- dispatch.tools = request.tools;
51092
+ dispatch.modelWork = true;
51097
51093
  } else if (request.tools !== undefined) {
51098
51094
  if (hasToolSelection(request.tools) && !translatesTools(options.tools, request.tools)) {
51099
51095
  throw new ConfigError(`The ${options.adapter} transport cannot enforce the resolved tool policy.`, "INVALID_CONFIG_FILE");
@@ -51289,12 +51285,10 @@ var claudeBuilder = {
51289
51285
  adapter: "claude",
51290
51286
  personaChannel: "native",
51291
51287
  nativeAgentSelector: true,
51292
- tools: "all",
51293
- modelWorkTools: true,
51294
- inference: ["reasoningEffort"]
51288
+ tools: "all"
51295
51289
  }),
51296
51290
  build(profile, req) {
51297
- const modelWork = isModelWorkTools(req.tools);
51291
+ const modelWork = req.modelWork === true;
51298
51292
  const args = modelWork ? [...MODEL_WORK_CLAUDE_FLAGS] : [...profile.args];
51299
51293
  if (req.agent) {
51300
51294
  args.push("--agent", req.agent);
@@ -51310,10 +51304,7 @@ var claudeBuilder = {
51310
51304
  if (model)
51311
51305
  args.push("--model", model);
51312
51306
  }
51313
- const effort = req.inference?.reasoningEffort;
51314
- if (typeof effort === "string" && effort.length > 0)
51315
- args.push("--effort", effort);
51316
- if (req.tools && !modelWork) {
51307
+ if (req.tools) {
51317
51308
  args.push("--allowedTools", normalizeTools(req.tools));
51318
51309
  }
51319
51310
  if (req.schema) {
@@ -52075,101 +52066,87 @@ class GeminiHarness extends BaseHarness {
52075
52066
  }
52076
52067
 
52077
52068
  // src/integrations/harnesses/opencode/model-config.ts
52069
+ var MODEL_WORK_AGENT_INFERENCE = ["temperature", "reasoningEffort", "enableThinking"];
52078
52070
  var isPositiveInteger = (value) => typeof value === "number" && Number.isInteger(value) && value > 0;
52079
- function carriedInference(inference) {
52080
- const carried = {};
52071
+ function opencodeInferenceConfig(inference, modelWork) {
52081
52072
  const { temperature, reasoningEffort, enableThinking, maxTokens, contextLength } = inference ?? {};
52073
+ const options = {};
52082
52074
  if (typeof temperature === "number" && Number.isFinite(temperature))
52083
- carried.temperature = temperature;
52075
+ options.temperature = temperature;
52084
52076
  if (typeof reasoningEffort === "string" && reasoningEffort.length > 0)
52085
- carried.reasoningEffort = reasoningEffort;
52086
- if (typeof enableThinking === "boolean")
52087
- carried.enableThinking = enableThinking;
52088
- const limit = isPositiveInteger(maxTokens) && isPositiveInteger(contextLength);
52089
- if (limit)
52090
- carried.limit = { context: contextLength, output: maxTokens };
52091
- const keys = [
52092
- ["temperature", carried.temperature !== undefined, temperature],
52093
- ["reasoningEffort", carried.reasoningEffort !== undefined, reasoningEffort],
52094
- ["enableThinking", carried.enableThinking !== undefined, enableThinking],
52095
- ["maxTokens", limit, maxTokens],
52096
- ["contextLength", limit, contextLength]
52097
- ].filter(([, isCarried, value]) => isCarried || value === null).map(([key]) => key);
52098
- return { carried, keys };
52099
- }
52100
- function splitOpencodeModel(model) {
52101
- const slash = model.indexOf("/");
52102
- if (slash <= 0 || slash === model.length - 1)
52103
- return;
52104
- return { providerID: model.slice(0, slash), modelID: model.slice(slash + 1) };
52105
- }
52106
- function opencodeCarriedKeys(attachable, inference, modelWork) {
52107
- const { keys } = carriedInference(inference);
52108
- if (attachable)
52109
- return keys;
52110
- return modelWork ? keys.filter((key) => key !== "maxTokens" && key !== "contextLength") : [];
52111
- }
52112
- function opencodeInferenceConfig(inference, modelWork) {
52113
- const { carried } = carriedInference(inference);
52114
- const options = {};
52115
- if (carried.temperature !== undefined)
52116
- options.temperature = carried.temperature;
52117
- if (carried.reasoningEffort !== undefined)
52118
- options.reasoningEffort = carried.reasoningEffort;
52119
- if (carried.enableThinking !== undefined) {
52120
- options.chat_template_kwargs = { enable_thinking: carried.enableThinking };
52121
- options.enable_thinking = carried.enableThinking;
52077
+ options.reasoningEffort = reasoningEffort;
52078
+ if (typeof enableThinking === "boolean") {
52079
+ options.chat_template_kwargs = { enable_thinking: enableThinking };
52080
+ options.enable_thinking = enableThinking;
52122
52081
  }
52123
52082
  const hasOptions = Object.keys(options).length > 0;
52124
52083
  return {
52125
52084
  entry: {
52126
52085
  ...hasOptions && !modelWork ? { options } : {},
52127
- ...carried.limit ? { limit: { ...carried.limit } } : {}
52086
+ ...isPositiveInteger(maxTokens) && isPositiveInteger(contextLength) ? { limit: { context: contextLength, output: maxTokens } } : {}
52128
52087
  },
52129
52088
  ...hasOptions && modelWork ? { agentOptions: options } : {}
52130
52089
  };
52131
52090
  }
52132
- function opencodeModelConfig(model, entry) {
52133
- const target = model === undefined ? undefined : splitOpencodeModel(model);
52134
- if (!target || Object.keys(entry).length === 0)
52135
- return;
52136
- return { provider: { [target.providerID]: { models: { [target.modelID]: entry } } } };
52137
- }
52138
52091
 
52139
52092
  // src/integrations/harnesses/opencode/model-work-agent.ts
52093
+ import path43 from "path";
52140
52094
  var MODEL_WORK_OPENCODE_AGENT = "akm-model-work";
52141
- var MODEL_WORK_STEPS = 8;
52142
52095
  var MODEL_WORK_PROMPT = "You do one bounded task for akm. Use tools only to check what the task needs, never repeat a tool call, and reply with exactly what the task asks for.";
52143
- var MODEL_WORK_PERMISSION = {
52144
- "*": "deny",
52145
- read: "allow",
52146
- edit: "allow",
52147
- external_directory: "deny",
52148
- bash: "deny",
52149
- doom_loop: "deny",
52150
- glob: "deny",
52151
- grep: "deny",
52152
- list: "deny",
52153
- lsp: "deny",
52154
- question: "deny",
52155
- skill: "deny",
52156
- task: "deny",
52157
- todowrite: "deny",
52158
- webfetch: "deny",
52159
- websearch: "deny"
52160
- };
52096
+ function modelWorkPermission(stash) {
52097
+ return {
52098
+ "*": "deny",
52099
+ read: "allow",
52100
+ grep: "allow",
52101
+ glob: "allow",
52102
+ edit: { "*": "allow", ...stash ? { [`${stash.slice(1)}/*`]: "deny" } : {} },
52103
+ external_directory: {
52104
+ ...stash ? { [`${stash}/*`]: "allow" } : {},
52105
+ "~/.local/share/opencode/tool-output/*": "deny"
52106
+ },
52107
+ akm_search: "allow",
52108
+ akm_show: "allow",
52109
+ akm_feedback: "deny",
52110
+ akm_remember: "deny",
52111
+ akm_curate: "deny",
52112
+ bash: "deny",
52113
+ doom_loop: "deny",
52114
+ list: "deny",
52115
+ lsp: "deny",
52116
+ question: "deny",
52117
+ skill: "deny",
52118
+ task: "deny",
52119
+ todowrite: "deny",
52120
+ webfetch: "deny",
52121
+ websearch: "deny"
52122
+ };
52123
+ }
52124
+ function modelWorkPluginEnv() {
52125
+ return {
52126
+ AKM_AUTO_CURATE: "0",
52127
+ AKM_AUTO_LEARNING: "0",
52128
+ AKM_AUTO_SKILL_PROPOSALS: "0",
52129
+ AKM_WRITE_GATE: "off",
52130
+ XDG_STATE_HOME: path43.join(getStateDir(), "opencode-model-work"),
52131
+ ...process.platform === "win32" ? {} : { AKM_OPENCODE_CLI: "/bin/true" }
52132
+ };
52133
+ }
52161
52134
  function modelWorkOpencodeConfig(options) {
52135
+ let stash;
52136
+ try {
52137
+ stash = resolveStashDir();
52138
+ } catch {}
52139
+ const permission = modelWorkPermission(stash);
52162
52140
  return {
52163
- permission: { ...MODEL_WORK_PERMISSION },
52141
+ permission: { ...permission },
52164
52142
  compaction: { auto: false },
52165
52143
  agent: {
52166
52144
  [MODEL_WORK_OPENCODE_AGENT]: {
52167
52145
  mode: "primary",
52168
52146
  description: "akm unattended model work: read and edit inside its working directory only.",
52169
52147
  prompt: MODEL_WORK_PROMPT,
52170
- steps: MODEL_WORK_STEPS,
52171
52148
  ...options ? { options } : {},
52172
- permission: { ...MODEL_WORK_PERMISSION }
52149
+ permission: { ...permission }
52173
52150
  }
52174
52151
  }
52175
52152
  };
@@ -52184,18 +52161,12 @@ var opencodeBuilder = {
52184
52161
  personaChannel: "prompt",
52185
52162
  nativeAgentSelector: true,
52186
52163
  tools: "none",
52187
- modelWorkTools: true,
52188
- inference: (profile, request) => {
52189
- const model = request.model?.resolved ?? modelFromArgs(profile.args);
52190
- return opencodeCarriedKeys(model !== undefined && splitOpencodeModel(model) !== undefined, request.inference, isModelWorkTools(request.tools));
52191
- }
52164
+ inference: MODEL_WORK_AGENT_INFERENCE
52192
52165
  }),
52193
52166
  build(profile, req) {
52194
- const model = req.model ?? modelFromArgs(profile.args);
52195
- const modelWork = isModelWorkTools(req.tools);
52196
- const { entry, agentOptions } = opencodeInferenceConfig(req.inference, modelWork);
52197
- const modelConfig = opencodeModelConfig(model, entry);
52198
- if (modelWork) {
52167
+ if (req.modelWork) {
52168
+ const model = req.model ?? modelFromArgs(profile.args);
52169
+ const { agentOptions } = opencodeInferenceConfig(req.inference, true);
52199
52170
  return {
52200
52171
  argv: [
52201
52172
  profile.bin,
@@ -52206,7 +52177,10 @@ var opencodeBuilder = {
52206
52177
  "--",
52207
52178
  req.prompt
52208
52179
  ],
52209
- env: { OPENCODE_CONFIG_CONTENT: JSON.stringify({ ...modelWorkOpencodeConfig(agentOptions), ...modelConfig }) }
52180
+ env: {
52181
+ ...modelWorkPluginEnv(),
52182
+ OPENCODE_CONFIG_CONTENT: JSON.stringify(modelWorkOpencodeConfig(agentOptions))
52183
+ }
52210
52184
  };
52211
52185
  }
52212
52186
  const args = req.model ? [] : [...profile.args];
@@ -52231,23 +52205,20 @@ var opencodeBuilder = {
52231
52205
  }
52232
52206
  args.push("--");
52233
52207
  args.push(req.prompt);
52234
- return {
52235
- argv: [profile.bin, ...args],
52236
- ...modelConfig ? { env: { OPENCODE_CONFIG_CONTENT: JSON.stringify(modelConfig) } } : {}
52237
- };
52208
+ return { argv: [profile.bin, ...args] };
52238
52209
  }
52239
52210
  };
52240
52211
 
52241
52212
  // src/integrations/harnesses/opencode/session-log.ts
52242
52213
  import fs37 from "fs";
52243
52214
  import os6 from "os";
52244
- import path44 from "path";
52215
+ import path45 from "path";
52245
52216
 
52246
52217
  // src/storage/sqlite-read-snapshot.ts
52247
52218
  import { spawnSync as spawnSync5 } from "child_process";
52248
52219
  import fs36 from "fs";
52249
52220
  import os5 from "os";
52250
- import path43 from "path";
52221
+ import path44 from "path";
52251
52222
  var SNAPSHOT_MAX_ATTEMPTS = 8;
52252
52223
  var SNAPSHOT_BACKOFF_MS = 25;
52253
52224
 
@@ -52312,8 +52283,8 @@ function copyFileOutsideThisProcess(source, destination) {
52312
52283
  function openSqliteReadSnapshot(dbPath) {
52313
52284
  if (!pathExists(dbPath))
52314
52285
  return;
52315
- const snapshotDir = fs36.mkdtempSync(path43.join(os5.tmpdir(), "akm-sqlite-read-"));
52316
- const snapshotPath = path43.join(snapshotDir, "snapshot.db");
52286
+ const snapshotDir = fs36.mkdtempSync(path44.join(os5.tmpdir(), "akm-sqlite-read-"));
52287
+ const snapshotPath = path44.join(snapshotDir, "snapshot.db");
52317
52288
  let db;
52318
52289
  try {
52319
52290
  let copied = false;
@@ -52383,9 +52354,9 @@ function openSqliteReadSnapshot(dbPath) {
52383
52354
  // src/integrations/harnesses/opencode/session-log.ts
52384
52355
  function getOpenCodeBaseDir() {
52385
52356
  if (process.platform === "darwin") {
52386
- return path44.join(os6.homedir(), "Library", "Application Support", "opencode");
52357
+ return path45.join(os6.homedir(), "Library", "Application Support", "opencode");
52387
52358
  }
52388
- return path44.join(os6.homedir(), ".local", "share", "opencode");
52359
+ return path45.join(os6.homedir(), ".local", "share", "opencode");
52389
52360
  }
52390
52361
  var OPENCODE_DB_FILENAME = "opencode.db";
52391
52362
 
@@ -52396,7 +52367,7 @@ class OpenCodeProvider extends AbstractSessionLogProvider {
52396
52367
  return this.#dbPath(this.#baseDir);
52397
52368
  }
52398
52369
  #dbPath(base) {
52399
- return path44.join(base, OPENCODE_DB_FILENAME);
52370
+ return path45.join(base, OPENCODE_DB_FILENAME);
52400
52371
  }
52401
52372
  listSessions(input = {}) {
52402
52373
  const base = input.location ?? this.#baseDir;
@@ -52534,8 +52505,7 @@ class OpencodeSdkHarness extends BaseHarness {
52534
52505
  personaChannel: "native",
52535
52506
  nativeAgentSelector: true,
52536
52507
  tools: "sdk",
52537
- modelWorkTools: true,
52538
- inference: (_profile, request) => opencodeCarriedKeys(Boolean(request.model?.resolved), request.inference, isModelWorkTools(request.tools))
52508
+ inference: MODEL_WORK_AGENT_INFERENCE
52539
52509
  })
52540
52510
  };
52541
52511
  capabilities = caps({
@@ -52812,11 +52782,6 @@ var VALID_HARNESS_IDS2 = Object.freeze(HARNESS_REGISTRY.map((h) => h.id));
52812
52782
  var SESSION_LOG_HARNESSES = HARNESS_REGISTRY.filter(isSessionLogHarness);
52813
52783
  var AGENT_DISPATCH_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.agentDispatch);
52814
52784
 
52815
- // src/integrations/agent/model-map.ts
52816
- var ENGINE_KEY_PATTERN = new RegExp(ENGINE_NAME_PATTERN_SOURCE);
52817
- var RESERVED_MAP_KEYS = new Set(["__proto__", "constructor", "prototype", "tostring"]);
52818
- var PROFILE_FIELD_KEYS = new Set(["model", "inference", "engine"]);
52819
-
52820
52785
  // src/core/spawn-env.ts
52821
52786
  var COMMON_SPAWN_ENV_PASSTHROUGH = [
52822
52787
  "HOME",
@@ -52828,6 +52793,12 @@ var COMMON_SPAWN_ENV_PASSTHROUGH = [
52828
52793
  "TMPDIR",
52829
52794
  "AKM_EVENT_SOURCE"
52830
52795
  ];
52796
+ var XDG_BASE_DIR_ENV_PASSTHROUGH = [
52797
+ "XDG_CONFIG_HOME",
52798
+ "XDG_DATA_HOME",
52799
+ "XDG_CACHE_HOME",
52800
+ "XDG_STATE_HOME"
52801
+ ];
52831
52802
  var supplementedPaths = new Map;
52832
52803
 
52833
52804
  // src/integrations/agent/profiles.ts
@@ -52838,7 +52809,7 @@ var BUILTINS = {
52838
52809
  bin: "opencode",
52839
52810
  args: ["run"],
52840
52811
  stdio: "interactive",
52841
- envPassthrough: [...COMMON_PASSTHROUGH, "OPENCODE_API_KEY", "OPENCODE_CONFIG"],
52812
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENCODE_API_KEY", "OPENCODE_CONFIG", ...XDG_BASE_DIR_ENV_PASSTHROUGH],
52842
52813
  parseOutput: "text"
52843
52814
  },
52844
52815
  claude: {
@@ -52918,6 +52889,11 @@ var FALLBACK_ANNOUNCEMENT = `No engine is configured; falling back to \`${FALLBA
52918
52889
  var NO_ENGINE_MESSAGE_SUFFIX = `has no selected engine, and no usable \`${OPENCODE_SDK_SERVER_BIN}\` binary was found to fall back to.`;
52919
52890
  var NO_ENGINE_REMEDY = "Run `akm setup` to detect an installed agent, or set one explicitly: " + '`akm config set engines.claude \'{"kind":"agent","platform":"claude"}\'` ' + "then `akm config set defaults.engine claude`. " + `Installing the \`${OPENCODE_SDK_SERVER_BIN}\` binary also works ` + "(`npm i -g opencode-ai`) \u2014 akm falls back to it automatically.";
52920
52891
 
52892
+ // src/integrations/agent/model-map.ts
52893
+ var ENGINE_KEY_PATTERN = new RegExp(ENGINE_NAME_PATTERN_SOURCE);
52894
+ var RESERVED_MAP_KEYS = new Set(["__proto__", "constructor", "prototype", "tostring"]);
52895
+ var PROFILE_FIELD_KEYS = new Set(["model", "inference", "engine"]);
52896
+
52921
52897
  // src/storage/repositories/improve-ledger-repository.ts
52922
52898
  var LEDGER_REJECTION_WINDOW_DAYS = Object.freeze({
52923
52899
  reflect: 14,
@@ -53270,7 +53246,7 @@ Commands:
53270
53246
 
53271
53247
  // scripts/akm-migrate/migrate/dead-residue.ts
53272
53248
  import fs38 from "fs";
53273
- import path45 from "path";
53249
+ import path46 from "path";
53274
53250
  var DEAD_RESIDUE_PATHS = [
53275
53251
  { name: "proposals", reason: "superseded by the `proposals` table in $DATA/state.db (0.9.0)" },
53276
53252
  { prefix: "runs.archived-", reason: "orphaned archive of a directory that no longer exists" },
@@ -53292,7 +53268,7 @@ function dirSizeBytes(target) {
53292
53268
  return 0;
53293
53269
  }
53294
53270
  for (const entry of entries) {
53295
- const entryPath = path45.join(target, entry.name);
53271
+ const entryPath = path46.join(target, entry.name);
53296
53272
  if (entry.isDirectory()) {
53297
53273
  total += dirSizeBytes(entryPath);
53298
53274
  } else if (entry.isFile()) {
@@ -53310,15 +53286,15 @@ function sizeOf(target) {
53310
53286
  function hostResidue() {
53311
53287
  const data = getDataDir();
53312
53288
  const state = getStateDir();
53313
- const configDir = path45.dirname(getConfigPath());
53289
+ const configDir = path46.dirname(getConfigPath());
53314
53290
  const named = [
53315
- { absolutePath: path45.join(data, "txn"), reason: "filesystem transaction journals (removed in 0.9.17)" },
53316
- { absolutePath: path45.join(data, "txn-quarantine"), reason: "quarantined transaction journals (removed in 0.9.17)" },
53317
- { absolutePath: path45.join(data, "maintenance.barrier.lock"), reason: "maintenance barrier (removed in 0.9.17)" },
53318
- { absolutePath: path45.join(data, "maintenance-activities"), reason: "per-process activity registry (removed in 0.9.17)" },
53319
- { absolutePath: path45.join(state, "maintenance-activities"), reason: "per-process activity registry (removed in 0.9.17)" },
53320
- { absolutePath: path45.join(state, "version-reconcile.json"), reason: "startup reconcile stamp (removed in 0.9.17)" },
53321
- { absolutePath: path45.join(state, "locks", "version-reconcile.lock"), reason: "startup reconcile lock (removed in 0.9.17)" }
53291
+ { absolutePath: path46.join(data, "txn"), reason: "filesystem transaction journals (removed in 0.9.17)" },
53292
+ { absolutePath: path46.join(data, "txn-quarantine"), reason: "quarantined transaction journals (removed in 0.9.17)" },
53293
+ { absolutePath: path46.join(data, "maintenance.barrier.lock"), reason: "maintenance barrier (removed in 0.9.17)" },
53294
+ { absolutePath: path46.join(data, "maintenance-activities"), reason: "per-process activity registry (removed in 0.9.17)" },
53295
+ { absolutePath: path46.join(state, "maintenance-activities"), reason: "per-process activity registry (removed in 0.9.17)" },
53296
+ { absolutePath: path46.join(state, "version-reconcile.json"), reason: "startup reconcile stamp (removed in 0.9.17)" },
53297
+ { absolutePath: path46.join(state, "locks", "version-reconcile.lock"), reason: "startup reconcile lock (removed in 0.9.17)" }
53322
53298
  ];
53323
53299
  const found = [];
53324
53300
  const claimed = new Set;
@@ -53353,7 +53329,7 @@ function findSidecars(root2, depth, skip) {
53353
53329
  }
53354
53330
  const found = [];
53355
53331
  for (const entry of entries) {
53356
- const entryPath = path45.join(root2, entry.name);
53332
+ const entryPath = path46.join(root2, entry.name);
53357
53333
  if (entry.isFile() && entry.name.endsWith(".operations.sensitive"))
53358
53334
  found.push(entryPath);
53359
53335
  else if (entry.isDirectory() && depth > 0 && !skip.has(entryPath)) {
@@ -53366,7 +53342,7 @@ function findDeadResidueEntries(stashDir) {
53366
53342
  const host = hostResidue();
53367
53343
  if (stashDir === undefined)
53368
53344
  return host;
53369
- const akmDir = path45.join(stashDir, ".akm");
53345
+ const akmDir = path46.join(stashDir, ".akm");
53370
53346
  let names;
53371
53347
  try {
53372
53348
  names = fs38.readdirSync(akmDir);
@@ -53379,14 +53355,14 @@ function findDeadResidueEntries(stashDir) {
53379
53355
  for (const name of matches) {
53380
53356
  if (!names.includes(name))
53381
53357
  continue;
53382
- const absolutePath = path45.join(akmDir, name);
53358
+ const absolutePath = path46.join(akmDir, name);
53383
53359
  let sizeBytes;
53384
53360
  try {
53385
53361
  sizeBytes = sizeOf(absolutePath);
53386
53362
  } catch {
53387
53363
  continue;
53388
53364
  }
53389
- found.push({ relativePath: path45.join(".akm", name), absolutePath, sizeBytes, reason: spec.reason });
53365
+ found.push({ relativePath: path46.join(".akm", name), absolutePath, sizeBytes, reason: spec.reason });
53390
53366
  }
53391
53367
  }
53392
53368
  return found;
@@ -53412,16 +53388,16 @@ function removeDeadResidue(stashDir) {
53412
53388
  import { randomUUID as randomUUID3 } from "crypto";
53413
53389
  import fs40 from "fs";
53414
53390
  import os7 from "os";
53415
- import path48 from "path";
53391
+ import path49 from "path";
53416
53392
 
53417
53393
  // scripts/akm-migrate/migrate/task-files.ts
53418
53394
  import crypto4 from "crypto";
53419
53395
  import fs39 from "fs";
53420
- import path47 from "path";
53396
+ import path48 from "path";
53421
53397
 
53422
53398
  // src/tasks/source/task-to-v4.ts
53423
53399
  import crypto3 from "crypto";
53424
- import path46 from "path";
53400
+ import path47 from "path";
53425
53401
 
53426
53402
  // src/tasks/task-id.ts
53427
53403
  var VALID_TASK_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
@@ -54230,7 +54206,7 @@ function addSharedNonPromptOverrides(data, akm) {
54230
54206
  }
54231
54207
  function promptSourceKind(raw) {
54232
54208
  const trimmed = raw.trim();
54233
- if (trimmed.startsWith("./") || trimmed.startsWith("../") || path46.isAbsolute(trimmed) || /^[A-Za-z]:[\\/]/.test(trimmed)) {
54209
+ if (trimmed.startsWith("./") || trimmed.startsWith("../") || path47.isAbsolute(trimmed) || /^[A-Za-z]:[\\/]/.test(trimmed)) {
54234
54210
  return "file";
54235
54211
  }
54236
54212
  try {
@@ -54334,7 +54310,7 @@ function planV2DataToV4(input, data) {
54334
54310
  return blocked(input, "read-only-source", !input.writable ? "the owning source is not writable" : "the source file or publication directory is read-only");
54335
54311
  }
54336
54312
  try {
54337
- validateTaskId(path46.basename(input.filePath, ".yml"));
54313
+ validateTaskId(path47.basename(input.filePath, ".yml"));
54338
54314
  } catch (cause) {
54339
54315
  return blocked(input, "invalid-v2-task", causeMessage(cause));
54340
54316
  }
@@ -54479,7 +54455,7 @@ function taskToV4PlanFromOutcomes(outcomes) {
54479
54455
  for (let index = 1;index < files.length; index += 1) {
54480
54456
  const previous = files[index - 1];
54481
54457
  const current = files[index];
54482
- if (previous && current && path46.resolve(previous.filePath) === path46.resolve(current.filePath)) {
54458
+ if (previous && current && path47.resolve(previous.filePath) === path47.resolve(current.filePath)) {
54483
54459
  throw new Error(`duplicate task migration file path: ${current.filePath}`);
54484
54460
  }
54485
54461
  }
@@ -54491,8 +54467,8 @@ function migrationError(detail) {
54491
54467
  return new ConfigError(`Task migration failed: ${detail}`, "INVALID_CONFIG_FILE");
54492
54468
  }
54493
54469
  function contained2(root2, candidate) {
54494
- const relative = path47.relative(root2, candidate);
54495
- return relative === "" || !relative.startsWith("..") && !path47.isAbsolute(relative);
54470
+ const relative = path48.relative(root2, candidate);
54471
+ return relative === "" || !relative.startsWith("..") && !path48.isAbsolute(relative);
54496
54472
  }
54497
54473
  function realDirectory(filePath) {
54498
54474
  const stat = fs39.lstatSync(filePath);
@@ -54520,7 +54496,7 @@ function walkTasks(root2, tasksDir, out) {
54520
54496
  throw migrationError(`${directory} resolves outside bundle ${root2.bundleId}.`);
54521
54497
  }
54522
54498
  for (const entry of fs39.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
54523
- const candidate = path47.join(directory, entry.name);
54499
+ const candidate = path48.join(directory, entry.name);
54524
54500
  if (entry.isSymbolicLink())
54525
54501
  throw migrationError(`task migration does not follow symbolic link ${candidate}.`);
54526
54502
  if (entry.isDirectory()) {
@@ -54546,7 +54522,7 @@ function walkTasks(root2, tasksDir, out) {
54546
54522
  function inspectTaskFiles(roots) {
54547
54523
  const files = [];
54548
54524
  for (const root2 of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
54549
- const tasksDir = root2.layout === "akm-task" ? root2.root : path47.join(root2.root, "tasks");
54525
+ const tasksDir = root2.layout === "akm-task" ? root2.root : path48.join(root2.root, "tasks");
54550
54526
  try {
54551
54527
  const stat = fs39.lstatSync(tasksDir);
54552
54528
  if (stat.isSymbolicLink())
@@ -54566,8 +54542,8 @@ function planTaskFilesMigration(inputs) {
54566
54542
  return taskToV4PlanFromOutcomes(inputs.map(planTaskToV4File));
54567
54543
  }
54568
54544
  function taskFileBackupPath(backupRoot, filePath) {
54569
- const digest = crypto4.createHash("sha256").update(path47.resolve(filePath)).digest("hex").slice(0, 16);
54570
- return path47.join(backupRoot, "files", `${digest}-${path47.basename(filePath)}`);
54545
+ const digest = crypto4.createHash("sha256").update(path48.resolve(filePath)).digest("hex").slice(0, 16);
54546
+ return path48.join(backupRoot, "files", `${digest}-${path48.basename(filePath)}`);
54571
54547
  }
54572
54548
  function fsyncDirectory(directory) {
54573
54549
  if (process.platform === "win32")
@@ -54586,7 +54562,7 @@ function fsyncDirectory(directory) {
54586
54562
  }
54587
54563
  }
54588
54564
  function writeDurable(filePath, bytes, mode, exclusive = false) {
54589
- fs39.mkdirSync(path47.dirname(filePath), { recursive: true });
54565
+ fs39.mkdirSync(path48.dirname(filePath), { recursive: true });
54590
54566
  const fd = fs39.openSync(filePath, exclusive ? "wx" : "w", mode);
54591
54567
  try {
54592
54568
  fs39.writeFileSync(fd, bytes);
@@ -54595,14 +54571,14 @@ function writeDurable(filePath, bytes, mode, exclusive = false) {
54595
54571
  fs39.closeSync(fd);
54596
54572
  }
54597
54573
  fs39.chmodSync(filePath, mode);
54598
- fsyncDirectory(path47.dirname(filePath));
54574
+ fsyncDirectory(path48.dirname(filePath));
54599
54575
  }
54600
54576
  function replaceAtomically(filePath, bytes, mode) {
54601
- const temporary = path47.join(path47.dirname(filePath), `.${path47.basename(filePath)}.migrate-${crypto4.randomUUID()}`);
54577
+ const temporary = path48.join(path48.dirname(filePath), `.${path48.basename(filePath)}.migrate-${crypto4.randomUUID()}`);
54602
54578
  try {
54603
54579
  writeDurable(temporary, bytes, mode, true);
54604
54580
  fs39.renameSync(temporary, filePath);
54605
- fsyncDirectory(path47.dirname(filePath));
54581
+ fsyncDirectory(path48.dirname(filePath));
54606
54582
  } finally {
54607
54583
  fs39.rmSync(temporary, { force: true });
54608
54584
  }
@@ -54639,7 +54615,7 @@ function expandTilde(value) {
54639
54615
  if (value === "~")
54640
54616
  return os7.homedir();
54641
54617
  if (value.startsWith("~/") || value.startsWith("~\\"))
54642
- return path48.join(os7.homedir(), value.slice(2));
54618
+ return path49.join(os7.homedir(), value.slice(2));
54643
54619
  return value;
54644
54620
  }
54645
54621
  function existingDirectory(target) {
@@ -54665,14 +54641,14 @@ function taskRoots(config, resolutionBase = process.cwd()) {
54665
54641
  const source = sources.get(bundleId);
54666
54642
  if (!source)
54667
54643
  continue;
54668
- const configuredRoot = source.type === "filesystem" && source.path ? path48.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
54644
+ const configuredRoot = source.type === "filesystem" && source.path ? path49.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
54669
54645
  if (!configuredRoot || !existingDirectory(configuredRoot))
54670
54646
  continue;
54671
- const bundleRoot = path48.resolve(configuredRoot);
54647
+ const bundleRoot = path49.resolve(configuredRoot);
54672
54648
  const component = bundleComponentConfig(bundle);
54673
- const componentRoot = path48.resolve(bundleRoot, component?.root ?? ".");
54674
- const relative = path48.relative(bundleRoot, componentRoot);
54675
- if (relative === ".." || relative.startsWith(`..${path48.sep}`) || path48.isAbsolute(relative)) {
54649
+ const componentRoot = path49.resolve(bundleRoot, component?.root ?? ".");
54650
+ const relative = path49.relative(bundleRoot, componentRoot);
54651
+ if (relative === ".." || relative.startsWith(`..${path49.sep}`) || path49.isAbsolute(relative)) {
54676
54652
  throw new ConfigError(`Task migration component root ${componentRoot} escapes bundle ${bundleId} at ${bundleRoot}.`, "INVALID_CONFIG_FILE");
54677
54653
  }
54678
54654
  if (!existingDirectory(componentRoot))
@@ -54689,7 +54665,7 @@ function taskRoots(config, resolutionBase = process.cwd()) {
54689
54665
  }
54690
54666
  const envStash = process.env.AKM_BUNDLE_DIR?.trim();
54691
54667
  if (envStash && existingDirectory(envStash)) {
54692
- const stashRoot = path48.resolve(envStash);
54668
+ const stashRoot = path49.resolve(envStash);
54693
54669
  if (!rootsByPath.has(stashRoot)) {
54694
54670
  const bundleId = deriveBundleId(undefined, stashRoot, new Set(Object.keys(config.bundles ?? {})));
54695
54671
  const candidate = taskRoot(bundleId, stashRoot, stashRoot, detectAdapterId(stashRoot), () => true);
@@ -54758,7 +54734,7 @@ function applyTaskFilesMigration() {
54758
54734
  const before = inspectCurrent();
54759
54735
  if (before.result.taskFiles.changed === 0)
54760
54736
  return before.result;
54761
- const backupPath = path48.join(getDataDir(), "backups", "tasks", `${Date.now()}-${randomUUID3()}`);
54737
+ const backupPath = path49.join(getDataDir(), "backups", "tasks", `${Date.now()}-${randomUUID3()}`);
54762
54738
  const applied = applyTaskFilesPlan(before.plan, { backupRoot: backupPath });
54763
54739
  return { ...inspectCurrent().result, backupPath, applied: applied.changed.length };
54764
54740
  });