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
@@ -4,7 +4,6 @@
4
4
  * Provides:
5
5
  * - Atomic write (tmp + rename) with dir auto-creation
6
6
  * - JSON read/write helpers
7
- * - MemoryStore disk persistence (auto-save on mutation)
8
7
  */
9
8
  /**
10
9
  * Write data atomically: write to a temp file in the same directory,
@@ -19,18 +18,3 @@ export declare function readJsonFile<T = unknown>(filePath: string): Promise<T |
19
18
  * Write a JSON file atomically.
20
19
  */
21
20
  export declare function writeJsonFile(filePath: string, data: unknown): Promise<void>;
22
- /** Path to user-level memory file: `~/.qlogicagent/memory.json` */
23
- export declare function getMemoryFilePath(): string;
24
- export interface PersistedMemory {
25
- memory: string;
26
- user: string;
27
- /** ISO 8601 timestamp of last save. */
28
- savedAt: string;
29
- }
30
- /** Load persisted memory from disk. Returns undefined if no file exists. */
31
- export declare function loadPersistedMemory(): Promise<PersistedMemory | undefined>;
32
- /** Save memory to disk atomically. */
33
- export declare function savePersistedMemory(data: {
34
- memory: string;
35
- user: string;
36
- }): Promise<void>;
@@ -1,18 +1,18 @@
1
- export { AGENT_DOT_DIR, getUserAgentHome, getUserSessionDir, getUserCredentialsPath, getUserPluginsDir, getUserSkillsDir, getUserSettingsPath, getUserCacheDir, getUserDebugLogsDir, getUserCheckpointsDir, getUserPluginCacheDir, getUserMcpConfigPath, getUserMarketplaceConfigPath, getUserWorkflowsDir, getUserInstructionsPath, getProjectAgentDir, getProjectWorkflowsDir, getProjectPluginsDir, getProjectSkillsDir, getProjectSettingsPath, getProjectInstructionsPath, getProjectRulesDir, getGitRootHooksDir, } from "./agent-paths.js";
1
+ export { AGENT_DOT_DIR, getUserAgentHome, getUserSessionDir, getUserCredentialsPath, getUserPluginsDir, getUserSkillsDir, getUserSettingsPath, getUserCacheDir, getUserDebugLogsDir, getUserCheckpointsDir, getUserPluginCacheDir, getUserMcpConfigPath, getUserMarketplaceConfigPath, getUserWorkflowsDir, getUserInstructionsPath, getProjectAgentDir, getProjectWorkflowsDir, getProjectPluginsDir, getProjectSkillsDir, getProjectSettingsPath, getProjectInstructionsPath, getProjectRulesDir, getGitRootHooksDir, getKnownProjectDirs, getAllProjectSkillDirs, } from "./agent-paths.js";
2
2
  export { getBudgetContinuationMessage } from "./token-budget.js";
3
3
  export { type SecureStorage, saveApiKey, loadApiKey } from "./secure-storage.js";
4
4
  export { createFileWatcher, FileWatcher } from "./file-watcher.js";
5
5
  export { TaskStore } from "./task-runtime.js";
6
6
  export { createWorktreeBackend } from "./worktree-backend.js";
7
7
  export { registerCleanup, runCleanupFunctions } from "./cleanup-registry.js";
8
- export { atomicWriteFile, readJsonFile, writeJsonFile, loadPersistedMemory, savePersistedMemory, getMemoryFilePath, type PersistedMemory, } from "./disk-storage.js";
8
+ export { atomicWriteFile, readJsonFile, writeJsonFile, } from "./disk-storage.js";
9
9
  export { AcpDetector, ACP_BACKENDS } from "./acp-detector.js";
10
- export { AcpProtocolAdapter, type TranslatedNotification } from "./acp-protocol-adapter.js";
10
+ export { AcpProtocolAdapter, type TranslatedNotification, type AcpHostRequestHandler } from "./acp-protocol-adapter.js";
11
11
  export { AcpUsageTracker, type AccumulatedUsage } from "./acp-usage-tracker.js";
12
12
  export { AgentConfigStore } from "./agent-config-store.js";
13
13
  export { ModelIdTranslator } from "./model-id-translator.js";
14
14
  export { SkillInjector } from "./skill-injector.js";
15
15
  export { ACP_FAULT_LEVEL, type AcpFaultLevel, buildLlmEnvForTeammate } from "./agent-process.js";
16
16
  export { McpBridge, MCP_BRIDGE_TOOLS } from "./mcp-bridge.js";
17
- export type { AgentCategory, AgentProtocol, AgentStatus, AcpBackendConfig, AgentDescriptor, ExternalAgentDescriptor, CustomAgentDef, AgentConfig, AgentConfigStoreData, AgentCapabilities, AcpInitializeResult, AcpSessionResult, AcpPromptResponse, AcpContentItem, AcpPromptResponseUsage, AcpUsageUpdatePayload, McpServerConfig, AgentsScanParams, AgentsConfigParams, AgentsSetConfigParams, AgentsGetConfigParams, AgentsRemoveConfigParams, AgentsSetGatewayParams, SoloState, SoloAgentState, SoloAgentResult, SoloEvaluation, SoloStatus, SoloStartParams, SoloIdParams, SoloSelectParams, ProductPhase, ProductInstanceState, ProductTaskStatus, ProductBudget, ProductInstanceDef, ProductTaskDef, ProductCreateParams, ProductIdParams, ProductInstanceStatus, ProductTaskState, ProductStatus, ProductSummary, AgentsGetGatewayResult, AgentsListConfiguredItem, AgentsProcessInfo, AgentsKillParams, AgentsGetLogParams, AgentsGetLogResult, AgentsTestConnectionParams, AgentsTestConnectionResult, SoloDeleteParams, ProductDeleteParams, AgentSource, } from "./acp-types.js";
17
+ export type { AgentCategory, AgentProtocol, AgentStatus, AcpBackendConfig, AgentDescriptor, ExternalAgentDescriptor, CustomAgentDef, AgentConfig, AgentConfigStoreData, AgentCapabilities, AcpInitializeResult, AcpSessionResult, AcpPromptResponse, AcpPromptResponseUsage, AcpStopReason, AcpUsageUpdatePayload, McpServerConfig, AgentsScanParams, AgentsConfigParams, AgentsSetConfigParams, AgentsGetConfigParams, AgentsRemoveConfigParams, AgentsSetGatewayParams, SoloState, SoloAgentState, SoloAgentResult, SoloEvaluation, SoloStatus, SoloStartParams, SoloIdParams, SoloSelectParams, ProductPhase, ProductInstanceState, ProductTaskStatus, ProductBudget, ProductInstanceDef, ProductTaskDef, ProductCreateParams, ProductIdParams, ProductInstanceStatus, ProductTaskState, ProductStatus, ProductSummary, AgentsGetGatewayResult, AgentsListConfiguredItem, AgentsProcessInfo, AgentsKillParams, AgentsGetLogParams, AgentsGetLogResult, AgentsTestConnectionParams, AgentsTestConnectionResult, SoloDeleteParams, ProductDeleteParams, AgentSource, } from "./acp-types.js";
18
18
  export type { AgentsStatusNotification, AgentsErrorNotification, SoloProgressNotification, SoloEvaluationNotification, SoloAgentDeltaNotification, ProductTaskStartedNotification, ProductTaskCompletedNotification, ProductTaskFailedNotification, ProductCheckpointedNotification, ProductBudgetWarningNotification, ProductCompletedNotification, } from "../../protocol/notifications.js";
@@ -52,8 +52,10 @@ export interface SessionListEntry {
52
52
  /**
53
53
  * Append a message to the session transcript.
54
54
  * Creates the session directory if it doesn't exist.
55
+ * When turnId is provided, it acts as a per-turn boundary marker enabling
56
+ * reconciliation with Gateway's token_usage records.
55
57
  */
56
- export declare function appendMessage(sessionId: string, message: ChatMessage, projectRoot?: string): Promise<void>;
58
+ export declare function appendMessage(sessionId: string, message: ChatMessage, projectRoot?: string, turnId?: string): Promise<void>;
57
59
  /**
58
60
  * Save session state (cost + metadata) atomically.
59
61
  */
@@ -1,11 +1,11 @@
1
1
  export type { PortableTool, PortableToolResult, ToolContentBlock, } from "./portable-tool.js";
2
2
  export { setToolPool, addTool, addTools, removeTool, findTool, hasTool, getToolNames, getToolCount, executeTool, getToolManifest, getTools, activateTool, isToolActivated, clearActivatedTools, AGENT_DISALLOWED_TOOLS, CUSTOM_AGENT_DISALLOWED_TOOLS, filterToolsForAgent, } from "./tools.js";
3
- export { MEMORY_TOOL_NAME, MEMORY_TOOL_MAX_CONTENT_LENGTH, MEMORY_TOOL_ACTIONS, MEMORY_TOOL_SCHEMA, MEMORY_TOOL_DESCRIPTION, MEMORY_TOOL_LABEL, isMemoryContentSafe, executeMemoryTool, } from "./memory/memory-tool.js";
4
- export type { MemoryToolAction, MemoryToolParams, MemoryToolResult, MemoryToolExecutorDeps, MediaPreferencesSummary, } from "./memory/memory-tool.js";
5
- export { MemoryStore, MEMORY_ENTRY_DELIMITER, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_USER_CHAR_LIMIT, } from "./memory/memory-store.js";
6
- export type { MemoryStoreTarget, MemoryStoreResult, MemoryStoreOptions, MemoryStoreSerialized, } from "./memory/memory-store.js";
3
+ export { MEMORY_TOOL_NAME, MEMORY_TOOL_ACTIONS, MEMORY_TOOL_SCHEMA, MEMORY_TOOL_DESCRIPTION, MEMORY_TOOL_LABEL, isMemoryContentSafe, executeMemoryTool, } from "./memory/memory-tool.js";
4
+ export type { MemoryToolAction, MemoryToolParams, MemoryToolResult, MemoryToolExecutorDeps, } from "./memory/memory-tool.js";
5
+ export { Memdir, getMemdirPath, getIndexPath } from "./memory/memdir.js";
6
+ export type { MemdirFileInfo, MemdirResult } from "./memory/memdir.js";
7
7
  export { createQMemoryAdapter } from "./memory/qmemory-adapter.js";
8
- export type { QMemoryAdapterConfig, QMemoryHealthStatus, ExtractedMemoryItem } from "./memory/qmemory-adapter.js";
8
+ export type { QMemoryAdapterConfig, QMemoryHealthStatus, ExtractedMemoryItem, DecayOptions, DecayResult } from "./memory/qmemory-adapter.js";
9
9
  export { THINK_TOOL_NAME, THINK_TOOL_SCHEMA, createThinkTool } from "./think-tool.js";
10
10
  export type { ThinkToolParams } from "./think-tool.js";
11
11
  export { TODO_TOOL_NAME, TODO_TOOL_SCHEMA, TODO_ACTIONS, createTodoTool } from "./todo-tool.js";
@@ -0,0 +1,70 @@
1
+ export declare const RELEVANT_MEMORIES_CONFIG: {
2
+ /** Max topic files to consider during scan. */
3
+ readonly MAX_SCAN_FILES: 100;
4
+ /** Max files to surface per turn. */
5
+ readonly MAX_SELECTED: 5;
6
+ /** Max bytes per surfaced file (CC: 4096). */
7
+ readonly MAX_FILE_BYTES: 4096;
8
+ /** Max total bytes for all surfaced files combined. */
9
+ readonly MAX_TOTAL_BYTES: number;
10
+ /** Minimum score to be selected (0.0-1.0). */
11
+ readonly MIN_SCORE: 0.2;
12
+ /** Lines to read for header/description extraction. */
13
+ readonly HEADER_LINES: 10;
14
+ /** Recency boost: files modified within this many days get a bonus. */
15
+ readonly RECENCY_DAYS: 7;
16
+ /** Recency boost amount. */
17
+ readonly RECENCY_BOOST: 0.15;
18
+ };
19
+ /** Scanned memory file header (CC MemoryHeader parity). */
20
+ export interface MemoryFileHeader {
21
+ /** Filename (e.g. "lesson-docker.md") */
22
+ filename: string;
23
+ /** Absolute path */
24
+ filePath: string;
25
+ /** Last modified timestamp (ms since epoch) */
26
+ mtimeMs: number;
27
+ /** File size in bytes */
28
+ sizeBytes: number;
29
+ /** Description extracted from first non-heading line */
30
+ description: string | null;
31
+ /** Category inferred from filename prefix */
32
+ category: string | null;
33
+ }
34
+ /** A selected relevant memory with content loaded. */
35
+ export interface RelevantMemory {
36
+ /** Filename */
37
+ filename: string;
38
+ /** Full file path */
39
+ filePath: string;
40
+ /** Last modified timestamp */
41
+ mtimeMs: number;
42
+ /** Relevance score (0.0 - 1.0) */
43
+ score: number;
44
+ /** Content (possibly truncated) */
45
+ content: string;
46
+ /** Whether content was truncated */
47
+ truncated: boolean;
48
+ }
49
+ /**
50
+ * Find memory files relevant to a user query.
51
+ *
52
+ * CC parity: scans topic files, scores by keyword + filename + recency,
53
+ * selects top-N, loads content. No LLM needed (unlike CC's Sonnet call).
54
+ *
55
+ * @param query - User query text
56
+ * @param memoryDir - Root of the MEMDIR directory (~/.qlogicagent/memory/)
57
+ * @param alreadySurfaced - Paths already shown in prior turns (for dedup)
58
+ * @returns Relevant memories with content, sorted by score
59
+ */
60
+ export declare function findRelevantMemories(query: string, memoryDir: string, alreadySurfaced?: ReadonlySet<string>): Promise<RelevantMemory[]>;
61
+ /**
62
+ * Scan memory directory for topic files (excludes INDEX.md).
63
+ * Returns headers sorted by modification time (newest first).
64
+ */
65
+ export declare function scanMemoryHeaders(memoryDir: string): Promise<MemoryFileHeader[]>;
66
+ /**
67
+ * Format relevant memories as a single block for system prompt injection.
68
+ * CC parity: includes freshness header per file.
69
+ */
70
+ export declare function formatRelevantMemoriesBlock(memories: RelevantMemory[]): string;
@@ -0,0 +1,80 @@
1
+ /** Max chars for INDEX.md to inject into system prompt (CC uses 25KB, we use 12KB). */
2
+ export declare const INDEX_MAX_CHARS = 12288;
3
+ /** Max lines for INDEX.md injection. */
4
+ export declare const INDEX_MAX_LINES = 200;
5
+ /** Max chars for a single topic file. */
6
+ export declare const TOPIC_FILE_MAX_CHARS = 8192;
7
+ /** Root directory: ~/.qlogicagent/memory/ */
8
+ export declare function getMemdirPath(): string;
9
+ /** Full path to INDEX.md */
10
+ export declare function getIndexPath(): string;
11
+ export interface MemdirFileInfo {
12
+ name: string;
13
+ /** Size in bytes */
14
+ size: number;
15
+ /** Last modified ISO timestamp */
16
+ modifiedAt: string;
17
+ /** First non-empty line (preview) */
18
+ preview?: string;
19
+ }
20
+ export interface MemdirResult {
21
+ ok: boolean;
22
+ message: string;
23
+ /** File path relative to memdir */
24
+ file?: string;
25
+ /** Current INDEX.md char usage */
26
+ indexUsage?: string;
27
+ }
28
+ export declare function isMemoryContentSafe(text: string): boolean;
29
+ export declare class Memdir {
30
+ private readonly root;
31
+ private indexCache;
32
+ constructor(root?: string);
33
+ /** Get the root directory path of this MEMDIR. */
34
+ getRootPath(): string;
35
+ /** Ensure memdir exists with a default INDEX.md if missing. */
36
+ ensureInitialized(): void;
37
+ /**
38
+ * Get INDEX.md content for system prompt injection.
39
+ * Truncated to INDEX_MAX_CHARS / INDEX_MAX_LINES.
40
+ */
41
+ getIndexForPrompt(): string;
42
+ /** Get raw INDEX.md content (untruncated). */
43
+ getIndexRaw(): string;
44
+ /** Get INDEX.md usage stats. */
45
+ getIndexUsage(): {
46
+ chars: number;
47
+ lines: number;
48
+ percent: number;
49
+ };
50
+ /** Append a line/entry to INDEX.md. */
51
+ addToIndex(content: string): Promise<MemdirResult>;
52
+ /** Replace text in INDEX.md (str_replace semantics). */
53
+ replaceInIndex(oldText: string, newText: string): Promise<MemdirResult>;
54
+ /** Remove text from INDEX.md. */
55
+ removeFromIndex(oldText: string): Promise<MemdirResult>;
56
+ /** List all memory files (excluding INDEX.md). */
57
+ listFiles(): Promise<MemdirFileInfo[]>;
58
+ /** Create a new topic file. Fails if it already exists. */
59
+ createFile(name: string, content: string): Promise<MemdirResult>;
60
+ /** Write/overwrite a topic file. */
61
+ writeFile(name: string, content: string): Promise<MemdirResult>;
62
+ /** Read a topic file. */
63
+ readFile(name: string): Promise<{
64
+ ok: boolean;
65
+ content?: string;
66
+ message: string;
67
+ }>;
68
+ /** Delete a topic file. INDEX.md cannot be deleted. */
69
+ deleteFile(name: string): Promise<MemdirResult>;
70
+ /** Search all memory files for keyword matches. Returns matching snippets. */
71
+ searchLocal(query: string): Promise<Array<{
72
+ file: string;
73
+ snippet: string;
74
+ score: number;
75
+ }>>;
76
+ private writeIndex;
77
+ private ensureDir;
78
+ /** Append an entry to the file listing section of INDEX.md (idempotent). */
79
+ private appendIndexEntry;
80
+ }
@@ -1,16 +1,8 @@
1
1
  import type { MemoryProvider, MemorySearchResult } from "qlogicagent-runtime-contracts";
2
- import type { MemoryStore, MemoryStoreTarget } from "./memory-store.js";
3
- export interface MediaPreferencesSummary {
4
- imageStyle?: string;
5
- videoStyle?: string;
6
- musicGenre?: string;
7
- musicMood?: string;
8
- primaryPurpose?: string;
9
- colorPreference?: string;
10
- }
2
+ import type { Memdir } from "./memdir.js";
11
3
  export declare const MEMORY_TOOL_NAME: "memory";
12
- export declare const MEMORY_TOOL_MAX_CONTENT_LENGTH = 2000;
13
- export declare const MEMORY_TOOL_ACTIONS: readonly ["add", "replace", "remove", "search"];
4
+ export declare const MEMORY_TOOL_LABEL = "Memory";
5
+ export declare const MEMORY_TOOL_ACTIONS: readonly ["add", "replace", "remove", "create_file", "write_file", "read_file", "delete_file", "list_files", "search"];
14
6
  export type MemoryToolAction = (typeof MEMORY_TOOL_ACTIONS)[number];
15
7
  export declare const MEMORY_TOOL_SCHEMA: {
16
8
  readonly type: "object";
@@ -20,68 +12,48 @@ export declare const MEMORY_TOOL_SCHEMA: {
20
12
  readonly enum: string[];
21
13
  readonly description: string;
22
14
  };
23
- readonly target: {
24
- readonly type: "string";
25
- readonly enum: readonly ["memory", "user"];
26
- readonly description: string;
27
- };
28
15
  readonly content: {
29
16
  readonly type: "string";
30
17
  readonly description: string;
31
18
  };
32
19
  readonly old_text: {
33
20
  readonly type: "string";
34
- readonly description: "Required for 'replace' and 'remove'. A substring that uniquely identifies the note entry to modify.";
21
+ readonly description: "For 'replace'/'remove': the exact text to find in INDEX.md.";
35
22
  };
36
- readonly query: {
23
+ readonly new_text: {
37
24
  readonly type: "string";
38
- readonly description: "Required for 'search'. Natural language query to find relevant memories.";
25
+ readonly description: "For 'replace': the replacement text.";
39
26
  };
40
- readonly category: {
27
+ readonly file: {
41
28
  readonly type: "string";
42
- readonly enum: readonly ["profile", "facts", "media", "projects"];
43
- readonly description: string;
29
+ readonly description: "Filename for file operations (e.g. 'project-notes.md', 'lesson-esbuild.md'). Must be kebab-case .md.";
30
+ };
31
+ readonly query: {
32
+ readonly type: "string";
33
+ readonly description: "For 'search': natural language query to find relevant memories.";
44
34
  };
45
35
  };
46
36
  readonly required: readonly ["action"];
47
37
  };
48
38
  export declare const MEMORY_TOOL_DESCRIPTION: string;
49
- export declare const MEMORY_TOOL_LABEL = "Memory";
50
39
  export declare function isMemoryContentSafe(text: string): boolean;
51
40
  export interface MemoryToolParams {
52
41
  action: MemoryToolAction;
53
- target?: MemoryStoreTarget;
54
42
  content?: string;
55
43
  old_text?: string;
44
+ new_text?: string;
45
+ file?: string;
56
46
  query?: string;
57
- category?: "profile" | "facts" | "media" | "projects";
58
47
  }
59
48
  export interface MemoryToolResult {
60
49
  ok: boolean;
61
50
  message: string;
62
51
  action: string;
63
- /** For MD store operations: live entry count */
64
- entryCount?: number;
65
- /** For MD store operations: usage string */
66
- usage?: string;
67
- /** For search: qmemory results */
68
52
  results?: MemorySearchResult[];
69
- /** Indicates MD store was mutated (consumer should persist) */
70
- storeModified?: boolean;
71
- errorCode?: string;
72
53
  }
73
54
  export interface MemoryToolExecutorDeps {
74
- /** QMemory provider for semantic search. */
75
- provider: MemoryProvider;
76
- /** Local MD memory store for notes. */
77
- store?: MemoryStore;
55
+ memdir: Memdir;
56
+ provider?: MemoryProvider;
78
57
  userId: string;
79
- sessionId?: string;
80
- /** Query recalled facts/memories by natural language. */
81
- queryGraph?: (query: string, userId: string) => string[];
82
- /** Retrieve user profile summary. */
83
- getProfileSummary?: (userId: string) => string | null;
84
- /** Retrieve media preferences. */
85
- getMediaPreferences?: (userId: string) => MediaPreferencesSummary | null;
86
58
  }
87
59
  export declare function executeMemoryTool(params: MemoryToolParams, deps: MemoryToolExecutorDeps): Promise<MemoryToolResult>;
@@ -0,0 +1,46 @@
1
+ import type { MemorySearchResult } from "qlogicagent-runtime-contracts";
2
+ /**
3
+ * Memory categories for QMemory writes.
4
+ * Each has different value thresholds and retention policies.
5
+ */
6
+ export type QMemoryCategory = "lesson" | "preference" | "pattern" | "fact" | "decision" | "skill-learning";
7
+ /**
8
+ * A candidate memory extracted from a turn.
9
+ */
10
+ export interface MemoryCandidate {
11
+ text: string;
12
+ category: QMemoryCategory;
13
+ importance: number;
14
+ tags: string[];
15
+ }
16
+ /**
17
+ * Extract memory candidates from a completed turn.
18
+ *
19
+ * Strategy: scan assistant response for category signal patterns.
20
+ * This is a fast pattern-based approach (no LLM call needed).
21
+ * Only extracts segments that match high-value patterns.
22
+ */
23
+ export declare function extractCandidates(userPrompt: string, assistantResponse: string): MemoryCandidate[];
24
+ /**
25
+ * Quality gate: filter candidates by minimum importance threshold.
26
+ */
27
+ export declare function applyQualityGate(candidates: MemoryCandidate[], minImportance?: number): MemoryCandidate[];
28
+ /**
29
+ * Result of supersedes check for a single candidate.
30
+ */
31
+ export interface SupersedesCheckResult {
32
+ candidate: MemoryCandidate;
33
+ supersedes: string[];
34
+ }
35
+ /**
36
+ * Check if candidates supersede existing memories.
37
+ *
38
+ * Strategy: for each candidate, search QMemory for semantically similar
39
+ * existing entries. If similarity is high (>0.80) and the candidate is
40
+ * newer/more specific, mark the old one for supersede.
41
+ *
42
+ * @param candidates - Memory candidates to check
43
+ * @param existingSearch - Function to search existing memories
44
+ * @returns Candidates with supersedes info
45
+ */
46
+ export declare function checkSupersedes(candidates: MemoryCandidate[], existingSearch: (query: string) => Promise<MemorySearchResult[]>): Promise<SupersedesCheckResult[]>;
@@ -0,0 +1,44 @@
1
+ import type { MemorySearchResult } from "qlogicagent-runtime-contracts";
2
+ import type { ExtractedMemoryItem } from "./qmemory-adapter.js";
3
+ export declare const WRITE_HOOK_CONFIG: {
4
+ /** Minimum importance to pass the quality gate. */
5
+ readonly MIN_IMPORTANCE: 0.4;
6
+ /** Max candidates to write per turn (prevent flood). */
7
+ readonly MAX_PER_TURN: 3;
8
+ /** Cooldown between writes (ms) — prevents rapid duplicate writes. */
9
+ readonly COOLDOWN_MS: 5000;
10
+ };
11
+ export interface MemoryWriteHookDeps {
12
+ /** Write extracted items to QMemory. */
13
+ ingestExtracted: (items: ExtractedMemoryItem[], userId: string) => Promise<{
14
+ memoriesAdded: number;
15
+ }>;
16
+ /** Search existing memories (for supersedes check). */
17
+ searchMemories: (query: string, userId: string) => Promise<MemorySearchResult[]>;
18
+ /** Remove a superseded memory by ID. */
19
+ removeMemory?: (memoryId: string) => Promise<boolean>;
20
+ /** User ID for QMemory writes. */
21
+ userId: string;
22
+ /** Logger. */
23
+ log: {
24
+ debug(msg: string): void;
25
+ warn(msg: string): void;
26
+ };
27
+ }
28
+ /** Per-session state for the write hook. */
29
+ export interface MemoryWriteState {
30
+ /** Timestamp of last write (for cooldown). */
31
+ lastWriteAt: number;
32
+ /** Total memories written this session (for budget). */
33
+ sessionWrites: number;
34
+ /** Recent write texts (for intra-session dedup). */
35
+ recentTexts: Set<string>;
36
+ }
37
+ export declare function createMemoryWriteState(): MemoryWriteState;
38
+ /**
39
+ * Process a completed turn for memory-worthy content.
40
+ * Called directly from stdio-server after turn.end (fire-and-forget).
41
+ *
42
+ * Pipeline: extract → gate → dedup → supersedes check → write.
43
+ */
44
+ export declare function processMemoryWriteGate(userPrompt: string, assistantResponse: string, deps: MemoryWriteHookDeps, state: MemoryWriteState): Promise<void>;
@@ -19,6 +19,17 @@ export interface QMemoryAdapterConfig {
19
19
  /** Prefix prepended to userId for multi-tenant isolation. */
20
20
  userIdPrefix?: string;
21
21
  }
22
+ /** Options for triggering a decay cycle. */
23
+ export interface DecayOptions {
24
+ temporalExpiry?: boolean;
25
+ stalenessDecay?: boolean;
26
+ noiseArchival?: boolean;
27
+ }
28
+ /** Result of a decay cycle. */
29
+ export interface DecayResult {
30
+ decayed: number;
31
+ archived: number;
32
+ }
22
33
  /** Health status returned by qmemory `/v1/health/`. */
23
34
  export interface QMemoryHealthStatus {
24
35
  status: string;
@@ -40,4 +51,5 @@ export declare function createQMemoryAdapter(config: QMemoryAdapterConfig): Memo
40
51
  memoriesAdded: number;
41
52
  }>;
42
53
  feedback(memoryIds: string[], signal: string, sessionId?: string): Promise<void>;
54
+ triggerDecay(userId: string, options?: DecayOptions): Promise<DecayResult>;
43
55
  };
@@ -0,0 +1,54 @@
1
+ import type { QMemoryCategory } from "../../skills/memory/memory-write-gate.js";
2
+ /** Detected query scenario with preferred categories. */
3
+ export interface RecallCategoryHint {
4
+ /** Detected scenario label. */
5
+ scenario: QueryScenario;
6
+ /** Preferred categories for this scenario (ordered by priority). */
7
+ preferred: QMemoryCategory[];
8
+ /** Categories to deprioritize (still recalled but scored lower). */
9
+ deprioritized: QMemoryCategory[];
10
+ /** Confidence of scenario detection (0.0-1.0). */
11
+ confidence: number;
12
+ }
13
+ /** Known query scenarios. */
14
+ export type QueryScenario = "coding" | "config" | "conversation" | "learning" | "decision" | "general";
15
+ /**
16
+ * Detect the query scenario and return category preferences.
17
+ *
18
+ * Uses pattern matching on the user query to infer intent.
19
+ * Returns "general" (no filtering) when confidence is below threshold.
20
+ *
21
+ * @param query - User query text
22
+ * @returns Category hint with preferred/deprioritized categories
23
+ */
24
+ export declare function detectRecallCategories(query: string): RecallCategoryHint;
25
+ /**
26
+ * Apply category boost/penalty to a recall score.
27
+ *
28
+ * Used by recall hooks to adjust memory scores based on category alignment.
29
+ *
30
+ * @param baseScore - Original relevance score (0.0-1.0)
31
+ * @param memoryCategory - Category of the memory entry (if known)
32
+ * @param hint - Category hint from detectRecallCategories()
33
+ * @returns Adjusted score
34
+ */
35
+ export declare function applyCategoryBoost(baseScore: number, memoryCategory: string | undefined | null, hint: RecallCategoryHint): number;
36
+ /**
37
+ * Filter and re-rank a list of recalled memories based on category preferences.
38
+ *
39
+ * @param memories - Raw recalled memories with optional category
40
+ * @param hint - Category hint from detectRecallCategories()
41
+ * @param minScore - Minimum adjusted score to keep (default: 0)
42
+ * @returns Re-ranked memories (highest adjusted score first)
43
+ */
44
+ export declare function filterByCategory<T extends {
45
+ score?: number;
46
+ category?: string | null;
47
+ }>(memories: T[], hint: RecallCategoryHint, minScore?: number): T[];
48
+ /**
49
+ * Infer memory category from filename prefix convention.
50
+ * E.g. "lesson-docker.md" → "lesson", "fact-ports.md" → "fact"
51
+ *
52
+ * Exported for use by recall hooks.
53
+ */
54
+ export declare function inferCategoryFromFilename(filename: string): QMemoryCategory | null;
@@ -1,7 +1,7 @@
1
1
  import type { PortableTool } from "../portable-tool.js";
2
2
  import type { WorkspaceSkill } from "../skill-system/skill-types.js";
3
3
  export declare const SKILL_TOOL_NAME: "skill";
4
- export type SkillAction = "invoke" | "list" | "view" | "create" | "edit" | "patch" | "delete";
4
+ export type SkillAction = "invoke" | "list" | "view" | "create" | "edit" | "patch" | "delete" | "promote" | "install";
5
5
  export interface SkillToolParams {
6
6
  action: SkillAction;
7
7
  name?: string;
@@ -12,18 +12,20 @@ export interface SkillToolParams {
12
12
  fileContent?: string;
13
13
  oldString?: string;
14
14
  newString?: string;
15
+ /** URL to download skill from (for 'install' action). */
16
+ url?: string;
15
17
  }
16
18
  export declare const SKILL_TOOL_SCHEMA: {
17
19
  readonly type: "object";
18
20
  readonly properties: {
19
21
  readonly action: {
20
22
  readonly type: "string";
21
- readonly enum: readonly ["invoke", "list", "view", "create", "edit", "patch", "delete"];
23
+ readonly enum: readonly ["invoke", "list", "view", "create", "edit", "patch", "delete", "promote", "install"];
22
24
  readonly description: string;
23
25
  };
24
26
  readonly name: {
25
27
  readonly type: "string";
26
- readonly description: "Skill name (required for invoke/view/create/edit/patch/delete).";
28
+ readonly description: "Skill name (required for invoke/view/create/edit/patch/delete/promote).";
27
29
  };
28
30
  readonly args: {
29
31
  readonly type: "string";
@@ -53,6 +55,10 @@ export declare const SKILL_TOOL_SCHEMA: {
53
55
  readonly type: "string";
54
56
  readonly description: "Replacement text for patch action.";
55
57
  };
58
+ readonly url: {
59
+ readonly type: "string";
60
+ readonly description: "URL to download a skill from (for 'install' action). Supports skill stores (skillhub.cn, skill.io, GitHub raw links, etc.) and any direct .md URL.";
61
+ };
56
62
  };
57
63
  readonly required: readonly ["action"];
58
64
  };
@@ -61,6 +67,8 @@ export interface SkillListItem {
61
67
  description: string;
62
68
  version?: string;
63
69
  category?: string;
70
+ /** Where the skill lives: "global" (user-level) or "project" (cwd-level). */
71
+ scope?: "global" | "project" | "plugin" | "config";
64
72
  }
65
73
  export interface SkillListOutput {
66
74
  skills: SkillListItem[];
@@ -91,11 +99,16 @@ export interface SkillToolDeps {
91
99
  manageSkill(params: {
92
100
  action: string;
93
101
  name: string;
102
+ category?: string;
94
103
  content?: string;
95
104
  filePath?: string;
96
105
  fileContent?: string;
97
106
  oldString?: string;
98
107
  newString?: string;
99
108
  }): Promise<SkillManageResult>;
109
+ /** Promote a project-level skill to user/global level. Returns success message. */
110
+ promoteSkill?(name: string): Promise<SkillManageResult>;
111
+ /** Install a skill from a URL. Downloads .md content and saves it. */
112
+ installSkill?(url: string, name?: string): Promise<SkillManageResult>;
100
113
  }
101
114
  export declare function createSkillMetaTool(deps: SkillToolDeps): PortableTool<SkillToolParams>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * ACP Event Emitter — translates internal qlogicagent notifications to ACP
3
+ * session/update notifications.
4
+ *
5
+ * Maps the 47+ internal notification methods (turn.delta, turn.tool_call, etc.)
6
+ * to 9 standard + 19 extended ACP sessionUpdate types.
7
+ *
8
+ * Usage: Called by the StdioServer event loop. Instead of (or in addition to)
9
+ * emitting raw notifications, events are translated and emitted through the
10
+ * AcpServer.emitSessionUpdate() method.
11
+ */
12
+ import type { AcpServer } from "./acp-server.js";
13
+ /**
14
+ * Translates and emits a qlogicagent internal notification as an ACP session/update.
15
+ *
16
+ * @param server The AcpServer instance to emit through
17
+ * @param sessionId Active ACP session ID
18
+ * @param method Internal notification method name
19
+ * @param params Internal notification payload
20
+ */
21
+ export declare function emitAcpUpdate(server: AcpServer, sessionId: string, method: string, params: Record<string, unknown>): void;