portable-agent-layer 0.63.2 → 0.63.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "portable-agent-layer",
3
- "version": "0.63.2",
3
+ "version": "0.63.3",
4
4
  "description": "PAL — Portable Agent Layer: persistent personal context for AI coding assistants",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Called from UserPromptOrchestrator. Reads the retrieval index, ranks the prompt
5
5
  * against the corpus, prints a `<system-reminder>` block to stdout (Claude Code
6
- * prepends UserPromptSubmit hook stdout to the prompt). Fail-closed: any error or
7
- * timeout produces empty output, never blocks the prompt.
6
+ * prepends UserPromptSubmit hook stdout to the prompt). Fail-closed: any error
7
+ * produces empty output, never blocks the prompt.
8
8
  */
9
9
 
10
10
  import { isCodex, isCursor } from "../lib/agent";
@@ -14,21 +14,25 @@ import { ensureIndex } from "../lib/retrieval-index";
14
14
  import { isEnabled } from "../lib/settings";
15
15
  import { getSteeringReminder } from "../lib/steering";
16
16
 
17
- const TIMEOUT_MS = 250;
17
+ const BUDGET_MS = 250;
18
18
 
19
- function withTimeout<T>(work: () => T, ms: number): Promise<T | null> {
20
- return new Promise((resolve) => {
21
- const timer = setTimeout(() => resolve(null), ms);
22
- try {
23
- const result = work();
24
- clearTimeout(timer);
25
- resolve(result);
26
- } catch (err) {
27
- clearTimeout(timer);
28
- logError("inject-retrieval", err);
29
- resolve(null);
19
+ /** Run sync work on the prompt path, containing any throw. A synchronous call cannot
20
+ * be preempted on a single thread, so the budget is measured and logged, never
21
+ * enforced an overrun still returns its result rather than being discarded.
22
+ * @lintignore exported for test/inject-retrieval.test.ts */
23
+ export function withinBudget<T>(work: () => T, ms: number): T | null {
24
+ const started = performance.now();
25
+ try {
26
+ return work();
27
+ } catch (err) {
28
+ logError("inject-retrieval", err);
29
+ return null;
30
+ } finally {
31
+ const elapsed = performance.now() - started;
32
+ if (elapsed > ms) {
33
+ logDebug("inject-retrieval", `over budget: ${elapsed.toFixed(0)}ms > ${ms}ms`);
30
34
  }
31
- });
35
+ }
32
36
  }
33
37
 
34
38
  /** Returns the retrieval reminder string, or null if nothing to inject. @lintignore dynamically imported by opencode plugin */
@@ -36,11 +40,11 @@ export async function getRetrievalReminder(prompt: string): Promise<string | nul
36
40
  if (!prompt?.trim()) return null;
37
41
  if (!isEnabled("learningInjection")) return null;
38
42
 
39
- const result = await withTimeout(() => {
43
+ const result = withinBudget(() => {
40
44
  const index = ensureIndex();
41
45
  if (index.corpusSize === 0) return null;
42
46
  return runRetrieval(prompt, index, process.cwd());
43
- }, TIMEOUT_MS);
47
+ }, BUDGET_MS);
44
48
 
45
49
  if (!result?.reminder) return null;
46
50