qlogicagent 1.3.0 → 2.1.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.
Files changed (44) hide show
  1. package/README.md +35 -8
  2. package/dist/agent.js +14 -14
  3. package/dist/cli.js +261 -224
  4. package/dist/index.js +260 -224
  5. package/dist/qlogicagent.cmd +2 -0
  6. package/dist/types/cli/main.d.ts +5 -1
  7. package/dist/types/cli/stdio-server.d.ts +62 -6
  8. package/dist/types/contracts/hooks.d.ts +3 -0
  9. package/dist/types/index.d.ts +1 -1
  10. package/dist/types/llm/index.d.ts +1 -1
  11. package/dist/types/llm/transports/media-resolve.d.ts +25 -0
  12. package/dist/types/runtime/execution/dream-agent.d.ts +2 -0
  13. package/dist/types/runtime/execution/dream-category-context.d.ts +47 -0
  14. package/dist/types/runtime/execution/dream-category-context.test.d.ts +1 -0
  15. package/dist/types/runtime/execution/index.d.ts +1 -0
  16. package/dist/types/runtime/execution/memory-decay.d.ts +57 -0
  17. package/dist/types/runtime/execution/memory-decay.test.d.ts +1 -0
  18. package/dist/types/runtime/hooks/index.d.ts +1 -0
  19. package/dist/types/runtime/hooks/memory-hooks.d.ts +20 -0
  20. package/dist/types/runtime/hooks/skill-recall-hooks.d.ts +36 -0
  21. package/dist/types/runtime/infra/acp-protocol-adapter.d.ts +72 -18
  22. package/dist/types/runtime/infra/acp-types.d.ts +30 -17
  23. package/dist/types/runtime/infra/agent-paths.d.ts +15 -3
  24. package/dist/types/runtime/infra/disk-storage.d.ts +0 -16
  25. package/dist/types/runtime/infra/index.d.ts +4 -4
  26. package/dist/types/runtime/session/session-persistence.d.ts +3 -1
  27. package/dist/types/skills/index.d.ts +5 -5
  28. package/dist/types/skills/memory/find-relevant-memories.d.ts +70 -0
  29. package/dist/types/skills/memory/memdir.d.ts +80 -0
  30. package/dist/types/skills/memory/memory-tool.d.ts +16 -44
  31. package/dist/types/skills/memory/memory-write-gate.d.ts +46 -0
  32. package/dist/types/skills/memory/memory-write-hook.d.ts +44 -0
  33. package/dist/types/skills/memory/qmemory-adapter.d.ts +12 -0
  34. package/dist/types/skills/memory/recall-category-filter.d.ts +54 -0
  35. package/dist/types/skills/tools/skill-tool.d.ts +16 -3
  36. package/dist/types/transport/acp-event-emitter.d.ts +21 -0
  37. package/dist/types/transport/acp-server.d.ts +130 -0
  38. package/dist/types/transport/index.d.ts +6 -0
  39. package/package.json +1 -1
  40. package/dist/types/skills/memory/memory-store.d.ts +0 -86
  41. package/dist/types/skills/tools/skill-invoke-tool.d.ts +0 -46
  42. package/dist/types/skills/tools/skill-list-tool.d.ts +0 -33
  43. package/dist/types/skills/tools/skill-manage-tool.d.ts +0 -73
  44. package/dist/types/skills/tools/skill-view-tool.d.ts +0 -37
@@ -0,0 +1,2 @@
1
+ @echo off
2
+ node "%~dp0cli.js" %*
@@ -6,6 +6,10 @@
6
6
  * All log/debug output goes to stderr (never pollutes the protocol).
7
7
  *
8
8
  * Usage:
9
- * qlogicagent [--verbose]
9
+ * qlogicagent [--verbose] [--acp]
10
+ *
11
+ * Flags:
12
+ * --verbose Enable debug logging to stderr
13
+ * --acp Enable ACP (Agent-Client Protocol) server alongside legacy protocol
10
14
  */
11
15
  export {};
@@ -9,6 +9,7 @@
9
9
  * The physical I/O layer is abstracted via the Transport interface.
10
10
  */
11
11
  import type { Transport } from "./transport.js";
12
+ import { AcpServer } from "../transport/acp-server.js";
12
13
  export interface StdioServerConfig {
13
14
  verbose: boolean;
14
15
  transport?: Transport;
@@ -35,6 +36,8 @@ export declare class StdioServer {
35
36
  private currentTransport;
36
37
  private currentApiKey;
37
38
  private currentModel;
39
+ private currentProvider;
40
+ private currentBaseUrl;
38
41
  private sessionState;
39
42
  private currentMediaApiKeys;
40
43
  private taskStore;
@@ -43,6 +46,10 @@ export declare class StdioServer {
43
46
  /** QMemory adapter (when QMEMORY_BASE_URL env is set). Used by Dream hippocampus bridge. */
44
47
  private qmemoryAdapter;
45
48
  private qmemoryUserId;
49
+ /** MEMDIR file-based memory (CC memdir parity). */
50
+ private memdir;
51
+ /** Memory write gate state (P2+P3: category gate + supersedes). */
52
+ private memoryWriteState;
46
53
  private fileWatcher;
47
54
  /** Pending ask_user requests waiting for host response */
48
55
  private pendingAskUser;
@@ -59,6 +66,20 @@ export declare class StdioServer {
59
66
  /** Process managers for solo/product (stored for agents.processes/kill). */
60
67
  private soloProcessManager;
61
68
  private productProcessManager;
69
+ /** ACP Server instance — handles ACP protocol alongside legacy protocol. */
70
+ private acpServer;
71
+ /** Idle dream timer — fires after configurable idle period to trigger memory consolidation. */
72
+ private idleDreamTimer;
73
+ /** Idle dream config (minutes). Default: 30 min idle = trigger dream. */
74
+ private idleDreamMinutes;
75
+ /** Whether idle dream is enabled. Requires LLM config + memory root to be set. */
76
+ private idleDreamEnabled;
77
+ /** Last dream timestamp to enforce cooldown. */
78
+ private lastDreamAt;
79
+ /** Dream cooldown (ms). Default: 4 hours. */
80
+ private dreamCooldownMs;
81
+ /** Max dream duration (ms). Default: 5 minutes. */
82
+ private dreamMaxDurationMs;
62
83
  constructor(config: StdioServerConfig);
63
84
  start(): void;
64
85
  stop(): void;
@@ -104,15 +125,15 @@ export declare class StdioServer {
104
125
  */
105
126
  private handleSessionGetInfo;
106
127
  /**
107
- * `memory.list` — Enumerate available memory sources (local store + qmemory).
128
+ * `memory.list` — Enumerate available memory sources (memdir + qmemory).
108
129
  */
109
130
  private handleMemoryList;
110
131
  /**
111
- * `memory.read` — Read memory content from local store or QMemory.
132
+ * `memory.read` — Read memory content from memdir (INDEX.md or topic file).
112
133
  */
113
134
  private handleMemoryRead;
114
135
  /**
115
- * `memory.write` — Write memory content to local store (agent notes / user profile).
136
+ * `memory.write` — Write memory content to memdir (INDEX.md or topic file).
116
137
  */
117
138
  private handleMemoryWrite;
118
139
  /**
@@ -157,12 +178,11 @@ export declare class StdioServer {
157
178
  */
158
179
  private handleTodosList;
159
180
  /**
160
- * `memory.search` — Vector search via QMemory adapter.
161
- * Powers the memory page's search feature.
181
+ * `memory.search` — Search memory via QMemory (vector) or memdir (local keyword).
162
182
  */
163
183
  private handleMemorySearch;
164
184
  /**
165
- * `memory.delete` — Remove a memory entry by substring match (local) or ID (qmemory).
185
+ * `memory.delete` — Remove memory entry from memdir (INDEX.md line) or QMemory (by ID).
166
186
  */
167
187
  private handleMemoryDelete;
168
188
  /**
@@ -243,4 +263,40 @@ export declare class StdioServer {
243
263
  private sendNotification;
244
264
  private writeStdout;
245
265
  private log;
266
+ /**
267
+ * Enable idle dream scheduling. Called after session setup when LLM config is available.
268
+ */
269
+ enableIdleDream(minutes?: number): void;
270
+ private resetIdleDreamTimer;
271
+ private cancelIdleDreamTimer;
272
+ private triggerIdleDream;
273
+ /**
274
+ * Initialize the ACP server alongside the legacy protocol.
275
+ * Called once when the host is an ACP-compliant client.
276
+ */
277
+ initAcpServer(): void;
278
+ /** Get the ACP server instance (for external wiring, e.g., main.ts). */
279
+ getAcpServer(): AcpServer | null;
280
+ private acpHandleInitialize;
281
+ private acpHandleSessionNew;
282
+ private acpHandleSessionPrompt;
283
+ /**
284
+ * Run a turn in ACP mode — streams events via session/update, returns final result.
285
+ * This duplicates the core logic of handleTurn but returns a promise with the final content.
286
+ */
287
+ private runAcpTurn;
288
+ private acpHandleSessionEnd;
289
+ private acpHandleSessionSetConfig;
290
+ private acpHandleSessionSetModel;
291
+ private acpHandleSessionSetMode;
292
+ private acpHandlePermissionResponse;
293
+ private acpHandleAbort;
294
+ private acpHandleDream;
295
+ private acpHandleSoloStart;
296
+ private acpHandleSoloStatus;
297
+ private acpHandleSoloSelect;
298
+ private acpHandleProductCreate;
299
+ private acpHandleProductResume;
300
+ private acpHandleProductStatus;
301
+ private acpHandleTeamDelegate;
246
302
  }
@@ -114,7 +114,10 @@ export interface HookContextMap {
114
114
  recalledMemories?: Array<{
115
115
  text: string;
116
116
  score?: number;
117
+ category?: string | null;
117
118
  }>;
119
+ preferredCategories?: string[];
120
+ deprioritizedCategories?: string[];
118
121
  };
119
122
  "memory.after_recall": HookTurnContext & {
120
123
  blockCount?: number;
@@ -10,7 +10,7 @@ export type { AgentConfig } from "./config/config.js";
10
10
  export type { Transport } from "./cli/transport.js";
11
11
  export { StdioTransport } from "./cli/transport.js";
12
12
  export { StdioServer, type StdioServerConfig } from "./cli/stdio-server.js";
13
- export { ProviderRegistry, createLLMClient, autoDetectProvider, } from "./llm/index.js";
13
+ export { ProviderRegistry, createLLMClient, } from "./llm/index.js";
14
14
  export type { LLMTransport, LLMRequest, LLMChunk } from "./llm/index.js";
15
15
  export { createHookRegistry } from "./runtime/hooks/hook-registry.js";
16
16
  export { buildSkillInstruction, } from "./orchestration/index.js";
@@ -12,7 +12,7 @@ export { ProviderRegistry } from "./provider-registry.js";
12
12
  export { BUILTIN_PROVIDERS } from "./builtin-providers.js";
13
13
  export { ModelCatalog } from "./model-catalog.js";
14
14
  export type { LLMClientConfig, LLMClient } from "./llm-client.js";
15
- export { createLLMClient, autoDetectProvider } from "./llm-client.js";
15
+ export { createLLMClient } from "./llm-client.js";
16
16
  export { OpenAIChatTransport } from "./transports/openai-chat.js";
17
17
  export { AnthropicMessagesTransport } from "./transports/anthropic-messages.js";
18
18
  export { GeminiGenerateContentTransport } from "./transports/gemini-generatecontent.js";
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Media URL Resolution — converts local/private URLs to inline base64 data URLs.
3
+ *
4
+ * Cloud LLM APIs (OpenAI, Anthropic, DeepSeek) cannot fetch content from
5
+ * localhost or private networks. This utility detects such URLs and resolves
6
+ * them to base64 data URLs that can be sent inline.
7
+ *
8
+ * URL-first design: the gateway stores media as HTTP URLs; this layer handles
9
+ * the last-mile transformation before sending to provider APIs.
10
+ */
11
+ /** Check if a URL points to a local/private address that cloud APIs cannot reach. */
12
+ export declare function isLocalUrl(url: string): boolean;
13
+ /**
14
+ * Resolve a URL to a base64 data URL if it's a local address.
15
+ * Public URLs are returned as-is (the LLM API can fetch them directly).
16
+ *
17
+ * Returns the original URL for non-local addresses.
18
+ * Returns a `data:<mime>;base64,...` string for local addresses.
19
+ */
20
+ export declare function resolveMediaUrl(url: string, fallbackMime?: string): Promise<string>;
21
+ /**
22
+ * Batch-resolve multiple URLs. Returns array in same order.
23
+ * Failures are logged and the original URL is kept (best-effort).
24
+ */
25
+ export declare function resolveMediaUrls(urls: string[], fallbackMime?: string): Promise<string[]>;
@@ -72,9 +72,11 @@ export declare function canUseDreamTool(memoryRoot: string, restriction: DreamTo
72
72
  * Build the 4-phase memory consolidation prompt.
73
73
  *
74
74
  * Adapted from CC's consolidationPrompt.ts with our project context.
75
+ * P5: Enhanced with category-aware merge rules from write gate taxonomy.
75
76
  */
76
77
  export declare function buildConsolidationPrompt(memoryRoot: string, transcriptDir: string, sessionIds: string[], opts?: {
77
78
  hasQMemory?: boolean;
79
+ categoryContext?: string;
78
80
  }): string;
79
81
  /**
80
82
  * Check whether dream consolidation should run.
@@ -0,0 +1,47 @@
1
+ import type { QMemoryCategory } from "../../skills/memory/memory-write-gate.js";
2
+ /** A memory file with its inferred category and metadata. */
3
+ export interface CategorizedMemoryFile {
4
+ filename: string;
5
+ category: QMemoryCategory | "uncategorized";
6
+ /** First line description. */
7
+ description: string;
8
+ /** File size bytes. */
9
+ sizeBytes: number;
10
+ /** Count of entries/bullets in the file. */
11
+ entryCount: number;
12
+ }
13
+ /** Category statistics for the dream prompt. */
14
+ export interface CategoryManifest {
15
+ /** Per-category file groups. */
16
+ categories: Record<string, CategorizedMemoryFile[]>;
17
+ /** Total files scanned. */
18
+ totalFiles: number;
19
+ /** Files that couldn't be classified. */
20
+ uncategorizedCount: number;
21
+ }
22
+ /**
23
+ * Scan MEMDIR and classify all topic files by category.
24
+ *
25
+ * @param memoryRoot - The MEMDIR root directory
26
+ * @returns Category manifest with grouped files
27
+ */
28
+ export declare function scanCategoryManifest(memoryRoot: string): Promise<CategoryManifest>;
29
+ /**
30
+ * Category-specific merge/conflict rules for the dream prompt.
31
+ *
32
+ * These rules tell the dream agent how to handle each category:
33
+ * - facts: supersede (newer replaces older when same topic)
34
+ * - lessons: accumulate (append new insights, don't delete old)
35
+ * - preferences: overwrite (latest preference wins)
36
+ * - patterns: merge (consolidate duplicates into one authoritative entry)
37
+ * - decisions: update (add "update" section if decision changed)
38
+ */
39
+ export declare const CATEGORY_MERGE_RULES: Record<QMemoryCategory | "uncategorized", string>;
40
+ /**
41
+ * Format the category manifest and merge rules as an injection block
42
+ * for the dream consolidation prompt.
43
+ *
44
+ * This replaces the blind "grep transcripts" approach with structured
45
+ * guidance about what exists and how to handle each category.
46
+ */
47
+ export declare function formatCategoryContextBlock(manifest: CategoryManifest): string;
@@ -3,4 +3,5 @@ export { createContentReplacementState, enforceToolResultBudget, maybePersistLar
3
3
  export { resolveToolEligibility, type ToolEligibilityContext, type ToolEligibilityResult } from "./tool-eligibility.js";
4
4
  export { runForkedAgent, type ForkedAgentParams, type CanUseToolFn } from "./forked-agent.js";
5
5
  export { runDream, type DreamRunDeps } from "./dream-agent.js";
6
+ export { runDecayCycle, shouldTriggerDecay, markDecayComplete, type DecayCycleDeps, type DecayCycleResult, type DecayConfig } from "./memory-decay.js";
6
7
  export { createProgressTracker, updateProgressFromUsage, recordToolUse, getProgressUpdate, type AgentProgress, } from "./progress-tracker.js";
@@ -0,0 +1,57 @@
1
+ import type { DecayOptions, DecayResult } from "../../skills/memory/qmemory-adapter.js";
2
+ export interface DecayConfig {
3
+ /** Minimum hours between decay cycles. Default: 24. */
4
+ minIntervalHours: number;
5
+ /** Enable temporal expiry (event/plan memories past grace period). Default: true. */
6
+ temporalExpiry: boolean;
7
+ /** Enable staleness decay (reduce importance of unaccessed memories). Default: true. */
8
+ stalenessDecay: boolean;
9
+ /** Enable noise archival (archive memories below threshold). Default: true. */
10
+ noiseArchival: boolean;
11
+ }
12
+ export declare const DEFAULT_DECAY_CONFIG: DecayConfig;
13
+ /**
14
+ * Check whether enough time has elapsed since last decay.
15
+ * Returns true if decay should run.
16
+ */
17
+ export declare function shouldTriggerDecay(memoryRoot: string, config?: Partial<DecayConfig>): Promise<boolean>;
18
+ /**
19
+ * Mark decay as having just run (persist timestamp).
20
+ */
21
+ export declare function markDecayComplete(memoryRoot: string): Promise<void>;
22
+ export interface DecayCycleDeps {
23
+ /** QMemory adapter with triggerDecay method. */
24
+ adapter: {
25
+ triggerDecay(userId: string, options?: DecayOptions): Promise<DecayResult>;
26
+ };
27
+ /** User ID for QMemory operations. */
28
+ userId: string;
29
+ /** Memory root directory (for gate marker). */
30
+ memoryRoot: string;
31
+ /** Decay configuration overrides. */
32
+ config?: Partial<DecayConfig>;
33
+ /** Logger. */
34
+ log?: {
35
+ info(msg: string): void;
36
+ debug?(msg: string): void;
37
+ };
38
+ }
39
+ export interface DecayCycleResult {
40
+ /** Whether decay actually ran (false = skipped by gate). */
41
+ ran: boolean;
42
+ /** Number of memories whose importance was reduced. */
43
+ decayed: number;
44
+ /** Number of memories archived (below threshold). */
45
+ archived: number;
46
+ /** Duration in ms. */
47
+ durationMs: number;
48
+ }
49
+ /**
50
+ * Run a full decay cycle with gate check.
51
+ *
52
+ * Lifecycle:
53
+ * 1. Check time gate (24h default)
54
+ * 2. Call QMemory /v1/admin/decay
55
+ * 3. Mark completion timestamp
56
+ */
57
+ export declare function runDecayCycle(deps: DecayCycleDeps): Promise<DecayCycleResult>;
@@ -1,3 +1,4 @@
1
1
  export { createHookRegistry, type RuntimeLogger } from "./hook-registry.js";
2
2
  export { registerMemoryHooks, createMemoryPrefetchState, type MemoryHooksDeps, type MemoryPrefetchState, MEMORY_PREFETCH_CONFIG, } from "./memory-hooks.js";
3
3
  export { registerContextCompressionHook, compressMessages } from "./context-compression.js";
4
+ export { registerSkillRecallHooks, detectRetrospectiveTrigger, invalidateSkillRecallCache, type SkillRecallHooksDeps, SKILL_RECALL_CONFIG, } from "./skill-recall-hooks.js";
@@ -1,5 +1,6 @@
1
1
  import type { HookRegistry } from "../../contracts/hooks.js";
2
2
  import type { MemoryProvider } from "qlogicagent-runtime-contracts";
3
+ import type { Memdir } from "../../skills/memory/memdir.js";
3
4
  export declare const MEMORY_PREFETCH_CONFIG: {
4
5
  /** Max bytes of memory content to inject per session (CC: 60KB) */
5
6
  readonly MAX_SESSION_BYTES: number;
@@ -47,3 +48,22 @@ export declare function createMemoryPrefetchState(): MemoryPrefetchState;
47
48
  export declare function registerMemoryHooks(hooks: HookRegistry, deps: MemoryHooksDeps,
48
49
  /** Shared state — pass the same object across hook re-registrations in a session. */
49
50
  prefetchState?: MemoryPrefetchState): () => void;
51
+ export interface MemdirRecallHookDeps {
52
+ /** MEMDIR instance (lazy: may be null at registration time). */
53
+ getMemdir: () => Memdir | null;
54
+ /** Logger. */
55
+ log: {
56
+ debug(msg: string): void;
57
+ warn(msg: string): void;
58
+ };
59
+ }
60
+ /**
61
+ * Register the MEMDIR cross-file recall hook on `memory.before_recall`.
62
+ *
63
+ * - Priority 40 (before QMemory at 50)
64
+ * - Scans topic files, selects top-5 relevant
65
+ * - Injects content into recalledMemories (merged with QMemory results)
66
+ * - Respects session byte budget from shared MemoryPrefetchState
67
+ * - Dedup via surfacedPaths (shared with QMemory hook)
68
+ */
69
+ export declare function registerMemdirRecallHook(hooks: HookRegistry, deps: MemdirRecallHookDeps, prefetchState?: MemoryPrefetchState): () => void;
@@ -0,0 +1,36 @@
1
+ import type { HookRegistry } from "../../contracts/hooks.js";
2
+ export declare const SKILL_RECALL_CONFIG: {
3
+ /** Max number of cross-project skills to inject per turn. */
4
+ readonly MAX_RECALLED_SKILLS: 3;
5
+ /** Max chars of skill content to include in recall context. */
6
+ readonly MAX_SKILL_CONTENT_CHARS: 800;
7
+ /** Cache TTL for known project skill index (ms). */
8
+ readonly CACHE_TTL_MS: number;
9
+ };
10
+ /**
11
+ * Detect whether user message contains retrospective/cross-reference semantics.
12
+ * Returns extracted keywords for skill matching if triggered, or null.
13
+ */
14
+ export declare function detectRetrospectiveTrigger(message: string): string[] | null;
15
+ export interface SkillRecallHooksDeps {
16
+ /** Current project cwd (to exclude from cross-project search). */
17
+ currentCwd?: string;
18
+ /** Logger. */
19
+ log: {
20
+ debug(msg: string): void;
21
+ warn(msg: string): void;
22
+ };
23
+ }
24
+ /**
25
+ * Register the cross-project skill recall hook on `memory.before_recall`.
26
+ * Runs at lower priority (60) than QMemory prefetch (50) so it supplements,
27
+ * not replaces, the standard memory recall.
28
+ *
29
+ * When triggered, injects cross-project skill metadata into recalledMemories.
30
+ */
31
+ export declare function registerSkillRecallHooks(hooks: HookRegistry, deps: SkillRecallHooksDeps): () => void;
32
+ /**
33
+ * Invalidate the cross-project skill index cache.
34
+ * Call when skills are created/deleted/promoted to refresh.
35
+ */
36
+ export declare function invalidateSkillRecallCache(): void;
@@ -2,17 +2,54 @@
2
2
  * ACP Protocol Adapter — translates between qlogicagent's internal JSON-RPC
3
3
  * protocol and the ACP (Agent-Client Protocol) wire format.
4
4
  *
5
- * ACP = JSON-RPC 2.0 over stdio with different method names:
6
- * initialize initialize (compatible)
7
- * session/new → create session with workspaceRoot + mcpServers
8
- * prompt → send task
9
- * session/close → abort
10
- * message notifications → turn.delta / turn.end
5
+ * Aligned with @agentclientprotocol/sdk v0.18.2 (PROTOCOL_VERSION = 1).
6
+ * Reference: AionUI ClientSideConnection, @agentclientprotocol/sdk.
11
7
  *
12
- * Reference: AionUI AcpAgentManager, ACP protocol spec.
8
+ * ACP = JSON-RPC 2.0 over NDJSON stdio:
9
+ * HOST → AGENT (requests):
10
+ * initialize, session/new, session/prompt, session/close, session/resume
11
+ * AGENT → HOST (notifications):
12
+ * session/update — carries { sessionId, update: { sessionUpdate: "...", ...payload } }
13
+ * AGENT → HOST (requests, host must respond):
14
+ * fs/read_text_file, fs/write_text_file, session/request_permission,
15
+ * session/elicitation, terminal/create, terminal/output, terminal/release,
16
+ * terminal/wait_for_exit, terminal/kill
13
17
  */
14
18
  import type { ChildProcess } from "node:child_process";
15
19
  import type { AcpInitializeResult, AcpSessionResult, AcpPromptResponse, McpServerConfig } from "./acp-types.js";
20
+ /**
21
+ * Handler for agent→host requests (fs, terminal, permission, elicitation).
22
+ * Host implementations should implement the methods they support.
23
+ */
24
+ export interface AcpHostRequestHandler {
25
+ /** Read a text file from the host filesystem. */
26
+ readTextFile?(params: {
27
+ path: string;
28
+ }): Promise<{
29
+ content: string;
30
+ } | undefined>;
31
+ /** Write a text file on the host filesystem. */
32
+ writeTextFile?(params: {
33
+ path: string;
34
+ content: string;
35
+ }): Promise<Record<string, unknown> | undefined>;
36
+ /** Request permission for a tool call (return selected option). */
37
+ requestPermission?(params: Record<string, unknown>): Promise<Record<string, unknown>>;
38
+ /** Elicitation request (ask user for input). */
39
+ elicitation?(params: Record<string, unknown>): Promise<Record<string, unknown>>;
40
+ /** Create a terminal session. */
41
+ createTerminal?(params: Record<string, unknown>): Promise<Record<string, unknown> | undefined>;
42
+ /** Terminal output data. */
43
+ terminalOutput?(params: Record<string, unknown>): Promise<Record<string, unknown> | undefined>;
44
+ /** Release a terminal. */
45
+ releaseTerminal?(params: Record<string, unknown>): Promise<Record<string, unknown>>;
46
+ /** Wait for terminal exit. */
47
+ waitForTerminalExit?(params: Record<string, unknown>): Promise<Record<string, unknown> | undefined>;
48
+ /** Kill a terminal. */
49
+ killTerminal?(params: Record<string, unknown>): Promise<Record<string, unknown>>;
50
+ /** Extension method (unknown method from agent). */
51
+ extMethod?(method: string, params: unknown): Promise<unknown>;
52
+ }
16
53
  /** Internal representation of an ACP notification translated to qlogicagent format. */
17
54
  export interface TranslatedNotification {
18
55
  method: string;
@@ -21,45 +58,59 @@ export interface TranslatedNotification {
21
58
  export declare class AcpProtocolAdapter {
22
59
  private pendingRpcs;
23
60
  private rl;
61
+ private child;
24
62
  private onNotification;
63
+ private hostHandler;
25
64
  /**
26
65
  * Attach to a child process's stdio for ACP communication.
27
66
  * Must be called before any RPC methods.
67
+ *
68
+ * @param child The spawned ACP agent process
69
+ * @param onNotification Callback for agent notifications (session/update, etc.)
70
+ * @param hostHandler Optional handler for agent→host requests (fs, terminal, permission)
71
+ */
72
+ attach(child: ChildProcess, onNotification?: (method: string, params: unknown) => void, hostHandler?: AcpHostRequestHandler): void;
73
+ /**
74
+ * Handle an incoming JSON-RPC request from the agent (reverse-RPC).
75
+ * Agent calls host for fs operations, terminal, permissions, etc.
28
76
  */
29
- attach(child: ChildProcess, onNotification?: (method: string, params: unknown) => void): void;
77
+ private handleAgentRequest;
30
78
  /** Detach from the child process. */
31
79
  detach(): void;
32
80
  /** Send a raw JSON-RPC request and await response. */
33
81
  sendRpc(child: ChildProcess, method: string, params?: unknown, timeoutMs?: number): Promise<unknown>;
34
82
  /**
35
83
  * Perform ACP initialize handshake.
36
- * Permissive: fallback protocolVersion to 0 if missing.
37
- * Extracts `supportsResume` from capabilities for D-1 session resume.
84
+ * Sends standard clientInfo + clientCapabilities (aligned with SDK).
38
85
  */
39
86
  initialize(child: ChildProcess): Promise<AcpInitializeResult>;
40
87
  /**
41
88
  * Create an ACP session.
42
- * Optionally injects MCP servers and system prompt.
89
+ * Official SDK params: { cwd, mcpServers, additionalDirectories? }
90
+ * Optionally injects system prompt as extension field.
43
91
  */
44
92
  createSession(child: ChildProcess, options: {
45
- workspaceRoot: string;
93
+ cwd: string;
46
94
  mcpServers?: McpServerConfig[];
95
+ additionalDirectories?: string[];
47
96
  systemPrompt?: string;
48
97
  }): Promise<AcpSessionResult>;
49
98
  /**
50
99
  * Send a prompt to a running ACP session.
51
- * Returns the complete response.
100
+ * Official SDK params: { sessionId, prompt: ContentBlock[], messageId? }
101
+ * Official SDK response: { stopReason, usage?, userMessageId? }
102
+ *
103
+ * Note: Actual content is delivered via session/update notifications DURING
104
+ * the prompt execution. The response only signals completion.
52
105
  */
53
106
  sendPrompt(child: ChildProcess, sessionId: string, content: string, timeoutMs?: number): Promise<AcpPromptResponse>;
54
107
  /**
55
- * Resume an existing ACP session (D-1).
56
- * Only call if the agent's capabilities.supportsResume is true.
57
- * Falls back to createSession + summary injection if session/resume fails.
108
+ * Resume an existing ACP session (loadSession capability).
109
+ * Official SDK method: session/load (same schema as session/new + sessionId).
58
110
  */
59
111
  resumeSession(child: ChildProcess, sessionId: string, options?: {
60
- workspaceRoot?: string;
112
+ cwd?: string;
61
113
  mcpServers?: McpServerConfig[];
62
- summary?: string;
63
114
  }): Promise<AcpSessionResult>;
64
115
  /**
65
116
  * Close an ACP session.
@@ -68,6 +119,9 @@ export declare class AcpProtocolAdapter {
68
119
  /**
69
120
  * Translate an ACP notification into qlogicagent's internal format.
70
121
  * Returns null if the notification is not translatable (handled separately).
122
+ *
123
+ * Standard ACP: agent sends "session/update" notification with
124
+ * params: { sessionId, update: { sessionUpdate: "<type>", ...payload } }
71
125
  */
72
126
  static translateNotification(method: string, params: unknown): TranslatedNotification | null;
73
127
  }
@@ -136,39 +136,52 @@ export interface AgentConfigStoreData {
136
136
  /** ACP initialize result (from agent's response). */
137
137
  export interface AcpInitializeResult {
138
138
  protocolVersion: number;
139
- capabilities: {
140
- prompts?: boolean;
141
- /** Whether this agent supports session/resume (D-1). */
142
- supportsResume?: boolean;
139
+ /** Standard ACP agentCapabilities (official SDK field). */
140
+ agentCapabilities: {
141
+ loadSession?: boolean;
142
+ mcpCapabilities?: {
143
+ http?: boolean;
144
+ sse?: boolean;
145
+ };
146
+ promptCapabilities?: {
147
+ audio?: boolean;
148
+ embeddedContext?: boolean;
149
+ image?: boolean;
150
+ };
151
+ sessionCapabilities?: Record<string, unknown>;
143
152
  [key: string]: unknown;
144
153
  };
145
- serverInfo?: {
154
+ /** Standard ACP agentInfo (official SDK field). */
155
+ agentInfo?: {
146
156
  name: string;
147
157
  version?: string;
148
158
  };
159
+ authMethods?: Array<{
160
+ type: string;
161
+ [key: string]: unknown;
162
+ }>;
149
163
  }
150
- /** ACP session/new result. */
164
+ /** ACP session/new result (official: { sessionId, configOptions?, models?, modes? }). */
151
165
  export interface AcpSessionResult {
152
- id: string;
166
+ sessionId: string;
153
167
  }
154
- /** ACP prompt response content item. */
155
- export interface AcpContentItem {
156
- type: "text" | "image" | "resource";
157
- text?: string;
158
- data?: string;
159
- mimeType?: string;
160
- }
161
- /** ACP prompt response. */
168
+ /** Standard ACP stopReason. */
169
+ export type AcpStopReason = "end_turn" | "max_tokens" | "max_turn_requests" | "refusal" | "cancelled";
170
+ /** ACP prompt response (official: { stopReason, usage?, userMessageId? }). */
162
171
  export interface AcpPromptResponse {
163
- content: AcpContentItem[];
172
+ stopReason: AcpStopReason;
164
173
  usage?: AcpPromptResponseUsage;
174
+ userMessageId?: string;
175
+ /** Aggregated text from session/update notifications (populated by adapter). */
176
+ text?: string;
165
177
  }
166
- /** ACP per-turn usage stats. */
178
+ /** ACP per-turn usage stats (aligned with SDK zUsage). */
167
179
  export interface AcpPromptResponseUsage {
168
180
  inputTokens?: number;
169
181
  outputTokens?: number;
170
182
  totalTokens?: number;
171
183
  cachedReadTokens?: number;
184
+ cachedWriteTokens?: number;
172
185
  thoughtTokens?: number;
173
186
  }
174
187
  /** ACP usage_update notification payload (session-level). */
@@ -7,7 +7,7 @@
7
7
  */
8
8
  /** Dot-directory name used for both user-level and project-level storage. */
9
9
  export declare const AGENT_DOT_DIR = ".qlogicagent";
10
- /** `~/.qlogicagent/` */
10
+ /** `~/.qlogicagent/` (or QLOGICAGENT_HOME override) */
11
11
  export declare function getUserAgentHome(): string;
12
12
  /** `~/.qlogicagent/sessions/` */
13
13
  export declare function getUserSessionsRoot(): string;
@@ -59,7 +59,19 @@ export declare function getProjectSessionsRoot(cwd: string): string;
59
59
  export declare function getProjectSessionDir(cwd: string, sessionId: string): string;
60
60
  /** `<cwd>/.qlogicagent/checkpoints/` or `<cwd>/.qlogicagent/checkpoints/{sessionId}` */
61
61
  export declare function getProjectCheckpointsDir(cwd: string, sessionId?: string): string;
62
- /** `<cwd>/.qlogicagent/memory.json` */
63
- export declare function getProjectMemoryPath(cwd: string): string;
64
62
  /** `<gitRoot>/.qlogicagent/hooks/` */
65
63
  export declare function getGitRootHooksDir(gitRoot: string): string;
64
+ /**
65
+ * Discover all known project directories from session history.
66
+ * Scans `~/.qlogicagent/sessions/` metadata to extract unique `cwd` paths.
67
+ * Used for cross-project skill recall (read-only, never writes to foreign projects).
68
+ *
69
+ * @param excludeCwd - Current project cwd to exclude from results
70
+ * @returns Array of absolute paths to project roots that have been worked on
71
+ */
72
+ export declare function getKnownProjectDirs(excludeCwd?: string): string[];
73
+ /**
74
+ * Get skill directories from all known projects (excluding current).
75
+ * Returns paths to `<project>/.qlogicagent/skills/` for recall-only access.
76
+ */
77
+ export declare function getAllProjectSkillDirs(excludeCwd?: string): string[];