bobo-ai-cli 2.0.0 → 3.0.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 +52 -9
- package/dist/agent.js +70 -45
- package/dist/agent.js.map +1 -1
- package/dist/agents/catalog.d.ts +40 -0
- package/dist/agents/catalog.js +172 -0
- package/dist/agents/catalog.js.map +1 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/index.js +4 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/router.d.ts +43 -0
- package/dist/agents/router.js +87 -0
- package/dist/agents/router.js.map +1 -0
- package/dist/agents/spawn.d.ts +46 -0
- package/dist/agents/spawn.js +91 -0
- package/dist/agents/spawn.js.map +1 -0
- package/dist/autonomous.js +41 -1
- package/dist/autonomous.js.map +1 -1
- package/dist/claude-bridge.d.ts +18 -0
- package/dist/claude-bridge.js +91 -0
- package/dist/claude-bridge.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +667 -0
- package/dist/cli.js.map +1 -0
- package/dist/compactor.d.ts +49 -4
- package/dist/compactor.js +164 -17
- package/dist/compactor.js.map +1 -1
- package/dist/completer.js +2 -0
- package/dist/completer.js.map +1 -1
- package/dist/cost-tracker.js +35 -2
- package/dist/cost-tracker.js.map +1 -1
- package/dist/dream.d.ts +42 -0
- package/dist/dream.js +321 -0
- package/dist/dream.js.map +1 -0
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +4 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.js +8 -1099
- package/dist/index.js.map +1 -1
- package/dist/insight.js +4 -11
- package/dist/insight.js.map +1 -1
- package/dist/knowledge.d.ts +13 -0
- package/dist/knowledge.js +13 -2
- package/dist/knowledge.js.map +1 -1
- package/dist/memory.d.ts +4 -0
- package/dist/memory.js +6 -0
- package/dist/memory.js.map +1 -1
- package/dist/repl.d.ts +16 -0
- package/dist/repl.js +702 -0
- package/dist/repl.js.map +1 -0
- package/dist/sessions.js +23 -0
- package/dist/sessions.js.map +1 -1
- package/dist/skills/composer.d.ts +18 -0
- package/dist/skills/composer.js +59 -0
- package/dist/skills/composer.js.map +1 -0
- package/dist/skills/index.d.ts +3 -0
- package/dist/skills/index.js +3 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/loader.d.ts +12 -0
- package/dist/skills/loader.js +150 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/types.d.ts +28 -0
- package/dist/skills/types.js +9 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/skills.d.ts +1 -0
- package/dist/skills.js +1 -0
- package/dist/skills.js.map +1 -1
- package/dist/state/artifacts.d.ts +71 -0
- package/dist/state/artifacts.js +131 -0
- package/dist/state/artifacts.js.map +1 -0
- package/dist/state/index.d.ts +9 -0
- package/dist/state/index.js +7 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/manager.d.ts +89 -0
- package/dist/state/manager.js +130 -0
- package/dist/state/manager.js.map +1 -0
- package/dist/state/project-memory.d.ts +24 -0
- package/dist/state/project-memory.js +81 -0
- package/dist/state/project-memory.js.map +1 -0
- package/dist/state/recovery.d.ts +24 -0
- package/dist/state/recovery.js +94 -0
- package/dist/state/recovery.js.map +1 -0
- package/dist/statusbar.d.ts +1 -0
- package/dist/statusbar.js +12 -1
- package/dist/statusbar.js.map +1 -1
- package/dist/sub-agent-runner.d.ts +1 -0
- package/dist/sub-agent-runner.js +29 -3
- package/dist/sub-agent-runner.js.map +1 -1
- package/dist/sub-agents.d.ts +19 -1
- package/dist/sub-agents.js +137 -2
- package/dist/sub-agents.js.map +1 -1
- package/dist/tool-governance.d.ts +77 -0
- package/dist/tool-governance.js +335 -0
- package/dist/tool-governance.js.map +1 -0
- package/dist/tools/claude-bridge-tool.d.ts +4 -0
- package/dist/tools/claude-bridge-tool.js +44 -0
- package/dist/tools/claude-bridge-tool.js.map +1 -0
- package/dist/tools/claude-code.d.ts +33 -0
- package/dist/tools/claude-code.js +279 -0
- package/dist/tools/claude-code.js.map +1 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/ui/hud.d.ts +25 -0
- package/dist/ui/hud.js +67 -0
- package/dist/ui/hud.js.map +1 -0
- package/dist/verification-agent.d.ts +46 -0
- package/dist/verification-agent.js +528 -0
- package/dist/verification-agent.js.map +1 -0
- package/dist/workflows/ask.d.ts +13 -0
- package/dist/workflows/ask.js +66 -0
- package/dist/workflows/ask.js.map +1 -0
- package/dist/workflows/index.d.ts +5 -0
- package/dist/workflows/index.js +6 -0
- package/dist/workflows/index.js.map +1 -0
- package/dist/workflows/interview.d.ts +11 -0
- package/dist/workflows/interview.js +36 -0
- package/dist/workflows/interview.js.map +1 -0
- package/dist/workflows/plan.d.ts +13 -0
- package/dist/workflows/plan.js +34 -0
- package/dist/workflows/plan.js.map +1 -0
- package/dist/workflows/team.d.ts +17 -0
- package/dist/workflows/team.js +86 -0
- package/dist/workflows/team.js.map +1 -0
- package/dist/workflows/verify.d.ts +11 -0
- package/dist/workflows/verify.js +21 -0
- package/dist/workflows/verify.js.map +1 -0
- package/package.json +2 -4
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifacts Manager — 产物管理
|
|
3
|
+
*
|
|
4
|
+
* 管理 .bobo/artifacts/ 目录下的所有产物文件
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
/**
|
|
9
|
+
* 获取产物根目录
|
|
10
|
+
*/
|
|
11
|
+
export function getArtifactsRoot() {
|
|
12
|
+
return join(process.cwd(), '.bobo', 'artifacts');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 确保目录存在
|
|
16
|
+
*/
|
|
17
|
+
function ensureDir(dir) {
|
|
18
|
+
if (!existsSync(dir)) {
|
|
19
|
+
mkdirSync(dir, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 获取产物类型目录
|
|
24
|
+
*/
|
|
25
|
+
export function getArtifactDir(type) {
|
|
26
|
+
const dir = join(getArtifactsRoot(), type);
|
|
27
|
+
ensureDir(dir);
|
|
28
|
+
return dir;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 写入产物
|
|
32
|
+
*/
|
|
33
|
+
export function writeArtifact(type, filename, content) {
|
|
34
|
+
const dir = getArtifactDir(type);
|
|
35
|
+
const path = join(dir, filename);
|
|
36
|
+
writeFileSync(path, content, 'utf-8');
|
|
37
|
+
return path;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 读取产物
|
|
41
|
+
*/
|
|
42
|
+
export function readArtifact(type, filename) {
|
|
43
|
+
const path = join(getArtifactDir(type), filename);
|
|
44
|
+
if (!existsSync(path))
|
|
45
|
+
return null;
|
|
46
|
+
try {
|
|
47
|
+
return readFileSync(path, 'utf-8');
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 列出产物
|
|
55
|
+
*/
|
|
56
|
+
export function listArtifacts(type) {
|
|
57
|
+
const dir = getArtifactDir(type);
|
|
58
|
+
if (!existsSync(dir))
|
|
59
|
+
return [];
|
|
60
|
+
try {
|
|
61
|
+
return readdirSync(dir).filter(f => f.endsWith('.md') || f.endsWith('.json'));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 生成带时间戳的文件名
|
|
69
|
+
*/
|
|
70
|
+
export function generateFilename(prefix, ext = 'md') {
|
|
71
|
+
const timestamp = Date.now();
|
|
72
|
+
return `${prefix}-${timestamp}.${ext}`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 写入 plan 产物
|
|
76
|
+
*/
|
|
77
|
+
export function writePlan(content) {
|
|
78
|
+
const filename = generateFilename('plan');
|
|
79
|
+
return writeArtifact('plans', filename, content);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 写入 PRD 产物
|
|
83
|
+
*/
|
|
84
|
+
export function writePRD(content) {
|
|
85
|
+
const filename = generateFilename('prd');
|
|
86
|
+
return writeArtifact('plans', filename, content);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 写入 research 产物
|
|
90
|
+
*/
|
|
91
|
+
export function writeResearch(topic, content) {
|
|
92
|
+
const filename = generateFilename(`research-${topic.replace(/\s+/g, '-')}`);
|
|
93
|
+
return writeArtifact('research', filename, content);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 写入 ask 产物
|
|
97
|
+
*/
|
|
98
|
+
export function writeAsk(model, content) {
|
|
99
|
+
const filename = generateFilename(`ask-${model}`);
|
|
100
|
+
return writeArtifact('ask', filename, content);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 写入 verify 产物
|
|
104
|
+
*/
|
|
105
|
+
export function writeVerify(content) {
|
|
106
|
+
const filename = generateFilename('verify');
|
|
107
|
+
return writeArtifact('verify', filename, content);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 写入 team 产物
|
|
111
|
+
*/
|
|
112
|
+
export function writeTeam(content) {
|
|
113
|
+
const filename = generateFilename('team');
|
|
114
|
+
return writeArtifact('team', filename, content);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 获取最新产物
|
|
118
|
+
*/
|
|
119
|
+
export function getLatestArtifact(type) {
|
|
120
|
+
const files = listArtifacts(type);
|
|
121
|
+
if (files.length === 0)
|
|
122
|
+
return null;
|
|
123
|
+
// 按时间戳排序(文件名格式: prefix-<timestamp>.md)
|
|
124
|
+
const sorted = files.sort((a, b) => {
|
|
125
|
+
const aTime = parseInt(a.split('-').pop()?.split('.')[0] || '0');
|
|
126
|
+
const bTime = parseInt(b.split('-').pop()?.split('.')[0] || '0');
|
|
127
|
+
return bTime - aTime;
|
|
128
|
+
});
|
|
129
|
+
return readArtifact(type, sorted[0]);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=artifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/state/artifacts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { getStateRoot, getUserStateRoot, getSessionDir } from './manager.js';
|
|
2
|
+
export { readSessionState, writeSessionState, appendSessionHistory } from './manager.js';
|
|
3
|
+
export { readActiveWorkflows, writeActiveWorkflows, addWorkflow, updateWorkflow, removeWorkflow, getSessionWorkflows } from './manager.js';
|
|
4
|
+
export type { SessionState, WorkflowState } from './manager.js';
|
|
5
|
+
export { getArtifactsRoot, getArtifactDir, writeArtifact, readArtifact, listArtifacts } from './artifacts.js';
|
|
6
|
+
export { generateFilename, writePlan, writePRD, writeResearch, writeAsk, writeVerify, writeTeam, getLatestArtifact } from './artifacts.js';
|
|
7
|
+
export type { ArtifactType } from './artifacts.js';
|
|
8
|
+
export { recoverContext, getRecentHistory, buildRecoveryPrompt } from './recovery.js';
|
|
9
|
+
export type { RecoveryContext } from './recovery.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { getStateRoot, getUserStateRoot, getSessionDir } from './manager.js';
|
|
2
|
+
export { readSessionState, writeSessionState, appendSessionHistory } from './manager.js';
|
|
3
|
+
export { readActiveWorkflows, writeActiveWorkflows, addWorkflow, updateWorkflow, removeWorkflow, getSessionWorkflows } from './manager.js';
|
|
4
|
+
export { getArtifactsRoot, getArtifactDir, writeArtifact, readArtifact, listArtifacts } from './artifacts.js';
|
|
5
|
+
export { generateFilename, writePlan, writePRD, writeResearch, writeAsk, writeVerify, writeTeam, getLatestArtifact } from './artifacts.js';
|
|
6
|
+
export { recoverContext, getRecentHistory, buildRecoveryPrompt } from './recovery.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAE3I,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAE3I,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Manager — 状态管理
|
|
3
|
+
*
|
|
4
|
+
* 管理 .bobo/state/ 目录下的所有状态文件
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 状态目录结构
|
|
8
|
+
*
|
|
9
|
+
* .bobo/
|
|
10
|
+
* state/
|
|
11
|
+
* sessions/
|
|
12
|
+
* <session-id>/
|
|
13
|
+
* context.json
|
|
14
|
+
* history.jsonl
|
|
15
|
+
* active-workflows.json
|
|
16
|
+
*/
|
|
17
|
+
export interface SessionState {
|
|
18
|
+
sessionId: string;
|
|
19
|
+
startedAt: string;
|
|
20
|
+
lastActiveAt: string;
|
|
21
|
+
model: string;
|
|
22
|
+
effort: string;
|
|
23
|
+
permissionMode: string;
|
|
24
|
+
messageCount: number;
|
|
25
|
+
tokenUsage: {
|
|
26
|
+
input: number;
|
|
27
|
+
output: number;
|
|
28
|
+
total: number;
|
|
29
|
+
};
|
|
30
|
+
activeWorkflows: string[];
|
|
31
|
+
matchedSkills: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface WorkflowState {
|
|
34
|
+
workflowId: string;
|
|
35
|
+
type: 'team' | 'interview' | 'verify' | 'plan';
|
|
36
|
+
status: 'running' | 'completed' | 'failed';
|
|
37
|
+
startedAt: string;
|
|
38
|
+
completedAt?: string;
|
|
39
|
+
sessionId: string;
|
|
40
|
+
metadata: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 获取状态根目录
|
|
44
|
+
*/
|
|
45
|
+
export declare function getStateRoot(): string;
|
|
46
|
+
/**
|
|
47
|
+
* 获取用户级状态目录
|
|
48
|
+
*/
|
|
49
|
+
export declare function getUserStateRoot(): string;
|
|
50
|
+
/**
|
|
51
|
+
* 获取 session 状态目录
|
|
52
|
+
*/
|
|
53
|
+
export declare function getSessionDir(sessionId: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* 读取 session 状态
|
|
56
|
+
*/
|
|
57
|
+
export declare function readSessionState(sessionId: string): SessionState | null;
|
|
58
|
+
/**
|
|
59
|
+
* 写入 session 状态
|
|
60
|
+
*/
|
|
61
|
+
export declare function writeSessionState(sessionId: string, state: SessionState): void;
|
|
62
|
+
/**
|
|
63
|
+
* 追加 session 历史(JSONL 格式)
|
|
64
|
+
*/
|
|
65
|
+
export declare function appendSessionHistory(sessionId: string, entry: Record<string, unknown>): void;
|
|
66
|
+
/**
|
|
67
|
+
* 读取活跃 workflows
|
|
68
|
+
*/
|
|
69
|
+
export declare function readActiveWorkflows(): WorkflowState[];
|
|
70
|
+
/**
|
|
71
|
+
* 写入活跃 workflows
|
|
72
|
+
*/
|
|
73
|
+
export declare function writeActiveWorkflows(workflows: WorkflowState[]): void;
|
|
74
|
+
/**
|
|
75
|
+
* 添加 workflow
|
|
76
|
+
*/
|
|
77
|
+
export declare function addWorkflow(workflow: WorkflowState): void;
|
|
78
|
+
/**
|
|
79
|
+
* 更新 workflow 状态
|
|
80
|
+
*/
|
|
81
|
+
export declare function updateWorkflow(workflowId: string, updates: Partial<WorkflowState>): void;
|
|
82
|
+
/**
|
|
83
|
+
* 移除 workflow
|
|
84
|
+
*/
|
|
85
|
+
export declare function removeWorkflow(workflowId: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* 获取 session 的活跃 workflows
|
|
88
|
+
*/
|
|
89
|
+
export declare function getSessionWorkflows(sessionId: string): WorkflowState[];
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Manager — 状态管理
|
|
3
|
+
*
|
|
4
|
+
* 管理 .bobo/state/ 目录下的所有状态文件
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
/**
|
|
10
|
+
* 获取状态根目录
|
|
11
|
+
*/
|
|
12
|
+
export function getStateRoot() {
|
|
13
|
+
return join(process.cwd(), '.bobo', 'state');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 获取用户级状态目录
|
|
17
|
+
*/
|
|
18
|
+
export function getUserStateRoot() {
|
|
19
|
+
return join(homedir(), '.bobo', 'state');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 确保目录存在
|
|
23
|
+
*/
|
|
24
|
+
function ensureDir(dir) {
|
|
25
|
+
if (!existsSync(dir)) {
|
|
26
|
+
mkdirSync(dir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 获取 session 状态目录
|
|
31
|
+
*/
|
|
32
|
+
export function getSessionDir(sessionId) {
|
|
33
|
+
const dir = join(getStateRoot(), 'sessions', sessionId);
|
|
34
|
+
ensureDir(dir);
|
|
35
|
+
return dir;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 读取 session 状态
|
|
39
|
+
*/
|
|
40
|
+
export function readSessionState(sessionId) {
|
|
41
|
+
const contextPath = join(getSessionDir(sessionId), 'context.json');
|
|
42
|
+
if (!existsSync(contextPath))
|
|
43
|
+
return null;
|
|
44
|
+
try {
|
|
45
|
+
const content = readFileSync(contextPath, 'utf-8');
|
|
46
|
+
return JSON.parse(content);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 写入 session 状态
|
|
54
|
+
*/
|
|
55
|
+
export function writeSessionState(sessionId, state) {
|
|
56
|
+
const contextPath = join(getSessionDir(sessionId), 'context.json');
|
|
57
|
+
writeFileSync(contextPath, JSON.stringify(state, null, 2), 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 追加 session 历史(JSONL 格式)
|
|
61
|
+
*/
|
|
62
|
+
export function appendSessionHistory(sessionId, entry) {
|
|
63
|
+
const historyPath = join(getSessionDir(sessionId), 'history.jsonl');
|
|
64
|
+
const line = JSON.stringify(entry) + '\n';
|
|
65
|
+
if (existsSync(historyPath)) {
|
|
66
|
+
const existing = readFileSync(historyPath, 'utf-8');
|
|
67
|
+
writeFileSync(historyPath, existing + line, 'utf-8');
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
writeFileSync(historyPath, line, 'utf-8');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 读取活跃 workflows
|
|
75
|
+
*/
|
|
76
|
+
export function readActiveWorkflows() {
|
|
77
|
+
const path = join(getStateRoot(), 'active-workflows.json');
|
|
78
|
+
if (!existsSync(path))
|
|
79
|
+
return [];
|
|
80
|
+
try {
|
|
81
|
+
const content = readFileSync(path, 'utf-8');
|
|
82
|
+
return JSON.parse(content);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 写入活跃 workflows
|
|
90
|
+
*/
|
|
91
|
+
export function writeActiveWorkflows(workflows) {
|
|
92
|
+
ensureDir(getStateRoot());
|
|
93
|
+
const path = join(getStateRoot(), 'active-workflows.json');
|
|
94
|
+
writeFileSync(path, JSON.stringify(workflows, null, 2), 'utf-8');
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 添加 workflow
|
|
98
|
+
*/
|
|
99
|
+
export function addWorkflow(workflow) {
|
|
100
|
+
const workflows = readActiveWorkflows();
|
|
101
|
+
workflows.push(workflow);
|
|
102
|
+
writeActiveWorkflows(workflows);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 更新 workflow 状态
|
|
106
|
+
*/
|
|
107
|
+
export function updateWorkflow(workflowId, updates) {
|
|
108
|
+
const workflows = readActiveWorkflows();
|
|
109
|
+
const index = workflows.findIndex(w => w.workflowId === workflowId);
|
|
110
|
+
if (index !== -1) {
|
|
111
|
+
workflows[index] = { ...workflows[index], ...updates };
|
|
112
|
+
writeActiveWorkflows(workflows);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 移除 workflow
|
|
117
|
+
*/
|
|
118
|
+
export function removeWorkflow(workflowId) {
|
|
119
|
+
const workflows = readActiveWorkflows();
|
|
120
|
+
const filtered = workflows.filter(w => w.workflowId !== workflowId);
|
|
121
|
+
writeActiveWorkflows(filtered);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 获取 session 的活跃 workflows
|
|
125
|
+
*/
|
|
126
|
+
export function getSessionWorkflows(sessionId) {
|
|
127
|
+
const workflows = readActiveWorkflows();
|
|
128
|
+
return workflows.filter(w => w.sessionId === sessionId);
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/state/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Memory — 项目级记忆
|
|
3
|
+
*
|
|
4
|
+
* .bobo/project-memory.json — 结构化项目记忆
|
|
5
|
+
* .bobo/notepad.md — 自由格式 scratchpad
|
|
6
|
+
*/
|
|
7
|
+
export interface ProjectMemoryEntry {
|
|
8
|
+
key: string;
|
|
9
|
+
value: string;
|
|
10
|
+
category: 'architecture' | 'decision' | 'convention' | 'gotcha' | 'todo';
|
|
11
|
+
createdAt: string;
|
|
12
|
+
updatedAt: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ProjectMemory {
|
|
15
|
+
version: number;
|
|
16
|
+
entries: ProjectMemoryEntry[];
|
|
17
|
+
}
|
|
18
|
+
export declare function readProjectMemory(): ProjectMemory;
|
|
19
|
+
export declare function writeProjectMemory(memory: ProjectMemory): void;
|
|
20
|
+
export declare function addMemoryEntry(entry: Omit<ProjectMemoryEntry, 'createdAt' | 'updatedAt'>): void;
|
|
21
|
+
export declare function queryMemory(category?: string, keyword?: string): ProjectMemoryEntry[];
|
|
22
|
+
export declare function readNotepad(): string;
|
|
23
|
+
export declare function writeNotepad(content: string): void;
|
|
24
|
+
export declare function appendNotepad(text: string): void;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Memory — 项目级记忆
|
|
3
|
+
*
|
|
4
|
+
* .bobo/project-memory.json — 结构化项目记忆
|
|
5
|
+
* .bobo/notepad.md — 自由格式 scratchpad
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
const PROJECT_MEMORY_FILE = 'project-memory.json';
|
|
10
|
+
const NOTEPAD_FILE = 'notepad.md';
|
|
11
|
+
function getProjectDir() {
|
|
12
|
+
return join(process.cwd(), '.bobo');
|
|
13
|
+
}
|
|
14
|
+
function getProjectMemoryPath() {
|
|
15
|
+
return join(getProjectDir(), PROJECT_MEMORY_FILE);
|
|
16
|
+
}
|
|
17
|
+
export function readProjectMemory() {
|
|
18
|
+
const path = getProjectMemoryPath();
|
|
19
|
+
if (!existsSync(path)) {
|
|
20
|
+
return { version: 1, entries: [] };
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return { version: 1, entries: [] };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function writeProjectMemory(memory) {
|
|
30
|
+
writeFileSync(getProjectMemoryPath(), JSON.stringify(memory, null, 2) + '\n', 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
export function addMemoryEntry(entry) {
|
|
33
|
+
const memory = readProjectMemory();
|
|
34
|
+
const now = new Date().toISOString();
|
|
35
|
+
const existing = memory.entries.findIndex(e => e.key === entry.key);
|
|
36
|
+
if (existing !== -1) {
|
|
37
|
+
memory.entries[existing] = { ...entry, createdAt: memory.entries[existing].createdAt, updatedAt: now };
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
memory.entries.push({ ...entry, createdAt: now, updatedAt: now });
|
|
41
|
+
}
|
|
42
|
+
writeProjectMemory(memory);
|
|
43
|
+
}
|
|
44
|
+
export function queryMemory(category, keyword) {
|
|
45
|
+
const memory = readProjectMemory();
|
|
46
|
+
let results = memory.entries;
|
|
47
|
+
if (category) {
|
|
48
|
+
results = results.filter(e => e.category === category);
|
|
49
|
+
}
|
|
50
|
+
if (keyword) {
|
|
51
|
+
const lower = keyword.toLowerCase();
|
|
52
|
+
results = results.filter(e => e.key.toLowerCase().includes(lower) ||
|
|
53
|
+
e.value.toLowerCase().includes(lower));
|
|
54
|
+
}
|
|
55
|
+
return results;
|
|
56
|
+
}
|
|
57
|
+
// ─── Notepad (freeform scratchpad) ──────────────────────────
|
|
58
|
+
function getNotepadPath() {
|
|
59
|
+
return join(getProjectDir(), NOTEPAD_FILE);
|
|
60
|
+
}
|
|
61
|
+
export function readNotepad() {
|
|
62
|
+
const path = getNotepadPath();
|
|
63
|
+
if (!existsSync(path))
|
|
64
|
+
return '';
|
|
65
|
+
try {
|
|
66
|
+
return readFileSync(path, 'utf-8');
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return '';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export function writeNotepad(content) {
|
|
73
|
+
writeFileSync(getNotepadPath(), content, 'utf-8');
|
|
74
|
+
}
|
|
75
|
+
export function appendNotepad(text) {
|
|
76
|
+
const existing = readNotepad();
|
|
77
|
+
const timestamp = new Date().toISOString().slice(0, 19).replace('T', ' ');
|
|
78
|
+
const entry = `\n## ${timestamp}\n\n${text}\n`;
|
|
79
|
+
writeNotepad(existing + entry);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=project-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-memory.js","sourceRoot":"","sources":["../../src/state/project-memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Recovery — 会话恢复
|
|
3
|
+
*
|
|
4
|
+
* 从 .bobo/state/sessions/ 恢复之前的会话上下文
|
|
5
|
+
*/
|
|
6
|
+
import { type SessionState, type WorkflowState } from './manager.js';
|
|
7
|
+
export interface RecoveryContext {
|
|
8
|
+
lastSession: SessionState | null;
|
|
9
|
+
activeWorkflows: WorkflowState[];
|
|
10
|
+
recentSessions: SessionState[];
|
|
11
|
+
summary: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 恢复最近的会话上下文
|
|
15
|
+
*/
|
|
16
|
+
export declare function recoverContext(): RecoveryContext;
|
|
17
|
+
/**
|
|
18
|
+
* 获取最近 session 的历史行
|
|
19
|
+
*/
|
|
20
|
+
export declare function getRecentHistory(sessionId: string, maxLines?: number): string[];
|
|
21
|
+
/**
|
|
22
|
+
* 生成恢复 prompt(注入到新 session 开头)
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildRecoveryPrompt(): string;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Recovery — 会话恢复
|
|
3
|
+
*
|
|
4
|
+
* 从 .bobo/state/sessions/ 恢复之前的会话上下文
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { getStateRoot, readActiveWorkflows } from './manager.js';
|
|
9
|
+
/**
|
|
10
|
+
* 恢复最近的会话上下文
|
|
11
|
+
*/
|
|
12
|
+
export function recoverContext() {
|
|
13
|
+
const sessionsDir = join(getStateRoot(), 'sessions');
|
|
14
|
+
if (!existsSync(sessionsDir)) {
|
|
15
|
+
return {
|
|
16
|
+
lastSession: null,
|
|
17
|
+
activeWorkflows: [],
|
|
18
|
+
recentSessions: [],
|
|
19
|
+
summary: 'No previous sessions found.',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const sessionDirs = readdirSync(sessionsDir).sort().reverse();
|
|
23
|
+
const recentSessions = [];
|
|
24
|
+
for (const dir of sessionDirs.slice(0, 5)) {
|
|
25
|
+
const contextPath = join(sessionsDir, dir, 'context.json');
|
|
26
|
+
if (!existsSync(contextPath))
|
|
27
|
+
continue;
|
|
28
|
+
try {
|
|
29
|
+
const state = JSON.parse(readFileSync(contextPath, 'utf-8'));
|
|
30
|
+
recentSessions.push(state);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const lastSession = recentSessions[0] ?? null;
|
|
37
|
+
const activeWorkflows = readActiveWorkflows();
|
|
38
|
+
const parts = [];
|
|
39
|
+
if (lastSession) {
|
|
40
|
+
parts.push(`Last session: ${lastSession.sessionId} (${lastSession.messageCount} messages, ${lastSession.lastActiveAt})`);
|
|
41
|
+
}
|
|
42
|
+
if (activeWorkflows.length > 0) {
|
|
43
|
+
parts.push(`Active workflows: ${activeWorkflows.map(w => `${w.type}[${w.status}]`).join(', ')}`);
|
|
44
|
+
}
|
|
45
|
+
if (parts.length === 0) {
|
|
46
|
+
parts.push('Clean slate — no previous context.');
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
lastSession,
|
|
50
|
+
activeWorkflows,
|
|
51
|
+
recentSessions,
|
|
52
|
+
summary: parts.join('\n'),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 获取最近 session 的历史行
|
|
57
|
+
*/
|
|
58
|
+
export function getRecentHistory(sessionId, maxLines = 50) {
|
|
59
|
+
const historyPath = join(getStateRoot(), 'sessions', sessionId, 'history.jsonl');
|
|
60
|
+
if (!existsSync(historyPath))
|
|
61
|
+
return [];
|
|
62
|
+
try {
|
|
63
|
+
const content = readFileSync(historyPath, 'utf-8');
|
|
64
|
+
const lines = content.trim().split('\n').filter(Boolean);
|
|
65
|
+
return lines.slice(-maxLines);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 生成恢复 prompt(注入到新 session 开头)
|
|
73
|
+
*/
|
|
74
|
+
export function buildRecoveryPrompt() {
|
|
75
|
+
const ctx = recoverContext();
|
|
76
|
+
if (!ctx.lastSession)
|
|
77
|
+
return '';
|
|
78
|
+
const parts = [
|
|
79
|
+
'# Session Recovery',
|
|
80
|
+
'',
|
|
81
|
+
ctx.summary,
|
|
82
|
+
];
|
|
83
|
+
if (ctx.lastSession.matchedSkills.length > 0) {
|
|
84
|
+
parts.push(`\nPrevious skills: ${ctx.lastSession.matchedSkills.join(', ')}`);
|
|
85
|
+
}
|
|
86
|
+
if (ctx.activeWorkflows.length > 0) {
|
|
87
|
+
parts.push('\n## Active Workflows');
|
|
88
|
+
for (const w of ctx.activeWorkflows) {
|
|
89
|
+
parts.push(`- ${w.type} (${w.status}) started ${w.startedAt}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return parts.join('\n');
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../src/state/recovery.ts"],"names":[],"mappings":"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"}
|
package/dist/statusbar.d.ts
CHANGED
package/dist/statusbar.js
CHANGED
|
@@ -36,7 +36,18 @@ export function renderStatusBar() {
|
|
|
36
36
|
const cols = process.stdout.columns || 80;
|
|
37
37
|
const sep = chalk.dim(' · ');
|
|
38
38
|
// Left: permission mode indicator
|
|
39
|
-
const
|
|
39
|
+
const permMode = currentInfo.permissionMode || 'auto';
|
|
40
|
+
let permLabel;
|
|
41
|
+
if (permMode === 'yolo') {
|
|
42
|
+
permLabel = chalk.red('▸▸') + ' ' + chalk.red('yolo');
|
|
43
|
+
}
|
|
44
|
+
else if (permMode === 'ask') {
|
|
45
|
+
permLabel = chalk.green('▸▸') + ' ' + chalk.green('ask');
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// auto
|
|
49
|
+
permLabel = chalk.yellow('▸▸') + ' ' + chalk.yellow('auto');
|
|
50
|
+
}
|
|
40
51
|
// Center/Right: effort + model
|
|
41
52
|
const effortDot = currentInfo.thinkingLevel === 'high' ? chalk.green('●')
|
|
42
53
|
: currentInfo.thinkingLevel === 'low' ? chalk.dim('●')
|
package/dist/statusbar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statusbar.js","sourceRoot":"","sources":["../src/statusbar.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"statusbar.js","sourceRoot":"","sources":["../src/statusbar.ts"],"names":[],"mappings":"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"}
|