aegiscode 3.1.8 → 3.1.10
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 +23 -15
- package/dist/main.js +549 -552
- package/package.json +4 -2
- package/src/agent/Agent.ts +903 -0
- package/src/agent/SimpleAgent.ts +48 -0
- package/src/agent/index.ts +54 -0
- package/src/agent/orchestrator/AppBuilder.ts +443 -0
- package/src/agent/orchestrator/CouncilAgent.ts +310 -0
- package/src/agent/orchestrator/DiscussionRoom.ts +462 -0
- package/src/agent/orchestrator/OrchestratorAgent.ts +637 -0
- package/src/agent/orchestrator/index.ts +38 -0
- package/src/agent/orchestrator/utils.ts +397 -0
- package/src/agent/pricing.ts +115 -0
- package/src/agent/router.ts +74 -0
- package/src/agent/routerStats.ts +121 -0
- package/src/agent/types.ts +318 -0
- package/src/auth/login.ts +383 -0
- package/src/cli/config.ts +189 -0
- package/src/cli/index.ts +17 -0
- package/src/cli/middleware.ts +119 -0
- package/src/cli/types.ts +75 -0
- package/src/config/ConfigManager.ts +587 -0
- package/src/config/index.ts +7 -0
- package/src/config/types.ts +584 -0
- package/src/context/CompactionService.ts +300 -0
- package/src/context/ContextManager.ts +450 -0
- package/src/context/FileAnalyzer.ts +267 -0
- package/src/context/TokenCounter.ts +265 -0
- package/src/context/index.ts +27 -0
- package/src/context/storage/CacheStore.ts +176 -0
- package/src/context/storage/JSONLStore.ts +201 -0
- package/src/context/storage/MemoryStore.ts +205 -0
- package/src/context/storage/PersistentStore.ts +327 -0
- package/src/context/storage/index.ts +9 -0
- package/src/context/storage/pathUtils.ts +114 -0
- package/src/context/test.ts +309 -0
- package/src/context/types.ts +268 -0
- package/src/hooks/HookExecutor.ts +434 -0
- package/src/hooks/HookManager.ts +596 -0
- package/src/hooks/HookService.ts +269 -0
- package/src/hooks/Matcher.ts +157 -0
- package/src/hooks/index.ts +63 -0
- package/src/hooks/types.ts +424 -0
- package/src/main.tsx +596 -0
- package/src/mcp/HealthMonitor.ts +150 -0
- package/src/mcp/McpClient.ts +491 -0
- package/src/mcp/McpRegistry.ts +321 -0
- package/src/mcp/createMcpTool.ts +251 -0
- package/src/mcp/index.ts +15 -0
- package/src/mcp/server.ts +334 -0
- package/src/mcp/test-server.ts +88 -0
- package/src/mcp/test.ts +372 -0
- package/src/mcp/types.ts +247 -0
- package/src/memory/AgentMemoryBus.ts +432 -0
- package/src/memory/CloudSync.ts +99 -0
- package/src/memory/DriveSync.ts +106 -0
- package/src/memory/SharedMemory.ts +951 -0
- package/src/memory/index.ts +14 -0
- package/src/memory/machineFingerprint.ts +40 -0
- package/src/orchestrator/SubAgentMetadata.ts +136 -0
- package/src/prompts/builder.ts +213 -0
- package/src/prompts/default.ts +144 -0
- package/src/prompts/index.ts +16 -0
- package/src/prompts/plan.ts +64 -0
- package/src/prompts/test.ts +78 -0
- package/src/services/AnthropicChatService.ts +341 -0
- package/src/services/ChatService.ts +347 -0
- package/src/services/ClaudeCliChatService.ts +256 -0
- package/src/services/CloudSync.ts +168 -0
- package/src/services/CostLedger.ts +211 -0
- package/src/services/Heartbeat.ts +135 -0
- package/src/services/LearningCollector.ts +291 -0
- package/src/services/OllamaInstaller.ts +342 -0
- package/src/services/VersionChecker.ts +445 -0
- package/src/services/index.ts +57 -0
- package/src/services/streaming/OpenAIEventAdapter.ts +126 -0
- package/src/services/streaming/RenderingProfile.ts +90 -0
- package/src/services/streaming/StreamEventParser.ts +181 -0
- package/src/services/streaming/ThrottledRenderer.ts +139 -0
- package/src/services/streaming/TranscriptBuffer.ts +574 -0
- package/src/services/streaming/eventStatusMap.ts +52 -0
- package/src/services/streaming/index.ts +46 -0
- package/src/services/streaming/renderFormatting.ts +79 -0
- package/src/services/streaming/types.ts +234 -0
- package/src/skills/SkillLoader.ts +126 -0
- package/src/skills/SkillRegistry.ts +366 -0
- package/src/skills/index.ts +48 -0
- package/src/skills/types.ts +146 -0
- package/src/slash-commands/billing.ts +70 -0
- package/src/slash-commands/build.ts +413 -0
- package/src/slash-commands/builtinCommands.ts +2733 -0
- package/src/slash-commands/clone.ts +242 -0
- package/src/slash-commands/council.ts +125 -0
- package/src/slash-commands/custom/CustomCommandExecutor.ts +143 -0
- package/src/slash-commands/custom/CustomCommandLoader.ts +251 -0
- package/src/slash-commands/custom/CustomCommandRegistry.ts +144 -0
- package/src/slash-commands/custom/index.ts +7 -0
- package/src/slash-commands/debate.ts +254 -0
- package/src/slash-commands/gmail.ts +105 -0
- package/src/slash-commands/index.ts +388 -0
- package/src/slash-commands/mcpCommand.ts +205 -0
- package/src/slash-commands/types.ts +201 -0
- package/src/store/index.ts +76 -0
- package/src/store/selectors.ts +246 -0
- package/src/store/slices/appSlice.ts +205 -0
- package/src/store/slices/commandSlice.ts +115 -0
- package/src/store/slices/configSlice.ts +46 -0
- package/src/store/slices/focusSlice.ts +64 -0
- package/src/store/slices/index.ts +9 -0
- package/src/store/slices/sessionSlice.ts +424 -0
- package/src/store/streaming-buffer.ts +425 -0
- package/src/store/test.ts +296 -0
- package/src/store/types.ts +274 -0
- package/src/store/vanilla.ts +186 -0
- package/src/tools/builtin/bash.ts +236 -0
- package/src/tools/builtin/council.ts +105 -0
- package/src/tools/builtin/edit.ts +213 -0
- package/src/tools/builtin/glob.ts +136 -0
- package/src/tools/builtin/grep.ts +263 -0
- package/src/tools/builtin/index.ts +61 -0
- package/src/tools/builtin/memory.ts +66 -0
- package/src/tools/builtin/read.ts +168 -0
- package/src/tools/builtin/skill.ts +97 -0
- package/src/tools/builtin/snapshot.ts +40 -0
- package/src/tools/builtin/task.ts +106 -0
- package/src/tools/builtin/write.ts +134 -0
- package/src/tools/createTool.ts +221 -0
- package/src/tools/execution/ExecutionPipeline.ts +263 -0
- package/src/tools/execution/index.ts +40 -0
- package/src/tools/execution/stages/CacheStage.ts +131 -0
- package/src/tools/execution/stages/ConfirmationStage.ts +203 -0
- package/src/tools/execution/stages/DiscoveryStage.ts +46 -0
- package/src/tools/execution/stages/ExecutionStage.ts +48 -0
- package/src/tools/execution/stages/FormattingStage.ts +44 -0
- package/src/tools/execution/stages/HookStage.ts +72 -0
- package/src/tools/execution/stages/PermissionStage.ts +287 -0
- package/src/tools/execution/stages/PostHookStage.ts +71 -0
- package/src/tools/execution/stages/index.ts +12 -0
- package/src/tools/execution/test.ts +266 -0
- package/src/tools/execution/types.ts +273 -0
- package/src/tools/index.ts +81 -0
- package/src/tools/registry.ts +304 -0
- package/src/tools/schemas.ts +109 -0
- package/src/tools/test.ts +220 -0
- package/src/tools/types.ts +175 -0
- package/src/tools/validation/PermissionChecker.ts +242 -0
- package/src/tools/validation/SensitiveFileDetector.ts +210 -0
- package/src/tools/validation/index.ts +11 -0
- package/src/ui/App.tsx +166 -0
- package/src/ui/components/AegisInterface.tsx +484 -0
- package/src/ui/components/common/ChatSearch.tsx +150 -0
- package/src/ui/components/common/ErrorBoundary.tsx +82 -0
- package/src/ui/components/common/ExitMessage.tsx +120 -0
- package/src/ui/components/common/LoadingIndicator.tsx +49 -0
- package/src/ui/components/common/index.ts +6 -0
- package/src/ui/components/dialog/ConfirmationPrompt.tsx +208 -0
- package/src/ui/components/dialog/InteractiveSelector.tsx +149 -0
- package/src/ui/components/dialog/SetupWizard.tsx +297 -0
- package/src/ui/components/dialog/UpdatePrompt.tsx +155 -0
- package/src/ui/components/dialog/index.ts +8 -0
- package/src/ui/components/index.ts +28 -0
- package/src/ui/components/input/CommandSuggestions.tsx +139 -0
- package/src/ui/components/input/CustomTextInput.tsx +220 -0
- package/src/ui/components/input/InputArea.tsx +361 -0
- package/src/ui/components/input/PromptSuggestions.tsx +66 -0
- package/src/ui/components/input/index.ts +6 -0
- package/src/ui/components/layout/ChatStatusBar.tsx +90 -0
- package/src/ui/components/layout/ContextBar.tsx +79 -0
- package/src/ui/components/layout/MessageArea.tsx +96 -0
- package/src/ui/components/layout/MessageList.tsx +647 -0
- package/src/ui/components/layout/MessageSeparator.tsx +26 -0
- package/src/ui/components/layout/WelcomeMessage.tsx +93 -0
- package/src/ui/components/layout/index.ts +7 -0
- package/src/ui/components/markdown/CodeHighlighter.tsx +292 -0
- package/src/ui/components/markdown/MessageRenderer.tsx +1211 -0
- package/src/ui/components/markdown/index.ts +8 -0
- package/src/ui/components/markdown/parser.ts +336 -0
- package/src/ui/components/markdown/types.ts +66 -0
- package/src/ui/focus/FocusManager.ts +137 -0
- package/src/ui/focus/index.ts +13 -0
- package/src/ui/focus/types.ts +54 -0
- package/src/ui/focus/useFocus.ts +75 -0
- package/src/ui/hooks/index.ts +11 -0
- package/src/ui/hooks/useAgent.ts +284 -0
- package/src/ui/hooks/useCommandHistory.ts +87 -0
- package/src/ui/hooks/useCommandProcessor.ts +443 -0
- package/src/ui/hooks/useConfirmation.ts +99 -0
- package/src/ui/hooks/useCtrlCHandler.ts +100 -0
- package/src/ui/hooks/useInputBuffer.ts +122 -0
- package/src/ui/hooks/useTerminalSize.ts +68 -0
- package/src/ui/hooks/useTerminalWidth.ts +5 -0
- package/src/ui/hooks/useWindowedList.ts +118 -0
- package/src/ui/render-debugger.ts +621 -0
- package/src/ui/test.ts +189 -0
- package/src/ui/themes/ThemeManager.ts +332 -0
- package/src/ui/themes/aegisTheme.ts +87 -0
- package/src/ui/themes/darkTheme.ts +87 -0
- package/src/ui/themes/defaultTheme.ts +85 -0
- package/src/ui/themes/index.ts +10 -0
- package/src/ui/themes/lightTheme.ts +89 -0
- package/src/ui/themes/popularThemes.ts +187 -0
- package/src/ui/themes/types.ts +130 -0
- package/src/utils/clipboard.ts +48 -0
- package/src/utils/debug.ts +43 -0
- package/src/utils/environment.ts +68 -0
- package/src/utils/index.ts +10 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory module exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { SharedMemory, sharedMemory, setOllamaBaseUrl, type MemoryEntry, type MemoryConfig } from './SharedMemory.js';
|
|
6
|
+
export { syncSessionToDrive } from './DriveSync.js';
|
|
7
|
+
export { pushEntries, pullSince } from './CloudSync.js';
|
|
8
|
+
export {
|
|
9
|
+
AgentMemoryBus,
|
|
10
|
+
agentMemoryBus,
|
|
11
|
+
type AgentChannel,
|
|
12
|
+
type AgentMemoryMessage,
|
|
13
|
+
type AgentMemoryQuery,
|
|
14
|
+
} from './AgentMemoryBus.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anonymous machine fingerprint — used only to gate the free memory tier
|
|
3
|
+
* against trivial reset (deleting config.json, fresh container). Soft
|
|
4
|
+
* anti-abuse signal, not a security boundary: never send the raw machine
|
|
5
|
+
* ID anywhere, only a salted hash of it.
|
|
6
|
+
*/
|
|
7
|
+
import * as crypto from 'crypto';
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
import * as os from 'os';
|
|
11
|
+
|
|
12
|
+
function readRawMachineId(): string {
|
|
13
|
+
try {
|
|
14
|
+
if (process.platform === 'linux') {
|
|
15
|
+
try {
|
|
16
|
+
return fs.readFileSync('/etc/machine-id', 'utf8').trim();
|
|
17
|
+
} catch {
|
|
18
|
+
return fs.readFileSync('/var/lib/dbus/machine-id', 'utf8').trim();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (process.platform === 'darwin') {
|
|
22
|
+
const out = execSync('ioreg -rd1 -c IOPlatformExpertDevice', { encoding: 'utf8', timeout: 3000 });
|
|
23
|
+
const m = out.match(/"IOPlatformUUID"\s*=\s*"([^"]+)"/);
|
|
24
|
+
if (m) return m[1];
|
|
25
|
+
}
|
|
26
|
+
if (process.platform === 'win32') {
|
|
27
|
+
const out = execSync('reg query HKLM\\SOFTWARE\\Microsoft\\Cryptography /v MachineGuid', { encoding: 'utf8', timeout: 3000 });
|
|
28
|
+
const m = out.match(/MachineGuid\s+REG_SZ\s+(\S+)/);
|
|
29
|
+
if (m) return m[1];
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
// fall through to weak fallback below
|
|
33
|
+
}
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getMachineFingerprint(): string {
|
|
38
|
+
const raw = readRawMachineId() || `${os.hostname()}:${os.platform()}:${os.arch()}`;
|
|
39
|
+
return crypto.createHash('sha256').update(`aegis-fp-v1:${raw}`).digest('hex');
|
|
40
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubAgentMetadata — tracks sub-agent lifecycle metadata alongside session logs
|
|
3
|
+
*
|
|
4
|
+
* Mirrors Claude Code's `agent-<id>.meta.json` pattern, writing a structured
|
|
5
|
+
* metadata file for every sub-agent spawn so post-hoc debugging, observability,
|
|
6
|
+
* and session replay can see agent name, role, task, timing, and outcome.
|
|
7
|
+
*
|
|
8
|
+
* File location:
|
|
9
|
+
* ~/.aegis/projects/{escaped-project-path}/subagents/{agentName}-{spawnId}.meta.json
|
|
10
|
+
*
|
|
11
|
+
* This is the smallest version of the agent-<id>.meta.json pattern from Claude.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import * as fs from 'node:fs/promises';
|
|
15
|
+
import * as path from 'node:path';
|
|
16
|
+
import { getProjectStoragePath } from '../context/storage/pathUtils.js';
|
|
17
|
+
|
|
18
|
+
// ── Types ────────────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
export interface AgentSpawnMeta {
|
|
21
|
+
/** Unique spawn ID — deterministic from the session + sequence */
|
|
22
|
+
spawnId: string;
|
|
23
|
+
/** Agent name (matches SubAgentConfig.name) */
|
|
24
|
+
agentName: string;
|
|
25
|
+
/** Agent role (from SubAgentConfig.role) */
|
|
26
|
+
role: string;
|
|
27
|
+
/** The task string this agent was asked to execute */
|
|
28
|
+
task: string;
|
|
29
|
+
/** ISO timestamp of spawn */
|
|
30
|
+
spawnedAt: string;
|
|
31
|
+
/** ISO timestamp of completion (set when finish() is called) */
|
|
32
|
+
completedAt?: string;
|
|
33
|
+
/** Execution outcome */
|
|
34
|
+
status: 'running' | 'success' | 'error';
|
|
35
|
+
/** Duration in milliseconds */
|
|
36
|
+
durationMs?: number;
|
|
37
|
+
/** Token usage if reported */
|
|
38
|
+
tokensUsed?: number;
|
|
39
|
+
/** Tool call count if reported */
|
|
40
|
+
toolCallsCount?: number;
|
|
41
|
+
/** Error message on failure */
|
|
42
|
+
error?: string;
|
|
43
|
+
/** Session ID this agent belongs to */
|
|
44
|
+
sessionId: string;
|
|
45
|
+
/** Agent type hint — e.g. 'subagent', 'council', 'explore' */
|
|
46
|
+
agentType?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── Store ────────────────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
export class SubAgentMetadataStore {
|
|
52
|
+
private readonly metaDir: string;
|
|
53
|
+
|
|
54
|
+
constructor(projectPath?: string) {
|
|
55
|
+
const base = projectPath || process.cwd();
|
|
56
|
+
this.metaDir = path.join(getProjectStoragePath(base), 'subagents');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Record that an agent was spawned.
|
|
61
|
+
* Returns the metadata object so callers can call .finish() later.
|
|
62
|
+
*/
|
|
63
|
+
async spawn(meta: Omit<AgentSpawnMeta, 'spawnedAt' | 'status'>): Promise<AgentSpawnMeta> {
|
|
64
|
+
const entry: AgentSpawnMeta = {
|
|
65
|
+
...meta,
|
|
66
|
+
spawnedAt: new Date().toISOString(),
|
|
67
|
+
status: 'running',
|
|
68
|
+
};
|
|
69
|
+
await this.write(entry);
|
|
70
|
+
return entry;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Mark a previously spawned agent as finished (success or error).
|
|
75
|
+
*/
|
|
76
|
+
async finish(
|
|
77
|
+
spawnId: string,
|
|
78
|
+
status: 'success' | 'error',
|
|
79
|
+
details?: { durationMs?: number; tokensUsed?: number; toolCallsCount?: number; error?: string },
|
|
80
|
+
): Promise<AgentSpawnMeta | null> {
|
|
81
|
+
// Read existing, update, re-write
|
|
82
|
+
const all = await this.list();
|
|
83
|
+
const idx = all.findIndex(m => m.spawnId === spawnId);
|
|
84
|
+
if (idx === -1) return null;
|
|
85
|
+
|
|
86
|
+
const entry: AgentSpawnMeta = {
|
|
87
|
+
...all[idx],
|
|
88
|
+
completedAt: new Date().toISOString(),
|
|
89
|
+
status,
|
|
90
|
+
...(details?.durationMs !== undefined ? { durationMs: details.durationMs } : {}),
|
|
91
|
+
...(details?.tokensUsed !== undefined ? { tokensUsed: details.tokensUsed } : {}),
|
|
92
|
+
...(details?.toolCallsCount !== undefined ? { toolCallsCount: details.toolCallsCount } : {}),
|
|
93
|
+
...(details?.error !== undefined ? { error: details.error } : {}),
|
|
94
|
+
};
|
|
95
|
+
await this.write(entry);
|
|
96
|
+
return entry;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Read all metadata entries for the current project.
|
|
101
|
+
*/
|
|
102
|
+
async list(): Promise<AgentSpawnMeta[]> {
|
|
103
|
+
try {
|
|
104
|
+
await fs.mkdir(this.metaDir, { recursive: true });
|
|
105
|
+
const files = await fs.readdir(this.metaDir);
|
|
106
|
+
const metas: AgentSpawnMeta[] = [];
|
|
107
|
+
for (const file of files) {
|
|
108
|
+
if (!file.endsWith('.meta.json')) continue;
|
|
109
|
+
try {
|
|
110
|
+
const content = await fs.readFile(path.join(this.metaDir, file), 'utf-8');
|
|
111
|
+
metas.push(JSON.parse(content) as AgentSpawnMeta);
|
|
112
|
+
} catch { /* skip corrupt files */ }
|
|
113
|
+
}
|
|
114
|
+
return metas.sort((a, b) => a.spawnedAt.localeCompare(b.spawnedAt));
|
|
115
|
+
} catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get the most recent N metadata entries for a given agent name.
|
|
122
|
+
*/
|
|
123
|
+
async recentForAgent(agentName: string, limit = 5): Promise<AgentSpawnMeta[]> {
|
|
124
|
+
const all = await this.list();
|
|
125
|
+
return all.filter(m => m.agentName === agentName).reverse().slice(0, limit);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ── Private ──────────────────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
private async write(entry: AgentSpawnMeta): Promise<void> {
|
|
131
|
+
await fs.mkdir(this.metaDir, { recursive: true });
|
|
132
|
+
const fileName = `${entry.agentName}-${entry.spawnId}.meta.json`;
|
|
133
|
+
const filePath = path.join(this.metaDir, fileName);
|
|
134
|
+
await fs.writeFile(filePath, JSON.stringify(entry, null, 2), 'utf-8');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*
|
|
4
|
+
*
|
|
5
|
+
* 1. 环境上下文 - 动态生成
|
|
6
|
+
* 2. 基础提示词 - DEFAULT_SYSTEM_PROMPT 或 PLAN_MODE_SYSTEM_PROMPT
|
|
7
|
+
* 3. 可用 Skills 列表 - 渐进式披露的"发现阶段"
|
|
8
|
+
* 4. 项目配置 - AEGIS.md
|
|
9
|
+
* 5. 追加内容 - 用户自定义
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'fs/promises';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { getEnvironmentContext } from '../utils/environment.js';
|
|
15
|
+
import { DEFAULT_SYSTEM_PROMPT } from './default.js';
|
|
16
|
+
import { PLAN_MODE_SYSTEM_PROMPT } from './plan.js';
|
|
17
|
+
import { getSkillRegistry } from '../skills/index.js';
|
|
18
|
+
import type { PermissionMode } from '../agent/types.js';
|
|
19
|
+
|
|
20
|
+
// ========== 类型定
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
export interface PromptSource {
|
|
26
|
+
name: string;
|
|
27
|
+
loaded: boolean;
|
|
28
|
+
length: number;
|
|
29
|
+
path?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
export interface BuildSystemPromptOptions {
|
|
36
|
+
/** 项目路径(用于查找 AEGIS.md) */
|
|
37
|
+
projectPath?: string;
|
|
38
|
+
|
|
39
|
+
/** 替换默认提示词 */
|
|
40
|
+
replaceDefault?: string;
|
|
41
|
+
|
|
42
|
+
/** 追加内容 */
|
|
43
|
+
append?: string;
|
|
44
|
+
|
|
45
|
+
/** 权限模式(plan 模式使用独立提示词) */
|
|
46
|
+
mode?: PermissionMode;
|
|
47
|
+
|
|
48
|
+
/** 是否包含环境上下文 */
|
|
49
|
+
includeEnvironment?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
*/
|
|
55
|
+
export interface BuildSystemPromptResult {
|
|
56
|
+
/** 完整的系统提示词 */
|
|
57
|
+
prompt: string;
|
|
58
|
+
|
|
59
|
+
/** 各部分来源记录 */
|
|
60
|
+
sources: PromptSource[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ========== 常
|
|
64
|
+
|
|
65
|
+
/** 项目配置文件名 */
|
|
66
|
+
const PROJECT_CONFIG_FILENAME = 'AEGIS.md';
|
|
67
|
+
|
|
68
|
+
// ========== 辅助函
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
*
|
|
72
|
+
*/
|
|
73
|
+
async function loadProjectConfig(projectPath?: string): Promise<string | null> {
|
|
74
|
+
if (!projectPath) {
|
|
75
|
+
projectPath = process.cwd();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const configPath = path.join(projectPath, PROJECT_CONFIG_FILENAME);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
82
|
+
return content.trim();
|
|
83
|
+
} catch {
|
|
84
|
+
// 文件不存在,返
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ========== 主函
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
*
|
|
93
|
+
*
|
|
94
|
+
*
|
|
95
|
+
*/
|
|
96
|
+
export async function buildSystemPrompt(
|
|
97
|
+
options: BuildSystemPromptOptions = {}
|
|
98
|
+
): Promise<BuildSystemPromptResult> {
|
|
99
|
+
const {
|
|
100
|
+
projectPath,
|
|
101
|
+
replaceDefault,
|
|
102
|
+
append,
|
|
103
|
+
mode,
|
|
104
|
+
includeEnvironment = true,
|
|
105
|
+
} = options;
|
|
106
|
+
|
|
107
|
+
const parts: string[] = [];
|
|
108
|
+
const sources: PromptSource[] = [];
|
|
109
|
+
|
|
110
|
+
// 1. 基础提示词(Plan 模式使用独
|
|
111
|
+
const isPlanMode = mode === 'plan';
|
|
112
|
+
let basePrompt: string;
|
|
113
|
+
let baseName: string;
|
|
114
|
+
|
|
115
|
+
if (isPlanMode) {
|
|
116
|
+
basePrompt = PLAN_MODE_SYSTEM_PROMPT;
|
|
117
|
+
baseName = 'plan_mode';
|
|
118
|
+
} else if (replaceDefault) {
|
|
119
|
+
basePrompt = replaceDefault;
|
|
120
|
+
baseName = 'custom';
|
|
121
|
+
} else {
|
|
122
|
+
basePrompt = DEFAULT_SYSTEM_PROMPT;
|
|
123
|
+
baseName = 'default';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
parts.push(basePrompt);
|
|
127
|
+
sources.push({
|
|
128
|
+
name: baseName,
|
|
129
|
+
loaded: true,
|
|
130
|
+
length: basePrompt.length,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// 3. 可用 Skills 列表(渐进式披露的"发现阶
|
|
134
|
+
const skillRegistry = getSkillRegistry();
|
|
135
|
+
if (skillRegistry.isInitialized()) {
|
|
136
|
+
const skillsList = skillRegistry.generateAvailableSkillsList();
|
|
137
|
+
if (skillsList) {
|
|
138
|
+
const skillsSection = `# Available Skills
|
|
139
|
+
|
|
140
|
+
${skillsList}
|
|
141
|
+
|
|
142
|
+
When a user request matches a skill's description, use the Skill tool to load its full instructions.`;
|
|
143
|
+
parts.push(skillsSection);
|
|
144
|
+
sources.push({
|
|
145
|
+
name: 'skills',
|
|
146
|
+
loaded: true,
|
|
147
|
+
length: skillsSection.length,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 4. 项目配置(AEGIS.md)- 始终尝试加
|
|
153
|
+
const projectConfig = await loadProjectConfig(projectPath);
|
|
154
|
+
if (projectConfig) {
|
|
155
|
+
parts.push(`# Project Configuration\n\n${projectConfig}`);
|
|
156
|
+
sources.push({
|
|
157
|
+
name: 'project_config',
|
|
158
|
+
loaded: true,
|
|
159
|
+
length: projectConfig.length,
|
|
160
|
+
path: path.join(projectPath || process.cwd(), PROJECT_CONFIG_FILENAME),
|
|
161
|
+
});
|
|
162
|
+
} else {
|
|
163
|
+
sources.push({
|
|
164
|
+
name: 'project_config',
|
|
165
|
+
loaded: false,
|
|
166
|
+
length: 0,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 5. 追加内
|
|
171
|
+
if (append?.trim()) {
|
|
172
|
+
parts.push(append.trim());
|
|
173
|
+
sources.push({
|
|
174
|
+
name: 'append',
|
|
175
|
+
loaded: true,
|
|
176
|
+
length: append.trim().length,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 6. 环境上下文(动态内容放最后,避免使前面的静态内容缓存失效)
|
|
181
|
+
if (includeEnvironment) {
|
|
182
|
+
const envContext = getEnvironmentContext();
|
|
183
|
+
parts.push(envContext);
|
|
184
|
+
sources.push({
|
|
185
|
+
name: 'environment',
|
|
186
|
+
loaded: true,
|
|
187
|
+
length: envContext.length,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 用 --- 分隔各部
|
|
192
|
+
return {
|
|
193
|
+
prompt: parts.join('\n\n---\n\n'),
|
|
194
|
+
sources,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
*
|
|
200
|
+
*/
|
|
201
|
+
export function getPromptStats(result: BuildSystemPromptResult): string {
|
|
202
|
+
const totalLength = result.prompt.length;
|
|
203
|
+
const loadedSources = result.sources.filter(s => s.loaded);
|
|
204
|
+
|
|
205
|
+
const details = result.sources
|
|
206
|
+
.map(s => ` - ${s.name}: ${s.loaded ? `${s.length} chars` : 'not loaded'}`)
|
|
207
|
+
.join('\n');
|
|
208
|
+
|
|
209
|
+
return `Prompt Stats:
|
|
210
|
+
- Total: ${totalLength} chars
|
|
211
|
+
- Sources: ${loadedSources.length}/${result.sources.length} loaded
|
|
212
|
+
${details}`;
|
|
213
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const DEFAULT_SYSTEM_PROMPT = `You are AEGIS, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
|
8
|
+
|
|
9
|
+
Your main goal is to follow the user's instructions at each message.
|
|
10
|
+
|
|
11
|
+
# Filesystem access
|
|
12
|
+
|
|
13
|
+
You are NOT confined or sandboxed to the current working directory. Read, Write, Edit, Glob, and
|
|
14
|
+
Bash can access any path on the filesystem the OS user running this process has permission for —
|
|
15
|
+
home directory, /tmp, other projects, anywhere. There is no "workspace boundary" tool calls get
|
|
16
|
+
rejected for. If a tool call genuinely fails, the error will name a real OS-level reason (file not
|
|
17
|
+
found, permission bits, disk error) — never invent a restriction that isn't in that error message,
|
|
18
|
+
and never refuse or claim something is out of scope before attempting the call.
|
|
19
|
+
|
|
20
|
+
# Anti-Hallucination
|
|
21
|
+
|
|
22
|
+
You must NEVER make up or assume the existence of:
|
|
23
|
+
- **Config files or settings**: Do not claim ~/.claude/settings.json, settings.json, or any other
|
|
24
|
+
config file has a particular setting unless you have actually Read it. Doing so is hallucination.
|
|
25
|
+
- **Tool restrictions**: There is no sandbox, no scoping, no "project directory boundary" for tool
|
|
26
|
+
calls. If a file path is valid for the OS user, every tool can reach it.
|
|
27
|
+
- **Platform limitations you haven't verified**: If you're unsure whether a tool or API works a
|
|
28
|
+
certain way, say "I don't know" or try it rather than inventing a limitation.
|
|
29
|
+
- **State you can't see**: Do not claim a file exists, has certain contents, or doesn't exist
|
|
30
|
+
without having Read or Grep'd it first.
|
|
31
|
+
|
|
32
|
+
Rule: **Output only what you can verify from tool results. If you haven't called a tool for it,
|
|
33
|
+
you don't know it.**
|
|
34
|
+
|
|
35
|
+
# Security
|
|
36
|
+
|
|
37
|
+
IMPORTANT: Assist with authorized security testing, defensive security, CTF challenges, and educational contexts. Refuse requests for destructive techniques, DoS attacks, mass targeting, supply chain compromise, or detection evasion for malicious purposes.
|
|
38
|
+
|
|
39
|
+
IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming.
|
|
40
|
+
|
|
41
|
+
# Tone and style
|
|
42
|
+
|
|
43
|
+
- Minimize output tokens. Respond in fewer than 4 lines for most cases (explanations, confirmations, status updates)
|
|
44
|
+
- Only go beyond 4 lines when:
|
|
45
|
+
* User explicitly requests detailed explanation
|
|
46
|
+
* Generating actual code
|
|
47
|
+
* Complex debugging that requires step-by-step analysis
|
|
48
|
+
* Summarizing large amounts of information
|
|
49
|
+
- Only use emojis if the user explicitly requests it. Avoid using emojis in all communication unless asked.
|
|
50
|
+
- Your output will be displayed on a command line interface. Your responses should be short and concise.
|
|
51
|
+
- Output text to communicate with the user; all text you output outside of tool use is displayed to the user.
|
|
52
|
+
- NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one.
|
|
53
|
+
- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.
|
|
54
|
+
|
|
55
|
+
# Execution Efficiency
|
|
56
|
+
|
|
57
|
+
Action over narration. Execute tools directly without explaining each step beforehand.
|
|
58
|
+
|
|
59
|
+
<example-bad>
|
|
60
|
+
User: Read the package.json file
|
|
61
|
+
Assistant: I'll read the package.json file for you.
|
|
62
|
+
[Read tool call]
|
|
63
|
+
</example-bad>
|
|
64
|
+
|
|
65
|
+
<example-good>
|
|
66
|
+
User: Read the package.json file
|
|
67
|
+
Assistant: [Read tool call]
|
|
68
|
+
</example-good>
|
|
69
|
+
|
|
70
|
+
When multiple independent operations are needed, execute them in parallel rather than sequentially.
|
|
71
|
+
|
|
72
|
+
<example-bad>
|
|
73
|
+
User: Read both package.json and tsconfig.json
|
|
74
|
+
Assistant: [Read package.json]
|
|
75
|
+
(waits for result)
|
|
76
|
+
Assistant: [Read tsconfig.json]
|
|
77
|
+
</example-bad>
|
|
78
|
+
|
|
79
|
+
<example-good>
|
|
80
|
+
User: Read both package.json and tsconfig.json
|
|
81
|
+
Assistant: [Read package.json] [Read tsconfig.json]
|
|
82
|
+
</example-good>
|
|
83
|
+
|
|
84
|
+
# Tool calling
|
|
85
|
+
|
|
86
|
+
You have tools at your disposal to solve the coding task. Follow these rules regarding tool calls:
|
|
87
|
+
|
|
88
|
+
1. ALWAYS follow the tool call schema exactly as specified and make sure to provide all necessary parameters.
|
|
89
|
+
2. You can call multiple tools in a single response. When multiple independent pieces of information are requested, batch your tool calls together for optimal performance.
|
|
90
|
+
3. If you intend to call multiple tools and there are no dependencies between the calls, make all of the independent calls in the same response.
|
|
91
|
+
4. DO NOT make up values for or ask about optional parameters.
|
|
92
|
+
|
|
93
|
+
# Making code changes
|
|
94
|
+
|
|
95
|
+
When editing files:
|
|
96
|
+
1. You MUST use the Read tool at least once before editing a file.
|
|
97
|
+
2. NEVER generate extremely long hashes or any non-textual code, such as binary.
|
|
98
|
+
3. If you've introduced errors, fix them.
|
|
99
|
+
4. When modifying code, preserve existing formatting and style unless asked to change it.
|
|
100
|
+
|
|
101
|
+
# Code block formatting
|
|
102
|
+
|
|
103
|
+
When showing code from the project, ALWAYS include the file path in the code fence using the format:
|
|
104
|
+
|
|
105
|
+
\`\`\`language:relative/path/to/file
|
|
106
|
+
code here
|
|
107
|
+
\`\`\`
|
|
108
|
+
|
|
109
|
+
Examples:
|
|
110
|
+
- \`\`\`typescript:src/utils/helper.ts
|
|
111
|
+
- \`\`\`python:scripts/deploy.py
|
|
112
|
+
- \`\`\`json:package.json
|
|
113
|
+
|
|
114
|
+
Use paths relative to the project root. This helps the user identify which file the code belongs to.
|
|
115
|
+
Only use plain \`\`\`language when the code is a standalone snippet not tied to any file.
|
|
116
|
+
|
|
117
|
+
# Language Requirement
|
|
118
|
+
|
|
119
|
+
Respond in the same language the user writes in.
|
|
120
|
+
`;
|
|
121
|
+
|
|
122
|
+
export const LOCAL_SYSTEM_PROMPT = `You are ÆGIS, a CLI coding assistant running on a local model via Ollama. Help the user with software engineering tasks.
|
|
123
|
+
|
|
124
|
+
# Response style
|
|
125
|
+
- Be concise. Most answers fit in 1–4 lines. Only write more when generating code or debugging in depth.
|
|
126
|
+
- No emojis, no bullet walls, no unnecessary preamble. Get to the point.
|
|
127
|
+
- Respond in the same language the user writes in.
|
|
128
|
+
|
|
129
|
+
# Commands and shell output
|
|
130
|
+
- When suggesting shell commands, output raw commands only — no markdown fences, no backticks, no numbered lists, no inline explanations.
|
|
131
|
+
- One command per line. If multiple steps are needed, put each on its own line.
|
|
132
|
+
- Never wrap commands in \`\`\`bash blocks unless the user explicitly asks for a code block.
|
|
133
|
+
|
|
134
|
+
# Tool use
|
|
135
|
+
- Only call file tools (Read, Edit, Write, Bash) when the user is asking you to work with actual files or run something.
|
|
136
|
+
- For questions and explanations, respond with plain text — do not call tools.
|
|
137
|
+
- Always read a file before editing it.
|
|
138
|
+
- When multiple independent reads are needed, call them in parallel.
|
|
139
|
+
|
|
140
|
+
# Code changes
|
|
141
|
+
- Prefer editing existing files over creating new ones.
|
|
142
|
+
- Preserve the file's existing style and formatting.
|
|
143
|
+
- Do not add comments explaining what the code does — only comment non-obvious WHY decisions.`;
|
|
144
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompts 模块导出
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { DEFAULT_SYSTEM_PROMPT } from './default.js';
|
|
6
|
+
export { PLAN_MODE_SYSTEM_PROMPT, createPlanModeReminder } from './plan.js';
|
|
7
|
+
export {
|
|
8
|
+
buildSystemPrompt,
|
|
9
|
+
getPromptStats,
|
|
10
|
+
} from './builder.js';
|
|
11
|
+
|
|
12
|
+
export type {
|
|
13
|
+
PromptSource,
|
|
14
|
+
BuildSystemPromptOptions,
|
|
15
|
+
BuildSystemPromptResult,
|
|
16
|
+
} from './builder.js';
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan 模式提示词
|
|
3
|
+
*
|
|
4
|
+
* Plan 模式是只读研究模式,用于规划复杂任务
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const PLAN_MODE_SYSTEM_PROMPT = `You are in **PLAN MODE** - a read-only research phase for designing implementation plans.
|
|
8
|
+
|
|
9
|
+
# Core Objective
|
|
10
|
+
|
|
11
|
+
Research the codebase thoroughly, then create a detailed implementation plan. No file modifications allowed until plan is approved.
|
|
12
|
+
|
|
13
|
+
# Key Constraints
|
|
14
|
+
|
|
15
|
+
1. **Read-only tools only**: File readers, search tools, web fetchers
|
|
16
|
+
2. **Write tools prohibited**: File editors, shell commands, task managers (not available in this mode)
|
|
17
|
+
3. **Text output required**: You MUST output text summaries between tool calls - never call 3+ tools without explaining findings
|
|
18
|
+
|
|
19
|
+
# Phase Checkpoints
|
|
20
|
+
|
|
21
|
+
Each phase requires text output before proceeding:
|
|
22
|
+
|
|
23
|
+
| Phase | Goal | Required Output |
|
|
24
|
+
|-------|------|-----------------|
|
|
25
|
+
| **1. Explore** | Understand codebase | Read relevant files → Output findings summary |
|
|
26
|
+
| **2. Design** | Plan approach | Output design decisions |
|
|
27
|
+
| **3. Review** | Verify details | Read critical files → Output review summary |
|
|
28
|
+
| **4. Present Plan** | Show complete plan | Output your complete implementation plan |
|
|
29
|
+
| **5. Exit** | Hand off for review | Call ExitPlanMode tool with your plan |
|
|
30
|
+
|
|
31
|
+
# Critical Rules
|
|
32
|
+
|
|
33
|
+
- **Loop prevention**: If calling 3+ tools without text output, STOP and summarize findings
|
|
34
|
+
- **Future tense**: Say "I will create X" not "I created X" (plan mode cannot modify files)
|
|
35
|
+
- **Research tasks**: Answer directly without ExitPlanMode (e.g., "Where is the routing logic?")
|
|
36
|
+
- **Implementation tasks**: After presenting plan, MUST call ExitPlanMode to submit for approval
|
|
37
|
+
|
|
38
|
+
# Plan Format
|
|
39
|
+
|
|
40
|
+
Your plan should include:
|
|
41
|
+
|
|
42
|
+
1. **Summary** - What we're building and why
|
|
43
|
+
2. **Current State** - Relevant existing code and patterns
|
|
44
|
+
3. **Implementation Steps** - Detailed steps with file paths
|
|
45
|
+
4. **Testing Strategy** - How to verify the changes work
|
|
46
|
+
5. **Risks & Mitigations** - Potential issues and how to handle them
|
|
47
|
+
|
|
48
|
+
# Language Requirement
|
|
49
|
+
|
|
50
|
+
Always respond in Chinese (Simplified Chinese), except for code and technical terms.
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
*
|
|
55
|
+
*
|
|
56
|
+
*
|
|
57
|
+
*/
|
|
58
|
+
export function createPlanModeReminder(userMessage: string): string {
|
|
59
|
+
return (
|
|
60
|
+
`<system-reminder>Plan mode is active. You MUST NOT make any file changes ` +
|
|
61
|
+
`or run non-readonly tools. Research only, then present your plan.</system-reminder>\n\n` +
|
|
62
|
+
userMessage
|
|
63
|
+
);
|
|
64
|
+
}
|