@hongmaple0820/scale-engine 0.3.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +15 -15
  2. package/README.md +1004 -64
  3. package/dist/adapters/ClaudeCodeAdapter.d.ts +2 -2
  4. package/dist/adapters/ClaudeCodeAdapter.js +33 -45
  5. package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
  6. package/dist/adapters/CodexAdapter.js +28 -28
  7. package/dist/adapters/CursorAdapter.d.ts +14 -0
  8. package/dist/adapters/CursorAdapter.js +169 -0
  9. package/dist/adapters/CursorAdapter.js.map +1 -0
  10. package/dist/adapters/GeminiAdapter.d.ts +13 -0
  11. package/dist/adapters/GeminiAdapter.js +157 -0
  12. package/dist/adapters/GeminiAdapter.js.map +1 -0
  13. package/dist/adapters/HermesAdapter.d.ts +13 -0
  14. package/dist/adapters/HermesAdapter.js +157 -0
  15. package/dist/adapters/HermesAdapter.js.map +1 -0
  16. package/dist/adapters/OpenClawAdapter.d.ts +13 -0
  17. package/dist/adapters/OpenClawAdapter.js +157 -0
  18. package/dist/adapters/OpenClawAdapter.js.map +1 -0
  19. package/dist/adapters/OpenCodeAdapter.d.ts +14 -0
  20. package/dist/adapters/OpenCodeAdapter.js +170 -0
  21. package/dist/adapters/OpenCodeAdapter.js.map +1 -0
  22. package/dist/adapters/index.d.ts +17 -0
  23. package/dist/adapters/index.js +42 -0
  24. package/dist/adapters/index.js.map +1 -0
  25. package/dist/api/cli.js +227 -9
  26. package/dist/api/cli.js.map +1 -1
  27. package/dist/artifact/fsm.d.ts +5 -0
  28. package/dist/artifact/fsm.js +24 -0
  29. package/dist/artifact/fsm.js.map +1 -1
  30. package/dist/artifact/fsmDefinitions.js +41 -1
  31. package/dist/artifact/fsmDefinitions.js.map +1 -1
  32. package/dist/artifact/sqliteStore.js +89 -89
  33. package/dist/artifact/types.d.ts +62 -1
  34. package/dist/artifact/types.js +27 -0
  35. package/dist/artifact/types.js.map +1 -1
  36. package/dist/context/ContextBuilder.d.ts +5 -1
  37. package/dist/context/ContextBuilder.js +90 -5
  38. package/dist/context/ContextBuilder.js.map +1 -1
  39. package/dist/evolution/EvolutionEngine.js +31 -31
  40. package/dist/guardrails/advancedDetectors.d.ts +12 -0
  41. package/dist/guardrails/advancedDetectors.js +50 -2
  42. package/dist/guardrails/advancedDetectors.js.map +1 -1
  43. package/dist/index.d.ts +8 -3
  44. package/dist/index.js +23 -4
  45. package/dist/index.js.map +1 -1
  46. package/dist/knowledge/SQLiteKnowledgeBase.d.ts +28 -0
  47. package/dist/knowledge/SQLiteKnowledgeBase.js +177 -0
  48. package/dist/knowledge/SQLiteKnowledgeBase.js.map +1 -0
  49. package/dist/skills/SkillDiscovery.d.ts +28 -0
  50. package/dist/skills/SkillDiscovery.js +171 -0
  51. package/dist/skills/SkillDiscovery.js.map +1 -0
  52. package/dist/tasks/TaskEngine.js +24 -0
  53. package/dist/tasks/TaskEngine.js.map +1 -1
  54. package/dist/workflows/presets.d.ts +34 -0
  55. package/dist/workflows/presets.js +224 -0
  56. package/dist/workflows/presets.js.map +1 -0
  57. package/package.json +54 -48
@@ -17,67 +17,67 @@ import { dirname, join } from 'node:path';
17
17
  // ============================================================================
18
18
  // Schema DDL
19
19
  // ============================================================================
20
- const SCHEMA_DDL = `
21
- -- Artifacts 主表
22
- CREATE TABLE IF NOT EXISTS artifacts (
23
- id TEXT PRIMARY KEY,
24
- type TEXT NOT NULL,
25
- version INTEGER NOT NULL DEFAULT 1,
26
- status TEXT NOT NULL DEFAULT 'DRAFT',
27
- status_history TEXT NOT NULL DEFAULT '[]', -- JSON array of StatusChange
28
- parents TEXT NOT NULL DEFAULT '[]', -- JSON array of ArtifactId
29
- children TEXT NOT NULL DEFAULT '[]', -- JSON array of ArtifactId
30
- supersedes TEXT,
31
- title TEXT NOT NULL,
32
- content_ref TEXT NOT NULL DEFAULT '',
33
- payload TEXT NOT NULL DEFAULT '{}', -- JSON
34
- gates TEXT NOT NULL DEFAULT '[]', -- JSON array of Gate
35
- created_by TEXT NOT NULL DEFAULT '{}', -- JSON Actor
36
- created_at INTEGER NOT NULL,
37
- updated_at INTEGER NOT NULL,
38
- closed_at INTEGER,
39
- tags TEXT NOT NULL DEFAULT '[]', -- JSON array
40
- labels TEXT NOT NULL DEFAULT '{}' -- JSON object
41
- );
42
-
43
- CREATE INDEX IF NOT EXISTS idx_artifacts_type ON artifacts(type);
44
- CREATE INDEX IF NOT EXISTS idx_artifacts_status ON artifacts(status);
45
- CREATE INDEX IF NOT EXISTS idx_artifacts_created_at ON artifacts(created_at);
46
-
47
- -- Events 表(事件溯源的持久化副本)
48
- CREATE TABLE IF NOT EXISTS events (
49
- id TEXT PRIMARY KEY,
50
- type TEXT NOT NULL,
51
- timestamp INTEGER NOT NULL,
52
- session_id TEXT,
53
- artifact_id TEXT,
54
- actor TEXT DEFAULT '{}',
55
- payload TEXT NOT NULL DEFAULT '{}',
56
- metadata TEXT DEFAULT '{}'
57
- );
58
-
59
- CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);
60
- CREATE INDEX IF NOT EXISTS idx_events_artifact_id ON events(artifact_id);
61
- CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
62
-
63
- -- Artifact 关系边表(加速 parent/child 查询)
64
- CREATE TABLE IF NOT EXISTS artifact_edges (
65
- parent_id TEXT NOT NULL,
66
- child_id TEXT NOT NULL,
67
- PRIMARY KEY (parent_id, child_id)
68
- );
69
-
70
- CREATE INDEX IF NOT EXISTS idx_edges_parent ON artifact_edges(parent_id);
71
- CREATE INDEX IF NOT EXISTS idx_edges_child ON artifact_edges(child_id);
72
-
73
- -- 元信息表
74
- CREATE TABLE IF NOT EXISTS meta (
75
- key TEXT PRIMARY KEY,
76
- value TEXT NOT NULL
77
- );
78
-
79
- -- 初始化 schema version
80
- INSERT OR IGNORE INTO meta (key, value) VALUES ('schema_version', '1');
20
+ const SCHEMA_DDL = `
21
+ -- Artifacts 主表
22
+ CREATE TABLE IF NOT EXISTS artifacts (
23
+ id TEXT PRIMARY KEY,
24
+ type TEXT NOT NULL,
25
+ version INTEGER NOT NULL DEFAULT 1,
26
+ status TEXT NOT NULL DEFAULT 'DRAFT',
27
+ status_history TEXT NOT NULL DEFAULT '[]', -- JSON array of StatusChange
28
+ parents TEXT NOT NULL DEFAULT '[]', -- JSON array of ArtifactId
29
+ children TEXT NOT NULL DEFAULT '[]', -- JSON array of ArtifactId
30
+ supersedes TEXT,
31
+ title TEXT NOT NULL,
32
+ content_ref TEXT NOT NULL DEFAULT '',
33
+ payload TEXT NOT NULL DEFAULT '{}', -- JSON
34
+ gates TEXT NOT NULL DEFAULT '[]', -- JSON array of Gate
35
+ created_by TEXT NOT NULL DEFAULT '{}', -- JSON Actor
36
+ created_at INTEGER NOT NULL,
37
+ updated_at INTEGER NOT NULL,
38
+ closed_at INTEGER,
39
+ tags TEXT NOT NULL DEFAULT '[]', -- JSON array
40
+ labels TEXT NOT NULL DEFAULT '{}' -- JSON object
41
+ );
42
+
43
+ CREATE INDEX IF NOT EXISTS idx_artifacts_type ON artifacts(type);
44
+ CREATE INDEX IF NOT EXISTS idx_artifacts_status ON artifacts(status);
45
+ CREATE INDEX IF NOT EXISTS idx_artifacts_created_at ON artifacts(created_at);
46
+
47
+ -- Events 表(事件溯源的持久化副本)
48
+ CREATE TABLE IF NOT EXISTS events (
49
+ id TEXT PRIMARY KEY,
50
+ type TEXT NOT NULL,
51
+ timestamp INTEGER NOT NULL,
52
+ session_id TEXT,
53
+ artifact_id TEXT,
54
+ actor TEXT DEFAULT '{}',
55
+ payload TEXT NOT NULL DEFAULT '{}',
56
+ metadata TEXT DEFAULT '{}'
57
+ );
58
+
59
+ CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);
60
+ CREATE INDEX IF NOT EXISTS idx_events_artifact_id ON events(artifact_id);
61
+ CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
62
+
63
+ -- Artifact 关系边表(加速 parent/child 查询)
64
+ CREATE TABLE IF NOT EXISTS artifact_edges (
65
+ parent_id TEXT NOT NULL,
66
+ child_id TEXT NOT NULL,
67
+ PRIMARY KEY (parent_id, child_id)
68
+ );
69
+
70
+ CREATE INDEX IF NOT EXISTS idx_edges_parent ON artifact_edges(parent_id);
71
+ CREATE INDEX IF NOT EXISTS idx_edges_child ON artifact_edges(child_id);
72
+
73
+ -- 元信息表
74
+ CREATE TABLE IF NOT EXISTS meta (
75
+ key TEXT PRIMARY KEY,
76
+ value TEXT NOT NULL
77
+ );
78
+
79
+ -- 初始化 schema version
80
+ INSERT OR IGNORE INTO meta (key, value) VALUES ('schema_version', '1');
81
81
  `;
82
82
  // ============================================================================
83
83
  // SQLiteArtifactStore
@@ -131,38 +131,38 @@ export class SQLiteArtifactStore {
131
131
  });
132
132
  }
133
133
  prepareStatements() {
134
- this.stmtInsert = this.db.prepare(`
135
- INSERT INTO artifacts (id, type, version, status, status_history, parents, children, supersedes,
136
- title, content_ref, payload, gates, created_by, created_at, updated_at, closed_at, tags, labels)
137
- VALUES (@id, @type, @version, @status, @statusHistory, @parents, @children, @supersedes,
138
- @title, @contentRef, @payload, @gates, @createdBy, @createdAt, @updatedAt, @closedAt, @tags, @labels)
134
+ this.stmtInsert = this.db.prepare(`
135
+ INSERT INTO artifacts (id, type, version, status, status_history, parents, children, supersedes,
136
+ title, content_ref, payload, gates, created_by, created_at, updated_at, closed_at, tags, labels)
137
+ VALUES (@id, @type, @version, @status, @statusHistory, @parents, @children, @supersedes,
138
+ @title, @contentRef, @payload, @gates, @createdBy, @createdAt, @updatedAt, @closedAt, @tags, @labels)
139
139
  `);
140
140
  this.stmtGet = this.db.prepare(`SELECT * FROM artifacts WHERE id = ?`);
141
- this.stmtUpdate = this.db.prepare(`
142
- UPDATE artifacts SET
143
- version = @version, status = @status, status_history = @statusHistory,
144
- parents = @parents, children = @children, supersedes = @supersedes,
145
- title = @title, content_ref = @contentRef, payload = @payload,
146
- gates = @gates, updated_at = @updatedAt, closed_at = @closedAt,
147
- tags = @tags, labels = @labels
148
- WHERE id = @id
141
+ this.stmtUpdate = this.db.prepare(`
142
+ UPDATE artifacts SET
143
+ version = @version, status = @status, status_history = @statusHistory,
144
+ parents = @parents, children = @children, supersedes = @supersedes,
145
+ title = @title, content_ref = @contentRef, payload = @payload,
146
+ gates = @gates, updated_at = @updatedAt, closed_at = @closedAt,
147
+ tags = @tags, labels = @labels
148
+ WHERE id = @id
149
149
  `);
150
150
  this.stmtDelete = this.db.prepare(`DELETE FROM artifacts WHERE id = ?`);
151
151
  this.stmtInsertEdge = this.db.prepare(`INSERT OR IGNORE INTO artifact_edges (parent_id, child_id) VALUES (?, ?)`);
152
152
  this.stmtDeleteEdges = this.db.prepare(`DELETE FROM artifact_edges WHERE child_id = ?`);
153
- this.stmtFindChildren = this.db.prepare(`
154
- SELECT a.* FROM artifacts a
155
- INNER JOIN artifact_edges e ON a.id = e.child_id
156
- WHERE e.parent_id = ?
153
+ this.stmtFindChildren = this.db.prepare(`
154
+ SELECT a.* FROM artifacts a
155
+ INNER JOIN artifact_edges e ON a.id = e.child_id
156
+ WHERE e.parent_id = ?
157
157
  `);
158
- this.stmtFindParents = this.db.prepare(`
159
- SELECT a.* FROM artifacts a
160
- INNER JOIN artifact_edges e ON a.id = e.parent_id
161
- WHERE e.child_id = ?
158
+ this.stmtFindParents = this.db.prepare(`
159
+ SELECT a.* FROM artifacts a
160
+ INNER JOIN artifact_edges e ON a.id = e.parent_id
161
+ WHERE e.child_id = ?
162
162
  `);
163
- this.stmtInsertEvent = this.db.prepare(`
164
- INSERT OR IGNORE INTO events (id, type, timestamp, session_id, artifact_id, actor, payload, metadata)
165
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
163
+ this.stmtInsertEvent = this.db.prepare(`
164
+ INSERT OR IGNORE INTO events (id, type, timestamp, session_id, artifact_id, actor, payload, metadata)
165
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
166
166
  `);
167
167
  }
168
168
  // ===== CRUD =====
@@ -276,10 +276,10 @@ export class SQLiteArtifactStore {
276
276
  }
277
277
  async findChildren(parentId, type) {
278
278
  if (type) {
279
- const rows = this.db.prepare(`
280
- SELECT a.* FROM artifacts a
281
- INNER JOIN artifact_edges e ON a.id = e.child_id
282
- WHERE e.parent_id = ? AND a.type = ?
279
+ const rows = this.db.prepare(`
280
+ SELECT a.* FROM artifacts a
281
+ INNER JOIN artifact_edges e ON a.id = e.child_id
282
+ WHERE e.parent_id = ? AND a.type = ?
283
283
  `).all(parentId, type);
284
284
  return rows.map((r) => this.fromRow(r));
285
285
  }
@@ -130,6 +130,11 @@ export interface TaskPayload {
130
130
  dependsOn: ArtifactId[];
131
131
  requiredRole: string;
132
132
  requiredCapabilities: string[];
133
+ buildStatus?: 'pending' | 'success' | 'failed';
134
+ buildExitCode?: number;
135
+ lintStatus?: 'pending' | 'success' | 'failed';
136
+ testPassed?: boolean;
137
+ testCoverage?: number;
133
138
  }
134
139
  /** Change —— 实际代码变更 */
135
140
  export interface ChangePayload {
@@ -235,10 +240,11 @@ export interface GuardFailure {
235
240
  }
236
241
  export interface Session {
237
242
  id: SessionId;
238
- agent: 'claude-code' | 'codex' | 'cursor' | 'gemini' | 'opencode' | 'unknown';
243
+ agent: AgentPlatform | 'unknown';
239
244
  startedAt: Timestamp;
240
245
  endedAt?: Timestamp;
241
246
  activeRole?: string;
247
+ scenarioMode?: ScenarioMode;
242
248
  metadata: Record<string, unknown>;
243
249
  }
244
250
  export interface ToolUseInput {
@@ -331,3 +337,58 @@ export declare class RoleDeniedError extends ScaleError {
331
337
  export declare class ArtifactNotFoundError extends ScaleError {
332
338
  constructor(id: string);
333
339
  }
340
+ /** 场景模式:控制检测器敏感度、上下文规则、权限级别 */
341
+ export type ScenarioMode = 'sandbox' | 'standard' | 'critical';
342
+ /** 场景模式配置 */
343
+ export interface ScenarioModeConfig {
344
+ mode: ScenarioMode;
345
+ detectorSensitivity: 'low' | 'medium' | 'high';
346
+ verificationRequired: boolean;
347
+ humanConfirmationRequired: boolean;
348
+ auditTrail: boolean;
349
+ maxRetries: number;
350
+ }
351
+ /** 场景模式预设配置 */
352
+ export declare const SCENARIO_MODE_CONFIGS: Record<ScenarioMode, ScenarioModeConfig>;
353
+ /** Agent 平台类型 */
354
+ export type AgentPlatform = 'claude-code' | 'codex' | 'opencode' | 'cursor' | 'gemini' | 'openclaw' | 'hermes';
355
+ /** Skill 引用 */
356
+ export interface SkillRef {
357
+ id: string;
358
+ name: string;
359
+ description: string;
360
+ platform: AgentPlatform;
361
+ path: string;
362
+ enabled: boolean;
363
+ }
364
+ /** Skill 目录扫描结果 */
365
+ export interface SkillScanResult {
366
+ platform: AgentPlatform;
367
+ skillsDir: string;
368
+ skills: SkillRef[];
369
+ exists: boolean;
370
+ }
371
+ /** 工作流步骤 */
372
+ export interface WorkflowStep {
373
+ stepId: string;
374
+ skillId?: string;
375
+ action: string;
376
+ verificationGate?: string;
377
+ isMandatory: boolean;
378
+ description?: string;
379
+ }
380
+ /** 工作流预设 */
381
+ export interface WorkflowPreset {
382
+ id: string;
383
+ name: string;
384
+ nameZh: string;
385
+ description: string;
386
+ steps: WorkflowStep[];
387
+ scenarioMode: ScenarioMode;
388
+ requiredArtifacts: Array<{
389
+ type: ArtifactType;
390
+ status?: string;
391
+ }>;
392
+ }
393
+ /** Agent 类型扩展(支持所有 7 种 Agent) */
394
+ export type AgentType = AgentPlatform;
@@ -47,4 +47,31 @@ export class ArtifactNotFoundError extends ScaleError {
47
47
  super(`Artifact '${id}' not found`, 'ARTIFACT_NOT_FOUND', { id });
48
48
  }
49
49
  }
50
+ /** 场景模式预设配置 */
51
+ export const SCENARIO_MODE_CONFIGS = {
52
+ sandbox: {
53
+ mode: 'sandbox',
54
+ detectorSensitivity: 'low',
55
+ verificationRequired: false,
56
+ humanConfirmationRequired: false,
57
+ auditTrail: false,
58
+ maxRetries: 10,
59
+ },
60
+ standard: {
61
+ mode: 'standard',
62
+ detectorSensitivity: 'medium',
63
+ verificationRequired: true,
64
+ humanConfirmationRequired: false,
65
+ auditTrail: true,
66
+ maxRetries: 5,
67
+ },
68
+ critical: {
69
+ mode: 'critical',
70
+ detectorSensitivity: 'high',
71
+ verificationRequired: true,
72
+ humanConfirmationRequired: true,
73
+ auditTrail: true,
74
+ maxRetries: 3,
75
+ },
76
+ };
50
77
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/artifact/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgeH,+EAA+E;AAC/E,WAAW;AACX,+EAA+E;AAE/E,MAAM,OAAO,UAAW,SAAQ,KAAK;IACC;IAAqB;IAAzD,YAAY,OAAe,EAAS,IAAY,EAAS,OAAiB;QACxE,KAAK,CAAC,OAAO,CAAC,CAAA;QADoB,SAAI,GAAJ,IAAI,CAAQ;QAAS,YAAO,GAAP,OAAO,CAAU;QAExE,IAAI,CAAC,IAAI,GAAG,YAAY,CAAA;IAC1B,CAAC;CACF;AAED,MAAM,OAAO,sBAAuB,SAAQ,UAAU;IACpD,YAAY,IAAY,EAAE,MAAc;QACtC,KAAK,CAAC,UAAU,IAAI,8BAA8B,MAAM,GAAG,EAAE,oBAAoB,EAAE;YACjF,IAAI;YACJ,MAAM;SACP,CAAC,CAAA;IACJ,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAC3B;IAAnB,YAAmB,QAAwB;QACzC,KAAK,CAAC,iCAAiC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE;YAChG,QAAQ;SACT,CAAC,CAAA;QAHe,aAAQ,GAAR,QAAQ,CAAgB;IAI3C,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,UAAU;IAC7C,YAAY,IAAY,EAAE,MAAc;QACtC,KAAK,CAAC,SAAS,IAAI,aAAa,MAAM,EAAE,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IAC5E,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,UAAU;IACnD,YAAY,EAAU;QACpB,KAAK,CAAC,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;IACnE,CAAC;CACF"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/artifact/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAweH,+EAA+E;AAC/E,WAAW;AACX,+EAA+E;AAE/E,MAAM,OAAO,UAAW,SAAQ,KAAK;IACC;IAAqB;IAAzD,YAAY,OAAe,EAAS,IAAY,EAAS,OAAiB;QACxE,KAAK,CAAC,OAAO,CAAC,CAAA;QADoB,SAAI,GAAJ,IAAI,CAAQ;QAAS,YAAO,GAAP,OAAO,CAAU;QAExE,IAAI,CAAC,IAAI,GAAG,YAAY,CAAA;IAC1B,CAAC;CACF;AAED,MAAM,OAAO,sBAAuB,SAAQ,UAAU;IACpD,YAAY,IAAY,EAAE,MAAc;QACtC,KAAK,CAAC,UAAU,IAAI,8BAA8B,MAAM,GAAG,EAAE,oBAAoB,EAAE;YACjF,IAAI;YACJ,MAAM;SACP,CAAC,CAAA;IACJ,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAC3B;IAAnB,YAAmB,QAAwB;QACzC,KAAK,CAAC,iCAAiC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE;YAChG,QAAQ;SACT,CAAC,CAAA;QAHe,aAAQ,GAAR,QAAQ,CAAgB;IAI3C,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,UAAU;IAC7C,YAAY,IAAY,EAAE,MAAc;QACtC,KAAK,CAAC,SAAS,IAAI,aAAa,MAAM,EAAE,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IAC5E,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,UAAU;IACnD,YAAY,EAAU;QACpB,KAAK,CAAC,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;IACnE,CAAC;CACF;AAmBD,eAAe;AACf,MAAM,CAAC,MAAM,qBAAqB,GAA6C;IAC7E,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,mBAAmB,EAAE,KAAK;QAC1B,oBAAoB,EAAE,KAAK;QAC3B,yBAAyB,EAAE,KAAK;QAChC,UAAU,EAAE,KAAK;QACjB,UAAU,EAAE,EAAE;KACf;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,mBAAmB,EAAE,QAAQ;QAC7B,oBAAoB,EAAE,IAAI;QAC1B,yBAAyB,EAAE,KAAK;QAChC,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,CAAC;KACd;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,mBAAmB,EAAE,MAAM;QAC3B,oBAAoB,EAAE,IAAI;QAC1B,yBAAyB,EAAE,IAAI;QAC/B,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,CAAC;KACd;CACF,CAAA"}
@@ -1,4 +1,4 @@
1
- import type { ArtifactId, SessionId } from '../artifact/types.js';
1
+ import type { ArtifactId, SessionId, ScenarioMode } from '../artifact/types.js';
2
2
  import type { IArtifactStore } from '../artifact/store.js';
3
3
  import type { IKnowledgeBase } from '../knowledge/KnowledgeBase.js';
4
4
  import type { IEventBus } from '../core/eventBus.js';
@@ -13,6 +13,7 @@ export interface BuiltContext {
13
13
  metadata: {
14
14
  totalTokens: number;
15
15
  layers: string[];
16
+ scenarioMode?: ScenarioMode;
16
17
  };
17
18
  }
18
19
  export interface ContextStatus {
@@ -27,12 +28,14 @@ export interface ContextStatus {
27
28
  current?: boolean;
28
29
  }>;
29
30
  constraints: string[];
31
+ scenarioMode?: ScenarioMode;
30
32
  }
31
33
  export interface IContextBuilder {
32
34
  build(opts: {
33
35
  roleId?: string;
34
36
  currentArtifactId?: ArtifactId;
35
37
  sessionId: SessionId;
38
+ scenarioMode?: ScenarioMode;
36
39
  }): Promise<BuiltContext>;
37
40
  getStatus(sessionId: SessionId, roleGate: {
38
41
  getRole(): {
@@ -52,6 +55,7 @@ export declare class ContextBuilder implements IContextBuilder {
52
55
  roleId?: string;
53
56
  currentArtifactId?: ArtifactId;
54
57
  sessionId: SessionId;
58
+ scenarioMode?: ScenarioMode;
55
59
  }): Promise<BuiltContext>;
56
60
  getStatus(sessionId: SessionId, roleGate: {
57
61
  getRole(): {
@@ -1,6 +1,75 @@
1
- // SCALE Engine — Context Builder (W6 完整实现)
2
- // 分层上下文加载 + Token 预算
1
+ // SCALE Engine — Context Builder (v0.5.0 完整实现)
2
+ // 分层上下文加载 + Token 预算 + SCALE v10.0 哲学 P1 层 + 场景模式感知
3
3
  // 设计参考:docs/03-CORE-MODULES.md §3.6
4
+ // ============================================================================
5
+ // SCALE v10.0 Philosophy — P1 system_rules layer content
6
+ // ============================================================================
7
+ const SCALE_V10_PHILOSOPHY = `## SCALE Engine v10.0 — System Rules
8
+
9
+ You are operating under SCALE Engine governance. These rules are PHYSICALLY ENFORCED — you cannot bypass them by choice.
10
+
11
+ ### Core Philosophy
12
+ - **S**caffold — Every action is scaffolded by artifacts (Spec→Plan→Task→Change→Evidence)
13
+ - **C**ontrol — Guardrails physically block dangerous actions; no "soft" suggestions
14
+ - **A**rtifact — All work products are tracked artifacts with FSM state machines
15
+ - **L**earn — Defects auto-extract to Lessons → Rules → Hooks (evolution loop)
16
+ - **E**volve — The system improves itself from mistakes
17
+
18
+ ### Physical Constraints (cannot be bypassed)
19
+ 🔴 **Dangerous commands** (rm -rf, DROP TABLE, format) are BLOCKED at the gate
20
+ 🔴 **Hardcoded secrets** (AWS keys, passwords, tokens) are BLOCKED on Edit/Write
21
+ 🔴 **Unapproved code** — Cannot implement until Spec is FROZEN and Plan is APPROVED
22
+ 🟡 **Brute retry** — 3+ identical retries detected → forced pause + context injection
23
+ 🟡 **Premature completion** — Cannot claim "done" without running tests
24
+ 🟡 **Blame shift** — Detected when AI blames environment without evidence
25
+
26
+ ### Mandatory Workflow
27
+ 1. **Explore** (role: explorer) — Read/Grep only, no edits
28
+ 2. **Plan** (role: planner) — Create Spec → refine → approve (guard: ambiguity ≤ 0.2)
29
+ 3. **Implement** (role: implementer) — Edit/Write/Bash unlocked only after Plan APPROVED
30
+ 4. **Verify** — Must run build+lint+test before marking task complete
31
+ 5. **Learn** — Defects auto-extract → lessons → rules → hooks
32
+
33
+ ### Artifact Lifecycle
34
+ - Every piece of work is an Artifact with typed FSM transitions
35
+ - Guards check quality gates at each transition (ambiguity score, test coverage, etc.)
36
+ - Artifacts form a DAG: Need→Insight→Spec→Plan→Task→Change→Evidence
37
+ - Challenging a FROZEN Spec invalidates downstream Plans and Tasks
38
+
39
+ ### Self-Evolution
40
+ - Defect → Lesson (auto-extracted from root cause)
41
+ - Lesson → Rule (promoted by access count + verification)
42
+ - Rule → Hook (auto-generated enforcement code)
43
+ - The system gets stricter over time, not weaker`;
44
+ // ============================================================================
45
+ // Scenario Mode Context Additions
46
+ // ============================================================================
47
+ const SCENARIO_CONTEXT = {
48
+ sandbox: `### Scenario Mode: SANDBOX 🏖️
49
+ - Lower detector sensitivity — exploratory work allowed
50
+ - Verification NOT required before completion
51
+ - Human confirmation NOT required
52
+ - Audit trail disabled (lighter weight)
53
+ - Max retries: 10 (freedom to experiment)
54
+ - Use for: prototyping, exploration, learning`,
55
+ standard: `### Scenario Mode: STANDARD ⚙️
56
+ - Medium detector sensitivity — production-quality required
57
+ - Verification REQUIRED before completion
58
+ - Human confirmation NOT required (trust the process)
59
+ - Audit trail ENABLED
60
+ - Max retries: 5 (balanced)
61
+ - Use for: feature development, bug fixes, regular work`,
62
+ critical: `### Scenario Mode: CRITICAL 🔒
63
+ - Maximum detector sensitivity — zero tolerance for errors
64
+ - Verification REQUIRED before completion
65
+ - Human confirmation REQUIRED for key transitions
66
+ - Audit trail ENABLED (comprehensive)
67
+ - Max retries: 3 (fail fast, escalate)
68
+ - Use for: security changes, production deployments, data migrations`,
69
+ };
70
+ // ============================================================================
71
+ // ContextBuilder
72
+ // ============================================================================
4
73
  export class ContextBuilder {
5
74
  store;
6
75
  kb;
@@ -12,11 +81,27 @@ export class ContextBuilder {
12
81
  this.eventBus = eventBus;
13
82
  }
14
83
  async build(opts) {
84
+ const scenarioMode = opts.scenarioMode ?? 'standard';
15
85
  const layers = [];
16
- layers.push({ name: 'system_rules', content: '## SCALE Core Rules\n...', priority: 1, estimatedTokens: 3000 });
86
+ // P1: System Rules SCALE v10.0 Philosophy (always present, highest priority)
87
+ layers.push({
88
+ name: 'system_rules',
89
+ content: SCALE_V10_PHILOSOPHY,
90
+ priority: 1,
91
+ estimatedTokens: 3500,
92
+ });
93
+ // P1.5: Scenario Mode awareness
94
+ layers.push({
95
+ name: 'scenario_mode',
96
+ content: SCENARIO_CONTEXT[scenarioMode],
97
+ priority: 1,
98
+ estimatedTokens: 800,
99
+ });
100
+ // P2: Role prompt
17
101
  if (opts.roleId) {
18
102
  layers.push({ name: 'role_prompt', content: `## Active Role: ${opts.roleId}\n...`, priority: 2, estimatedTokens: 1500 });
19
103
  }
104
+ // P3: Current artifact context
20
105
  if (opts.currentArtifactId) {
21
106
  const artifact = await this.store.get(opts.currentArtifactId);
22
107
  if (artifact) {
@@ -43,10 +128,10 @@ export class ContextBuilder {
43
128
  selected.push(layer);
44
129
  used += layer.estimatedTokens;
45
130
  }
46
- this.eventBus.emit('context.built', { layers: selected.map((l) => l.name), totalTokens: used }, { sessionId: opts.sessionId });
131
+ this.eventBus.emit('context.built', { layers: selected.map((l) => l.name), totalTokens: used, scenarioMode }, { sessionId: opts.sessionId });
47
132
  return {
48
133
  system: selected.map((l) => l.content).join('\n\n---\n\n'),
49
- metadata: { totalTokens: used, layers: selected.map((l) => l.name) },
134
+ metadata: { totalTokens: used, layers: selected.map((l) => l.name), scenarioMode },
50
135
  };
51
136
  }
52
137
  async getStatus(sessionId, roleGate) {
@@ -1 +1 @@
1
- {"version":3,"file":"ContextBuilder.js","sourceRoot":"","sources":["../../src/context/ContextBuilder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ContextBuilder.js","sourceRoot":"","sources":["../../src/context/ContextBuilder.ts"],"names":[],"mappings":"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"}
@@ -165,20 +165,20 @@ export class RuleProposer {
165
165
  mkdirSync(rulesDir, { recursive: true });
166
166
  const filename = `${rule.id}.md`;
167
167
  const path = join(rulesDir, filename);
168
- const content = `# ${rule.title}
169
-
170
- > Source: ${rule.sourceLesson}
171
- > Enforcement: ${rule.enforcement}
172
- > Approved: ${rule.approved ? `Yes (by ${rule.approvedBy})` : 'Pending'}
173
- > Created: ${new Date(rule.createdAt).toISOString()}
174
-
175
- ## Description
176
-
177
- ${rule.description}
178
-
179
- ## Pattern
180
-
181
- \`${rule.pattern}\`
168
+ const content = `# ${rule.title}
169
+
170
+ > Source: ${rule.sourceLesson}
171
+ > Enforcement: ${rule.enforcement}
172
+ > Approved: ${rule.approved ? `Yes (by ${rule.approvedBy})` : 'Pending'}
173
+ > Created: ${new Date(rule.createdAt).toISOString()}
174
+
175
+ ## Description
176
+
177
+ ${rule.description}
178
+
179
+ ## Pattern
180
+
181
+ \`${rule.pattern}\`
182
182
  `;
183
183
  writeFileSync(path, content, 'utf-8');
184
184
  return path;
@@ -205,23 +205,23 @@ export class HookGenerator {
205
205
  const scriptName = `${rule.id}.sh`;
206
206
  const scriptPath = join(hooksDir, scriptName);
207
207
  // Generate shell script
208
- const script = `#!/bin/bash
209
- # Auto-generated hook from Rule: ${rule.id}
210
- # Source lesson: ${rule.sourceLesson}
211
- # Pattern: ${rule.pattern}
212
- # Hook type: ${hookType} | Matcher: ${matcher}
213
- #
214
- # This hook was automatically promoted from a recurring lesson.
215
- # Edit with caution — it enforces a hard constraint.
216
-
217
- # Read tool input from stdin
218
- INPUT=$(cat)
219
-
220
- # Check condition
221
- # TODO: Implement specific check for pattern "${rule.pattern}"
222
- # For now, this is a placeholder that always passes.
223
- echo "Hook ${rule.id} checked (pattern: ${rule.pattern})" >&2
224
- exit 0
208
+ const script = `#!/bin/bash
209
+ # Auto-generated hook from Rule: ${rule.id}
210
+ # Source lesson: ${rule.sourceLesson}
211
+ # Pattern: ${rule.pattern}
212
+ # Hook type: ${hookType} | Matcher: ${matcher}
213
+ #
214
+ # This hook was automatically promoted from a recurring lesson.
215
+ # Edit with caution — it enforces a hard constraint.
216
+
217
+ # Read tool input from stdin
218
+ INPUT=$(cat)
219
+
220
+ # Check condition
221
+ # TODO: Implement specific check for pattern "${rule.pattern}"
222
+ # For now, this is a placeholder that always passes.
223
+ echo "Hook ${rule.id} checked (pattern: ${rule.pattern})" >&2
224
+ exit 0
225
225
  `;
226
226
  writeFileSync(scriptPath, script, 'utf-8');
227
227
  const hook = {
@@ -24,3 +24,15 @@ export declare class RoleGateDetector implements IDetector {
24
24
  getRole(): RoleDefinition;
25
25
  check(input: ToolUseInput, _ctx: DetectorContext): Promise<DetectorResult>;
26
26
  }
27
+ export declare class ScopeCreepDetector implements IDetector {
28
+ name: string;
29
+ /** Max distinct files allowed per session before warning */
30
+ private maxFiles;
31
+ /** Window in ms to track file edits */
32
+ private windowMs;
33
+ constructor(opts?: {
34
+ maxFiles?: number;
35
+ windowMs?: number;
36
+ });
37
+ check(input: ToolUseInput, ctx: DetectorContext): Promise<DetectorResult>;
38
+ }
@@ -1,5 +1,5 @@
1
- // SCALE Engine — 危险命令检测 + Role 权限网关
2
- // W5 补充检测器
1
+ // SCALE Engine — 危险命令检测 + Role 权限网关 + ScopeCreep 检测
2
+ // W5 补充检测器 + 9th detector
3
3
  // 设计参考:docs/01-ARCHITECTURE.md §二 L2
4
4
  // ============================================================================
5
5
  // 6. 危险命令检测器
@@ -135,4 +135,52 @@ export class RoleGateDetector {
135
135
  return { triggered: false };
136
136
  }
137
137
  }
138
+ // ============================================================================
139
+ // 9. ScopeCreep 检测器
140
+ // ============================================================================
141
+ export class ScopeCreepDetector {
142
+ name = 'scope-creep';
143
+ /** Max distinct files allowed per session before warning */
144
+ maxFiles;
145
+ /** Window in ms to track file edits */
146
+ windowMs;
147
+ constructor(opts = {}) {
148
+ this.maxFiles = opts.maxFiles ?? 15;
149
+ this.windowMs = opts.windowMs ?? 10 * 60 * 1000; // 10 minutes
150
+ }
151
+ async check(input, ctx) {
152
+ if (!['Edit', 'Write', 'MultiEdit'].includes(input.tool))
153
+ return { triggered: false };
154
+ const file = input.args.file_path;
155
+ if (!file)
156
+ return { triggered: false };
157
+ const key = `scope-creep:${input.sessionId}`;
158
+ const record = ctx.cache.get(key)
159
+ ?? { files: new Set(), timestamps: [] };
160
+ const now = Date.now();
161
+ // Prune old timestamps outside window
162
+ record.timestamps = record.timestamps.filter((t) => now - t < this.windowMs);
163
+ // Track new file
164
+ const isNew = !record.files.has(file);
165
+ record.files.add(file);
166
+ record.timestamps.push(now);
167
+ ctx.cache.set(key, record);
168
+ // Only warn when a NEW file is added and we exceed the threshold
169
+ if (isNew && record.files.size > this.maxFiles) {
170
+ ctx.eventBus.emit('tool.blocked', {
171
+ tool: input.tool,
172
+ detector: this.name,
173
+ reason: `scope_creep:${record.files.size}_files`,
174
+ file,
175
+ }, { sessionId: input.sessionId });
176
+ return {
177
+ triggered: true,
178
+ severity: 'warn',
179
+ reason: `⚠️ 检测到「范围蔓延」:本会话已编辑 ${record.files.size} 个不同文件(阈值 ${this.maxFiles})。请确认这些修改都在当前任务范围内,而非越界修改。`,
180
+ suggestion: '请检查是否偏离了原始任务范围。考虑收窄修改范围或拆分为多个任务。',
181
+ };
182
+ }
183
+ return { triggered: false };
184
+ }
185
+ }
138
186
  //# sourceMappingURL=advancedDetectors.js.map