@hongmaple0820/scale-engine 0.6.0 → 0.7.1
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 +29 -6
- package/dist/adapters/ClaudeCodeAdapter.d.ts +1 -1
- package/dist/adapters/ClaudeCodeAdapter.js +1 -1
- package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
- package/dist/adapters/QCoderAdapter.d.ts +13 -0
- package/dist/adapters/QCoderAdapter.js +153 -0
- package/dist/adapters/QCoderAdapter.js.map +1 -0
- package/dist/adapters/TraeAdapter.d.ts +13 -0
- package/dist/adapters/TraeAdapter.js +153 -0
- package/dist/adapters/TraeAdapter.js.map +1 -0
- package/dist/adapters/VSCAdapter.d.ts +13 -0
- package/dist/adapters/VSCAdapter.js +153 -0
- package/dist/adapters/VSCAdapter.js.map +1 -0
- package/dist/adapters/WorkBuddyAdapter.d.ts +13 -0
- package/dist/adapters/WorkBuddyAdapter.js +153 -0
- package/dist/adapters/WorkBuddyAdapter.js.map +1 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.js +13 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/api/cli.js +59 -3
- package/dist/api/cli.js.map +1 -1
- package/dist/api/doctor.js +29 -10
- package/dist/api/doctor.js.map +1 -1
- package/dist/artifact/types.d.ts +3 -3
- package/dist/artifact/types.js.map +1 -1
- package/dist/context/ContextBuilder.d.ts +4 -0
- package/dist/context/ContextBuilder.js +43 -9
- package/dist/context/ContextBuilder.js.map +1 -1
- package/dist/dashboard/DashboardServer.d.ts +63 -0
- package/dist/dashboard/DashboardServer.js +167 -0
- package/dist/dashboard/DashboardServer.js.map +1 -0
- package/dist/evolution/AutoDefectCreator.d.ts +34 -0
- package/dist/evolution/AutoDefectCreator.js +115 -0
- package/dist/evolution/AutoDefectCreator.js.map +1 -0
- package/dist/evolution/BehaviorTracker.d.ts +8 -0
- package/dist/evolution/BehaviorTracker.js +18 -1
- package/dist/evolution/BehaviorTracker.js.map +1 -1
- package/dist/evolution/EvolutionEvaluator.d.ts +59 -0
- package/dist/evolution/EvolutionEvaluator.js +115 -0
- package/dist/evolution/EvolutionEvaluator.js.map +1 -0
- package/dist/evolution/LessonValidator.d.ts +36 -0
- package/dist/evolution/LessonValidator.js +136 -0
- package/dist/evolution/LessonValidator.js.map +1 -0
- package/dist/fsm/FSMAgentBridge.d.ts +59 -0
- package/dist/fsm/FSMAgentBridge.js +195 -0
- package/dist/fsm/FSMAgentBridge.js.map +1 -0
- package/dist/fsm/index.d.ts +2 -0
- package/dist/fsm/index.js +3 -0
- package/dist/fsm/index.js.map +1 -0
- package/dist/guardrails/DetectorEnhanced.d.ts +111 -0
- package/dist/guardrails/DetectorEnhanced.js +200 -0
- package/dist/guardrails/DetectorEnhanced.js.map +1 -0
- package/dist/hooks/HookDeployer.d.ts +44 -0
- package/dist/hooks/HookDeployer.js +145 -0
- package/dist/hooks/HookDeployer.js.map +1 -0
- package/dist/hooks/HookGeneratorEnhanced.d.ts +67 -0
- package/dist/hooks/HookGeneratorEnhanced.js +238 -0
- package/dist/hooks/HookGeneratorEnhanced.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +26 -2
- package/dist/index.js +21 -5
- package/dist/index.js.map +1 -1
- package/dist/knowledge/SQLiteKnowledgeBase.js +28 -28
- package/dist/skills/SkillDiscovery.js +8 -0
- package/dist/skills/SkillDiscovery.js.map +1 -1
- package/dist/skills/SkillExecutor.d.ts +28 -0
- package/dist/skills/SkillExecutor.js +84 -0
- package/dist/skills/SkillExecutor.js.map +1 -0
- package/dist/skills/SkillRegistry.d.ts +93 -0
- package/dist/skills/SkillRegistry.js +130 -0
- package/dist/skills/SkillRegistry.js.map +1 -0
- package/dist/skills/TriggerEngine.d.ts +43 -0
- package/dist/skills/TriggerEngine.js +144 -0
- package/dist/skills/TriggerEngine.js.map +1 -0
- package/dist/skills/coreSkills.d.ts +6 -0
- package/dist/skills/coreSkills.js +41 -0
- package/dist/skills/coreSkills.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.js +6 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/workflows/GateParser.d.ts +55 -0
- package/dist/workflows/GateParser.js +73 -0
- package/dist/workflows/GateParser.js.map +1 -0
- package/dist/workflows/WorkflowExecutor.d.ts +56 -0
- package/dist/workflows/WorkflowExecutor.js +145 -0
- package/dist/workflows/WorkflowExecutor.js.map +1 -0
- package/dist/workflows/index.d.ts +4 -0
- package/dist/workflows/index.js +5 -0
- package/dist/workflows/index.js.map +1 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<img src="https://img.shields.io/badge/version-0.6.0-orange?style=flat-square" alt="version" />
|
|
3
|
-
<img src="https://img.shields.io/badge/agents-
|
|
3
|
+
<img src="https://img.shields.io/badge/agents-11-blue?style=flat-square" alt="agents" />
|
|
4
4
|
<img src="https://img.shields.io/badge/workflows-10-green?style=flat-square" alt="workflows" />
|
|
5
5
|
<img src="https://img.shields.io/badge/detectors-9-red?style=flat-square" alt="detectors" />
|
|
6
6
|
<img src="https://img.shields.io/badge/tests-197-passing-brightgreen?style=flat-square" alt="tests" />
|
|
@@ -157,9 +157,9 @@ SCALE Engine 通过 **六层架构** 实现 AI 工程化:
|
|
|
157
157
|
│ └───────────────────────────────────────────────────────────┘ │
|
|
158
158
|
│ │
|
|
159
159
|
│ ┌───────────────────────────────────────────────────────────┐ │
|
|
160
|
-
│ │
|
|
160
|
+
│ │ 11 Agent 适配器 │ │
|
|
161
161
|
│ │ Claude Code │ Codex CLI │ OpenCode │ Cursor │ Gemini │ │ │
|
|
162
|
-
│ │ OpenClaw │ Hermes
|
|
162
|
+
│ │ OpenClaw │ Hermes │ Trae │ WorkBuddy │ VSC │ QCoder │ │
|
|
163
163
|
│ └───────────────────────────────────────────────────────────┘ │
|
|
164
164
|
│ │
|
|
165
165
|
│ ┌──────────────────────┐ ┌──────────────────────────────────┐│
|
|
@@ -320,7 +320,7 @@ Defect (closed) → Lesson (extracted) → Rule (proposed) → Hook (generated)
|
|
|
320
320
|
|
|
321
321
|
## ✨ 功能特性
|
|
322
322
|
|
|
323
|
-
###
|
|
323
|
+
### 11 种 Agent 适配器
|
|
324
324
|
|
|
325
325
|
| Agent | 配置文件 | 知识文档 | 技能目录 | 特色能力 |
|
|
326
326
|
|-------|---------|---------|---------|---------|
|
|
@@ -331,6 +331,10 @@ Defect (closed) → Lesson (extracted) → Rule (proposed) → Hook (generated)
|
|
|
331
331
|
| 🔴 **Gemini** | `.gemini/settings.json` | `GEMINI.md` | — | Google 生态 + gstack + 免费额度 |
|
|
332
332
|
| 🟡 **OpenClaw** | `.openclaw/settings.json` | `AGENTS.md` | — | 开源 Agent 框架 |
|
|
333
333
|
| 🟤 **Hermes** | `.hermes/settings.json` | `.hermes.md` | — | 轻量级 Agent |
|
|
334
|
+
| 🟦 **Trae** | `.trae/settings.json` | `TRAE.md` | — | 字节跳动 AI 编程助手 |
|
|
335
|
+
| 🟪 **WorkBuddy** | `.workbuddy/settings.json` | `WORKBUDDY.md` | — | 腾讯 CodeBuddy 团队协作 |
|
|
336
|
+
| 🟦 **VSC** | `.vscode/scale.json` | `VSC.md` | — | VS Code Copilot CLI |
|
|
337
|
+
| 🟧 **QCoder** | `.qwen/settings.json` | `QWEN.md` | — | 阿里通义千问 Code CLI |
|
|
334
338
|
|
|
335
339
|
**统一工厂函数**:
|
|
336
340
|
|
|
@@ -505,13 +509,17 @@ scale init --agent claude-code --scenario sandbox # 🏖️ 探索/原型
|
|
|
505
509
|
scale init --agent claude-code --scenario standard # ⚙️ 日常开发(默认)
|
|
506
510
|
scale init --agent claude-code --scenario critical # 🔒 生产/安全
|
|
507
511
|
|
|
508
|
-
# 支持
|
|
512
|
+
# 支持 11 种 Agent
|
|
509
513
|
scale init --agent codex # Codex CLI
|
|
510
514
|
scale init --agent opencode # OpenCode
|
|
511
515
|
scale init --agent cursor # Cursor
|
|
512
516
|
scale init --agent gemini # Gemini
|
|
513
517
|
scale init --agent openclaw # OpenClaw
|
|
514
518
|
scale init --agent hermes # Hermes
|
|
519
|
+
scale init --agent trae # 字节 Trae
|
|
520
|
+
scale init --agent workbuddy # 腾讯 WorkBuddy
|
|
521
|
+
scale init --agent vsc # VS Code Copilot CLI
|
|
522
|
+
scale init --agent qcoder # 阿里 Qwen Code
|
|
515
523
|
```
|
|
516
524
|
|
|
517
525
|
### 环境诊断
|
|
@@ -657,7 +665,7 @@ console.log('生成的配置文件:', initResult.files)
|
|
|
657
665
|
| `ScenarioMode` | Type | `'sandbox' \| 'standard' \| 'critical'` |
|
|
658
666
|
| `ScenarioModeConfig` | Interface | 场景模式配置 |
|
|
659
667
|
| `SCENARIO_MODE_CONFIGS` | Constant | 3 种场景模式预设 |
|
|
660
|
-
| `AgentPlatform` | Type |
|
|
668
|
+
| `AgentPlatform` | Type | 11 种 Agent 平台联合类型 |
|
|
661
669
|
| `SkillRef` | Interface | 技能引用 |
|
|
662
670
|
| `SkillScanResult` | Interface | 技能扫描结果 |
|
|
663
671
|
| `WorkflowPreset` | Interface | 工作流预设 |
|
|
@@ -825,6 +833,21 @@ console.log('生成的配置文件:', initResult.files)
|
|
|
825
833
|
|
|
826
834
|
## 📋 CHANGELOG
|
|
827
835
|
|
|
836
|
+
### v0.6.1 (Unreleased)
|
|
837
|
+
|
|
838
|
+
**新增 4 种 Agent 适配器(共 11 种):**
|
|
839
|
+
- ✨ **TraeAdapter** — 字节跳动 Trae AI 编程助手(`.trae/settings.json` + `TRAE.md`)
|
|
840
|
+
- ✨ **WorkBuddyAdapter** — 腾讯 CodeBuddy 团队协作(`.workbuddy/settings.json` + `WORKBUDDY.md`)
|
|
841
|
+
- ✨ **VSCAdapter** — VS Code Copilot CLI(`.vscode/scale.json` + `VSC.md`)
|
|
842
|
+
- ✨ **QCoderAdapter** — 阿里通义千问 Code CLI(`.qwen/settings.json` + `QWEN.md`)
|
|
843
|
+
|
|
844
|
+
**集成完整性:**
|
|
845
|
+
- `AgentPlatform` 联合类型扩展至 11 种
|
|
846
|
+
- `Doctor.checkSettingsJson` / `checkKnowledgeDoc` 支持新增 4 种平台检测
|
|
847
|
+
- `SkillDiscovery.detectPlatform` 支持识别 4 种新平台
|
|
848
|
+
- `createAdapter` / `SUPPORTED_AGENTS` 注册新适配器
|
|
849
|
+
- 4 个测试套件 × 共 ~50 个新测试用例
|
|
850
|
+
|
|
828
851
|
### v0.6.0 (2026-04-29)
|
|
829
852
|
|
|
830
853
|
**新增功能:**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface AdapterConfig {
|
|
2
2
|
projectDir: string;
|
|
3
3
|
scaleDir?: string;
|
|
4
|
-
agentType?: 'claude-code' | 'codex' | 'opencode' | 'cursor' | 'gemini' | 'openclaw' | 'hermes';
|
|
4
|
+
agentType?: 'claude-code' | 'codex' | 'opencode' | 'cursor' | 'gemini' | 'openclaw' | 'hermes' | 'trae' | 'workbuddy' | 'vsc' | 'qcoder';
|
|
5
5
|
scenarioMode?: 'sandbox' | 'standard' | 'critical';
|
|
6
6
|
}
|
|
7
7
|
export interface HookEntry {
|
|
@@ -24,7 +24,7 @@ export class ClaudeCodeAdapter {
|
|
|
24
24
|
return {
|
|
25
25
|
hooks: {
|
|
26
26
|
SessionStart: [
|
|
27
|
-
{ matcher: '', command: 'scale
|
|
27
|
+
{ matcher: '', command: 'scale context inject --session-id $CLAUDE_SESSION_ID' },
|
|
28
28
|
],
|
|
29
29
|
PreToolUse: [
|
|
30
30
|
{ matcher: 'Bash', command: 'scale gate pre-tool Bash --args-json $TOOL_INPUT_JSON --session-id $CLAUDE_SESSION_ID' },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClaudeCodeAdapter.js","sourceRoot":"","sources":["../../src/adapters/ClaudeCodeAdapter.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,0CAA0C;AAC1C,8CAA8C;AAE9C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"ClaudeCodeAdapter.js","sourceRoot":"","sources":["../../src/adapters/ClaudeCodeAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IAgentAdapter, AdapterConfig, InitResult, SettingsJson } from './ClaudeCodeAdapter.js';
|
|
2
|
+
export declare class QCoderAdapter implements IAgentAdapter {
|
|
3
|
+
readonly agentType = "qcoder";
|
|
4
|
+
private projectDir;
|
|
5
|
+
private scaleDir;
|
|
6
|
+
getSettingsPath(): string;
|
|
7
|
+
getKnowledgeDocPath(): string;
|
|
8
|
+
isInstalled(): boolean;
|
|
9
|
+
generateSettings(): SettingsJson;
|
|
10
|
+
mergeSettings(existing: SettingsJson): SettingsJson;
|
|
11
|
+
generateKnowledgeDoc(projectName: string, techStack?: string[]): string;
|
|
12
|
+
init(config: AdapterConfig): Promise<InitResult>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// SCALE Engine — QCoder (Qwen Code) Adapter
|
|
2
|
+
// 生成 .qwen/settings.json + QWEN.md
|
|
3
|
+
// Qwen Code: 阿里通义千问 CLI (https://github.com/QwenLM/qwen-code)
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { logger } from '../core/logger.js';
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// QCoder Adapter
|
|
9
|
+
// ============================================================================
|
|
10
|
+
export class QCoderAdapter {
|
|
11
|
+
agentType = 'qcoder';
|
|
12
|
+
projectDir = '.';
|
|
13
|
+
scaleDir = '.scale';
|
|
14
|
+
getSettingsPath() {
|
|
15
|
+
return join(this.projectDir, '.qwen', 'settings.json');
|
|
16
|
+
}
|
|
17
|
+
getKnowledgeDocPath() {
|
|
18
|
+
return join(this.projectDir, 'QWEN.md');
|
|
19
|
+
}
|
|
20
|
+
isInstalled() {
|
|
21
|
+
return existsSync(join(this.projectDir, '.qwen'));
|
|
22
|
+
}
|
|
23
|
+
generateSettings() {
|
|
24
|
+
return {
|
|
25
|
+
hooks: {
|
|
26
|
+
'pre-exec': [
|
|
27
|
+
{ matcher: '', command: 'scale gate pre-tool Bash --args-json "$ARGS" --session-id "$SESSION_ID"' },
|
|
28
|
+
{ matcher: 'edit|write', command: 'scale gate pre-tool Edit --args-json "$ARGS" --session-id "$SESSION_ID"' },
|
|
29
|
+
],
|
|
30
|
+
'post-exec': [
|
|
31
|
+
{ matcher: 'edit|write', command: 'scale gate post-tool Edit --args-json "$ARGS" --exit-code "$EXIT_CODE" --session-id "$SESSION_ID"' },
|
|
32
|
+
{ matcher: '', command: 'scale gate post-tool Bash --args-json "$ARGS" --exit-code "$EXIT_CODE" --session-id "$SESSION_ID"' },
|
|
33
|
+
],
|
|
34
|
+
'before-stop': [
|
|
35
|
+
{ matcher: '', command: 'scale gate before-stop --session-id "$SESSION_ID"' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
permissions: {
|
|
39
|
+
allow: ['scale:*'],
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
mergeSettings(existing) {
|
|
44
|
+
const generated = this.generateSettings();
|
|
45
|
+
const merged = { ...existing };
|
|
46
|
+
if (!merged.hooks)
|
|
47
|
+
merged.hooks = {};
|
|
48
|
+
for (const [hookType, entries] of Object.entries(generated.hooks)) {
|
|
49
|
+
if (!merged.hooks[hookType])
|
|
50
|
+
merged.hooks[hookType] = [];
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const alreadyExists = merged.hooks[hookType].some((e) => e.command.includes('scale '));
|
|
53
|
+
if (!alreadyExists) {
|
|
54
|
+
merged.hooks[hookType].push(entry);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!merged.permissions)
|
|
59
|
+
merged.permissions = {};
|
|
60
|
+
if (!merged.permissions.allow)
|
|
61
|
+
merged.permissions.allow = [];
|
|
62
|
+
for (const perm of generated.permissions.allow) {
|
|
63
|
+
if (!merged.permissions.allow.includes(perm)) {
|
|
64
|
+
merged.permissions.allow.push(perm);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return merged;
|
|
68
|
+
}
|
|
69
|
+
generateKnowledgeDoc(projectName, techStack = []) {
|
|
70
|
+
const stackLine = techStack.length > 0
|
|
71
|
+
? `\n## Tech Stack\n${techStack.map((t) => `- ${t}`).join('\n')}\n`
|
|
72
|
+
: '';
|
|
73
|
+
return `# ${projectName}
|
|
74
|
+
${stackLine}
|
|
75
|
+
## SCALE Engine Integration (QCoder / Qwen Code)
|
|
76
|
+
|
|
77
|
+
This project uses SCALE Engine for AI engineering governance via Qwen Code CLI.
|
|
78
|
+
|
|
79
|
+
### Commands
|
|
80
|
+
- \`scale create <type> <title>\` — Create artifact
|
|
81
|
+
- \`scale transition <id> <action>\` — Transition artifact state
|
|
82
|
+
- \`scale list --type Spec\` — List artifacts
|
|
83
|
+
- \`scale role activate <role>\` — Switch role
|
|
84
|
+
- \`scale doctor\` — Health check
|
|
85
|
+
|
|
86
|
+
### Workflow
|
|
87
|
+
1. **Explore** → Role: explorer (Read/Grep only)
|
|
88
|
+
2. **Plan** → Create Spec → refine → approve (guard: ambiguity ≤ 0.2)
|
|
89
|
+
3. **Implement** → Role: implementer (Edit/Write/Bash unlocked)
|
|
90
|
+
4. **Verify** → Must run tests before claiming done
|
|
91
|
+
5. **Learn** → Defects → Lessons → Rules → Hooks
|
|
92
|
+
|
|
93
|
+
### Rules
|
|
94
|
+
- 🔴 Dangerous commands are physically blocked
|
|
95
|
+
- 🔴 Hardcoded secrets are blocked on Edit/Write
|
|
96
|
+
- 🟡 3 identical retries triggers brute-retry detection
|
|
97
|
+
- 🟡 Claiming done without running tests is blocked
|
|
98
|
+
- 🟢 All tool calls are tracked in .scale/events/
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
async init(config) {
|
|
102
|
+
this.projectDir = config.projectDir;
|
|
103
|
+
this.scaleDir = config.scaleDir ?? join(config.projectDir, '.scale');
|
|
104
|
+
const created = [];
|
|
105
|
+
const skipped = [];
|
|
106
|
+
for (const dir of ['events', 'artifacts', 'rules', 'hooks', 'checkpoints']) {
|
|
107
|
+
const fullDir = join(this.scaleDir, dir);
|
|
108
|
+
if (!existsSync(fullDir)) {
|
|
109
|
+
mkdirSync(fullDir, { recursive: true });
|
|
110
|
+
created.push(fullDir);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
skipped.push(fullDir);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const qwenDir = join(this.projectDir, '.qwen');
|
|
117
|
+
mkdirSync(qwenDir, { recursive: true });
|
|
118
|
+
const settingsPath = this.getSettingsPath();
|
|
119
|
+
if (existsSync(settingsPath)) {
|
|
120
|
+
const existing = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
121
|
+
const merged = this.mergeSettings(existing);
|
|
122
|
+
writeFileSync(settingsPath, JSON.stringify(merged, null, 2), 'utf-8');
|
|
123
|
+
skipped.push(settingsPath + ' (merged)');
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
writeFileSync(settingsPath, JSON.stringify(this.generateSettings(), null, 2), 'utf-8');
|
|
127
|
+
created.push(settingsPath);
|
|
128
|
+
}
|
|
129
|
+
const knowledgeDocPath = this.getKnowledgeDocPath();
|
|
130
|
+
if (!existsSync(knowledgeDocPath)) {
|
|
131
|
+
const projectName = config.projectDir.split(/[/\\]/).pop() ?? 'Project';
|
|
132
|
+
writeFileSync(knowledgeDocPath, this.generateKnowledgeDoc(projectName), 'utf-8');
|
|
133
|
+
created.push(knowledgeDocPath);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
skipped.push(knowledgeDocPath);
|
|
137
|
+
}
|
|
138
|
+
const gitignorePath = join(this.scaleDir, '.gitignore');
|
|
139
|
+
if (!existsSync(gitignorePath)) {
|
|
140
|
+
writeFileSync(gitignorePath, `*.db\n*.db-journal\nevents/\ncheckpoints/\nhooks/*.sh\n`, 'utf-8');
|
|
141
|
+
created.push(gitignorePath);
|
|
142
|
+
}
|
|
143
|
+
logger.info({ created: created.length, skipped: skipped.length }, 'SCALE init (qcoder) completed');
|
|
144
|
+
return {
|
|
145
|
+
settingsPath,
|
|
146
|
+
knowledgeDocPath,
|
|
147
|
+
scaleDir: this.scaleDir,
|
|
148
|
+
created,
|
|
149
|
+
skipped,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=QCoderAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QCoderAdapter.js","sourceRoot":"","sources":["../../src/adapters/QCoderAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IAgentAdapter, AdapterConfig, InitResult, SettingsJson } from './ClaudeCodeAdapter.js';
|
|
2
|
+
export declare class TraeAdapter implements IAgentAdapter {
|
|
3
|
+
readonly agentType = "trae";
|
|
4
|
+
private projectDir;
|
|
5
|
+
private scaleDir;
|
|
6
|
+
getSettingsPath(): string;
|
|
7
|
+
getKnowledgeDocPath(): string;
|
|
8
|
+
isInstalled(): boolean;
|
|
9
|
+
generateSettings(): SettingsJson;
|
|
10
|
+
mergeSettings(existing: SettingsJson): SettingsJson;
|
|
11
|
+
generateKnowledgeDoc(projectName: string, techStack?: string[]): string;
|
|
12
|
+
init(config: AdapterConfig): Promise<InitResult>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// SCALE Engine — Trae Adapter
|
|
2
|
+
// 生成 .trae/settings.json + TRAE.md
|
|
3
|
+
// Trae: ByteDance AI 编程助手 (https://www.trae.ai)
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { logger } from '../core/logger.js';
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Trae Adapter
|
|
9
|
+
// ============================================================================
|
|
10
|
+
export class TraeAdapter {
|
|
11
|
+
agentType = 'trae';
|
|
12
|
+
projectDir = '.';
|
|
13
|
+
scaleDir = '.scale';
|
|
14
|
+
getSettingsPath() {
|
|
15
|
+
return join(this.projectDir, '.trae', 'settings.json');
|
|
16
|
+
}
|
|
17
|
+
getKnowledgeDocPath() {
|
|
18
|
+
return join(this.projectDir, 'TRAE.md');
|
|
19
|
+
}
|
|
20
|
+
isInstalled() {
|
|
21
|
+
return existsSync(join(this.projectDir, '.trae'));
|
|
22
|
+
}
|
|
23
|
+
generateSettings() {
|
|
24
|
+
return {
|
|
25
|
+
hooks: {
|
|
26
|
+
'pre-exec': [
|
|
27
|
+
{ matcher: '', command: 'scale gate pre-tool Bash --args-json "$ARGS" --session-id "$SESSION_ID"' },
|
|
28
|
+
{ matcher: 'edit|write', command: 'scale gate pre-tool Edit --args-json "$ARGS" --session-id "$SESSION_ID"' },
|
|
29
|
+
],
|
|
30
|
+
'post-exec': [
|
|
31
|
+
{ matcher: 'edit|write', command: 'scale gate post-tool Edit --args-json "$ARGS" --exit-code "$EXIT_CODE" --session-id "$SESSION_ID"' },
|
|
32
|
+
{ matcher: '', command: 'scale gate post-tool Bash --args-json "$ARGS" --exit-code "$EXIT_CODE" --session-id "$SESSION_ID"' },
|
|
33
|
+
],
|
|
34
|
+
'before-stop': [
|
|
35
|
+
{ matcher: '', command: 'scale gate before-stop --session-id "$SESSION_ID"' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
permissions: {
|
|
39
|
+
allow: ['scale:*'],
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
mergeSettings(existing) {
|
|
44
|
+
const generated = this.generateSettings();
|
|
45
|
+
const merged = { ...existing };
|
|
46
|
+
if (!merged.hooks)
|
|
47
|
+
merged.hooks = {};
|
|
48
|
+
for (const [hookType, entries] of Object.entries(generated.hooks)) {
|
|
49
|
+
if (!merged.hooks[hookType])
|
|
50
|
+
merged.hooks[hookType] = [];
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const alreadyExists = merged.hooks[hookType].some((e) => e.command.includes('scale '));
|
|
53
|
+
if (!alreadyExists) {
|
|
54
|
+
merged.hooks[hookType].push(entry);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!merged.permissions)
|
|
59
|
+
merged.permissions = {};
|
|
60
|
+
if (!merged.permissions.allow)
|
|
61
|
+
merged.permissions.allow = [];
|
|
62
|
+
for (const perm of generated.permissions.allow) {
|
|
63
|
+
if (!merged.permissions.allow.includes(perm)) {
|
|
64
|
+
merged.permissions.allow.push(perm);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return merged;
|
|
68
|
+
}
|
|
69
|
+
generateKnowledgeDoc(projectName, techStack = []) {
|
|
70
|
+
const stackLine = techStack.length > 0
|
|
71
|
+
? `\n## Tech Stack\n${techStack.map((t) => `- ${t}`).join('\n')}\n`
|
|
72
|
+
: '';
|
|
73
|
+
return `# ${projectName}
|
|
74
|
+
${stackLine}
|
|
75
|
+
## SCALE Engine Integration (Trae)
|
|
76
|
+
|
|
77
|
+
This project uses SCALE Engine for AI engineering governance via Trae.
|
|
78
|
+
|
|
79
|
+
### Commands
|
|
80
|
+
- \`scale create <type> <title>\` — Create artifact
|
|
81
|
+
- \`scale transition <id> <action>\` — Transition artifact state
|
|
82
|
+
- \`scale list --type Spec\` — List artifacts
|
|
83
|
+
- \`scale role activate <role>\` — Switch role
|
|
84
|
+
- \`scale doctor\` — Health check
|
|
85
|
+
|
|
86
|
+
### Workflow
|
|
87
|
+
1. **Explore** → Role: explorer (Read/Grep only)
|
|
88
|
+
2. **Plan** → Create Spec → refine → approve (guard: ambiguity ≤ 0.2)
|
|
89
|
+
3. **Implement** → Role: implementer (Edit/Write/Bash unlocked)
|
|
90
|
+
4. **Verify** → Must run tests before claiming done
|
|
91
|
+
5. **Learn** → Defects → Lessons → Rules → Hooks
|
|
92
|
+
|
|
93
|
+
### Rules
|
|
94
|
+
- 🔴 Dangerous commands are physically blocked
|
|
95
|
+
- 🔴 Hardcoded secrets are blocked on Edit/Write
|
|
96
|
+
- 🟡 3 identical retries triggers brute-retry detection
|
|
97
|
+
- 🟡 Claiming done without running tests is blocked
|
|
98
|
+
- 🟢 All tool calls are tracked in .scale/events/
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
async init(config) {
|
|
102
|
+
this.projectDir = config.projectDir;
|
|
103
|
+
this.scaleDir = config.scaleDir ?? join(config.projectDir, '.scale');
|
|
104
|
+
const created = [];
|
|
105
|
+
const skipped = [];
|
|
106
|
+
for (const dir of ['events', 'artifacts', 'rules', 'hooks', 'checkpoints']) {
|
|
107
|
+
const fullDir = join(this.scaleDir, dir);
|
|
108
|
+
if (!existsSync(fullDir)) {
|
|
109
|
+
mkdirSync(fullDir, { recursive: true });
|
|
110
|
+
created.push(fullDir);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
skipped.push(fullDir);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const traeDir = join(this.projectDir, '.trae');
|
|
117
|
+
mkdirSync(traeDir, { recursive: true });
|
|
118
|
+
const settingsPath = this.getSettingsPath();
|
|
119
|
+
if (existsSync(settingsPath)) {
|
|
120
|
+
const existing = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
121
|
+
const merged = this.mergeSettings(existing);
|
|
122
|
+
writeFileSync(settingsPath, JSON.stringify(merged, null, 2), 'utf-8');
|
|
123
|
+
skipped.push(settingsPath + ' (merged)');
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
writeFileSync(settingsPath, JSON.stringify(this.generateSettings(), null, 2), 'utf-8');
|
|
127
|
+
created.push(settingsPath);
|
|
128
|
+
}
|
|
129
|
+
const knowledgeDocPath = this.getKnowledgeDocPath();
|
|
130
|
+
if (!existsSync(knowledgeDocPath)) {
|
|
131
|
+
const projectName = config.projectDir.split(/[/\\]/).pop() ?? 'Project';
|
|
132
|
+
writeFileSync(knowledgeDocPath, this.generateKnowledgeDoc(projectName), 'utf-8');
|
|
133
|
+
created.push(knowledgeDocPath);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
skipped.push(knowledgeDocPath);
|
|
137
|
+
}
|
|
138
|
+
const gitignorePath = join(this.scaleDir, '.gitignore');
|
|
139
|
+
if (!existsSync(gitignorePath)) {
|
|
140
|
+
writeFileSync(gitignorePath, `*.db\n*.db-journal\nevents/\ncheckpoints/\nhooks/*.sh\n`, 'utf-8');
|
|
141
|
+
created.push(gitignorePath);
|
|
142
|
+
}
|
|
143
|
+
logger.info({ created: created.length, skipped: skipped.length }, 'SCALE init (trae) completed');
|
|
144
|
+
return {
|
|
145
|
+
settingsPath,
|
|
146
|
+
knowledgeDocPath,
|
|
147
|
+
scaleDir: this.scaleDir,
|
|
148
|
+
created,
|
|
149
|
+
skipped,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=TraeAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TraeAdapter.js","sourceRoot":"","sources":["../../src/adapters/TraeAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IAgentAdapter, AdapterConfig, InitResult, SettingsJson } from './ClaudeCodeAdapter.js';
|
|
2
|
+
export declare class VSCAdapter implements IAgentAdapter {
|
|
3
|
+
readonly agentType = "vsc";
|
|
4
|
+
private projectDir;
|
|
5
|
+
private scaleDir;
|
|
6
|
+
getSettingsPath(): string;
|
|
7
|
+
getKnowledgeDocPath(): string;
|
|
8
|
+
isInstalled(): boolean;
|
|
9
|
+
generateSettings(): SettingsJson;
|
|
10
|
+
mergeSettings(existing: SettingsJson): SettingsJson;
|
|
11
|
+
generateKnowledgeDoc(projectName: string, techStack?: string[]): string;
|
|
12
|
+
init(config: AdapterConfig): Promise<InitResult>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// SCALE Engine — VSC Adapter
|
|
2
|
+
// 生成 .vscode/scale.json + VSC.md
|
|
3
|
+
// VSC: VS Code Copilot CLI / agent runtime
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { logger } from '../core/logger.js';
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// VSC Adapter
|
|
9
|
+
// ============================================================================
|
|
10
|
+
export class VSCAdapter {
|
|
11
|
+
agentType = 'vsc';
|
|
12
|
+
projectDir = '.';
|
|
13
|
+
scaleDir = '.scale';
|
|
14
|
+
getSettingsPath() {
|
|
15
|
+
return join(this.projectDir, '.vscode', 'scale.json');
|
|
16
|
+
}
|
|
17
|
+
getKnowledgeDocPath() {
|
|
18
|
+
return join(this.projectDir, 'VSC.md');
|
|
19
|
+
}
|
|
20
|
+
isInstalled() {
|
|
21
|
+
return existsSync(this.getSettingsPath());
|
|
22
|
+
}
|
|
23
|
+
generateSettings() {
|
|
24
|
+
return {
|
|
25
|
+
hooks: {
|
|
26
|
+
'pre-exec': [
|
|
27
|
+
{ matcher: '', command: 'scale gate pre-tool Bash --args-json "$ARGS" --session-id "$SESSION_ID"' },
|
|
28
|
+
{ matcher: 'edit|write', command: 'scale gate pre-tool Edit --args-json "$ARGS" --session-id "$SESSION_ID"' },
|
|
29
|
+
],
|
|
30
|
+
'post-exec': [
|
|
31
|
+
{ matcher: 'edit|write', command: 'scale gate post-tool Edit --args-json "$ARGS" --exit-code "$EXIT_CODE" --session-id "$SESSION_ID"' },
|
|
32
|
+
{ matcher: '', command: 'scale gate post-tool Bash --args-json "$ARGS" --exit-code "$EXIT_CODE" --session-id "$SESSION_ID"' },
|
|
33
|
+
],
|
|
34
|
+
'before-stop': [
|
|
35
|
+
{ matcher: '', command: 'scale gate before-stop --session-id "$SESSION_ID"' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
permissions: {
|
|
39
|
+
allow: ['scale:*'],
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
mergeSettings(existing) {
|
|
44
|
+
const generated = this.generateSettings();
|
|
45
|
+
const merged = { ...existing };
|
|
46
|
+
if (!merged.hooks)
|
|
47
|
+
merged.hooks = {};
|
|
48
|
+
for (const [hookType, entries] of Object.entries(generated.hooks)) {
|
|
49
|
+
if (!merged.hooks[hookType])
|
|
50
|
+
merged.hooks[hookType] = [];
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const alreadyExists = merged.hooks[hookType].some((e) => e.command.includes('scale '));
|
|
53
|
+
if (!alreadyExists) {
|
|
54
|
+
merged.hooks[hookType].push(entry);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!merged.permissions)
|
|
59
|
+
merged.permissions = {};
|
|
60
|
+
if (!merged.permissions.allow)
|
|
61
|
+
merged.permissions.allow = [];
|
|
62
|
+
for (const perm of generated.permissions.allow) {
|
|
63
|
+
if (!merged.permissions.allow.includes(perm)) {
|
|
64
|
+
merged.permissions.allow.push(perm);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return merged;
|
|
68
|
+
}
|
|
69
|
+
generateKnowledgeDoc(projectName, techStack = []) {
|
|
70
|
+
const stackLine = techStack.length > 0
|
|
71
|
+
? `\n## Tech Stack\n${techStack.map((t) => `- ${t}`).join('\n')}\n`
|
|
72
|
+
: '';
|
|
73
|
+
return `# ${projectName}
|
|
74
|
+
${stackLine}
|
|
75
|
+
## SCALE Engine Integration (VSC)
|
|
76
|
+
|
|
77
|
+
This project uses SCALE Engine for AI engineering governance via VS Code Copilot CLI.
|
|
78
|
+
|
|
79
|
+
### Commands
|
|
80
|
+
- \`scale create <type> <title>\` — Create artifact
|
|
81
|
+
- \`scale transition <id> <action>\` — Transition artifact state
|
|
82
|
+
- \`scale list --type Spec\` — List artifacts
|
|
83
|
+
- \`scale role activate <role>\` — Switch role
|
|
84
|
+
- \`scale doctor\` — Health check
|
|
85
|
+
|
|
86
|
+
### Workflow
|
|
87
|
+
1. **Explore** → Role: explorer (Read/Grep only)
|
|
88
|
+
2. **Plan** → Create Spec → refine → approve (guard: ambiguity ≤ 0.2)
|
|
89
|
+
3. **Implement** → Role: implementer (Edit/Write/Bash unlocked)
|
|
90
|
+
4. **Verify** → Must run tests before claiming done
|
|
91
|
+
5. **Learn** → Defects → Lessons → Rules → Hooks
|
|
92
|
+
|
|
93
|
+
### Rules
|
|
94
|
+
- 🔴 Dangerous commands are physically blocked
|
|
95
|
+
- 🔴 Hardcoded secrets are blocked on Edit/Write
|
|
96
|
+
- 🟡 3 identical retries triggers brute-retry detection
|
|
97
|
+
- 🟡 Claiming done without running tests is blocked
|
|
98
|
+
- 🟢 All tool calls are tracked in .scale/events/
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
async init(config) {
|
|
102
|
+
this.projectDir = config.projectDir;
|
|
103
|
+
this.scaleDir = config.scaleDir ?? join(config.projectDir, '.scale');
|
|
104
|
+
const created = [];
|
|
105
|
+
const skipped = [];
|
|
106
|
+
for (const dir of ['events', 'artifacts', 'rules', 'hooks', 'checkpoints']) {
|
|
107
|
+
const fullDir = join(this.scaleDir, dir);
|
|
108
|
+
if (!existsSync(fullDir)) {
|
|
109
|
+
mkdirSync(fullDir, { recursive: true });
|
|
110
|
+
created.push(fullDir);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
skipped.push(fullDir);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const vscDir = join(this.projectDir, '.vscode');
|
|
117
|
+
mkdirSync(vscDir, { recursive: true });
|
|
118
|
+
const settingsPath = this.getSettingsPath();
|
|
119
|
+
if (existsSync(settingsPath)) {
|
|
120
|
+
const existing = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
121
|
+
const merged = this.mergeSettings(existing);
|
|
122
|
+
writeFileSync(settingsPath, JSON.stringify(merged, null, 2), 'utf-8');
|
|
123
|
+
skipped.push(settingsPath + ' (merged)');
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
writeFileSync(settingsPath, JSON.stringify(this.generateSettings(), null, 2), 'utf-8');
|
|
127
|
+
created.push(settingsPath);
|
|
128
|
+
}
|
|
129
|
+
const knowledgeDocPath = this.getKnowledgeDocPath();
|
|
130
|
+
if (!existsSync(knowledgeDocPath)) {
|
|
131
|
+
const projectName = config.projectDir.split(/[/\\]/).pop() ?? 'Project';
|
|
132
|
+
writeFileSync(knowledgeDocPath, this.generateKnowledgeDoc(projectName), 'utf-8');
|
|
133
|
+
created.push(knowledgeDocPath);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
skipped.push(knowledgeDocPath);
|
|
137
|
+
}
|
|
138
|
+
const gitignorePath = join(this.scaleDir, '.gitignore');
|
|
139
|
+
if (!existsSync(gitignorePath)) {
|
|
140
|
+
writeFileSync(gitignorePath, `*.db\n*.db-journal\nevents/\ncheckpoints/\nhooks/*.sh\n`, 'utf-8');
|
|
141
|
+
created.push(gitignorePath);
|
|
142
|
+
}
|
|
143
|
+
logger.info({ created: created.length, skipped: skipped.length }, 'SCALE init (vsc) completed');
|
|
144
|
+
return {
|
|
145
|
+
settingsPath,
|
|
146
|
+
knowledgeDocPath,
|
|
147
|
+
scaleDir: this.scaleDir,
|
|
148
|
+
created,
|
|
149
|
+
skipped,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=VSCAdapter.js.map
|