qlogicagent 0.5.2 → 0.6.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/README.md +403 -402
- package/dist/agent.js +18 -0
- package/dist/cli.js +384 -0
- package/dist/contracts.js +1 -0
- package/dist/index.js +383 -0
- package/dist/orchestration.js +34 -0
- package/dist/types/agent/agent.d.ts +43 -0
- package/dist/types/agent/constants.d.ts +47 -0
- package/dist/types/agent/tool-access.d.ts +30 -0
- package/dist/types/agent/tool-loop.d.ts +94 -0
- package/dist/types/agent/types.d.ts +238 -0
- package/dist/types/cli/main.d.ts +11 -0
- package/dist/types/cli/stdio-server.d.ts +78 -0
- package/dist/types/cli/tool-bootstrap.d.ts +40 -0
- package/dist/types/cli/transport.d.ts +40 -0
- package/dist/types/config/config.d.ts +17 -0
- package/dist/types/contracts/hooks.d.ts +175 -0
- package/dist/types/contracts/index.d.ts +9 -0
- package/dist/types/contracts/planner.d.ts +35 -0
- package/dist/types/contracts/todo.d.ts +23 -0
- package/dist/types/index.d.ts +16 -0
- package/dist/types/llm/builtin-providers.d.ts +10 -0
- package/dist/types/llm/debug-transport.d.ts +12 -0
- package/dist/types/llm/index.d.ts +16 -0
- package/dist/types/llm/llm-client.d.ts +43 -0
- package/dist/types/llm/model-catalog.d.ts +53 -0
- package/dist/types/llm/provider-def.d.ts +59 -0
- package/dist/types/llm/provider-registry.d.ts +54 -0
- package/dist/types/llm/transport.d.ts +62 -0
- package/dist/types/llm/transports/anthropic-messages.d.ts +31 -0
- package/dist/types/llm/transports/openai-chat.d.ts +36 -0
- package/dist/types/orchestration/context/context-collapse.d.ts +58 -0
- package/dist/types/orchestration/context/context-compression.d.ts +301 -0
- package/dist/types/orchestration/context/reactive-compact.d.ts +73 -0
- package/dist/types/orchestration/context/turn-loop-guard.d.ts +86 -0
- package/dist/types/orchestration/error-handling/error-classification.d.ts +12 -0
- package/dist/types/orchestration/error-handling/failover-classification.d.ts +8 -0
- package/dist/types/orchestration/error-handling/failover-error.d.ts +33 -0
- package/dist/types/orchestration/error-handling/retry-loop.d.ts +69 -0
- package/dist/types/orchestration/index.d.ts +15 -0
- package/dist/types/orchestration/skill-improvement.d.ts +59 -0
- package/dist/types/orchestration/subagent/agent-registry.d.ts +46 -0
- package/dist/types/orchestration/subagent/fork-subagent.d.ts +98 -0
- package/dist/types/orchestration/subagent/task-types.d.ts +142 -0
- package/dist/types/orchestration/tool-loop/conversation-repair.d.ts +61 -0
- package/dist/types/orchestration/tool-loop/tool-choice-policy.d.ts +54 -0
- package/dist/types/orchestration/tool-loop/tool-loop-state.d.ts +50 -0
- package/dist/types/orchestration/tool-loop/tool-schema.d.ts +39 -0
- package/dist/types/runtime/execution/dream-agent.d.ts +199 -0
- package/dist/types/runtime/execution/forked-agent.d.ts +109 -0
- package/dist/types/runtime/execution/index.d.ts +6 -0
- package/dist/types/runtime/execution/progress-tracker.d.ts +78 -0
- package/dist/types/runtime/execution/remote-agent.d.ts +63 -0
- package/dist/types/runtime/execution/streaming-tool-executor.d.ts +100 -0
- package/dist/types/runtime/execution/tool-eligibility.d.ts +59 -0
- package/dist/types/runtime/execution/tool-result-storage.d.ts +87 -0
- package/dist/types/runtime/hooks/context-compression.d.ts +61 -0
- package/dist/types/runtime/hooks/hook-registry.d.ts +12 -0
- package/dist/types/runtime/hooks/index.d.ts +3 -0
- package/dist/types/runtime/hooks/memory-hooks.d.ts +49 -0
- package/dist/types/runtime/index.d.ts +5 -0
- package/dist/types/runtime/infra/agent-paths.d.ts +57 -0
- package/dist/types/runtime/infra/checkpoint-backend.d.ts +8 -0
- package/dist/types/runtime/infra/cleanup-registry.d.ts +23 -0
- package/dist/types/runtime/infra/disk-storage.d.ts +36 -0
- package/dist/types/runtime/infra/file-watcher.d.ts +72 -0
- package/dist/types/runtime/infra/index.d.ts +8 -0
- package/dist/types/runtime/infra/secure-storage.d.ts +81 -0
- package/dist/types/runtime/infra/task-runtime.d.ts +108 -0
- package/dist/types/runtime/infra/token-budget.d.ts +92 -0
- package/dist/types/runtime/infra/worktree-backend.d.ts +85 -0
- package/dist/types/runtime/prompt/environment-context.d.ts +23 -0
- package/dist/types/runtime/prompt/index.d.ts +3 -0
- package/dist/types/runtime/prompt/instruction-loader.d.ts +64 -0
- package/dist/types/runtime/prompt/system-prompt-sections.d.ts +63 -0
- package/dist/types/runtime/session/index.d.ts +2 -0
- package/dist/types/runtime/session/session-memory.d.ts +90 -0
- package/dist/types/runtime/session/session-persistence.d.ts +94 -0
- package/dist/types/runtime/session/session-state.d.ts +117 -0
- package/dist/types/skills/index.d.ts +119 -0
- package/dist/types/skills/mcp/index.d.ts +3 -0
- package/dist/types/skills/mcp/mcp-http-client.d.ts +66 -0
- package/dist/types/skills/mcp/mcp-manager.d.ts +83 -0
- package/dist/types/skills/mcp/mcp-stdio-client.d.ts +84 -0
- package/dist/types/skills/memory/memory-extractor.d.ts +64 -0
- package/dist/types/skills/memory/memory-store.d.ts +86 -0
- package/dist/types/skills/memory/memory-tool.d.ts +87 -0
- package/dist/types/skills/memory/qmemory-adapter.d.ts +42 -0
- package/dist/types/skills/permissions/bash-classifier.d.ts +30 -0
- package/dist/types/skills/permissions/classifier-cache.d.ts +51 -0
- package/dist/types/skills/permissions/denial-tracking.d.ts +42 -0
- package/dist/types/skills/permissions/hook-runner.d.ts +85 -0
- package/dist/types/skills/permissions/index.d.ts +12 -0
- package/dist/types/skills/permissions/permission-classifier.d.ts +41 -0
- package/dist/types/skills/permissions/rule-engine.d.ts +41 -0
- package/dist/types/skills/permissions/settings-watcher.d.ts +46 -0
- package/dist/types/skills/permissions/types.d.ts +113 -0
- package/dist/types/skills/plugins/index.d.ts +2 -0
- package/dist/types/skills/plugins/plugin-api.d.ts +38 -0
- package/dist/types/skills/plugins/plugin-loader.d.ts +42 -0
- package/dist/types/skills/plugins/plugin-marketplace.d.ts +61 -0
- package/dist/types/skills/portable-tool.d.ts +104 -0
- package/dist/types/skills/skill-system/skill-frontmatter.d.ts +19 -0
- package/dist/types/skills/skill-system/skill-guard.d.ts +23 -0
- package/dist/types/skills/skill-system/skill-loader.d.ts +16 -0
- package/dist/types/skills/skill-system/skill-source.d.ts +119 -0
- package/dist/types/skills/skill-system/skill-types.d.ts +199 -0
- package/dist/types/skills/think-tool.d.ts +16 -0
- package/dist/types/skills/todo-tool.d.ts +72 -0
- package/dist/types/skills/tools/agent-tool.d.ts +91 -0
- package/dist/types/skills/tools/apply-patch-tool.d.ts +29 -0
- package/dist/types/skills/tools/ask-user-tool.d.ts +80 -0
- package/dist/types/skills/tools/brief-tool.d.ts +74 -0
- package/dist/types/skills/tools/browser-tool.d.ts +114 -0
- package/dist/types/skills/tools/checkpoint-tool.d.ts +66 -0
- package/dist/types/skills/tools/config-tool.d.ts +63 -0
- package/dist/types/skills/tools/cron-tool.d.ts +116 -0
- package/dist/types/skills/tools/edit-tool.d.ts +43 -0
- package/dist/types/skills/tools/exec-tool.d.ts +97 -0
- package/dist/types/skills/tools/image-generate-tool.d.ts +62 -0
- package/dist/types/skills/tools/instructions-tool.d.ts +65 -0
- package/dist/types/skills/tools/lsp-tool.d.ts +153 -0
- package/dist/types/skills/tools/mcp-client-types.d.ts +269 -0
- package/dist/types/skills/tools/mcp-resource-tools.d.ts +14 -0
- package/dist/types/skills/tools/mcp-tool.d.ts +249 -0
- package/dist/types/skills/tools/monitor-tool.d.ts +113 -0
- package/dist/types/skills/tools/music-generate-tool.d.ts +55 -0
- package/dist/types/skills/tools/notebook-edit-tool.d.ts +15 -0
- package/dist/types/skills/tools/notify-tool.d.ts +53 -0
- package/dist/types/skills/tools/patch-tool.d.ts +45 -0
- package/dist/types/skills/tools/plan-mode-tool.d.ts +98 -0
- package/dist/types/skills/tools/read-tool.d.ts +51 -0
- package/dist/types/skills/tools/repl-tool.d.ts +70 -0
- package/dist/types/skills/tools/search-tool.d.ts +112 -0
- package/dist/types/skills/tools/send-message-tool.d.ts +51 -0
- package/dist/types/skills/tools/shell/bash-provider.d.ts +26 -0
- package/dist/types/skills/tools/shell/command-classification.d.ts +44 -0
- package/dist/types/skills/tools/shell/command-semantics.d.ts +14 -0
- package/dist/types/skills/tools/shell/destructive-command-warning.d.ts +10 -0
- package/dist/types/skills/tools/shell/exec-permissions.d.ts +52 -0
- package/dist/types/skills/tools/shell/index.d.ts +17 -0
- package/dist/types/skills/tools/shell/powershell-provider.d.ts +15 -0
- package/dist/types/skills/tools/shell/shell-command.d.ts +54 -0
- package/dist/types/skills/tools/shell/shell-exec.d.ts +33 -0
- package/dist/types/skills/tools/shell/shell-provider.d.ts +85 -0
- package/dist/types/skills/tools/shell/task-output.d.ts +45 -0
- package/dist/types/skills/tools/skill-invoke-tool.d.ts +46 -0
- package/dist/types/skills/tools/skill-list-tool.d.ts +33 -0
- package/dist/types/skills/tools/skill-manage-tool.d.ts +73 -0
- package/dist/types/skills/tools/skill-view-tool.d.ts +37 -0
- package/dist/types/skills/tools/sleep-tool.d.ts +49 -0
- package/dist/types/skills/tools/structured-output-tool.d.ts +116 -0
- package/dist/types/skills/tools/task-tool.d.ts +104 -0
- package/dist/types/skills/tools/team-tool.d.ts +89 -0
- package/dist/types/skills/tools/tool-search-tool.d.ts +51 -0
- package/dist/types/skills/tools/tts-tool.d.ts +38 -0
- package/dist/types/skills/tools/video-edit-tool.d.ts +69 -0
- package/dist/types/skills/tools/video-generate-tool.d.ts +62 -0
- package/dist/types/skills/tools/video-merge-tool.d.ts +105 -0
- package/dist/types/skills/tools/video-upscale-tool.d.ts +45 -0
- package/dist/types/skills/tools/web-fetch-tool.d.ts +78 -0
- package/dist/types/skills/tools/web-search-tool.d.ts +57 -0
- package/dist/types/skills/tools/workflow-tool.d.ts +44 -0
- package/dist/types/skills/tools/worktree-tool.d.ts +69 -0
- package/dist/types/skills/tools/write-tool.d.ts +45 -0
- package/dist/types/skills/tools.d.ts +65 -0
- package/package.json +4 -3
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure Storage — CC secureStorage parity.
|
|
3
|
+
*
|
|
4
|
+
* Platform-aware credential persistence abstraction:
|
|
5
|
+
* - Interface: get/set/delete with typed data
|
|
6
|
+
* - Implementation: file-based JSON with 0o600 permissions (CC plainTextStorage parity)
|
|
7
|
+
* - macOS Keychain / Windows Credential Manager can be added as plugins
|
|
8
|
+
*
|
|
9
|
+
* Storage layout:
|
|
10
|
+
* ~/.qlogicagent/.credentials.json — API keys, OAuth tokens
|
|
11
|
+
*
|
|
12
|
+
* Reference: claude-code-haha/src/utils/secureStorage/
|
|
13
|
+
*/
|
|
14
|
+
export interface SecureStorageData {
|
|
15
|
+
/** Primary API key (user-set) */
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
/** OAuth tokens (if using OAuth flow) */
|
|
18
|
+
oauth?: {
|
|
19
|
+
accessToken: string;
|
|
20
|
+
refreshToken: string;
|
|
21
|
+
expiresAt: number;
|
|
22
|
+
};
|
|
23
|
+
/** Arbitrary key-value pairs for extensibility */
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* CC SecureStorage interface parity.
|
|
28
|
+
*
|
|
29
|
+
* Implementations may use OS keychain, encrypted file, or plain-text file.
|
|
30
|
+
* Callers should not assume any specific storage backend.
|
|
31
|
+
*/
|
|
32
|
+
export interface SecureStorage {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
get(): Promise<SecureStorageData | null>;
|
|
35
|
+
set(data: SecureStorageData): Promise<{
|
|
36
|
+
success: boolean;
|
|
37
|
+
warning?: string;
|
|
38
|
+
}>;
|
|
39
|
+
delete(): Promise<boolean>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* File-based secure storage with restrictive permissions.
|
|
43
|
+
*
|
|
44
|
+
* On Unix: file created with 0o600 (owner-only read/write).
|
|
45
|
+
* On Windows: ACLs are not set (relies on user profile permissions).
|
|
46
|
+
*
|
|
47
|
+
* This matches CC's plainTextStorage.ts behavior — it's the default
|
|
48
|
+
* on Linux/Windows, and the fallback on macOS.
|
|
49
|
+
*/
|
|
50
|
+
export declare class FileSecureStorage implements SecureStorage {
|
|
51
|
+
readonly name = "file";
|
|
52
|
+
get(): Promise<SecureStorageData | null>;
|
|
53
|
+
set(data: SecureStorageData): Promise<{
|
|
54
|
+
success: boolean;
|
|
55
|
+
warning?: string;
|
|
56
|
+
}>;
|
|
57
|
+
delete(): Promise<boolean>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the platform-appropriate secure storage instance.
|
|
61
|
+
*
|
|
62
|
+
* Currently returns FileSecureStorage on all platforms.
|
|
63
|
+
* macOS Keychain integration can be added by checking platform
|
|
64
|
+
* and returning a KeychainSecureStorage wrapper.
|
|
65
|
+
*/
|
|
66
|
+
export declare function getSecureStorage(): SecureStorage;
|
|
67
|
+
/**
|
|
68
|
+
* Save an API key to secure storage.
|
|
69
|
+
*/
|
|
70
|
+
export declare function saveApiKey(apiKey: string): Promise<{
|
|
71
|
+
success: boolean;
|
|
72
|
+
warning?: string;
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Load the stored API key (returns null if none saved).
|
|
76
|
+
*/
|
|
77
|
+
export declare function loadApiKey(): Promise<string | null>;
|
|
78
|
+
/**
|
|
79
|
+
* Delete the stored API key.
|
|
80
|
+
*/
|
|
81
|
+
export declare function deleteApiKey(): Promise<boolean>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Runtime — CC framework.ts parity.
|
|
3
|
+
*
|
|
4
|
+
* Manages task lifecycle: creation, state updates, completion, cleanup.
|
|
5
|
+
* All task types (local_bash, local_agent, dream, etc.) use this framework.
|
|
6
|
+
*
|
|
7
|
+
* CC equivalent: src/utils/task/framework.ts + src/Task.ts
|
|
8
|
+
*
|
|
9
|
+
* Architecture note: CC uses React-style setAppState(prev => next). We use
|
|
10
|
+
* a simple Map-based store since we're in a subprocess (no React).
|
|
11
|
+
*/
|
|
12
|
+
import type { TaskState, TaskType, TaskLifecycle, PermissionRole, IsolationMode, LocalAgentTaskState, LocalBashTaskState } from "../../orchestration/subagent/task-types.js";
|
|
13
|
+
import type { HookRegistry } from "../../contracts/hooks.js";
|
|
14
|
+
/** Polling interval for running tasks (ms) */
|
|
15
|
+
export declare const POLL_INTERVAL_MS = 1000;
|
|
16
|
+
/** Display duration for killed tasks before eviction (ms) */
|
|
17
|
+
export declare const STOPPED_DISPLAY_MS = 3000;
|
|
18
|
+
/** Grace period for terminal tasks before eviction (ms) */
|
|
19
|
+
export declare const PANEL_GRACE_MS = 30000;
|
|
20
|
+
export declare function generateTaskId(type: TaskType): string;
|
|
21
|
+
/**
|
|
22
|
+
* In-memory task store — replaces CC's AppState.tasks.
|
|
23
|
+
*
|
|
24
|
+
* Thread-safe for single-process use. All mutations go through
|
|
25
|
+
* updateTaskState / registerTask for consistency.
|
|
26
|
+
*/
|
|
27
|
+
export declare class TaskStore {
|
|
28
|
+
private tasks;
|
|
29
|
+
private listeners;
|
|
30
|
+
private hooks;
|
|
31
|
+
private sessionId;
|
|
32
|
+
/** Attach a hook registry to fire task.created / task.completed hooks. */
|
|
33
|
+
setHooks(hooks: HookRegistry, sessionId: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Register a listener for task state changes.
|
|
36
|
+
* @returns Unregister function
|
|
37
|
+
*/
|
|
38
|
+
onTaskChange(listener: (taskId: string, task: TaskState | null) => void): () => void;
|
|
39
|
+
private notify;
|
|
40
|
+
/**
|
|
41
|
+
* Register a new task.
|
|
42
|
+
*/
|
|
43
|
+
registerTask(task: TaskState): void;
|
|
44
|
+
/**
|
|
45
|
+
* Update a task's state via an updater function.
|
|
46
|
+
* CC equivalent: updateTaskState()
|
|
47
|
+
*/
|
|
48
|
+
updateTask<T extends TaskState>(taskId: string, updater: (task: T) => T): void;
|
|
49
|
+
/**
|
|
50
|
+
* Get a task by ID.
|
|
51
|
+
*/
|
|
52
|
+
getTask(taskId: string): TaskState | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Get all running tasks.
|
|
55
|
+
*/
|
|
56
|
+
getRunningTasks(): TaskState[];
|
|
57
|
+
/**
|
|
58
|
+
* Get all tasks.
|
|
59
|
+
*/
|
|
60
|
+
getAllTasks(): TaskState[];
|
|
61
|
+
/**
|
|
62
|
+
* Evict a terminal task from the store.
|
|
63
|
+
*/
|
|
64
|
+
evictTask(taskId: string): void;
|
|
65
|
+
/**
|
|
66
|
+
* Evict all terminal tasks that have passed their grace period.
|
|
67
|
+
*/
|
|
68
|
+
evictStaleTasks(graceMs?: number): void;
|
|
69
|
+
}
|
|
70
|
+
export declare function isTerminalLifecycle(lifecycle: TaskLifecycle): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Transition a task to a terminal state.
|
|
73
|
+
*/
|
|
74
|
+
export declare function completeTask(store: TaskStore, taskId: string): void;
|
|
75
|
+
export declare function failTask(store: TaskStore, taskId: string, error?: string): void;
|
|
76
|
+
export declare function cancelTask(store: TaskStore, taskId: string): void;
|
|
77
|
+
/**
|
|
78
|
+
* Create and register a local agent task.
|
|
79
|
+
*/
|
|
80
|
+
export declare function createLocalAgentTask(store: TaskStore, opts: {
|
|
81
|
+
agentName: string;
|
|
82
|
+
systemPrompt: string;
|
|
83
|
+
allowedTools?: string[];
|
|
84
|
+
parentTaskId?: string;
|
|
85
|
+
tokenBudget?: number;
|
|
86
|
+
maxTurns?: number;
|
|
87
|
+
permissionRole?: PermissionRole;
|
|
88
|
+
isolation?: IsolationMode;
|
|
89
|
+
worktreeBranch?: string;
|
|
90
|
+
}): LocalAgentTaskState;
|
|
91
|
+
/**
|
|
92
|
+
* Create and register a local bash task.
|
|
93
|
+
*/
|
|
94
|
+
export declare function createLocalBashTask(store: TaskStore, opts: {
|
|
95
|
+
command: string;
|
|
96
|
+
cwd: string;
|
|
97
|
+
parentTaskId?: string;
|
|
98
|
+
label?: string;
|
|
99
|
+
}): LocalBashTaskState;
|
|
100
|
+
/**
|
|
101
|
+
* Build a task notification message in CC's XML format.
|
|
102
|
+
* This is injected into the conversation as context for the model.
|
|
103
|
+
*/
|
|
104
|
+
export declare function buildTaskNotification(task: TaskState, summary: string): string;
|
|
105
|
+
/**
|
|
106
|
+
* Get the global task store singleton.
|
|
107
|
+
*/
|
|
108
|
+
export declare function getTaskStore(): TaskStore;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sub-agent Token Budget Enforcer — CC-aligned budget limits.
|
|
3
|
+
*
|
|
4
|
+
* Prevents sub-agents from consuming infinite tokens by:
|
|
5
|
+
* 1. Per-task token budget (from TaskStateBase.tokenBudget)
|
|
6
|
+
* 2. Session-level aggregate budget (all tasks combined)
|
|
7
|
+
* 3. Budget continuation messages (CC tokenBudget.ts pattern)
|
|
8
|
+
* 4. Graceful degradation (warn → force-stop, never hard-crash)
|
|
9
|
+
*
|
|
10
|
+
* CC reference: utils/tokenBudget.ts, main.tsx --max-budget-usd / --task-budget
|
|
11
|
+
*
|
|
12
|
+
* Key difference from CC: We track prompt + completion tokens (not USD).
|
|
13
|
+
* CC has no explicit per-sub-agent budget; they rely on session-level maxBudgetUsd.
|
|
14
|
+
* We add per-task enforcement to prevent a single sub-agent from exhausting the budget.
|
|
15
|
+
*/
|
|
16
|
+
import type { TokenUsage } from "../../agent/types.js";
|
|
17
|
+
export interface BudgetConfig {
|
|
18
|
+
/** Per-task token budget (prompt + completion). 0 = unlimited. */
|
|
19
|
+
taskBudgetTokens: number;
|
|
20
|
+
/** Session-level token budget across all tasks. 0 = unlimited. */
|
|
21
|
+
sessionBudgetTokens: number;
|
|
22
|
+
/** Warning threshold as percentage (0-100). Default: 80. */
|
|
23
|
+
warningThresholdPct: number;
|
|
24
|
+
}
|
|
25
|
+
export interface TaskBudgetState {
|
|
26
|
+
taskId: string;
|
|
27
|
+
/** Token budget for this task. 0 = unlimited. */
|
|
28
|
+
budgetTokens: number;
|
|
29
|
+
/** Accumulated token usage for this task. */
|
|
30
|
+
usage: TokenUsage;
|
|
31
|
+
/** Whether a warning has been issued for this task. */
|
|
32
|
+
warned: boolean;
|
|
33
|
+
/** Whether this task has been force-stopped due to budget. */
|
|
34
|
+
stopped: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface SessionBudgetState {
|
|
37
|
+
/** Session-level budget. 0 = unlimited. */
|
|
38
|
+
budgetTokens: number;
|
|
39
|
+
/** Aggregate usage across ALL tasks in this session. */
|
|
40
|
+
totalUsage: TokenUsage;
|
|
41
|
+
/** Per-task states keyed by taskId. */
|
|
42
|
+
tasks: Map<string, TaskBudgetState>;
|
|
43
|
+
}
|
|
44
|
+
export type BudgetCheckResult = {
|
|
45
|
+
status: "ok";
|
|
46
|
+
} | {
|
|
47
|
+
status: "warning";
|
|
48
|
+
message: string;
|
|
49
|
+
usagePct: number;
|
|
50
|
+
} | {
|
|
51
|
+
status: "exceeded";
|
|
52
|
+
message: string;
|
|
53
|
+
usagePct: number;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Parse a token budget from user text input.
|
|
57
|
+
* CC reference: parseTokenBudget()
|
|
58
|
+
*
|
|
59
|
+
* Supports:
|
|
60
|
+
* - Shorthand start: "+500k", "+1.5m"
|
|
61
|
+
* - Shorthand end: "keep working +1m."
|
|
62
|
+
* - Verbose: "use 500k tokens", "spend 1.5M tokens"
|
|
63
|
+
*/
|
|
64
|
+
export declare function parseTokenBudget(text: string): number | null;
|
|
65
|
+
/**
|
|
66
|
+
* Generate a budget continuation message (CC getBudgetContinuationMessage pattern).
|
|
67
|
+
* Appended to the assistant context when approaching budget limits.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getBudgetContinuationMessage(usagePct: number, currentTokens: number, budgetTokens: number): string;
|
|
70
|
+
export declare function createSessionBudgetState(config?: Partial<BudgetConfig>): SessionBudgetState;
|
|
71
|
+
export declare function registerTaskBudget(session: SessionBudgetState, taskId: string, budgetTokens: number): TaskBudgetState;
|
|
72
|
+
/**
|
|
73
|
+
* Record token usage for a task and aggregate into session.
|
|
74
|
+
*/
|
|
75
|
+
export declare function recordTaskUsage(session: SessionBudgetState, taskId: string, usage: TokenUsage): void;
|
|
76
|
+
/**
|
|
77
|
+
* Check whether a task is within its token budget.
|
|
78
|
+
*/
|
|
79
|
+
export declare function checkTaskBudget(session: SessionBudgetState, taskId: string, config?: Partial<BudgetConfig>): BudgetCheckResult;
|
|
80
|
+
/**
|
|
81
|
+
* Get a summary of all task budgets in a session.
|
|
82
|
+
*/
|
|
83
|
+
export declare function getSessionBudgetSummary(session: SessionBudgetState): {
|
|
84
|
+
sessionUsed: number;
|
|
85
|
+
sessionBudget: number;
|
|
86
|
+
tasks: Array<{
|
|
87
|
+
taskId: string;
|
|
88
|
+
used: number;
|
|
89
|
+
budget: number;
|
|
90
|
+
stopped: boolean;
|
|
91
|
+
}>;
|
|
92
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worktree Backend — git command implementation for WorktreeToolDeps.
|
|
3
|
+
*
|
|
4
|
+
* CC reference: claude-code-haha/src/utils/worktree.ts
|
|
5
|
+
*
|
|
6
|
+
* Implements the host-provided git worktree backend:
|
|
7
|
+
* - enterWorktree(): git worktree add -B <branch> <path> HEAD
|
|
8
|
+
* - exitWorktree(): git worktree remove / keep
|
|
9
|
+
* - listWorktrees(): git worktree list --porcelain
|
|
10
|
+
* - isInWorktree(): check if cwd is inside a worktree
|
|
11
|
+
* - currentWorktree(): get current worktree info
|
|
12
|
+
*
|
|
13
|
+
* State management:
|
|
14
|
+
* - Tracks current worktree session in memory
|
|
15
|
+
* - CWD switching via process.chdir()
|
|
16
|
+
* - Safety checks: uncommitted changes, unpushed commits
|
|
17
|
+
*
|
|
18
|
+
* Security: validateWorktreeSlug() prevents path traversal.
|
|
19
|
+
*/
|
|
20
|
+
import type { WorktreeToolDeps } from "../../skills/tools/worktree-tool.js";
|
|
21
|
+
interface WorktreeSession {
|
|
22
|
+
originalCwd: string;
|
|
23
|
+
worktreePath: string;
|
|
24
|
+
worktreeName: string;
|
|
25
|
+
worktreeBranch: string;
|
|
26
|
+
/** tmux session name (CC parity). */
|
|
27
|
+
tmuxSessionName?: string;
|
|
28
|
+
/** Whether worktree was created via a user hook (CC hookBased). */
|
|
29
|
+
hookBased?: boolean;
|
|
30
|
+
/** Creation duration in ms (unset on resume). */
|
|
31
|
+
creationDurationMs?: number;
|
|
32
|
+
/** True if sparse-checkout was applied. */
|
|
33
|
+
usedSparsePaths?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** Get the current worktree session (CC getCurrentWorktreeSession parity). */
|
|
36
|
+
export declare function getCurrentWorktreeSession(): WorktreeSession | null;
|
|
37
|
+
/** Restore session on resume (CC restoreWorktreeSession parity). */
|
|
38
|
+
export declare function restoreWorktreeSession(session: WorktreeSession | null): void;
|
|
39
|
+
/** Check whether tmux is available on the system. */
|
|
40
|
+
export declare function isTmuxAvailable(): Promise<boolean>;
|
|
41
|
+
/** Generate a tmux session name from repo path and branch (CC parity). */
|
|
42
|
+
export declare function generateTmuxSessionName(repoPath: string, branch: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Create a tmux session for a worktree (CC createTmuxSessionForWorktree parity).
|
|
45
|
+
* Returns the session name, or null if tmux is not available.
|
|
46
|
+
*/
|
|
47
|
+
export declare function createTmuxSession(worktreePath: string, sessionName: string): Promise<string | null>;
|
|
48
|
+
/** Kill a tmux session (CC killTmuxSession parity). */
|
|
49
|
+
export declare function killTmuxSession(sessionName: string): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Create a lightweight worktree for a sub-agent without modifying the
|
|
52
|
+
* global session. CC reference: createAgentWorktree().
|
|
53
|
+
*/
|
|
54
|
+
export declare function createAgentWorktree(gitRoot: string, slug: string, log?: {
|
|
55
|
+
info(msg: string): void;
|
|
56
|
+
warn(msg: string): void;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
worktreePath: string;
|
|
59
|
+
branch: string;
|
|
60
|
+
} | null>;
|
|
61
|
+
/** Remove an agent worktree (CC removeAgentWorktree parity). */
|
|
62
|
+
export declare function removeAgentWorktree(gitRoot: string, worktreePath: string, branch: string, log?: {
|
|
63
|
+
info(msg: string): void;
|
|
64
|
+
warn(msg: string): void;
|
|
65
|
+
}): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Clean up stale agent worktrees older than maxAgeDays (CC cleanupStaleAgentWorktrees parity).
|
|
68
|
+
*/
|
|
69
|
+
export declare function cleanupStaleAgentWorktrees(gitRoot: string, maxAgeDays?: number, log?: {
|
|
70
|
+
info(msg: string): void;
|
|
71
|
+
warn(msg: string): void;
|
|
72
|
+
}): Promise<number>;
|
|
73
|
+
export interface WorktreeBackendOptions {
|
|
74
|
+
/** Logger for worktree operations */
|
|
75
|
+
log: {
|
|
76
|
+
info(msg: string): void;
|
|
77
|
+
warn(msg: string): void;
|
|
78
|
+
};
|
|
79
|
+
/** Directories to symlink from main repo (CC parity: node_modules, etc.) */
|
|
80
|
+
symlinkDirs?: string[];
|
|
81
|
+
/** Sparse-checkout paths (CC settings.worktree.sparsePaths parity). */
|
|
82
|
+
sparsePaths?: string[];
|
|
83
|
+
}
|
|
84
|
+
export declare function createWorktreeBackend(opts: WorktreeBackendOptions): WorktreeToolDeps;
|
|
85
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Context — CC environment-aware system prompt parity.
|
|
3
|
+
*
|
|
4
|
+
* Injects OS, shell, CWD, and platform info into the system prompt
|
|
5
|
+
* so the agent can generate platform-appropriate commands.
|
|
6
|
+
*
|
|
7
|
+
* CC reference: ShellSnapshot.ts (shell type detection),
|
|
8
|
+
* shellCompletion.ts (platform-aware command generation)
|
|
9
|
+
*
|
|
10
|
+
* This is a system prompt section that provides:
|
|
11
|
+
* - OS name + version
|
|
12
|
+
* - Shell type (bash/powershell/zsh)
|
|
13
|
+
* - Current working directory
|
|
14
|
+
* - Node.js version
|
|
15
|
+
* - Available package managers
|
|
16
|
+
*/
|
|
17
|
+
import { type SystemPromptSection } from "./system-prompt-sections.js";
|
|
18
|
+
export type ShellType = "bash" | "powershell" | "zsh" | "cmd" | "fish" | "unknown";
|
|
19
|
+
/**
|
|
20
|
+
* Create a system prompt section that provides environment context.
|
|
21
|
+
* Memoized — computed once per session (environment doesn't change mid-session).
|
|
22
|
+
*/
|
|
23
|
+
export declare function createEnvironmentContextSection(): SystemPromptSection;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { assembleSystemPrompt, clearSystemPromptSections, systemPromptSection, type SystemPromptSection, } from "./system-prompt-sections.js";
|
|
2
|
+
export { getInstructions, buildInstructionsPrompt, resetInstructionCache, } from "./instruction-loader.js";
|
|
3
|
+
export { createEnvironmentContextSection } from "./environment-context.js";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instruction Loader — CC claudemd.ts parity (adapted for qlogicagent).
|
|
3
|
+
*
|
|
4
|
+
* Discovers and loads instruction files following CC's load order:
|
|
5
|
+
* 1. User instructions (~/.qlogicagent/INSTRUCTIONS.md)
|
|
6
|
+
* 2. Project instructions (INSTRUCTIONS.md, .qlogicagent/INSTRUCTIONS.md,
|
|
7
|
+
* .qlogicagent/rules/*.md — walkup from cwd to git root)
|
|
8
|
+
* 3. Local instructions (INSTRUCTIONS.local.md — private, not checked in)
|
|
9
|
+
*
|
|
10
|
+
* Features ported from CC:
|
|
11
|
+
* - Walkup discovery (cwd → root)
|
|
12
|
+
* - @include directive support (text files only)
|
|
13
|
+
* - Frontmatter globs for conditional rules
|
|
14
|
+
* - HTML comment stripping
|
|
15
|
+
* - Memoized loading with cache invalidation
|
|
16
|
+
* - TEXT_FILE_EXTENSIONS whitelist
|
|
17
|
+
* - MAX_INCLUDE_DEPTH circular reference prevention
|
|
18
|
+
*
|
|
19
|
+
* Reference: claude-code src/utils/claudemd.ts
|
|
20
|
+
*/
|
|
21
|
+
import type { HookRegistry } from "../../contracts/hooks.js";
|
|
22
|
+
export type InstructionType = "User" | "Project" | "Local";
|
|
23
|
+
export interface InstructionFileInfo {
|
|
24
|
+
path: string;
|
|
25
|
+
type: InstructionType;
|
|
26
|
+
content: string;
|
|
27
|
+
/** Path of the file that @included this one */
|
|
28
|
+
parent?: string;
|
|
29
|
+
/** Glob patterns from frontmatter — file only applies when target path matches */
|
|
30
|
+
globs?: string[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Load all instruction files following CC's discovery order.
|
|
34
|
+
*
|
|
35
|
+
* Discovery order (priority: last loaded = highest):
|
|
36
|
+
* 1. User: ~/.qlogicagent/INSTRUCTIONS.md, ~/.qlogicagent/rules/*.md
|
|
37
|
+
* 2. Project: Walk from git root → cwd, each dir:
|
|
38
|
+
* - INSTRUCTIONS.md
|
|
39
|
+
* - .qlogicagent/INSTRUCTIONS.md
|
|
40
|
+
* - .qlogicagent/rules/*.md (unconditional)
|
|
41
|
+
* 3. Local: INSTRUCTIONS.local.md (per dir, walkup)
|
|
42
|
+
*
|
|
43
|
+
* @param cwd - Starting directory for walkup discovery
|
|
44
|
+
* @param hooks - Optional hook registry for instructions.loaded event
|
|
45
|
+
*/
|
|
46
|
+
export declare function loadInstructions(cwd: string, hooks?: HookRegistry): Promise<InstructionFileInfo[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Build the instructions prompt string from loaded files.
|
|
49
|
+
* CC parity: getClaudeMds()
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildInstructionsPrompt(files: InstructionFileInfo[]): string;
|
|
52
|
+
/**
|
|
53
|
+
* Get conditional rules that match a target file path.
|
|
54
|
+
* CC parity: getManagedAndUserConditionalRules() + getMemoryFilesForNestedDirectory()
|
|
55
|
+
*/
|
|
56
|
+
export declare function getConditionalRules(cwd: string, targetPath: string): Promise<InstructionFileInfo[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Load instructions with memoization.
|
|
59
|
+
* CC parity: getMemoryFiles() with memoize.
|
|
60
|
+
* Returns cached result if cwd hasn't changed.
|
|
61
|
+
*/
|
|
62
|
+
export declare function getInstructions(cwd: string, hooks?: HookRegistry): Promise<InstructionFileInfo[]>;
|
|
63
|
+
/** Clear the instruction cache. Called after file changes or compaction. */
|
|
64
|
+
export declare function resetInstructionCache(): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System Prompt Sections — CC systemPromptSections.ts parity.
|
|
3
|
+
*
|
|
4
|
+
* Provides a section-based system prompt assembly mechanism:
|
|
5
|
+
* - Memoized sections (computed once, cached until clear)
|
|
6
|
+
* - Volatile sections (recompute every turn, cache-breaking)
|
|
7
|
+
* - User-provided appendSystemPrompt / customSystemPrompt
|
|
8
|
+
* - Clear on session reset / compact
|
|
9
|
+
*
|
|
10
|
+
* CC reference: src/constants/systemPromptSections.ts
|
|
11
|
+
*/
|
|
12
|
+
type ComputeFn = () => string | null | Promise<string | null>;
|
|
13
|
+
export interface SystemPromptSection {
|
|
14
|
+
name: string;
|
|
15
|
+
compute: ComputeFn;
|
|
16
|
+
/** If true, recompute every turn (breaks prompt cache). CC: cacheBreak. */
|
|
17
|
+
cacheBreak: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create a memoized system prompt section.
|
|
21
|
+
* Computed once, cached until clearSystemPromptSections() is called.
|
|
22
|
+
*/
|
|
23
|
+
export declare function systemPromptSection(name: string, compute: ComputeFn): SystemPromptSection;
|
|
24
|
+
/**
|
|
25
|
+
* Create a volatile system prompt section that recomputes every turn.
|
|
26
|
+
* WARNING: This WILL break prompt cache when the value changes.
|
|
27
|
+
* Use sparingly — only for time-sensitive or frequently changing context.
|
|
28
|
+
*
|
|
29
|
+
* @param _reason - Why this section must be volatile (documentation only, CC parity).
|
|
30
|
+
*/
|
|
31
|
+
export declare function volatileSystemPromptSection(name: string, compute: ComputeFn, _reason?: string): SystemPromptSection;
|
|
32
|
+
/**
|
|
33
|
+
* Resolve all system prompt sections, returning non-null prompt strings.
|
|
34
|
+
* Memoized sections are cached; volatile sections are always recomputed.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveSystemPromptSections(sections: SystemPromptSection[]): Promise<string[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Clear all section caches. Called on session reset, /clear, or /compact.
|
|
39
|
+
*/
|
|
40
|
+
export declare function clearSystemPromptSections(): void;
|
|
41
|
+
export interface SystemPromptAssemblyOptions {
|
|
42
|
+
/** Base system prompt (from Gateway config) */
|
|
43
|
+
basePrompt?: string;
|
|
44
|
+
/** Prepended instruction block (from INSTRUCTIONS.md files) */
|
|
45
|
+
instructionBlock?: string;
|
|
46
|
+
/** User-provided custom system prompt (replaces base) */
|
|
47
|
+
customSystemPrompt?: string;
|
|
48
|
+
/** User-provided append text (appended after all sections) */
|
|
49
|
+
appendSystemPrompt?: string;
|
|
50
|
+
/** Dynamic sections to resolve */
|
|
51
|
+
sections?: SystemPromptSection[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Assemble the final system prompt from all sources.
|
|
55
|
+
*
|
|
56
|
+
* Order:
|
|
57
|
+
* 1. Instruction block (INSTRUCTIONS.md files)
|
|
58
|
+
* 2. Custom system prompt (replaces base) OR base prompt
|
|
59
|
+
* 3. Resolved sections
|
|
60
|
+
* 4. Append system prompt (user-provided suffix)
|
|
61
|
+
*/
|
|
62
|
+
export declare function assembleSystemPrompt(opts: SystemPromptAssemblyOptions): Promise<string>;
|
|
63
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { SessionState, type SessionCostSnapshot } from "./session-state.js";
|
|
2
|
+
export { appendMessage, saveSessionState, loadSessionForResume, listSessions, deleteSession, pruneOldSessions, shouldGenerateTaskSummary, maybeGenerateTaskSummary, type SessionMetadata, type PersistedSession, type SessionListEntry, type TaskSummaryDeps, } from "./session-persistence.js";
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Memory — CC SessionMemory background extraction parity.
|
|
3
|
+
*
|
|
4
|
+
* Automatically extracts key insights from the conversation and saves
|
|
5
|
+
* them to session memory files. Runs as a forked sub-agent with restricted
|
|
6
|
+
* tool access after each turn when extraction thresholds are met.
|
|
7
|
+
*
|
|
8
|
+
* CC reference:
|
|
9
|
+
* - src/services/SessionMemory/sessionMemory.ts
|
|
10
|
+
* - src/services/SessionMemory/extractMemories.ts
|
|
11
|
+
*
|
|
12
|
+
* Extraction process:
|
|
13
|
+
* 1. Check thresholds (tokens + tool calls since last extraction)
|
|
14
|
+
* 2. Fork a sub-agent with restricted tools (read-only + memory write)
|
|
15
|
+
* 3. Sub-agent reviews conversation, extracts key facts/decisions
|
|
16
|
+
* 4. Sub-agent writes to session-memory.md file
|
|
17
|
+
* 5. Reset threshold counters
|
|
18
|
+
*
|
|
19
|
+
* Tool restrictions for extractor:
|
|
20
|
+
* ✅ read, search, grep, glob (read-only fs)
|
|
21
|
+
* ✅ memory_write (to session-memory path only)
|
|
22
|
+
* ❌ Everything else (no file edits, no bash, no network)
|
|
23
|
+
*/
|
|
24
|
+
import type { ChatMessage, ToolDefinition, ToolInvoker, AgentLogger, HookRegistry } from "../../agent/types.js";
|
|
25
|
+
import type { LLMTransport } from "../../llm/transport.js";
|
|
26
|
+
import type { SessionState } from "./session-state.js";
|
|
27
|
+
/** Tool permission check function (mirrors execution/forked-agent CanUseToolFn). */
|
|
28
|
+
export type CanUseToolFn = (toolName: string, input: Record<string, unknown>) => {
|
|
29
|
+
allowed: true;
|
|
30
|
+
} | {
|
|
31
|
+
allowed: false;
|
|
32
|
+
reason: string;
|
|
33
|
+
};
|
|
34
|
+
/** Forked agent runner signature (injected by CLI layer). */
|
|
35
|
+
export type ForkedAgentRunner = (params: {
|
|
36
|
+
promptMessages: ChatMessage[];
|
|
37
|
+
systemPrompt?: string;
|
|
38
|
+
tools: ToolDefinition[];
|
|
39
|
+
canUseTool?: CanUseToolFn;
|
|
40
|
+
transport: LLMTransport;
|
|
41
|
+
toolInvoker: ToolInvoker;
|
|
42
|
+
apiKey: string;
|
|
43
|
+
model: string;
|
|
44
|
+
log: AgentLogger;
|
|
45
|
+
hooks?: HookRegistry;
|
|
46
|
+
forkLabel: string;
|
|
47
|
+
maxTurns?: number;
|
|
48
|
+
parentSignal?: AbortSignal;
|
|
49
|
+
skipTranscript?: boolean;
|
|
50
|
+
}) => Promise<{
|
|
51
|
+
ok: boolean;
|
|
52
|
+
content?: string;
|
|
53
|
+
error?: string;
|
|
54
|
+
durationMs: number;
|
|
55
|
+
totalUsage: {
|
|
56
|
+
prompt: number;
|
|
57
|
+
completion: number;
|
|
58
|
+
};
|
|
59
|
+
}>;
|
|
60
|
+
export interface SessionMemoryDeps {
|
|
61
|
+
/** Session state (for threshold tracking) */
|
|
62
|
+
sessionState: SessionState;
|
|
63
|
+
/** LLM transport for the extractor agent */
|
|
64
|
+
transport: LLMTransport;
|
|
65
|
+
/** Tool invoker */
|
|
66
|
+
toolInvoker: ToolInvoker;
|
|
67
|
+
/** Available tools (will be filtered for extraction) */
|
|
68
|
+
tools: ToolDefinition[];
|
|
69
|
+
/** API key */
|
|
70
|
+
apiKey: string;
|
|
71
|
+
/** Model for extraction (can use a cheaper/faster model) */
|
|
72
|
+
model: string;
|
|
73
|
+
/** Logger */
|
|
74
|
+
log: AgentLogger;
|
|
75
|
+
/** Hook registry */
|
|
76
|
+
hooks?: HookRegistry;
|
|
77
|
+
/** Path where session memory should be written */
|
|
78
|
+
memoryFilePath: string;
|
|
79
|
+
/** Parent abort signal */
|
|
80
|
+
parentSignal?: AbortSignal;
|
|
81
|
+
/** Forked agent runner (injected by CLI layer, decoupled from execution/) */
|
|
82
|
+
runForkedAgent: ForkedAgentRunner;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if memory extraction should run and execute if thresholds are met.
|
|
86
|
+
*
|
|
87
|
+
* Call this at the end of each turn (after turn.completed hook).
|
|
88
|
+
* It's a no-op if thresholds aren't met.
|
|
89
|
+
*/
|
|
90
|
+
export declare function maybeExtractSessionMemory(deps: SessionMemoryDeps, conversationMessages: ChatMessage[]): Promise<boolean>;
|