scene-capability-engine 3.6.65 → 3.6.67
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/CHANGELOG.md +16 -0
- package/README.md +17 -6
- package/README.zh.md +18 -6
- package/bin/scene-capability-engine.js +4 -0
- package/docs/README.md +2 -2
- package/docs/command-reference.md +382 -6
- package/docs/document-governance.md +3 -2
- package/docs/integration-modes.md +62 -478
- package/docs/integration-philosophy.md +56 -263
- package/docs/magicball-project-portfolio-contract.md +114 -2
- package/docs/project-management/README.md +14 -0
- package/docs/project-management/assurance/backup.md +3 -0
- package/docs/project-management/assurance/config.md +3 -0
- package/docs/project-management/assurance/evidence/README.md +3 -0
- package/docs/project-management/assurance/incidents/README.md +3 -0
- package/docs/project-management/assurance/logs.md +3 -0
- package/docs/project-management/assurance/overview.md +3 -0
- package/docs/project-management/assurance/recovery/README.md +3 -0
- package/docs/project-management/assurance/resource.md +3 -0
- package/docs/project-management/assurance/runbooks/README.md +3 -0
- package/docs/project-management/delivery/acceptance/README.md +3 -0
- package/docs/project-management/delivery/acceptance/evidence/README.md +3 -0
- package/docs/project-management/delivery/acceptance/exceptions/README.md +3 -0
- package/docs/project-management/delivery/acceptance/reports/README.md +3 -0
- package/docs/project-management/delivery/documents/changes.md +3 -0
- package/docs/project-management/delivery/documents/issues.md +3 -0
- package/docs/project-management/delivery/documents/overview.md +3 -0
- package/docs/project-management/delivery/documents/planning.md +3 -0
- package/docs/project-management/delivery/documents/requirements.md +3 -0
- package/docs/project-management/delivery/documents/tracking.md +3 -0
- package/docs/project-management/delivery/handoffs/README.md +3 -0
- package/docs/project-management/delivery/handoffs/evidence/README.md +3 -0
- package/docs/project-management/delivery/handoffs/records/README.md +3 -0
- package/docs/project-management/delivery/overview.md +10 -0
- package/docs/project-management/delivery/releases/README.md +3 -0
- package/docs/project-management/delivery/releases/baselines/README.md +3 -0
- package/docs/project-management/delivery/releases/evidence/README.md +3 -0
- package/docs/project-management/delivery/tables/changes.md +3 -0
- package/docs/project-management/delivery/tables/issues.md +3 -0
- package/docs/project-management/delivery/tables/planning.md +3 -0
- package/docs/project-management/delivery/tables/requirements.md +3 -0
- package/docs/project-management/delivery/tables/tracking.md +3 -0
- package/docs/project-management/environment/agent-discovery.md +3 -0
- package/docs/project-management/environment/development.md +3 -0
- package/docs/project-management/environment/overview.md +10 -0
- package/docs/project-management/environment/testing.md +3 -0
- package/docs/project-management/environment/version-alignment.md +3 -0
- package/docs/quick-start-with-ai-tools.md +68 -308
- package/docs/releases/README.md +2 -0
- package/docs/releases/v3.6.66.md +23 -0
- package/docs/releases/v3.6.67.md +23 -0
- package/docs/steering-governance.md +64 -2
- package/docs/zh/README.md +2 -2
- package/docs/zh/releases/README.md +2 -0
- package/docs/zh/releases/v3.6.66.md +23 -0
- package/docs/zh/releases/v3.6.67.md +23 -0
- package/lib/commands/adopt.js +24 -0
- package/lib/commands/native.js +158 -0
- package/lib/commands/project.js +95 -0
- package/lib/commands/semantic.js +1459 -0
- package/lib/commands/session.js +74 -3
- package/lib/commands/spec-bootstrap.js +10 -1
- package/lib/commands/spec-gate.js +10 -1
- package/lib/commands/spec-pipeline.js +10 -1
- package/lib/commands/studio.js +405 -30
- package/lib/commands/task.js +141 -7
- package/lib/governance/supreme-principles.js +530 -0
- package/lib/problem/problem-evaluator.js +4 -0
- package/lib/project/candidate-inspection-service.js +24 -1
- package/lib/project/portfolio-projection-service.js +315 -5
- package/lib/project/project-channel-output.js +94 -0
- package/lib/project/project-channel-projection.js +181 -0
- package/lib/project/root-onboarding-service.js +60 -8
- package/lib/project/semantic-shared-source-projection.js +150 -0
- package/lib/project/supervision-action-model.js +277 -0
- package/lib/project/supervision-projection-service.js +305 -5
- package/lib/project/target-resolution-service.js +70 -5
- package/lib/project/visibility-policy.js +93 -0
- package/lib/runtime/multi-spec-scene-session.js +8 -1
- package/lib/runtime/project-channel-context-store.js +387 -0
- package/lib/runtime/project-channel-context.js +406 -0
- package/lib/runtime/scene-session-binding.js +46 -0
- package/lib/runtime/session-store.js +186 -0
- package/lib/runtime/steering-contract.js +7 -1
- package/lib/semantic/archive-report.js +283 -0
- package/lib/semantic/archive-routing.js +67 -0
- package/lib/semantic/backflow-report.js +245 -0
- package/lib/semantic/capability-contract.js +30 -0
- package/lib/semantic/delta-export.js +145 -0
- package/lib/semantic/interaction-observer.js +254 -0
- package/lib/semantic/kernel-loader.js +881 -0
- package/lib/semantic/native-runtime.js +359 -0
- package/lib/semantic/progress-ledger.js +433 -0
- package/lib/semantic/replay-evaluator.js +382 -0
- package/lib/semantic/shared-publication.js +592 -0
- package/lib/semantic/shared-source-config.js +183 -0
- package/lib/semantic/shared-source-connect.js +139 -0
- package/lib/semantic/shared-source-discovery.js +98 -0
- package/lib/semantic/shared-sync-export.js +413 -0
- package/lib/semantic/shared-sync-intake.js +592 -0
- package/lib/semantic/shared-sync-merge.js +547 -0
- package/lib/semantic/shared-sync-release.js +463 -0
- package/lib/semantic/supreme-intent-report.js +300 -0
- package/lib/state/sce-state-store.js +1360 -0
- package/lib/steering/context-sync-manager.js +276 -25
- package/lib/studio/spec-intake-governor.js +39 -3
- package/lib/studio/task-envelope.js +35 -2
- package/lib/workspace/takeover-baseline.js +342 -83
- package/package.json +7 -2
- package/scripts/agent-governance-baseline-audit.js +395 -0
- package/scripts/clarification-first-audit.js +9 -9
- package/scripts/deprecated-entry-audit.js +240 -0
- package/scripts/release-posture-report.js +262 -0
- package/template/.sce/README.md +62 -228
- package/template/.sce/config/semantic-shared-sources.json +5 -0
- package/template/.sce/config/supreme-principles-policy.json +105 -0
- package/template/.sce/config/takeover-baseline.json +7 -0
- package/template/.sce/steering/CORE_PRINCIPLES.md +23 -63
- package/template/.sce/steering/CURRENT_CONTEXT.md +4 -0
- package/template/.sce/steering/RULES_GUIDE.md +17 -9
- package/template/README.md +32 -96
|
@@ -12,6 +12,11 @@ const path = require('path');
|
|
|
12
12
|
const fs = require('fs-extra');
|
|
13
13
|
const fsUtils = require('../utils/fs-utils');
|
|
14
14
|
const { MultiAgentConfig } = require('../collab/multi-agent-config');
|
|
15
|
+
const {
|
|
16
|
+
getFocusedChannelState,
|
|
17
|
+
listChannelIds,
|
|
18
|
+
normalizeProjectChannelContext
|
|
19
|
+
} = require('../runtime/project-channel-context');
|
|
15
20
|
|
|
16
21
|
const STEERING_DIR = '.sce/steering';
|
|
17
22
|
const CONTEXT_FILENAME = 'CURRENT_CONTEXT.md';
|
|
@@ -44,7 +49,7 @@ class ContextSyncManager {
|
|
|
44
49
|
return { success: true };
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
await this.
|
|
52
|
+
await this._withContextLock(async () => {
|
|
48
53
|
const context = await this.readContext();
|
|
49
54
|
context.specs[specName] = {
|
|
50
55
|
status: entry.status,
|
|
@@ -57,16 +62,39 @@ class ContextSyncManager {
|
|
|
57
62
|
return { success: true };
|
|
58
63
|
}
|
|
59
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Update CURRENT_CONTEXT project/channel summary without overwriting richer context sections.
|
|
67
|
+
*
|
|
68
|
+
* @param {string} projectId
|
|
69
|
+
* @param {object} projectChannelContext
|
|
70
|
+
* @returns {Promise<{success: boolean}>}
|
|
71
|
+
*/
|
|
72
|
+
async updateProjectChannelSummary(projectId, projectChannelContext) {
|
|
73
|
+
const normalizedProjectId = `${projectId || ''}`.trim();
|
|
74
|
+
if (!normalizedProjectId) {
|
|
75
|
+
throw new Error('projectId is required');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const summary = this._summarizeProjectChannelContext(projectChannelContext, normalizedProjectId);
|
|
79
|
+
await this._withContextLock(async () => {
|
|
80
|
+
const context = await this.readContext();
|
|
81
|
+
context.projectChannels[normalizedProjectId] = summary;
|
|
82
|
+
await this.writeContext(context);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return { success: true };
|
|
86
|
+
}
|
|
87
|
+
|
|
60
88
|
/**
|
|
61
89
|
* Read and parse CURRENT_CONTEXT.md into a structured object.
|
|
62
90
|
* Returns default empty object if file doesn't exist.
|
|
63
91
|
*
|
|
64
|
-
* @returns {Promise<
|
|
92
|
+
* @returns {Promise<object>}
|
|
65
93
|
*/
|
|
66
94
|
async readContext() {
|
|
67
95
|
const exists = await fs.pathExists(this._contextPath);
|
|
68
96
|
if (!exists) {
|
|
69
|
-
return
|
|
97
|
+
return this._createEmptyContext();
|
|
70
98
|
}
|
|
71
99
|
|
|
72
100
|
try {
|
|
@@ -74,7 +102,7 @@ class ContextSyncManager {
|
|
|
74
102
|
return this.parseContext(content);
|
|
75
103
|
} catch (err) {
|
|
76
104
|
console.warn(`[ContextSyncManager] Failed to read ${this._contextPath}: ${err.message}`);
|
|
77
|
-
return
|
|
105
|
+
return this._createEmptyContext();
|
|
78
106
|
}
|
|
79
107
|
}
|
|
80
108
|
|
|
@@ -82,7 +110,7 @@ class ContextSyncManager {
|
|
|
82
110
|
* Write a structured context object back to CURRENT_CONTEXT.md.
|
|
83
111
|
* Uses atomic write for file integrity.
|
|
84
112
|
*
|
|
85
|
-
* @param {
|
|
113
|
+
* @param {object} context
|
|
86
114
|
* @returns {Promise<void>}
|
|
87
115
|
*/
|
|
88
116
|
async writeContext(context) {
|
|
@@ -117,52 +145,162 @@ class ContextSyncManager {
|
|
|
117
145
|
|
|
118
146
|
/**
|
|
119
147
|
* Parse CURRENT_CONTEXT.md Markdown content into a structured object.
|
|
120
|
-
* Handles both old single-agent format and
|
|
148
|
+
* Handles both old single-agent format and richer multi-section format.
|
|
121
149
|
*
|
|
122
150
|
* @param {string} content
|
|
123
|
-
* @returns {
|
|
151
|
+
* @returns {object}
|
|
124
152
|
*/
|
|
125
153
|
parseContext(content) {
|
|
126
|
-
const result =
|
|
154
|
+
const result = this._createEmptyContext();
|
|
127
155
|
|
|
128
156
|
if (!content || typeof content !== 'string') {
|
|
129
157
|
return result;
|
|
130
158
|
}
|
|
131
159
|
|
|
132
160
|
const lines = content.split('\n');
|
|
161
|
+
let activeListKey = null;
|
|
162
|
+
let inSpecTable = false;
|
|
163
|
+
let inProjectChannelTable = false;
|
|
133
164
|
|
|
134
165
|
for (const line of lines) {
|
|
135
166
|
const trimmed = line.trim();
|
|
136
167
|
|
|
137
|
-
|
|
138
|
-
|
|
168
|
+
if (!trimmed) {
|
|
169
|
+
activeListKey = null;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const versionMatch = trimmed.match(/^\*\*版本\*\*[::]\s*(.+)$/);
|
|
139
174
|
if (versionMatch) {
|
|
140
175
|
result.version = versionMatch[1].trim();
|
|
141
176
|
continue;
|
|
142
177
|
}
|
|
143
178
|
|
|
144
|
-
|
|
145
|
-
const statusMatch = trimmed.match(/^\*\*状态\*\*:\s*(.+)$/);
|
|
179
|
+
const statusMatch = trimmed.match(/^\*\*状态\*\*[::]\s*(.+)$/);
|
|
146
180
|
if (statusMatch) {
|
|
147
181
|
result.globalStatus = statusMatch[1].trim();
|
|
148
182
|
continue;
|
|
149
183
|
}
|
|
150
184
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
185
|
+
const mainlineMatch = trimmed.match(/^\*\*当前主线\*\*[::]\s*(.+)$/);
|
|
186
|
+
if (mainlineMatch) {
|
|
187
|
+
result.currentMainline = mainlineMatch[1].trim();
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const collaborationMatch = trimmed.match(/^\*\*当前协作模型\*\*[::]\s*(.+)$/);
|
|
192
|
+
if (collaborationMatch) {
|
|
193
|
+
result.collaborationModel = collaborationMatch[1].trim();
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (trimmed === '**本轮重点**:') {
|
|
198
|
+
activeListKey = 'highlights';
|
|
199
|
+
inSpecTable = false;
|
|
200
|
+
inProjectChannelTable = false;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (trimmed === '**后续候选主线**:') {
|
|
205
|
+
activeListKey = 'nextCandidates';
|
|
206
|
+
inSpecTable = false;
|
|
207
|
+
inProjectChannelTable = false;
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (trimmed === '## Spec 进度') {
|
|
212
|
+
activeListKey = null;
|
|
213
|
+
inSpecTable = false;
|
|
214
|
+
inProjectChannelTable = false;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (trimmed === '## 项目通道快照') {
|
|
219
|
+
activeListKey = null;
|
|
220
|
+
inSpecTable = false;
|
|
221
|
+
inProjectChannelTable = false;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (activeListKey && trimmed.startsWith('- ')) {
|
|
226
|
+
result[activeListKey].push(trimmed.slice(2).trim());
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (trimmed === '| Spec | 状态 | 进度 | 摘要 |') {
|
|
231
|
+
activeListKey = null;
|
|
232
|
+
inSpecTable = true;
|
|
233
|
+
inProjectChannelTable = false;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (
|
|
238
|
+
trimmed === '| Project | Focused Channel | Active Scene | Active Spec | Active Doc | Channels | Updated |'
|
|
239
|
+
|| trimmed === '| Project | Focused Channel | Active Spec | Active Doc | Channels | Updated |'
|
|
240
|
+
) {
|
|
241
|
+
activeListKey = null;
|
|
242
|
+
inSpecTable = false;
|
|
243
|
+
inProjectChannelTable = true;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (inSpecTable && trimmed.startsWith('|') && !trimmed.startsWith('|---')) {
|
|
248
|
+
const cells = trimmed.split('|').map((cell) => cell.trim()).filter((cell) => cell.length > 0);
|
|
155
249
|
if (cells.length >= 4) {
|
|
156
250
|
const specName = cells[0];
|
|
157
251
|
const status = cells[1];
|
|
158
|
-
const
|
|
159
|
-
const progress = parseInt(progressStr, 10);
|
|
252
|
+
const progress = parseInt(cells[2].replace('%', ''), 10);
|
|
160
253
|
const summary = cells[3];
|
|
161
254
|
|
|
162
|
-
if (specName && status && !isNaN(progress)) {
|
|
255
|
+
if (specName && status && !Number.isNaN(progress)) {
|
|
163
256
|
result.specs[specName] = { status, progress, summary };
|
|
164
257
|
}
|
|
165
258
|
}
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (inProjectChannelTable && trimmed.startsWith('|') && !trimmed.startsWith('|---')) {
|
|
263
|
+
const cells = trimmed.split('|').map((cell) => cell.trim()).filter((cell) => cell.length > 0);
|
|
264
|
+
if (cells.length >= 7) {
|
|
265
|
+
const projectId = cells[0];
|
|
266
|
+
const channels = cells[5]
|
|
267
|
+
.split(',')
|
|
268
|
+
.map((item) => item.trim())
|
|
269
|
+
.filter(Boolean);
|
|
270
|
+
if (projectId) {
|
|
271
|
+
result.projectChannels[projectId] = {
|
|
272
|
+
projectId,
|
|
273
|
+
focusedChannelId: cells[1],
|
|
274
|
+
activeScene: cells[2],
|
|
275
|
+
activeSpecId: cells[3],
|
|
276
|
+
activeDoc: cells[4],
|
|
277
|
+
channelCount: channels.length,
|
|
278
|
+
channels,
|
|
279
|
+
updatedAt: cells[6]
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (cells.length >= 6) {
|
|
286
|
+
const projectId = cells[0];
|
|
287
|
+
const channels = cells[4]
|
|
288
|
+
.split(',')
|
|
289
|
+
.map((item) => item.trim())
|
|
290
|
+
.filter(Boolean);
|
|
291
|
+
if (projectId) {
|
|
292
|
+
result.projectChannels[projectId] = {
|
|
293
|
+
projectId,
|
|
294
|
+
focusedChannelId: cells[1],
|
|
295
|
+
activeScene: '',
|
|
296
|
+
activeSpecId: cells[2],
|
|
297
|
+
activeDoc: cells[3],
|
|
298
|
+
channelCount: channels.length,
|
|
299
|
+
channels,
|
|
300
|
+
updatedAt: cells[5]
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
166
304
|
}
|
|
167
305
|
}
|
|
168
306
|
|
|
@@ -172,23 +310,54 @@ class ContextSyncManager {
|
|
|
172
310
|
/**
|
|
173
311
|
* Format a structured context object into CURRENT_CONTEXT.md Markdown.
|
|
174
312
|
*
|
|
175
|
-
* @param {
|
|
313
|
+
* @param {object} context
|
|
176
314
|
* @returns {string}
|
|
177
315
|
*/
|
|
178
316
|
formatContext(context) {
|
|
317
|
+
const normalized = this._normalizeContext(context);
|
|
179
318
|
const lines = [];
|
|
180
319
|
|
|
181
320
|
lines.push('# 当前场景');
|
|
182
321
|
lines.push('');
|
|
183
322
|
|
|
184
|
-
if (
|
|
185
|
-
lines.push(`**版本**: ${
|
|
323
|
+
if (normalized.version) {
|
|
324
|
+
lines.push(`**版本**: ${normalized.version}`);
|
|
186
325
|
}
|
|
187
|
-
if (
|
|
188
|
-
lines.push(`**状态**: ${
|
|
326
|
+
if (normalized.globalStatus) {
|
|
327
|
+
lines.push(`**状态**: ${normalized.globalStatus}`);
|
|
328
|
+
}
|
|
329
|
+
if (normalized.currentMainline) {
|
|
330
|
+
lines.push(`**当前主线**: ${normalized.currentMainline}`);
|
|
331
|
+
}
|
|
332
|
+
if (normalized.collaborationModel) {
|
|
333
|
+
lines.push(`**当前协作模型**: ${normalized.collaborationModel}`);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (normalized.highlights.length > 0) {
|
|
337
|
+
lines.push('');
|
|
338
|
+
lines.push('**本轮重点**:');
|
|
339
|
+
for (const item of normalized.highlights) {
|
|
340
|
+
lines.push(`- ${item}`);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const projectChannelEntries = Object.values(normalized.projectChannels)
|
|
345
|
+
.sort((left, right) => left.projectId.localeCompare(right.projectId));
|
|
346
|
+
if (projectChannelEntries.length > 0) {
|
|
347
|
+
lines.push('');
|
|
348
|
+
lines.push('## 项目通道快照');
|
|
349
|
+
lines.push('');
|
|
350
|
+
lines.push('| Project | Focused Channel | Active Scene | Active Spec | Active Doc | Channels | Updated |');
|
|
351
|
+
lines.push('|---------|-----------------|--------------|-------------|------------|----------|---------|');
|
|
352
|
+
|
|
353
|
+
for (const entry of projectChannelEntries) {
|
|
354
|
+
lines.push(
|
|
355
|
+
`| ${entry.projectId} | ${entry.focusedChannelId || ''} | ${entry.activeScene || ''} | ${entry.activeSpecId || ''} | ${entry.activeDoc || ''} | ${(entry.channels || []).join(', ')} | ${entry.updatedAt || ''} |`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
189
358
|
}
|
|
190
359
|
|
|
191
|
-
const specEntries = Object.entries(
|
|
360
|
+
const specEntries = Object.entries(normalized.specs || {});
|
|
192
361
|
if (specEntries.length > 0) {
|
|
193
362
|
lines.push('');
|
|
194
363
|
lines.push('## Spec 进度');
|
|
@@ -204,6 +373,14 @@ class ContextSyncManager {
|
|
|
204
373
|
}
|
|
205
374
|
}
|
|
206
375
|
|
|
376
|
+
if (normalized.nextCandidates.length > 0) {
|
|
377
|
+
lines.push('');
|
|
378
|
+
lines.push('**后续候选主线**:');
|
|
379
|
+
for (const item of normalized.nextCandidates) {
|
|
380
|
+
lines.push(`- ${item}`);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
207
384
|
lines.push('');
|
|
208
385
|
lines.push('---');
|
|
209
386
|
lines.push('');
|
|
@@ -217,6 +394,80 @@ class ContextSyncManager {
|
|
|
217
394
|
|
|
218
395
|
// ── Private helpers ──────────────────────────────────────────────
|
|
219
396
|
|
|
397
|
+
_createEmptyContext() {
|
|
398
|
+
return {
|
|
399
|
+
version: null,
|
|
400
|
+
globalStatus: null,
|
|
401
|
+
currentMainline: null,
|
|
402
|
+
collaborationModel: null,
|
|
403
|
+
highlights: [],
|
|
404
|
+
nextCandidates: [],
|
|
405
|
+
specs: {},
|
|
406
|
+
projectChannels: {}
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
_normalizeContext(context = {}) {
|
|
411
|
+
const payload = context && typeof context === 'object' ? context : {};
|
|
412
|
+
|
|
413
|
+
const normalizeText = (value) => {
|
|
414
|
+
if (typeof value !== 'string') {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
const trimmed = value.trim();
|
|
418
|
+
return trimmed || null;
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
const normalizeList = (values) => {
|
|
422
|
+
if (!Array.isArray(values)) {
|
|
423
|
+
return [];
|
|
424
|
+
}
|
|
425
|
+
return values
|
|
426
|
+
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
|
427
|
+
.filter(Boolean);
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
return {
|
|
431
|
+
version: normalizeText(payload.version),
|
|
432
|
+
globalStatus: normalizeText(payload.globalStatus),
|
|
433
|
+
currentMainline: normalizeText(payload.currentMainline),
|
|
434
|
+
collaborationModel: normalizeText(payload.collaborationModel),
|
|
435
|
+
highlights: normalizeList(payload.highlights),
|
|
436
|
+
nextCandidates: normalizeList(payload.nextCandidates),
|
|
437
|
+
specs: payload.specs && typeof payload.specs === 'object' ? payload.specs : {},
|
|
438
|
+
projectChannels: payload.projectChannels && typeof payload.projectChannels === 'object'
|
|
439
|
+
? payload.projectChannels
|
|
440
|
+
: {}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
async _withContextLock(work) {
|
|
445
|
+
if (this._steeringFileLock && typeof this._steeringFileLock.withLock === 'function') {
|
|
446
|
+
return this._steeringFileLock.withLock(CONTEXT_FILENAME, work);
|
|
447
|
+
}
|
|
448
|
+
return work();
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
_summarizeProjectChannelContext(projectChannelContext, projectId) {
|
|
452
|
+
const normalized = normalizeProjectChannelContext(projectChannelContext, {
|
|
453
|
+
projectId,
|
|
454
|
+
allowDefaultChannelSynthesis: false
|
|
455
|
+
});
|
|
456
|
+
const focused = getFocusedChannelState(normalized);
|
|
457
|
+
const channels = listChannelIds(normalized);
|
|
458
|
+
|
|
459
|
+
return {
|
|
460
|
+
projectId: normalized.projectId,
|
|
461
|
+
focusedChannelId: normalized.focusedChannelId,
|
|
462
|
+
activeScene: focused && focused.activeScene ? focused.activeScene : '',
|
|
463
|
+
activeSpecId: focused && focused.activeSpecId ? focused.activeSpecId : '',
|
|
464
|
+
activeDoc: focused && focused.activeDoc ? focused.activeDoc : '',
|
|
465
|
+
channelCount: channels.length,
|
|
466
|
+
channels,
|
|
467
|
+
updatedAt: focused && focused.updatedAt ? focused.updatedAt : new Date().toISOString()
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
220
471
|
/**
|
|
221
472
|
* Compute progress from tasks.md content.
|
|
222
473
|
* Counts only leaf tasks (lines with checkbox patterns that have no sub-tasks).
|
|
@@ -21,6 +21,23 @@ const DEFAULT_STUDIO_SCENE_BACKFILL_RULES = Object.freeze([
|
|
|
21
21
|
scene_id: 'scene.moqui-core',
|
|
22
22
|
keywords: ['moqui']
|
|
23
23
|
},
|
|
24
|
+
{
|
|
25
|
+
id: 'semantic-kernel',
|
|
26
|
+
scene_id: 'scene.sce-semantic-kernel',
|
|
27
|
+
keywords: [
|
|
28
|
+
'semantic',
|
|
29
|
+
'dialogue',
|
|
30
|
+
'conversation',
|
|
31
|
+
'reply',
|
|
32
|
+
'prompt',
|
|
33
|
+
'self-eval',
|
|
34
|
+
'simulation',
|
|
35
|
+
'codex cli',
|
|
36
|
+
'claude code',
|
|
37
|
+
'kiro',
|
|
38
|
+
'standalone sce'
|
|
39
|
+
]
|
|
40
|
+
},
|
|
24
41
|
{
|
|
25
42
|
id: 'orchestration',
|
|
26
43
|
scene_id: 'scene.sce-orchestration',
|
|
@@ -692,6 +709,10 @@ async function runStudioAutoIntake(options = {}, dependencies = {}) {
|
|
|
692
709
|
const fileSystem = dependencies.fileSystem || fs;
|
|
693
710
|
const sceneId = normalizeText(options.scene_id || options.sceneId);
|
|
694
711
|
const goal = normalizeText(options.goal);
|
|
712
|
+
const supremeAssessment = options.supreme_principles && typeof options.supreme_principles === 'object'
|
|
713
|
+
? options.supreme_principles
|
|
714
|
+
: null;
|
|
715
|
+
const effectiveGoal = normalizeText(supremeAssessment && supremeAssessment.effective_text) || goal;
|
|
695
716
|
const fromChat = normalizeText(options.from_chat || options.fromChat);
|
|
696
717
|
const explicitSpecId = normalizeText(options.explicit_spec_id || options.spec_id || options.specId);
|
|
697
718
|
const apply = options.apply === true;
|
|
@@ -702,9 +723,9 @@ async function runStudioAutoIntake(options = {}, dependencies = {}) {
|
|
|
702
723
|
: await loadStudioIntakePolicy(projectPath, fileSystem);
|
|
703
724
|
|
|
704
725
|
const policy = loadedPolicy.policy;
|
|
705
|
-
const intent = classifyStudioGoalIntent(
|
|
726
|
+
const intent = classifyStudioGoalIntent(effectiveGoal, policy);
|
|
706
727
|
const decision = resolveStudioSpecIntakeDecision({
|
|
707
|
-
goal,
|
|
728
|
+
goal: effectiveGoal,
|
|
708
729
|
explicit_spec_id: explicitSpecId,
|
|
709
730
|
domain_chain_binding: options.domain_chain_binding || {},
|
|
710
731
|
related_specs: options.related_specs || {},
|
|
@@ -721,6 +742,8 @@ async function runStudioAutoIntake(options = {}, dependencies = {}) {
|
|
|
721
742
|
scene_id: sceneId || null,
|
|
722
743
|
from_chat: fromChat || null,
|
|
723
744
|
goal: goal || null,
|
|
745
|
+
effective_goal: effectiveGoal || null,
|
|
746
|
+
supreme_principles: supremeAssessment,
|
|
724
747
|
intent,
|
|
725
748
|
decision: {
|
|
726
749
|
...decision
|
|
@@ -749,6 +772,19 @@ async function runStudioAutoIntake(options = {}, dependencies = {}) {
|
|
|
749
772
|
return payload;
|
|
750
773
|
}
|
|
751
774
|
|
|
775
|
+
if (supremeAssessment && normalizeText(supremeAssessment.action) === 'refuse') {
|
|
776
|
+
payload.decision = {
|
|
777
|
+
action: 'refuse',
|
|
778
|
+
reason: normalizeText(supremeAssessment.message) || 'blocked by supreme principles',
|
|
779
|
+
confidence: 'high',
|
|
780
|
+
spec_id: null,
|
|
781
|
+
source: 'supreme-principles',
|
|
782
|
+
intent
|
|
783
|
+
};
|
|
784
|
+
payload.selected_spec_id = null;
|
|
785
|
+
return payload;
|
|
786
|
+
}
|
|
787
|
+
|
|
752
788
|
if (decision.action === 'create_spec') {
|
|
753
789
|
const existingSpecIds = await listExistingSpecIds(projectPath, fileSystem);
|
|
754
790
|
const autoSpecId = createAutoSpecId(sceneId, goal, existingSpecIds, policy);
|
|
@@ -758,7 +794,7 @@ async function runStudioAutoIntake(options = {}, dependencies = {}) {
|
|
|
758
794
|
const createdSpec = await materializeIntakeSpec(projectPath, {
|
|
759
795
|
scene_id: sceneId,
|
|
760
796
|
from_chat: fromChat,
|
|
761
|
-
goal,
|
|
797
|
+
goal: effectiveGoal,
|
|
762
798
|
spec_id: autoSpecId
|
|
763
799
|
}, {
|
|
764
800
|
fileSystem
|
|
@@ -3,6 +3,31 @@ function buildStudioTaskKey(stageName = '') {
|
|
|
3
3
|
return 'studio:' + normalizedStage;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
function extractProjectChannel(job = {}, normalizeString) {
|
|
7
|
+
const binding = job && job.session && job.session.project_channel && typeof job.session.project_channel === 'object'
|
|
8
|
+
? job.session.project_channel
|
|
9
|
+
: null;
|
|
10
|
+
if (!binding) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const projectChannel = {
|
|
15
|
+
project_id: normalizeString(binding.project_id) || null,
|
|
16
|
+
channel_id: normalizeString(binding.channel_id) || null,
|
|
17
|
+
focused_channel_id: normalizeString(binding.focused_channel_id) || null,
|
|
18
|
+
active_session_path: normalizeString(binding.active_session_path) || null,
|
|
19
|
+
active_scene: normalizeString(binding.active_scene) || null,
|
|
20
|
+
active_spec_id: normalizeString(binding.active_spec_id) || null,
|
|
21
|
+
active_doc: normalizeString(binding.active_doc) || null
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (!projectChannel.project_id && !projectChannel.channel_id) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return projectChannel;
|
|
29
|
+
}
|
|
30
|
+
|
|
6
31
|
async function resolveTaskReference(mode, job, options = {}, dependencies = {}) {
|
|
7
32
|
const normalizeString = dependencies.normalizeString;
|
|
8
33
|
const resolveTaskStage = dependencies.resolveTaskStage;
|
|
@@ -23,6 +48,7 @@ async function resolveTaskReference(mode, job, options = {}, dependencies = {})
|
|
|
23
48
|
const taskKey = normalizeString(options.taskKey) || buildStudioTaskKey(stageName);
|
|
24
49
|
const projectPath = normalizeString(options.projectPath) || process.cwd();
|
|
25
50
|
const taskRefRegistry = options.taskRefRegistry || new TaskRefRegistry(projectPath, { fileSystem });
|
|
51
|
+
const projectChannel = extractProjectChannel(job, normalizeString);
|
|
26
52
|
|
|
27
53
|
try {
|
|
28
54
|
const taskRef = await taskRefRegistry.resolveOrCreateRef({
|
|
@@ -33,7 +59,10 @@ async function resolveTaskReference(mode, job, options = {}, dependencies = {})
|
|
|
33
59
|
metadata: {
|
|
34
60
|
mode: normalizeString(mode) || null,
|
|
35
61
|
stage: stageName || null,
|
|
36
|
-
job_id: normalizeString(job && job.job_id) || null
|
|
62
|
+
job_id: normalizeString(job && job.job_id) || null,
|
|
63
|
+
project_id: projectChannel ? projectChannel.project_id : null,
|
|
64
|
+
channel_id: projectChannel ? projectChannel.channel_id : null,
|
|
65
|
+
project_channel: projectChannel
|
|
37
66
|
}
|
|
38
67
|
});
|
|
39
68
|
return taskRef.task_ref;
|
|
@@ -183,6 +212,7 @@ function buildTaskEnvelope(mode, job, options = {}, dependencies = {}) {
|
|
|
183
212
|
const sceneId = normalizeString(job && job.scene && job.scene.id) || null;
|
|
184
213
|
const specId = normalizeString(job && job.scene && job.scene.spec_id) || normalizeString(job && job.source && job.source.spec_id) || null;
|
|
185
214
|
const taskRef = normalizeString(options.taskRef) || null;
|
|
215
|
+
const projectChannel = extractProjectChannel(job, normalizeString);
|
|
186
216
|
|
|
187
217
|
const commands = normalizeTaskCommands([
|
|
188
218
|
...(Array.isArray(stageMetadata.commands) ? stageMetadata.commands : []),
|
|
@@ -206,7 +236,8 @@ function buildTaskEnvelope(mode, job, options = {}, dependencies = {}) {
|
|
|
206
236
|
|
|
207
237
|
const normalizedHandoff = {
|
|
208
238
|
...handoff,
|
|
209
|
-
task_ref: taskRef
|
|
239
|
+
task_ref: taskRef,
|
|
240
|
+
project_channel: projectChannel
|
|
210
241
|
};
|
|
211
242
|
|
|
212
243
|
return {
|
|
@@ -215,6 +246,7 @@ function buildTaskEnvelope(mode, job, options = {}, dependencies = {}) {
|
|
|
215
246
|
specId,
|
|
216
247
|
taskId,
|
|
217
248
|
taskRef,
|
|
249
|
+
project_channel: projectChannel,
|
|
218
250
|
eventId: normalizeString(latestEvent && latestEvent.event_id) || null,
|
|
219
251
|
task: {
|
|
220
252
|
ref: taskRef,
|
|
@@ -228,6 +260,7 @@ function buildTaskEnvelope(mode, job, options = {}, dependencies = {}) {
|
|
|
228
260
|
confidence: taskIntent.confidence,
|
|
229
261
|
status: taskStatus,
|
|
230
262
|
summary: buildTaskSummaryLines(job, stageName, taskStatus, nextAction, taskRef, dependencies.buildProgress),
|
|
263
|
+
project_channel: projectChannel,
|
|
231
264
|
handoff: normalizedHandoff,
|
|
232
265
|
next_action: nextAction,
|
|
233
266
|
file_changes: fileChanges,
|