agenr 3.1.0 → 3.2.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,36 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [3.2.0] - 2026-06-02
6
+
7
+ Cross-platform packaging, CI smoke coverage, and path handling hardening release.
8
+
9
+ ### Added
10
+
11
+ - **Repository checks now cover package smoke workflows across platforms.** The release adds local package smoke tooling, Windows simulation, Docker-based Linux checks, and a slimmer Windows CI workflow.
12
+ - **Path handling now has focused cross-platform helpers and tests.** Shared filesystem path utilities and test helpers cover Windows, Linux, and local temporary-path behavior.
13
+
14
+ ### Changed
15
+
16
+ - **Package build and smoke scripts are more portable.** Root and plugin package scripts now avoid shell-specific assumptions and handle install paths consistently across supported platforms.
17
+ - **Skeln adapter imports now use explicit shared host types.** The Skeln adapter has a dedicated type boundary for host-facing imports, reducing package-resolution friction during plugin builds.
18
+
19
+ ### Fixed
20
+
21
+ - **Windows package smoke tests are quoting-safe.** Smoke commands now pass arguments separately, preserve path quotes, avoid `npx`, and restore the `cmd.exe` npm shim path needed by Windows runs.
22
+ - **SQLite and temp-path tests now clean up safely on Windows.** Database and test cleanup paths avoid platform-sensitive deletion and quoting failures.
23
+ - **Line-ending and packaging behavior is more deterministic.** Repository checkout and packaging paths are hardened for Linux and Windows release validation.
24
+
25
+ ### Validation
26
+
27
+ Changes since last push to `origin/master`:
28
+
29
+ - Add local package smoke, Windows simulation, and Docker Linux test runners
30
+ - Add a slim Windows CI workflow and deterministic LF checkout configuration
31
+ - Harden package smoke command quoting, argument passing, and npm shim handling on Windows
32
+ - Add shared filesystem path helpers and cross-platform test temp-path helpers
33
+ - Harden SQLite, temp path, Skeln adapter, and plugin build paths for cross-platform package validation
34
+
5
35
  ## [3.1.0] - 2026-05-31
6
36
 
7
37
  Memory fetch tools, Skeln episode lifecycle hardening, and repository packaging cleanup release.
@@ -4,7 +4,7 @@ import {
4
4
  openClawTranscriptParser,
5
5
  parseTuiSessionKey,
6
6
  readOpenClawSessionsStore
7
- } from "../../chunk-JSVQILB3.js";
7
+ } from "../../chunk-ZAX3YSTU.js";
8
8
  import {
9
9
  BEFORE_TURN_DEBUG_ARTIFACT_DEFAULT_TOP_K,
10
10
  BEFORE_TURN_DEBUG_ARTIFACT_MAX_TOP_K,
@@ -43,7 +43,7 @@ import {
43
43
  runStoreMemoryTool,
44
44
  runUpdateMemoryTool,
45
45
  writeBoundedSingleTranscriptEpisode
46
- } from "../../chunk-E2DHUFZK.js";
46
+ } from "../../chunk-KL6X2E3I.js";
47
47
  import {
48
48
  asRecord,
49
49
  buildEntryMemoryResolverPorts,
@@ -54,13 +54,13 @@ import {
54
54
  resolveTargetEntry,
55
55
  sanitizeFetchToolParams,
56
56
  sanitizeUpdateToolParams
57
- } from "../../chunk-EEEL53X4.js";
57
+ } from "../../chunk-TMDNFBBC.js";
58
58
  import {
59
59
  containsAgenrMemoryContext,
60
60
  formatAgenrBeforeTurnRecall,
61
61
  runBeforeTurn,
62
62
  stripAgenrMemoryContext
63
- } from "../../chunk-V5CDMHRN.js";
63
+ } from "../../chunk-UEGURBBW.js";
64
64
  import {
65
65
  EMBEDDING_DIMENSIONS,
66
66
  buildRecallToolDetails,
@@ -69,7 +69,7 @@ import {
69
69
  sanitizeRecallToolParams,
70
70
  sanitizeStoreToolParams,
71
71
  truncate
72
- } from "../../chunk-NNO2V4GH.js";
72
+ } from "../../chunk-FMQTRTWE.js";
73
73
  import {
74
74
  resolveClaimSlotPolicy
75
75
  } from "../../chunk-5LADPJ4C.js";
@@ -759,7 +759,7 @@ function registerAgenrOpenClawTools(api, servicesPromise, logger) {
759
759
  var openclaw_plugin_default = {
760
760
  id: "agenr",
761
761
  name: "agenr",
762
- version: "3.1.0",
762
+ version: "3.2.0",
763
763
  description: "agenr memory plugin for OpenClaw",
764
764
  kind: "memory",
765
765
  contracts: {
@@ -1,7 +1,66 @@
1
- import { ExtensionContext, ExtensionAPI } from 'skeln';
1
+ import { TSchema } from 'typebox';
2
+ import { AgentToolResult, AgentMessage } from '@earendil-works/pi-agent-core';
2
3
  import { C as ClaimSlotPolicyConfig, a as ClaimSlotPolicy } from '../../claim-slot-policy-CdrW_1l4.js';
3
4
  import { E as EntryType, b as RecallPorts, r as ProcedureDatabasePort, t as Entry, u as DatabasePort, v as EpisodeDatabasePort, w as EmbeddingPort, L as LlmPort } from '../../ports-CpzWESmZ.js';
4
- import { AgentMessage } from '@earendil-works/pi-agent-core';
5
+
6
+ /** Minimal branch-entry shape needed for before-turn visibility filtering. */
7
+ interface SkelnBranchEntryLike {
8
+ /** Session tree entry discriminator. */
9
+ type?: unknown;
10
+ /** Session tree entry id. */
11
+ id?: unknown;
12
+ /** Parent id retained for compatibility with Skeln entries. */
13
+ parentId?: unknown;
14
+ /** Message payload when this is a message entry. */
15
+ message?: unknown;
16
+ /** First replayed entry after compaction when this is a compaction entry. */
17
+ firstKeptEntryId?: unknown;
18
+ }
19
+
20
+ /** Minimal Skeln extension API surface used by the agenr adapter. */
21
+ interface ExtensionAPI {
22
+ /** Reads one extension setting supplied by Skeln config. */
23
+ getSetting(key: string): unknown;
24
+ /** Registers one model-facing tool with the Skeln runtime. */
25
+ registerTool(tool: SkelnToolDefinition): void;
26
+ }
27
+ /** Minimal Skeln session manager surface used by the agenr adapter. */
28
+ interface SkelnSessionManager {
29
+ /** Returns the active Skeln session id. */
30
+ getSessionId(): string | number;
31
+ /** Returns the active session working directory. */
32
+ getCwd(): string;
33
+ /** Returns the active session JSONL file path when available. */
34
+ getSessionFile(): string;
35
+ /** Returns active branch entries visible to before-turn recall. */
36
+ getBranch(): SkelnBranchEntryLike[];
37
+ }
38
+ /** Minimal Skeln extension context surface used by the agenr adapter. */
39
+ interface ExtensionContext {
40
+ /** Current working directory when provided directly by newer Skeln hosts. */
41
+ cwd?: string;
42
+ /** Session manager for identity, cwd fallback, and transcript location. */
43
+ sessionManager: SkelnSessionManager;
44
+ }
45
+ /** Tool-update callback shape accepted by Skeln tool handlers. */
46
+ type SkelnToolUpdateCallback = (update: unknown) => void;
47
+ /** Minimal Skeln tool definition shape registered by the agenr adapter. */
48
+ interface SkelnToolDefinition {
49
+ /** Tool name exposed to the model. */
50
+ name: string;
51
+ /** Human-readable label shown by host UI. */
52
+ label?: string;
53
+ /** Tool description shown to the model and host UI. */
54
+ description: string;
55
+ /** Optional prompt snippet injected by Skeln. */
56
+ promptSnippet?: string;
57
+ /** Optional model-facing usage guidelines injected by Skeln. */
58
+ promptGuidelines?: string[];
59
+ /** TypeBox-compatible parameter schema. */
60
+ parameters?: TSchema;
61
+ /** Executes one Skeln tool call. */
62
+ execute(toolCallId: string, params: unknown, signal: AbortSignal | undefined, onUpdate: SkelnToolUpdateCallback | undefined, context: ExtensionContext): AgentToolResult<Record<string, unknown>> | Promise<AgentToolResult<Record<string, unknown>>>;
63
+ }
5
64
 
6
65
  /**
7
66
  * Canonical feature flags for staged working-memory, session-memory, and goal rollout.
@@ -40,7 +40,7 @@ import {
40
40
  runStoreMemoryTool,
41
41
  runUpdateMemoryTool,
42
42
  writeBoundedSingleTranscriptEpisode
43
- } from "../../chunk-E2DHUFZK.js";
43
+ } from "../../chunk-KL6X2E3I.js";
44
44
  import {
45
45
  asRecord,
46
46
  createSingleTranscriptDiscoveryPort,
@@ -48,11 +48,11 @@ import {
48
48
  formatTargetSelector,
49
49
  sanitizeFetchToolParams,
50
50
  sanitizeUpdateToolParams
51
- } from "../../chunk-EEEL53X4.js";
51
+ } from "../../chunk-TMDNFBBC.js";
52
52
  import {
53
53
  formatAgenrBeforeTurnRecall,
54
54
  runBeforeTurn
55
- } from "../../chunk-V5CDMHRN.js";
55
+ } from "../../chunk-UEGURBBW.js";
56
56
  import {
57
57
  AGENR_FEATURE_FLAG_KEYS,
58
58
  DEFAULT_AGENR_FEATURE_FLAGS,
@@ -63,7 +63,7 @@ import {
63
63
  readOptionalTrimmedString,
64
64
  resolveLlmApiKey,
65
65
  resolveModel
66
- } from "../../chunk-NNO2V4GH.js";
66
+ } from "../../chunk-FMQTRTWE.js";
67
67
  import "../../chunk-5LADPJ4C.js";
68
68
 
69
69
  // src/adapters/skeln/config.ts
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  formatAgenrBeforeTurnRecall,
14
14
  runBeforeTurn
15
- } from "./chunk-V5CDMHRN.js";
15
+ } from "./chunk-UEGURBBW.js";
16
16
  import {
17
17
  CLAIM_KEY_SOURCES,
18
18
  CLAIM_KEY_STATUSES,
@@ -41,7 +41,7 @@ import {
41
41
  resolveEmbeddingModel,
42
42
  resolveModel,
43
43
  runUnifiedRecall
44
- } from "./chunk-NNO2V4GH.js";
44
+ } from "./chunk-FMQTRTWE.js";
45
45
  import {
46
46
  recall
47
47
  } from "./chunk-5LADPJ4C.js";
@@ -37,8 +37,8 @@ function readOptionalTrimmedString(value) {
37
37
  function readOptionalFiniteNumber(value) {
38
38
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
39
39
  }
40
- function pushIssue(issues, path4, message) {
41
- issues.push({ path: path4, message });
40
+ function pushIssue(issues, path5, message) {
41
+ issues.push({ path: path5, message });
42
42
  }
43
43
  function pushUnexpectedFields(value, allowedKeys, basePath, issues) {
44
44
  for (const key of Object.keys(value)) {
@@ -48,68 +48,68 @@ function pushUnexpectedFields(value, allowedKeys, basePath, issues) {
48
48
  pushIssue(issues, joinPath(basePath, key), "Unexpected field.");
49
49
  }
50
50
  }
51
- function parseRequiredTrimmedString(value, path4, issues, message = "Expected a non-empty string.") {
51
+ function parseRequiredTrimmedString(value, path5, issues, message = "Expected a non-empty string.") {
52
52
  if (typeof value !== "string") {
53
- pushIssue(issues, path4, message);
53
+ pushIssue(issues, path5, message);
54
54
  return void 0;
55
55
  }
56
56
  const normalized = value.trim();
57
57
  if (normalized.length === 0) {
58
- pushIssue(issues, path4, message);
58
+ pushIssue(issues, path5, message);
59
59
  return void 0;
60
60
  }
61
61
  return normalized;
62
62
  }
63
- function parseOptionalTrimmedString(value, path4, issues, typeMessage = "Expected a string.", emptyMessage = "Expected a non-empty string.") {
63
+ function parseOptionalTrimmedString(value, path5, issues, typeMessage = "Expected a string.", emptyMessage = "Expected a non-empty string.") {
64
64
  if (value === void 0) {
65
65
  return void 0;
66
66
  }
67
67
  if (typeof value !== "string") {
68
- pushIssue(issues, path4, typeMessage);
68
+ pushIssue(issues, path5, typeMessage);
69
69
  return void 0;
70
70
  }
71
71
  const normalized = value.trim();
72
72
  if (normalized.length === 0) {
73
- pushIssue(issues, path4, emptyMessage);
73
+ pushIssue(issues, path5, emptyMessage);
74
74
  return void 0;
75
75
  }
76
76
  return normalized;
77
77
  }
78
- function parseOptionalBoolean(value, path4, issues, message = "Expected a boolean.") {
78
+ function parseOptionalBoolean(value, path5, issues, message = "Expected a boolean.") {
79
79
  if (value === void 0) {
80
80
  return void 0;
81
81
  }
82
82
  if (typeof value !== "boolean") {
83
- pushIssue(issues, path4, message);
83
+ pushIssue(issues, path5, message);
84
84
  return void 0;
85
85
  }
86
86
  return value;
87
87
  }
88
- function parseOptionalIntegerInRange(value, path4, issues, bounds) {
88
+ function parseOptionalIntegerInRange(value, path5, issues, bounds) {
89
89
  if (value === void 0) {
90
90
  return void 0;
91
91
  }
92
92
  if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value)) {
93
- pushIssue(issues, path4, integerRangeMessage(bounds));
93
+ pushIssue(issues, path5, integerRangeMessage(bounds));
94
94
  return void 0;
95
95
  }
96
96
  if (bounds.min !== void 0 && value < bounds.min) {
97
- pushIssue(issues, path4, integerRangeMessage(bounds));
97
+ pushIssue(issues, path5, integerRangeMessage(bounds));
98
98
  return void 0;
99
99
  }
100
100
  if (bounds.max !== void 0 && value > bounds.max) {
101
- pushIssue(issues, path4, integerRangeMessage(bounds));
101
+ pushIssue(issues, path5, integerRangeMessage(bounds));
102
102
  return void 0;
103
103
  }
104
104
  return value;
105
105
  }
106
- function parseOptionalTimestampString(value, path4, issues, message = "Expected a valid timestamp string.") {
107
- const timestamp = parseOptionalTrimmedString(value, path4, issues);
106
+ function parseOptionalTimestampString(value, path5, issues, message = "Expected a valid timestamp string.") {
107
+ const timestamp = parseOptionalTrimmedString(value, path5, issues);
108
108
  if (timestamp === void 0) {
109
109
  return void 0;
110
110
  }
111
111
  if (Number.isNaN(Date.parse(timestamp))) {
112
- pushIssue(issues, path4, message);
112
+ pushIssue(issues, path5, message);
113
113
  return void 0;
114
114
  }
115
115
  return timestamp;
@@ -142,8 +142,7 @@ function integerRangeMessage(bounds) {
142
142
  // src/config.ts
143
143
  import fs from "fs";
144
144
  import os from "os";
145
- import path from "path";
146
- import { fileURLToPath } from "url";
145
+ import path2 from "path";
147
146
 
148
147
  // src/app/features/types.ts
149
148
  var AGENR_FEATURE_FLAG_KEYS = ["workingMemory", "sessionTreeLineage", "sessionTreeCompaction", "goalContinuation"];
@@ -155,7 +154,7 @@ var DEFAULT_AGENR_FEATURE_FLAGS = {
155
154
  };
156
155
 
157
156
  // src/adapters/config/parse-feature-flags.ts
158
- function parseFeatureFlags(value, path4, issues) {
157
+ function parseFeatureFlags(value, path5, issues) {
159
158
  const defaults = DEFAULT_AGENR_FEATURE_FLAGS;
160
159
  if (value === void 0) {
161
160
  return {
@@ -163,17 +162,17 @@ function parseFeatureFlags(value, path4, issues) {
163
162
  };
164
163
  }
165
164
  if (!isRecord(value)) {
166
- pushIssue(issues, path4, "Expected an object.");
165
+ pushIssue(issues, path5, "Expected an object.");
167
166
  return {
168
167
  resolved: { ...defaults }
169
168
  };
170
169
  }
171
170
  const startIndex = issues.length;
172
- pushUnexpectedFields(value, new Set(AGENR_FEATURE_FLAG_KEYS), path4, issues);
173
- const workingMemory = parseOptionalBoolean(value.workingMemory, `${path4}.workingMemory`, issues);
174
- const sessionTreeLineage = parseOptionalBoolean(value.sessionTreeLineage, `${path4}.sessionTreeLineage`, issues);
175
- const sessionTreeCompaction = parseOptionalBoolean(value.sessionTreeCompaction, `${path4}.sessionTreeCompaction`, issues);
176
- const goalContinuation = parseOptionalBoolean(value.goalContinuation, `${path4}.goalContinuation`, issues);
171
+ pushUnexpectedFields(value, new Set(AGENR_FEATURE_FLAG_KEYS), path5, issues);
172
+ const workingMemory = parseOptionalBoolean(value.workingMemory, `${path5}.workingMemory`, issues);
173
+ const sessionTreeLineage = parseOptionalBoolean(value.sessionTreeLineage, `${path5}.sessionTreeLineage`, issues);
174
+ const sessionTreeCompaction = parseOptionalBoolean(value.sessionTreeCompaction, `${path5}.sessionTreeCompaction`, issues);
175
+ const goalContinuation = parseOptionalBoolean(value.goalContinuation, `${path5}.goalContinuation`, issues);
177
176
  if (issues.length > startIndex) {
178
177
  return {
179
178
  resolved: { ...defaults }
@@ -464,41 +463,41 @@ function pushTopLevelIssues(value, issues) {
464
463
  pushIssue(issues, "embeddingApiKey", "Removed field. Move this value to credentials.openaiApiKey, then delete embeddingApiKey.");
465
464
  }
466
465
  }
467
- function parseAuth(value, path4, issues) {
468
- const normalized = parseOptionalTrimmedString(value, path4, issues);
466
+ function parseAuth(value, path5, issues) {
467
+ const normalized = parseOptionalTrimmedString(value, path5, issues);
469
468
  if (!normalized) {
470
469
  return void 0;
471
470
  }
472
471
  if (!isAgenrAuthMethod(normalized)) {
473
- pushIssue(issues, path4, "Expected a supported auth method.");
472
+ pushIssue(issues, path5, "Expected a supported auth method.");
474
473
  return void 0;
475
474
  }
476
475
  return normalized;
477
476
  }
478
- function parseProvider(value, path4, issues) {
479
- const normalized = parseOptionalTrimmedString(value, path4, issues);
477
+ function parseProvider(value, path5, issues) {
478
+ const normalized = parseOptionalTrimmedString(value, path5, issues);
480
479
  if (!normalized) {
481
480
  return void 0;
482
481
  }
483
482
  if (!isAgenrProvider(normalized)) {
484
- pushIssue(issues, path4, "Expected a supported provider.");
483
+ pushIssue(issues, path5, "Expected a supported provider.");
485
484
  return void 0;
486
485
  }
487
486
  return normalized;
488
487
  }
489
- function parseCredentials(value, path4, issues) {
488
+ function parseCredentials(value, path5, issues) {
490
489
  if (value === void 0) {
491
490
  return void 0;
492
491
  }
493
492
  if (!isRecord(value)) {
494
- pushIssue(issues, path4, "Expected an object.");
493
+ pushIssue(issues, path5, "Expected an object.");
495
494
  return void 0;
496
495
  }
497
496
  const startIndex = issues.length;
498
- pushUnexpectedFields(value, /* @__PURE__ */ new Set(["openaiApiKey", "anthropicApiKey", "anthropicOauthToken"]), path4, issues);
499
- const openaiApiKey = parseOptionalTrimmedString(value.openaiApiKey, `${path4}.openaiApiKey`, issues);
500
- const anthropicApiKey = parseOptionalTrimmedString(value.anthropicApiKey, `${path4}.anthropicApiKey`, issues);
501
- const anthropicOauthToken = parseOptionalTrimmedString(value.anthropicOauthToken, `${path4}.anthropicOauthToken`, issues);
497
+ pushUnexpectedFields(value, /* @__PURE__ */ new Set(["openaiApiKey", "anthropicApiKey", "anthropicOauthToken"]), path5, issues);
498
+ const openaiApiKey = parseOptionalTrimmedString(value.openaiApiKey, `${path5}.openaiApiKey`, issues);
499
+ const anthropicApiKey = parseOptionalTrimmedString(value.anthropicApiKey, `${path5}.anthropicApiKey`, issues);
500
+ const anthropicOauthToken = parseOptionalTrimmedString(value.anthropicOauthToken, `${path5}.anthropicOauthToken`, issues);
502
501
  if (issues.length > startIndex) {
503
502
  return void 0;
504
503
  }
@@ -509,20 +508,20 @@ function parseCredentials(value, path4, issues) {
509
508
  };
510
509
  return hasStoredCredentials(credentials) ? credentials : void 0;
511
510
  }
512
- function parseModelConfig(value, path4, issues) {
511
+ function parseModelConfig(value, path5, issues) {
513
512
  if (value === void 0) {
514
513
  return void 0;
515
514
  }
516
515
  if (!isRecord(value)) {
517
- pushIssue(issues, path4, "Expected an object.");
516
+ pushIssue(issues, path5, "Expected an object.");
518
517
  return void 0;
519
518
  }
520
519
  const startIndex = issues.length;
521
- pushUnexpectedFields(value, /* @__PURE__ */ new Set(["provider", "model"]), path4, issues);
522
- const provider = parseProvider(value.provider, `${path4}.provider`, issues);
523
- const model = parseOptionalTrimmedString(value.model, `${path4}.model`, issues);
520
+ pushUnexpectedFields(value, /* @__PURE__ */ new Set(["provider", "model"]), path5, issues);
521
+ const provider = parseProvider(value.provider, `${path5}.provider`, issues);
522
+ const model = parseOptionalTrimmedString(value.model, `${path5}.model`, issues);
524
523
  if (!provider && !model) {
525
- pushIssue(issues, path4, "Expected at least one of provider or model.");
524
+ pushIssue(issues, path5, "Expected at least one of provider or model.");
526
525
  }
527
526
  if (issues.length > startIndex) {
528
527
  return void 0;
@@ -532,7 +531,7 @@ function parseModelConfig(value, path4, issues) {
532
531
  ...model ? { model } : {}
533
532
  };
534
533
  }
535
- function parseClaimExtractionConfig(value, path4, issues) {
534
+ function parseClaimExtractionConfig(value, path5, issues) {
536
535
  const defaults = createDefaultClaimExtractionConfig();
537
536
  if (value === void 0) {
538
537
  return {
@@ -540,20 +539,20 @@ function parseClaimExtractionConfig(value, path4, issues) {
540
539
  };
541
540
  }
542
541
  if (!isRecord(value)) {
543
- pushIssue(issues, path4, "Expected an object.");
542
+ pushIssue(issues, path5, "Expected an object.");
544
543
  return {
545
544
  resolved: defaults
546
545
  };
547
546
  }
548
547
  const startIndex = issues.length;
549
- pushUnexpectedFields(value, /* @__PURE__ */ new Set(["enabled", "confidenceThreshold", "eligibleTypes", "concurrency", "model"]), path4, issues);
550
- const enabled = parseOptionalBoolean(value.enabled, `${path4}.enabled`, issues);
551
- const confidenceThreshold = parseOptionalUnitInterval(value.confidenceThreshold, `${path4}.confidenceThreshold`, issues);
552
- const eligibleTypes = parseEligibleTypes(value.eligibleTypes, `${path4}.eligibleTypes`, issues);
553
- const concurrency = parseOptionalIntegerInRange(value.concurrency, `${path4}.concurrency`, issues, {
548
+ pushUnexpectedFields(value, /* @__PURE__ */ new Set(["enabled", "confidenceThreshold", "eligibleTypes", "concurrency", "model"]), path5, issues);
549
+ const enabled = parseOptionalBoolean(value.enabled, `${path5}.enabled`, issues);
550
+ const confidenceThreshold = parseOptionalUnitInterval(value.confidenceThreshold, `${path5}.confidenceThreshold`, issues);
551
+ const eligibleTypes = parseEligibleTypes(value.eligibleTypes, `${path5}.eligibleTypes`, issues);
552
+ const concurrency = parseOptionalIntegerInRange(value.concurrency, `${path5}.concurrency`, issues, {
554
553
  min: 1
555
554
  });
556
- const model = parseModelConfig(value.model, `${path4}.model`, issues);
555
+ const model = parseModelConfig(value.model, `${path5}.model`, issues);
557
556
  if (issues.length > startIndex) {
558
557
  return {
559
558
  resolved: defaults
@@ -577,7 +576,7 @@ function parseClaimExtractionConfig(value, path4, issues) {
577
576
  }
578
577
  };
579
578
  }
580
- function parseSurgeonConfig(value, path4, issues) {
579
+ function parseSurgeonConfig(value, path5, issues) {
581
580
  const defaults = createDefaultSurgeonConfig();
582
581
  if (value === void 0) {
583
582
  return {
@@ -585,19 +584,19 @@ function parseSurgeonConfig(value, path4, issues) {
585
584
  };
586
585
  }
587
586
  if (!isRecord(value)) {
588
- pushIssue(issues, path4, "Expected an object.");
587
+ pushIssue(issues, path5, "Expected an object.");
589
588
  return {
590
589
  resolved: defaults
591
590
  };
592
591
  }
593
592
  const startIndex = issues.length;
594
- pushUnexpectedFields(value, /* @__PURE__ */ new Set(["model", "costCap", "dailyCostCap", "contextLimit", "customInstructions", "passes"]), path4, issues);
595
- const model = parseModelConfig(value.model, `${path4}.model`, issues);
596
- const costCap = parseOptionalPositiveNumber(value.costCap, `${path4}.costCap`, issues);
597
- const dailyCostCap = parseOptionalNonNegativeNumber(value.dailyCostCap, `${path4}.dailyCostCap`, issues);
598
- const contextLimit = parseOptionalIntegerInRange(value.contextLimit, `${path4}.contextLimit`, issues, { min: 0 });
599
- const customInstructions = parseOptionalTrimmedString(value.customInstructions, `${path4}.customInstructions`, issues);
600
- const retirement = parseRetirementPassConfig(value.passes, `${path4}.passes`, issues);
593
+ pushUnexpectedFields(value, /* @__PURE__ */ new Set(["model", "costCap", "dailyCostCap", "contextLimit", "customInstructions", "passes"]), path5, issues);
594
+ const model = parseModelConfig(value.model, `${path5}.model`, issues);
595
+ const costCap = parseOptionalPositiveNumber(value.costCap, `${path5}.costCap`, issues);
596
+ const dailyCostCap = parseOptionalNonNegativeNumber(value.dailyCostCap, `${path5}.dailyCostCap`, issues);
597
+ const contextLimit = parseOptionalIntegerInRange(value.contextLimit, `${path5}.contextLimit`, issues, { min: 0 });
598
+ const customInstructions = parseOptionalTrimmedString(value.customInstructions, `${path5}.customInstructions`, issues);
599
+ const retirement = parseRetirementPassConfig(value.passes, `${path5}.passes`, issues);
601
600
  if (issues.length > startIndex) {
602
601
  return {
603
602
  resolved: defaults
@@ -629,7 +628,7 @@ function parseSurgeonConfig(value, path4, issues) {
629
628
  }
630
629
  };
631
630
  }
632
- function parseRetirementPassConfig(value, path4, issues) {
631
+ function parseRetirementPassConfig(value, path5, issues) {
633
632
  const defaults = createDefaultRetirementPassConfig();
634
633
  if (value === void 0) {
635
634
  return {
@@ -637,36 +636,36 @@ function parseRetirementPassConfig(value, path4, issues) {
637
636
  };
638
637
  }
639
638
  if (!isRecord(value)) {
640
- pushIssue(issues, path4, "Expected an object.");
639
+ pushIssue(issues, path5, "Expected an object.");
641
640
  return {
642
641
  resolved: defaults
643
642
  };
644
643
  }
645
644
  const startIndex = issues.length;
646
- pushUnexpectedFields(value, /* @__PURE__ */ new Set(["retirement"]), path4, issues);
645
+ pushUnexpectedFields(value, /* @__PURE__ */ new Set(["retirement"]), path5, issues);
647
646
  const retirement = value.retirement;
648
647
  if (retirement === void 0) {
649
648
  if (issues.length === startIndex) {
650
- pushIssue(issues, path4, "Expected a retirement config when passes is provided.");
649
+ pushIssue(issues, path5, "Expected a retirement config when passes is provided.");
651
650
  }
652
651
  return {
653
652
  resolved: defaults
654
653
  };
655
654
  }
656
655
  if (!isRecord(retirement)) {
657
- pushIssue(issues, `${path4}.retirement`, "Expected an object.");
656
+ pushIssue(issues, `${path5}.retirement`, "Expected an object.");
658
657
  return {
659
658
  resolved: defaults
660
659
  };
661
660
  }
662
- pushUnexpectedFields(retirement, /* @__PURE__ */ new Set(["protectRecalledDays", "protectMinImportance", "skipRecentlyEvaluatedDays"]), `${path4}.retirement`, issues);
663
- const protectRecalledDays = parseOptionalIntegerInRange(retirement.protectRecalledDays, `${path4}.retirement.protectRecalledDays`, issues, {
661
+ pushUnexpectedFields(retirement, /* @__PURE__ */ new Set(["protectRecalledDays", "protectMinImportance", "skipRecentlyEvaluatedDays"]), `${path5}.retirement`, issues);
662
+ const protectRecalledDays = parseOptionalIntegerInRange(retirement.protectRecalledDays, `${path5}.retirement.protectRecalledDays`, issues, {
664
663
  min: 0
665
664
  });
666
- const protectMinImportance = parseOptionalIntegerInRange(retirement.protectMinImportance, `${path4}.retirement.protectMinImportance`, issues, {
665
+ const protectMinImportance = parseOptionalIntegerInRange(retirement.protectMinImportance, `${path5}.retirement.protectMinImportance`, issues, {
667
666
  min: 0
668
667
  });
669
- const skipRecentlyEvaluatedDays = parseOptionalIntegerInRange(retirement.skipRecentlyEvaluatedDays, `${path4}.retirement.skipRecentlyEvaluatedDays`, issues, {
668
+ const skipRecentlyEvaluatedDays = parseOptionalIntegerInRange(retirement.skipRecentlyEvaluatedDays, `${path5}.retirement.skipRecentlyEvaluatedDays`, issues, {
670
669
  min: 0
671
670
  });
672
671
  if (issues.length > startIndex) {
@@ -688,54 +687,54 @@ function parseRetirementPassConfig(value, path4, issues) {
688
687
  }
689
688
  };
690
689
  }
691
- function parseOptionalUnitInterval(value, path4, issues) {
690
+ function parseOptionalUnitInterval(value, path5, issues) {
692
691
  if (value === void 0) {
693
692
  return void 0;
694
693
  }
695
694
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
696
- pushIssue(issues, path4, "Expected a number from 0 to 1.");
695
+ pushIssue(issues, path5, "Expected a number from 0 to 1.");
697
696
  return void 0;
698
697
  }
699
698
  return value;
700
699
  }
701
- function parseOptionalPositiveNumber(value, path4, issues) {
700
+ function parseOptionalPositiveNumber(value, path5, issues) {
702
701
  if (value === void 0) {
703
702
  return void 0;
704
703
  }
705
704
  if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
706
- pushIssue(issues, path4, "Expected a positive number.");
705
+ pushIssue(issues, path5, "Expected a positive number.");
707
706
  return void 0;
708
707
  }
709
708
  return value;
710
709
  }
711
- function parseOptionalNonNegativeNumber(value, path4, issues) {
710
+ function parseOptionalNonNegativeNumber(value, path5, issues) {
712
711
  if (value === void 0) {
713
712
  return void 0;
714
713
  }
715
714
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
716
- pushIssue(issues, path4, "Expected a non-negative number.");
715
+ pushIssue(issues, path5, "Expected a non-negative number.");
717
716
  return void 0;
718
717
  }
719
718
  return value;
720
719
  }
721
- function parseEligibleTypes(value, path4, issues) {
720
+ function parseEligibleTypes(value, path5, issues) {
722
721
  if (value === void 0) {
723
722
  return void 0;
724
723
  }
725
724
  if (!Array.isArray(value)) {
726
- pushIssue(issues, path4, "Expected an array of entry types.");
725
+ pushIssue(issues, path5, "Expected an array of entry types.");
727
726
  return void 0;
728
727
  }
729
728
  const normalized = [];
730
729
  const seen = /* @__PURE__ */ new Set();
731
730
  for (const [index, item] of value.entries()) {
732
731
  if (typeof item !== "string") {
733
- pushIssue(issues, `${path4}.${index}`, "Expected a supported entry type.");
732
+ pushIssue(issues, `${path5}.${index}`, "Expected a supported entry type.");
734
733
  continue;
735
734
  }
736
735
  const trimmed = item.trim();
737
736
  if (!isEntryType(trimmed)) {
738
- pushIssue(issues, `${path4}.${index}`, "Expected a supported entry type.");
737
+ pushIssue(issues, `${path5}.${index}`, "Expected a supported entry type.");
739
738
  continue;
740
739
  }
741
740
  if (!seen.has(trimmed)) {
@@ -744,7 +743,7 @@ function parseEligibleTypes(value, path4, issues) {
744
743
  }
745
744
  }
746
745
  if (normalized.length === 0) {
747
- pushIssue(issues, path4, "Expected at least one supported entry type.");
746
+ pushIssue(issues, path5, "Expected at least one supported entry type.");
748
747
  return void 0;
749
748
  }
750
749
  return normalized;
@@ -818,8 +817,53 @@ function toSurgeonInput(value) {
818
817
  return hasSurgeonInput(input) ? input : void 0;
819
818
  }
820
819
 
820
+ // src/filesystem-path.ts
821
+ import path from "path";
822
+ import { fileURLToPath, pathToFileURL } from "url";
823
+ function toAbsoluteFileUrl(filePath) {
824
+ return pathToFileURL(path.resolve(filePath)).href;
825
+ }
826
+ function resolveLocalFilesystemPath(targetPath) {
827
+ const trimmedPath = targetPath.trim();
828
+ if (trimmedPath.length === 0 || trimmedPath === ":memory:" || isInMemoryFileUrl(trimmedPath)) {
829
+ return null;
830
+ }
831
+ if (trimmedPath.startsWith("file:")) {
832
+ if (isAbsoluteFileUrl(trimmedPath)) {
833
+ try {
834
+ return fileURLToPath(trimmedPath);
835
+ } catch {
836
+ return null;
837
+ }
838
+ }
839
+ const relativePath = decodeRelativeFileUrlPath(trimmedPath);
840
+ return relativePath ? path.resolve(relativePath) : null;
841
+ }
842
+ return path.resolve(trimmedPath);
843
+ }
844
+ function resolveConfigFilesystemPath(targetPath) {
845
+ return resolveLocalFilesystemPath(targetPath) ?? targetPath;
846
+ }
847
+ function isAbsoluteFileUrl(targetPath) {
848
+ return /^file:(?:\/|[A-Za-z]:[\\/])/u.test(targetPath);
849
+ }
850
+ function isInMemoryFileUrl(targetPath) {
851
+ return targetPath === "file::memory:" || targetPath.startsWith("file::memory:?");
852
+ }
853
+ function decodeRelativeFileUrlPath(targetPath) {
854
+ const rawPath = targetPath.slice("file:".length).split(/[?#]/u, 1)[0]?.trim();
855
+ if (!rawPath) {
856
+ return null;
857
+ }
858
+ try {
859
+ return decodeURIComponent(rawPath);
860
+ } catch {
861
+ return rawPath;
862
+ }
863
+ }
864
+
821
865
  // src/config.ts
822
- var DEFAULT_CONFIG_DIR = path.join(os.homedir(), ".agenr");
866
+ var DEFAULT_CONFIG_DIR = path2.join(os.homedir(), ".agenr");
823
867
  var DEFAULT_DB_NAME = "knowledge.db";
824
868
  var CONFIG_DIR_MODE = 448;
825
869
  var CONFIG_FILE_MODE = 384;
@@ -839,7 +883,7 @@ function resolveConfigPath(options = {}) {
839
883
  if (adjacentConfigPath) {
840
884
  return adjacentConfigPath;
841
885
  }
842
- return path.join(resolveConfigDir(), "config.json");
886
+ return path2.join(resolveConfigDir(), "config.json");
843
887
  }
844
888
  function resolveDbPath(config) {
845
889
  return normalizeOptionalString(process.env.AGENR_DB_PATH) ?? normalizeOptionalString(config?.dbPath) ?? resolvePersistedDefaultDbPath();
@@ -880,7 +924,7 @@ function resolveClaimExtractionConfig(config) {
880
924
  };
881
925
  }
882
926
  function readConfig(options = {}) {
883
- const configPath = resolveFilesystemPath(resolveConfigPath(options));
927
+ const configPath = resolveConfigFilesystemPath(resolveConfigPath(options));
884
928
  const defaultDbPath = resolveReadDefaultDbPath(options);
885
929
  if (!fs.existsSync(configPath)) {
886
930
  const parsed2 = parseAgenrConfig(void 0, { defaultDbPath });
@@ -906,11 +950,11 @@ function readConfig(options = {}) {
906
950
  return parsed.value;
907
951
  }
908
952
  function configFileExists(options = {}) {
909
- return fs.existsSync(resolveFilesystemPath(resolveConfigPath(options)));
953
+ return fs.existsSync(resolveConfigFilesystemPath(resolveConfigPath(options)));
910
954
  }
911
955
  function writeConfig(config, options = {}) {
912
- const configPath = resolveFilesystemPath(resolveConfigPath(options));
913
- const configDir = path.dirname(configPath);
956
+ const configPath = resolveConfigFilesystemPath(resolveConfigPath(options));
957
+ const configDir = path2.dirname(configPath);
914
958
  const canonical = canonicalizeAgenrConfigInput(config, {
915
959
  defaultDbPath: resolvePersistedDefaultDbPath()
916
960
  });
@@ -938,30 +982,17 @@ function resolveAdjacentConfigPath(dbPath) {
938
982
  return void 0;
939
983
  }
940
984
  if (normalizedDbPath.startsWith("file:")) {
941
- try {
942
- return path.join(path.dirname(fileURLToPath(normalizedDbPath)), "config.json");
943
- } catch {
944
- return void 0;
945
- }
985
+ const filePath = resolveLocalFilesystemPath(normalizedDbPath);
986
+ return filePath ? path2.join(path2.dirname(filePath), "config.json") : void 0;
946
987
  }
947
- return path.join(path.dirname(normalizedDbPath), "config.json");
988
+ return path2.join(path2.dirname(normalizedDbPath), "config.json");
948
989
  }
949
990
  function normalizeOptionalString(value) {
950
991
  const normalized = value?.trim();
951
992
  return normalized && normalized.length > 0 ? normalized : void 0;
952
993
  }
953
- function resolveFilesystemPath(targetPath) {
954
- if (!targetPath.startsWith("file:")) {
955
- return targetPath;
956
- }
957
- try {
958
- return fileURLToPath(targetPath);
959
- } catch {
960
- return targetPath;
961
- }
962
- }
963
994
  function resolvePersistedDefaultDbPath() {
964
- return path.join(resolveConfigDir(), DEFAULT_DB_NAME);
995
+ return path2.join(resolveConfigDir(), DEFAULT_DB_NAME);
965
996
  }
966
997
  function resolveReadDefaultDbPath(options) {
967
998
  return normalizeOptionalString(process.env.AGENR_DB_PATH) ?? normalizeOptionalString(options.dbPath) ?? resolvePersistedDefaultDbPath();
@@ -1151,7 +1182,7 @@ async function sleep(durationMs) {
1151
1182
  import { createHash } from "crypto";
1152
1183
  import fs2 from "fs";
1153
1184
  import os2 from "os";
1154
- import path2 from "path";
1185
+ import path3 from "path";
1155
1186
  import { createRequire } from "module";
1156
1187
  import { completeSimple, getEnvApiKey, getModel } from "@earendil-works/pi-ai";
1157
1188
  var DEFAULT_REASONING = "medium";
@@ -1330,33 +1361,38 @@ function safeReadJson(filePath) {
1330
1361
  }
1331
1362
  }
1332
1363
  function resolveHomeDir(env) {
1333
- const home = normalizeOptionalString2(env.HOME);
1364
+ const home = normalizeOptionalString2(env.HOME) ?? normalizeOptionalString2(env.USERPROFILE) ?? resolveWindowsHomeFromParts(env);
1334
1365
  return home ? resolveUserPath(home) : os2.homedir();
1335
1366
  }
1336
1367
  function resolveCodexHome(env) {
1337
1368
  const configured = normalizeOptionalString2(env.CODEX_HOME) ?? "~/.codex";
1338
- const resolved = resolveUserPath(configured);
1369
+ const resolved = resolveUserPath(configured, resolveHomeDir(env));
1339
1370
  try {
1340
1371
  return fs2.realpathSync.native(resolved);
1341
1372
  } catch {
1342
1373
  return resolved;
1343
1374
  }
1344
1375
  }
1345
- function resolveUserPath(value) {
1376
+ function resolveUserPath(value, homeDir = os2.homedir()) {
1346
1377
  const trimmed = value.trim();
1347
1378
  if (trimmed === "~") {
1348
- return os2.homedir();
1379
+ return homeDir;
1349
1380
  }
1350
1381
  if (trimmed.startsWith("~/")) {
1351
- return path2.join(os2.homedir(), trimmed.slice(2));
1382
+ return path3.join(homeDir, trimmed.slice(2));
1352
1383
  }
1353
1384
  if (trimmed.startsWith("~\\")) {
1354
- return path2.join(os2.homedir(), trimmed.slice(2));
1385
+ return path3.join(homeDir, trimmed.slice(2));
1355
1386
  }
1356
- return path2.resolve(trimmed);
1387
+ return path3.resolve(trimmed);
1388
+ }
1389
+ function resolveWindowsHomeFromParts(env) {
1390
+ const drive = normalizeOptionalString2(env.HOMEDRIVE);
1391
+ const homePath = normalizeOptionalString2(env.HOMEPATH);
1392
+ return drive && homePath ? `${drive}${homePath}` : void 0;
1357
1393
  }
1358
1394
  function parseCodexFromFile(env) {
1359
- const authPath = path2.join(resolveCodexHome(env), "auth.json");
1395
+ const authPath = path3.join(resolveCodexHome(env), "auth.json");
1360
1396
  const parsed = safeReadJson(authPath);
1361
1397
  if (!parsed || typeof parsed !== "object") {
1362
1398
  return null;
@@ -1419,7 +1455,7 @@ function parseClaudeCredentialRecord(parsed, source) {
1419
1455
  }
1420
1456
  function parseClaudeFromFiles(env) {
1421
1457
  const homeDir = resolveHomeDir(env);
1422
- const candidates = [path2.join(homeDir, ".claude", ".credentials.json"), path2.join(homeDir, ".claude", "credentials.json")];
1458
+ const candidates = [path3.join(homeDir, ".claude", ".credentials.json"), path3.join(homeDir, ".claude", "credentials.json")];
1423
1459
  for (const candidate of candidates) {
1424
1460
  const parsed = safeReadJson(candidate);
1425
1461
  const resolved = parseClaudeCredentialRecord(parsed, `file:${candidate}`);
@@ -1747,7 +1783,7 @@ async function sleep2(durationMs) {
1747
1783
 
1748
1784
  // src/adapters/db/client.ts
1749
1785
  import fs3 from "fs/promises";
1750
- import path3 from "path";
1786
+ import path4 from "path";
1751
1787
  import { createClient } from "@libsql/client";
1752
1788
 
1753
1789
  // src/adapters/db/episode-queries.ts
@@ -3192,14 +3228,14 @@ function normalizeProcedureSources(value, label, filePath, options = {}) {
3192
3228
  function normalizeProcedureSource(record, label, filePath) {
3193
3229
  rejectUnexpectedProcedureFields(record, SOURCE_KEYS, label, filePath);
3194
3230
  const kind = readProcedureSourceKind(record.kind, `${label}.kind`, filePath, PROCEDURE_SOURCE_KINDS);
3195
- const path4 = readOptionalProcedureString(record.path, `${label}.path`, filePath);
3231
+ const path5 = readOptionalProcedureString(record.path, `${label}.path`, filePath);
3196
3232
  const locator = readOptionalProcedureString(record.locator, `${label}.locator`, filePath);
3197
3233
  const sourceLabel = readOptionalProcedureString(record.label, `${label}.label`, filePath);
3198
3234
  switch (kind) {
3199
3235
  case "skill":
3200
3236
  case "doc":
3201
3237
  case "repo_file":
3202
- if (!path4) {
3238
+ if (!path5) {
3203
3239
  throw new Error(`Invalid procedure ${filePath}: ${label}.${kind} sources require a path.`);
3204
3240
  }
3205
3241
  break;
@@ -3217,7 +3253,7 @@ function normalizeProcedureSource(record, label, filePath) {
3217
3253
  }
3218
3254
  return {
3219
3255
  kind,
3220
- ...path4 ? { path: path4 } : {},
3256
+ ...path5 ? { path: path5 } : {},
3221
3257
  ...locator ? { locator } : {},
3222
3258
  ...sourceLabel ? { label: sourceLabel } : {}
3223
3259
  };
@@ -5371,9 +5407,9 @@ async function openClient(dbPath) {
5371
5407
  if (trimmedPath.length === 0) {
5372
5408
  throw new Error("Database path must not be empty.");
5373
5409
  }
5374
- if (trimmedPath !== ":memory:" && !trimmedPath.startsWith("file:")) {
5375
- const resolvedPath = path3.resolve(trimmedPath);
5376
- await fs3.mkdir(path3.dirname(resolvedPath), { recursive: true });
5410
+ const localDbPath = resolveLocalFilesystemPath(trimmedPath);
5411
+ if (localDbPath) {
5412
+ await fs3.mkdir(path4.dirname(localDbPath), { recursive: true });
5377
5413
  }
5378
5414
  const client = createClient({ url: resolveClientUrl(trimmedPath) });
5379
5415
  await client.execute("PRAGMA foreign_keys = ON");
@@ -5390,7 +5426,7 @@ function resolveClientUrl(dbPath) {
5390
5426
  if (dbPath.startsWith("file:")) {
5391
5427
  return dbPath;
5392
5428
  }
5393
- return `file:${path3.resolve(dbPath)}`;
5429
+ return toAbsoluteFileUrl(dbPath);
5394
5430
  }
5395
5431
  async function rollbackTransaction(transaction) {
5396
5432
  if (transaction.closed) {
@@ -7909,6 +7945,7 @@ function dedupePreservingOrder2(values) {
7909
7945
  }
7910
7946
 
7911
7947
  export {
7948
+ resolveLocalFilesystemPath,
7912
7949
  ENTRY_TYPES,
7913
7950
  EXPIRY_LEVELS,
7914
7951
  CLAIM_KEY_STATUSES,
@@ -15,14 +15,14 @@ import {
15
15
  parseRecallMode,
16
16
  resolveTargetEntry,
17
17
  storeEntriesDetailed
18
- } from "./chunk-EEEL53X4.js";
18
+ } from "./chunk-TMDNFBBC.js";
19
19
  import {
20
20
  containsAgenrMemoryContext,
21
21
  formatInjectionEntryBodyLines,
22
22
  formatInjectionEntryHeader,
23
23
  stripAgenrMemoryContext,
24
24
  wrapAgenrMemoryContext
25
- } from "./chunk-V5CDMHRN.js";
25
+ } from "./chunk-UEGURBBW.js";
26
26
  import {
27
27
  ENTRY_PREVIEW_MAX_CHARS,
28
28
  ENTRY_SELECT_COLUMNS,
@@ -57,7 +57,7 @@ import {
57
57
  runUnifiedRecall,
58
58
  truncate,
59
59
  validateTemporalValidityRange
60
- } from "./chunk-NNO2V4GH.js";
60
+ } from "./chunk-FMQTRTWE.js";
61
61
  import {
62
62
  recall
63
63
  } from "./chunk-5LADPJ4C.js";
@@ -23,7 +23,7 @@ import {
23
23
  readRequiredString,
24
24
  truncate,
25
25
  validateTemporalValidityRange
26
- } from "./chunk-NNO2V4GH.js";
26
+ } from "./chunk-FMQTRTWE.js";
27
27
  import {
28
28
  compactClaimKey,
29
29
  describeClaimKeyNormalizationFailure,
@@ -2,7 +2,7 @@ import {
2
2
  projectClaimCentricRecallEntry,
3
3
  runProcedureRecall,
4
4
  truncate
5
- } from "./chunk-NNO2V4GH.js";
5
+ } from "./chunk-FMQTRTWE.js";
6
6
  import {
7
7
  recall
8
8
  } from "./chunk-5LADPJ4C.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  formatTargetSelectorFromParams
3
- } from "./chunk-EEEL53X4.js";
3
+ } from "./chunk-TMDNFBBC.js";
4
4
 
5
5
  // src/adapters/openclaw/transcript/parser.ts
6
6
  import { createHash } from "crypto";
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  openClawTranscriptParser,
10
10
  parseTuiSessionKey,
11
11
  readOpenClawSessionsStore
12
- } from "./chunk-JSVQILB3.js";
12
+ } from "./chunk-ZAX3YSTU.js";
13
13
  import {
14
14
  applyClaimExtractionResultToEntry,
15
15
  backfillEpisodeEmbeddings,
@@ -33,7 +33,7 @@ import {
33
33
  tokenizeGroundingText,
34
34
  validateEntriesWithIndexes,
35
35
  validateSupersessionRules
36
- } from "./chunk-EEEL53X4.js";
36
+ } from "./chunk-TMDNFBBC.js";
37
37
  import {
38
38
  DEFAULT_CLAIM_EXTRACTION_CONCURRENCY,
39
39
  DEFAULT_SURGEON_CONTEXT_LIMIT,
@@ -93,6 +93,7 @@ import {
93
93
  resolveEmbeddingModel,
94
94
  resolveLlmApiKey,
95
95
  resolveLlmCredentials,
96
+ resolveLocalFilesystemPath,
96
97
  resolveModel,
97
98
  retireEntry,
98
99
  supersedeEntry,
@@ -100,7 +101,7 @@ import {
100
101
  updateEntry,
101
102
  validateTemporalValidityRange,
102
103
  writeConfig
103
- } from "./chunk-NNO2V4GH.js";
104
+ } from "./chunk-FMQTRTWE.js";
104
105
  import {
105
106
  compactClaimKey,
106
107
  describeClaimKeyNormalizationFailure,
@@ -168,7 +169,6 @@ function formatLabel(label, value) {
168
169
  // src/cli/commands/db.ts
169
170
  import fs from "fs/promises";
170
171
  import path from "path";
171
- import { fileURLToPath } from "url";
172
172
  import * as clack from "@clack/prompts";
173
173
  function registerDbCommand(program2) {
174
174
  const dbCommand = program2.command("db").description("Database utilities");
@@ -199,25 +199,11 @@ function registerDbCommand(program2) {
199
199
  });
200
200
  }
201
201
  function resolveResetPath(dbPath) {
202
- if (dbPath === ":memory:") {
202
+ const trimmedPath = dbPath.trim();
203
+ if (trimmedPath === ":memory:") {
203
204
  return { displayPath: dbPath };
204
205
  }
205
- if (dbPath.startsWith("file:")) {
206
- try {
207
- const filePath = fileURLToPath(dbPath);
208
- return {
209
- deletePath: filePath,
210
- displayPath: filePath
211
- };
212
- } catch {
213
- const resolvedPath2 = path.resolve(dbPath.slice("file:".length));
214
- return {
215
- deletePath: resolvedPath2,
216
- displayPath: resolvedPath2
217
- };
218
- }
219
- }
220
- const resolvedPath = path.resolve(dbPath);
206
+ const resolvedPath = resolveLocalFilesystemPath(trimmedPath) ?? path.resolve(trimmedPath);
221
207
  return {
222
208
  deletePath: resolvedPath,
223
209
  displayPath: resolvedPath
@@ -5135,7 +5121,11 @@ import path11 from "path";
5135
5121
  var OPENCLAW_PLUGIN_PACKAGE = "@agenr/agenr-plugin";
5136
5122
  function execAsync(command, args, options) {
5137
5123
  return new Promise((resolve, reject) => {
5138
- execFile(command, args, options, (error, stdout, stderr) => {
5124
+ const execOptions = {
5125
+ ...options,
5126
+ ...shouldUseShellForCommand(command) ? { shell: true } : {}
5127
+ };
5128
+ execFile(command, args, execOptions, (error, stdout, stderr) => {
5139
5129
  if (error) {
5140
5130
  const message = [String(stderr ?? "").trim(), error.message].filter((value) => value.length > 0).join("\n");
5141
5131
  reject(new Error(message || error.message));
@@ -5148,11 +5138,18 @@ function execAsync(command, args, options) {
5148
5138
  });
5149
5139
  });
5150
5140
  }
5141
+ function shouldUseShellForCommand(command, platform = process.platform) {
5142
+ if (platform !== "win32") {
5143
+ return false;
5144
+ }
5145
+ const extension = path11.extname(command).toLowerCase();
5146
+ return extension === ".cmd" || extension === ".bat";
5147
+ }
5151
5148
  function findBinaryPath(name) {
5152
5149
  try {
5153
5150
  const lookupCommand = process.platform === "win32" ? "where" : "which";
5154
5151
  const output = execFileSync(lookupCommand, [name], { encoding: "utf8" }).trim();
5155
- const firstLine = output.split("\n")[0]?.trim();
5152
+ const firstLine = output.split(/\r?\n/u)[0]?.trim();
5156
5153
  return firstLine && firstLine.length > 0 ? firstLine : null;
5157
5154
  } catch {
5158
5155
  return null;
@@ -14212,10 +14209,10 @@ function readRequiredTrue(value, label, filePath) {
14212
14209
  // src/app/scenarios/claim-keys/validation/scenario-root.ts
14213
14210
  import { existsSync } from "fs";
14214
14211
  import path16 from "path";
14215
- import { fileURLToPath as fileURLToPath2 } from "url";
14212
+ import { fileURLToPath } from "url";
14216
14213
  var SCENARIO_ROOT_SEGMENTS = ["tests", "scenarios", "claim-keys"];
14217
14214
  function getDefaultClaimKeyScenarioRoot(options = {}) {
14218
- const moduleDirectory = path16.dirname(fileURLToPath2(options.moduleUrl ?? import.meta.url));
14215
+ const moduleDirectory = path16.dirname(fileURLToPath(options.moduleUrl ?? import.meta.url));
14219
14216
  const startDirectories = Array.from(/* @__PURE__ */ new Set([path16.resolve(options.cwd ?? process.cwd()), moduleDirectory]));
14220
14217
  for (const startDirectory of startDirectories) {
14221
14218
  const discovered = findScenarioRootFrom(startDirectory);
@@ -15653,7 +15650,7 @@ import { InvalidArgumentError as InvalidArgumentError6, Option as Option5 } from
15653
15650
  // src/app/surgeon/runtime.ts
15654
15651
  import { copyFile, mkdir as mkdir3 } from "fs/promises";
15655
15652
  import path21 from "path";
15656
- import { fileURLToPath as fileURLToPath3 } from "url";
15653
+ import { fileURLToPath as fileURLToPath2 } from "url";
15657
15654
  import { getModel as getModel2 } from "@earendil-works/pi-ai";
15658
15655
  var DEFAULT_SURGEON_PROVIDER = "openai";
15659
15656
  var DEFAULT_SURGEON_MODEL = "gpt-5.4-mini";
@@ -15918,7 +15915,7 @@ function resolveFilesystemPath(value) {
15918
15915
  return path21.resolve(value);
15919
15916
  }
15920
15917
  try {
15921
- return fileURLToPath3(value);
15918
+ return fileURLToPath2(value);
15922
15919
  } catch {
15923
15920
  return path21.resolve(value.slice("file:".length));
15924
15921
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-NOIZQRQV.js";
2
+ import "./chunk-6HY5F5FE.js";
3
3
  import "./chunk-ZYADFKX3.js";
4
4
  import "./chunk-GELCEVFA.js";
5
- import "./chunk-V5CDMHRN.js";
6
- import "./chunk-NNO2V4GH.js";
5
+ import "./chunk-UEGURBBW.js";
6
+ import "./chunk-FMQTRTWE.js";
7
7
  import "./chunk-5LADPJ4C.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-NOIZQRQV.js";
2
+ import "./chunk-6HY5F5FE.js";
3
3
  import "./chunk-ZYADFKX3.js";
4
4
  import "./chunk-GELCEVFA.js";
5
- import "./chunk-V5CDMHRN.js";
6
- import "./chunk-NNO2V4GH.js";
5
+ import "./chunk-UEGURBBW.js";
6
+ import "./chunk-FMQTRTWE.js";
7
7
  import "./chunk-5LADPJ4C.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenr",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Agent memory - local-first knowledge infrastructure for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -26,7 +26,6 @@
26
26
  "devDependencies": {
27
27
  "@eslint/js": "^10.0.1",
28
28
  "@types/node": "^25.5.0",
29
- "skeln": "file:../skeln",
30
29
  "typebox": "^1.1.38",
31
30
  "eslint": "^10.1.0",
32
31
  "eslint-plugin-jsdoc": "^62.8.1",
@@ -57,7 +56,11 @@
57
56
  "lint": "eslint .",
58
57
  "format": "prettier --write .",
59
58
  "format:check": "prettier --check .",
59
+ "smoke:packages": "node scripts/package-smoke.mjs",
60
60
  "test": "vitest run",
61
+ "test:win-sim": "node scripts/test-win-sim.mjs",
62
+ "test:docker": "node scripts/test-docker.mjs",
63
+ "test:docker:check": "node scripts/test-docker.mjs check",
61
64
  "test:watch": "vitest"
62
65
  }
63
66
  }