akm-cli 0.9.0-beta.48 → 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.
@@ -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 { runAgentSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
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 runAgentSdk(profile, prompt ?? "", runOptions, options.llmConfig)
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 { runAgentSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
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 runAgentSdk(profile, prompt ?? "", runOptions)
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/resolveAkmBin.js";
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";
@@ -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
@@ -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
- * `AgentProfileConfigV2` platform union, `parseAgentProfilesMapV2`'s membership
13
- * check, and setup's `DetectedHarness` union all derive from one place and
14
- * cannot drift. Add a harness in `src/integrations/harnesses/index.ts`.
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 };
@@ -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
- db.exec("BEGIN IMMEDIATE");
474
- try {
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("ROLLBACK");
501
+ db.exec("BEGIN IMMEDIATE");
482
502
  }
483
- catch {
484
- // Ignore rollback failures so the original error is preserved.
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
- timeoutMs: base.timeoutMs,
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
- }
@@ -1,26 +1,10 @@
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
- * Internal entry point for the `agent` integration. CLI-only project — no
6
- * public exports map. Other akm modules import from this barrel for the
7
- * sake of grouping imports.
8
- *
9
- * Surface:
10
- * • Types: AgentProfile, AgentConfig, AgentRunResult, AgentFailureReason.
11
- * • Profiles: getBuiltinAgentProfile, listBuiltinAgentProfiles, BUILTIN_AGENT_PROFILE_NAMES.
12
- * • Config: parseAgentConfig, resolveProfileFromConfig, requireAgentProfile, listResolvedAgentProfiles, listAgentProfileNames.
13
- * • Spawn: runAgent. Builders: getCommandBuilder, AgentCommandBuilder, AgentDispatchRequest — platform-specific argv construction.
14
- * • Detection: detectAgentCliProfiles, pickDefaultAgentProfile, defaultWhich.
15
- */
16
- // The OpenCode SDK runner moved to its harness directory in #564
17
- // (`harnesses/opencode-sdk/`). Re-exported here so existing `agent/index`
18
- // import sites keep working.
19
- export { runAgentSdk } from "../harnesses/opencode-sdk/index.js";
20
4
  export { getCommandBuilder } from "./builders.js";
21
- export { DEFAULT_AGENT_TIMEOUT_MS, listAgentProfileNames, listResolvedAgentProfiles, parseAgentConfig, requireAgentProfile, resolveAgentProfile, resolveDefaultProfileName, resolveProfileFromConfig, } from "./config.js";
5
+ export { DEFAULT_AGENT_TIMEOUT_MS, listAgentProfileNames, listResolvedAgentProfiles, requireAgentProfile, resolveAgentProfile, resolveDefaultProfileName, resolveProfileFromConfig, } from "./config.js";
22
6
  export { defaultWhich, detectAgentCliProfiles, pickDefaultAgentProfile } from "./detect.js";
23
7
  export { listBuiltinModelAliases, resolveModel } from "./model-aliases.js";
24
8
  export { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles.js";
25
- export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload, stripJsonFences, } from "./prompts.js";
9
+ export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload, } from "./prompts.js";
26
10
  export { runAgent } from "./spawn.js";
@@ -444,11 +444,3 @@ export function parseAgentProposalPayload(stdout) {
444
444
  }
445
445
  return out;
446
446
  }
447
- /**
448
- * Strip `\`\`\`json … \`\`\`` fences and `<think>…</think>` reasoning blocks
449
- * from agent output. Thin wrapper around `core/parse` helpers, kept exported
450
- * for backward compatibility (re-exported from `integrations/agent/index.ts`).
451
- */
452
- export function stripJsonFences(text) {
453
- return stripCodeFences(stripThinkBlocks(text));
454
- }
@@ -60,9 +60,8 @@ const HARNESS_BY_ANY_ID = (() => {
60
60
  })();
61
61
  /**
62
62
  * Canonical, ordered list of valid harness / platform ids. The Zod
63
- * `AgentPlatformSchema` enum, the `AgentProfileConfigV2` platform union,
64
- * `parseAgentProfilesMapV2`'s membership check, and setup's `DetectedHarness`
65
- * union all derive from this so they cannot drift.
63
+ * `AgentPlatformSchema` enum, the `AgentProfileConfig` platform union, and
64
+ * setup's `DetectedHarness` union all derive from this so they cannot drift.
66
65
  */
67
66
  export const VALID_HARNESS_IDS = Object.freeze(HARNESS_REGISTRY.map((h) => h.id));
68
67
  /** Harnesses that expose readable native session logs. */
@@ -5,7 +5,7 @@
5
5
  * OpenCode SDK harness (#564).
6
6
  *
7
7
  * Per-harness barrel for the SDK-mode dispatch path:
8
- * - agent runner → ./sdk-runner.ts (runOpencodeSdk / runAgentSdk)
8
+ * - agent runner → ./sdk-runner.ts (runOpencodeSdk)
9
9
  *
10
10
  * It also defines {@link OpencodeSdkHarness}, the {@link AkmHarness} descriptor
11
11
  * that `HARNESS_REGISTRY` registers.
@@ -17,7 +17,7 @@
17
17
  * names. Canonical id is `'opencode-sdk'` with no alias.
18
18
  */
19
19
  import { BaseHarness } from "../types.js";
20
- export { closeServer, runAgentSdk, runOpencodeSdk } from "./sdk-runner.js";
20
+ export { closeServer, runOpencodeSdk } from "./sdk-runner.js";
21
21
  function caps(c) {
22
22
  return {
23
23
  sessionLogs: false,
@@ -230,5 +230,3 @@ export async function runOpencodeSdk(profile, prompt, opts = {}, llmConfig) {
230
230
  await client.session.delete({ path: { id: sessionId } }).catch(() => { });
231
231
  }
232
232
  }
233
- /** @deprecated Use {@link runOpencodeSdk} instead. */
234
- export const runAgentSdk = runOpencodeSdk;
@@ -12,10 +12,10 @@
12
12
  * Initialized from `cli.ts` before `runMain`.
13
13
  */
14
14
  import { UsageError } from "../core/errors.js";
15
- export const OUTPUT_FORMATS = ["json", "yaml", "text", "jsonl", "md", "html"];
16
- export const DETAIL_LEVELS = ["brief", "normal", "full"];
17
- export const SHAPE_MODES = ["human", "agent", "summary"];
18
- export function parseOutputFormat(value) {
15
+ const OUTPUT_FORMATS = ["json", "yaml", "text", "jsonl", "md", "html"];
16
+ const DETAIL_LEVELS = ["brief", "normal", "full"];
17
+ const SHAPE_MODES = ["human", "agent", "summary"];
18
+ function parseOutputFormat(value) {
19
19
  if (!value)
20
20
  return undefined;
21
21
  if (OUTPUT_FORMATS.includes(value))
@@ -29,7 +29,7 @@ export function parseDetailLevel(value) {
29
29
  return value;
30
30
  throw new UsageError(`Invalid value for --detail: ${value}. Expected one of: ${DETAIL_LEVELS.join("|")}`, "INVALID_DETAIL_VALUE");
31
31
  }
32
- export function parseShapeMode(value) {
32
+ function parseShapeMode(value) {
33
33
  if (!value)
34
34
  return undefined;
35
35
  if (SHAPE_MODES.includes(value))
@@ -9699,18 +9699,43 @@ function insertProposalIfAbsent(db, proposal, stashDir) {
9699
9699
  const changes = result.changes ?? 0;
9700
9700
  return Number(changes) > 0;
9701
9701
  }
9702
+ function isRetryableBeginError(err) {
9703
+ const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
9704
+ return msg.includes("within a transaction") || msg.includes("database is locked") || msg.includes("database table is locked");
9705
+ }
9706
+ function sleepSyncMs(ms) {
9707
+ if (ms <= 0)
9708
+ return;
9709
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
9710
+ }
9702
9711
  function withImmediateTransaction(db, fn) {
9703
- db.exec("BEGIN IMMEDIATE");
9704
- try {
9705
- const result = fn();
9706
- db.exec("COMMIT");
9707
- return result;
9708
- } catch (err) {
9712
+ let lastBeginErr;
9713
+ for (let attempt = 1;attempt <= WITH_IMMEDIATE_TX_MAX_ATTEMPTS; attempt++) {
9709
9714
  try {
9710
- db.exec("ROLLBACK");
9711
- } catch {}
9712
- throw err;
9715
+ db.exec("BEGIN IMMEDIATE");
9716
+ } catch (err) {
9717
+ lastBeginErr = err;
9718
+ if (isRetryableBeginError(err) && attempt < WITH_IMMEDIATE_TX_MAX_ATTEMPTS) {
9719
+ try {
9720
+ db.exec("ROLLBACK");
9721
+ } catch {}
9722
+ sleepSyncMs(2 ** (attempt - 1));
9723
+ continue;
9724
+ }
9725
+ throw err;
9726
+ }
9727
+ try {
9728
+ const result = fn();
9729
+ db.exec("COMMIT");
9730
+ return result;
9731
+ } catch (err) {
9732
+ try {
9733
+ db.exec("ROLLBACK");
9734
+ } catch {}
9735
+ throw err;
9736
+ }
9713
9737
  }
9738
+ throw lastBeginErr;
9714
9739
  }
9715
9740
  function upsertTaskHistory(db, row) {
9716
9741
  db.prepare(`
@@ -10074,6 +10099,7 @@ function upsertBodyEmbeddings(db, entries) {
10074
10099
  }
10075
10100
  })();
10076
10101
  }
10102
+ var WITH_IMMEDIATE_TX_MAX_ATTEMPTS = 5;
10077
10103
  var init_state_db = __esm(() => {
10078
10104
  init_managed_db();
10079
10105
  init_improve_types();
@@ -10327,7 +10353,7 @@ function pruneOldBackups(backupDir) {
10327
10353
  function getConfigLockPath() {
10328
10354
  return path7.join(getConfigDir(), "config.json.lck");
10329
10355
  }
10330
- function sleepSyncMs(ms) {
10356
+ function sleepSyncMs2(ms) {
10331
10357
  sleepSync(ms);
10332
10358
  }
10333
10359
  function acquireConfigLock() {
@@ -10348,7 +10374,7 @@ function acquireConfigLock() {
10348
10374
  continue;
10349
10375
  }
10350
10376
  if (attempt < CONFIG_LOCK_MAX_RETRIES - 1) {
10351
- sleepSyncMs(CONFIG_LOCK_RETRY_DELAY_MS);
10377
+ sleepSyncMs2(CONFIG_LOCK_RETRY_DELAY_MS);
10352
10378
  }
10353
10379
  }
10354
10380
  return () => {};
@@ -11241,9 +11267,7 @@ var init_profiles = __esm(() => {
11241
11267
 
11242
11268
  // src/integrations/agent/config.ts
11243
11269
  var init_config = __esm(() => {
11244
- init_config2();
11245
11270
  init_errors();
11246
- init_warn();
11247
11271
  init_profiles();
11248
11272
  });
11249
11273
 
@@ -29,7 +29,7 @@ import fs from "node:fs";
29
29
  import path from "node:path";
30
30
  import { ConfigError } from "../../core/errors.js";
31
31
  import { getTaskLogDir } from "../../core/paths.js";
32
- import { resolveAkmInvocation } from "../resolveAkmBin.js";
32
+ import { resolveAkmInvocation } from "../resolve-akm-bin.js";
33
33
  import { parseSchedule, translateToCron } from "../schedule.js";
34
34
  const BEGIN = (id) => `# akm:task ${id} BEGIN`;
35
35
  const END = (id) => `# akm:task ${id} END`;
@@ -27,7 +27,7 @@ import path from "node:path";
27
27
  import launchdTemplate from "../../assets/backends/launchd-template.xml" with { type: "text" };
28
28
  import { ConfigError } from "../../core/errors.js";
29
29
  import { getTaskLogDir } from "../../core/paths.js";
30
- import { resolveAkmInvocation } from "../resolveAkmBin.js";
30
+ import { resolveAkmInvocation } from "../resolve-akm-bin.js";
31
31
  import { parseSchedule, translateToLaunchd } from "../schedule.js";
32
32
  import { escapeXml, nodeExec, nodeFs } from "./exec-utils.js";
33
33
  export const LAUNCHD_LABEL_PREFIX = "com.akm.task.";
@@ -35,7 +35,7 @@ import path from "node:path";
35
35
  import schtasksTemplate from "../../assets/backends/schtasks-template.xml" with { type: "text" };
36
36
  import { ConfigError } from "../../core/errors.js";
37
37
  import { getTaskLogDir } from "../../core/paths.js";
38
- import { resolveAkmInvocation } from "../resolveAkmBin.js";
38
+ import { resolveAkmInvocation } from "../resolve-akm-bin.js";
39
39
  import { parseSchedule, translateToSchtasks } from "../schedule.js";
40
40
  import { escapeXml, nodeExec, nodeFs } from "./exec-utils.js";
41
41
  export const DEFAULT_FOLDER_PREFIX = "\\akm\\";
@@ -44,8 +44,8 @@ export function resolveAkmInvocation(options = {}) {
44
44
  /**
45
45
  * From the URL of a module inside `src/tasks/` figure out the CLI entry.
46
46
  *
47
- * • dev `…/src/tasks/resolveAkmBin.ts` → `…/src/cli.ts`
48
- * • build `…/dist/tasks/resolveAkmBin.js` → `…/dist/cli.js`
47
+ * • dev `…/src/tasks/resolve-akm-bin.ts` → `…/src/cli.ts`
48
+ * • build `…/dist/tasks/resolve-akm-bin.js` → `…/dist/cli.js`
49
49
  */
50
50
  function resolveCliEntry(moduleUrl) {
51
51
  let modulePath;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.0-beta.48",
3
+ "version": "0.9.0-beta.49",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Management) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
6
6
  "keywords": [
@@ -1,120 +0,0 @@
1
- // This Source Code Form is subject to the terms of the Mozilla Public
2
- // License, v. 2.0. If a copy of the MPL was not distributed with this
3
- // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- /**
5
- * #627 — getRelatedSessions helper.
6
- *
7
- * Finds session assets related to a seed by SHARED TAGS / GRAPH ENTITIES —
8
- * NEVER embedding similarity. Modeled on recombine.ts buildRelatednessClusters:
9
- * two sessions relate when they share at least one *topic* tag or graph entity;
10
- * two textually near-identical sessions with no shared topic signal do NOT
11
- * relate. This makes the helper a pure query-layer relatedness lookup that
12
- * makes NO network / embedding calls.
13
- *
14
- * The generic base tags every session asset carries (`session` + the harness
15
- * id, see session-asset.ts) are IGNORED for relatedness — otherwise every
16
- * session would trivially relate to every other. Callers should therefore seed
17
- * with derived topic tags, but the helper defensively strips the generic base
18
- * tags from candidate sessions too.
19
- *
20
- * Relatedness source:
21
- * - `"tags"` — score by count of (seedTags ∩ session tags).
22
- * - `"graph"` — score by count of (seedEntities ∩ session graph entities);
23
- * falls open to tag relatedness when the graph table is empty.
24
- * - `"both"` — sum of the tag + entity overlap.
25
- */
26
- import { makeAssetRef } from "../../core/asset/asset-ref.js";
27
- import { closeDatabase, getAllEntries, getEntitiesByEntryIds, openExistingDatabase, } from "../../indexer/db/db.js";
28
- /** Generic base tags every session asset carries — never a relatedness signal. */
29
- const GENERIC_SESSION_TAGS = new Set(["session"]);
30
- /**
31
- * Build the set of topic tags for a session entry, excluding generic base tags
32
- * (`session`) and the harness segment of the entry name (the harness id is the
33
- * first path component of `<harness>/<id>` and is also carried as a base tag).
34
- */
35
- function topicTagsForSession(entry) {
36
- const harness = entry.entry.name.split("/")[0];
37
- const result = new Set();
38
- for (const tag of entry.entry.tags ?? []) {
39
- if (GENERIC_SESSION_TAGS.has(tag))
40
- continue;
41
- if (harness && tag === harness)
42
- continue;
43
- result.add(tag);
44
- }
45
- return result;
46
- }
47
- /**
48
- * Find session assets related to a seed by shared tags / graph entities.
49
- * Relatedness is signal-based, NOT embedding similarity.
50
- */
51
- export function getRelatedSessions(opts) {
52
- const seedTags = (opts.seedTags ?? [])
53
- .filter((t) => !GENERIC_SESSION_TAGS.has(t))
54
- .map((t) => t.trim())
55
- .filter(Boolean);
56
- const seedEntities = (opts.seedEntities ?? []).map((e) => e.trim().toLowerCase()).filter(Boolean);
57
- const minShared = opts.minShared ?? 1;
58
- const limit = opts.limit ?? 5;
59
- const relatednessSource = opts.relatednessSource ?? "tags";
60
- const excludeRefs = new Set(opts.excludeRefs ?? []);
61
- // Empty seed input → nothing to relate to.
62
- if (seedTags.length === 0 && seedEntities.length === 0)
63
- return [];
64
- const seedTagSet = new Set(seedTags);
65
- const seedEntitySet = new Set(seedEntities);
66
- let db = opts.db;
67
- let ownsDb = false;
68
- if (!db) {
69
- db = openExistingDatabase();
70
- ownsDb = true;
71
- }
72
- try {
73
- const sessions = getAllEntries(db, "session");
74
- // Resolve graph entities for the candidate sessions when requested. Fail
75
- // open to tag relatedness when the graph table is empty (no rows).
76
- let entityByEntryId;
77
- const wantGraph = relatednessSource === "graph" || relatednessSource === "both";
78
- if (wantGraph) {
79
- try {
80
- entityByEntryId = getEntitiesByEntryIds(db, sessions.map((s) => s.id));
81
- }
82
- catch {
83
- entityByEntryId = undefined;
84
- }
85
- }
86
- const hasEntities = !!entityByEntryId && entityByEntryId.size > 0;
87
- // Effective signal selection. "graph" with no entities falls open to tags.
88
- const useTags = relatednessSource === "tags" || relatednessSource === "both" || (wantGraph && !hasEntities);
89
- const useGraph = wantGraph && hasEntities;
90
- const scored = [];
91
- for (const session of sessions) {
92
- const ref = makeAssetRef(session.entry.type, session.entry.name);
93
- if (excludeRefs.has(ref))
94
- continue;
95
- let sharedCount = 0;
96
- if (useTags && seedTagSet.size > 0) {
97
- for (const tag of topicTagsForSession(session)) {
98
- if (seedTagSet.has(tag))
99
- sharedCount += 1;
100
- }
101
- }
102
- if (useGraph && seedEntitySet.size > 0 && entityByEntryId) {
103
- for (const ent of entityByEntryId.get(session.id) ?? []) {
104
- if (seedEntitySet.has(ent))
105
- sharedCount += 1;
106
- }
107
- }
108
- if (sharedCount >= minShared) {
109
- scored.push({ ref, name: session.entry.name, sharedCount });
110
- }
111
- }
112
- // Rank by shared-signal count desc, then ref for a deterministic tiebreak.
113
- scored.sort((a, b) => b.sharedCount - a.sharedCount || a.ref.localeCompare(b.ref));
114
- return scored.slice(0, Math.max(0, limit));
115
- }
116
- finally {
117
- if (ownsDb && db)
118
- closeDatabase(db);
119
- }
120
- }
@@ -1,4 +0,0 @@
1
- // This Source Code Form is subject to the terms of the Mozilla Public
2
- // License, v. 2.0. If a copy of the MPL was not distributed with this
3
- // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- export { akmLint } from "./lint/index.js";