@miphamai/cli 0.49.0 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mipham.ts +1 -9
- package/package.json +1 -1
- package/skills/standard/github-ops.SKILL.md +1 -1
- package/skills/standard/web-access/references/cdp-api.md +2 -1
- package/skills/standard/web-access/scripts/cdp-proxy.mjs +75 -1
- package/skills/standard/web-access/scripts/check-deps.mjs +17 -2
- package/skills/standard/web-access/scripts/find-url.mjs +0 -0
- package/skills/standard/web-access/scripts/match-site.mjs +0 -0
- package/skills/standard/web-access.SKILL.md +10 -3
- package/src/agent/cross-session/discovery.ts +26 -1
- package/src/commands/project.ts +1 -1
- package/src/config/defaults.ts +8 -0
- package/src/core/auto-memory.ts +3 -3
- package/src/core/behavior-tasks.json +101 -0
- package/src/core/behavior-tasks.ts +44 -0
- package/src/core/constitution-loader.ts +0 -2
- package/src/core/context.ts +0 -1
- package/src/core/credential-masker/index.ts +1 -0
- package/src/core/credential-masker/matcher.ts +18 -7
- package/src/core/credential-masker/search.ts +73 -0
- package/src/core/credential-masker.ts +1 -0
- package/src/core/crsi-producer.ts +214 -0
- package/src/core/crsi-sandbox.ts +5 -1
- package/src/core/dream-engine.ts +0 -2
- package/src/core/eval-harness.ts +7 -0
- package/src/core/instructions.ts +11 -0
- package/src/core/memory/memory-loader.ts +3 -1
- package/src/core/permission-rules.ts +23 -12
- package/src/core/proposal-guard.ts +100 -0
- package/src/core/rules-loader.ts +8 -10
- package/src/core/task-runner-tasks.json +14 -0
- package/src/core/task-runner.ts +163 -0
- package/src/daemon/database.ts +0 -1
- package/src/daemon/feishu/adapter.ts +2 -1
- package/src/daemon/heartbeat.ts +83 -0
- package/src/daemon/index.ts +18 -8
- package/src/daemon/server.ts +78 -3
- package/src/daemon/session-manager.ts +5 -4
- package/src/daemon/telegram/adapter.ts +70 -0
- package/src/daemon/telegram/api.ts +45 -0
- package/src/daemon/telegram/env.ts +14 -0
- package/src/daemon/telegram/poller.ts +64 -0
- package/src/daemon/telegram/types.ts +10 -0
- package/src/i18n-core/locales/en-US.json +123 -0
- package/src/i18n-core/locales/zh-CN.json +123 -0
- package/src/index.tsx +6 -0
- package/src/shared/package-info.ts +4 -1
- package/src/shared/types.ts +2 -0
- package/src/skills/bundled-skill-assets.ts +5 -5
- package/src/skills/bundled-skills.ts +2 -2
- package/src/tools/agent/exit-plan.ts +1 -3
- package/src/tools/agent/memory.ts +2 -1
- package/src/tools/file/glob.ts +38 -23
- package/src/tools/file/grep.ts +96 -64
- package/src/tools/index.ts +5 -5
- package/src/ui/app.tsx +21 -1
- package/src/ui/commands.ts +269 -125
- package/src/ui/config-wizard.tsx +1 -1
package/src/ui/commands.ts
CHANGED
|
@@ -15,12 +15,19 @@ import { runCrsiModification, approvePending, rejectPending, hasPending } from '
|
|
|
15
15
|
import {
|
|
16
16
|
produceCrsiProposal,
|
|
17
17
|
produceRuleProposal,
|
|
18
|
+
produceProseProposal,
|
|
18
19
|
selectCrsiSignal,
|
|
20
|
+
collectSkillFiles,
|
|
21
|
+
proseProposalId,
|
|
22
|
+
hasProposedProse,
|
|
23
|
+
appendProseProposal,
|
|
24
|
+
clearProseProposals,
|
|
19
25
|
LESSONS_FILE,
|
|
20
26
|
MANAGED_RULES_FILE,
|
|
21
27
|
} from '../core/crsi-producer'
|
|
28
|
+
import { prefilterProposal } from '../core/proposal-guard'
|
|
22
29
|
import { runEval, appendEvalScore } from '../core/eval-harness'
|
|
23
|
-
import { NPM_UPDATE_COMMAND, PACKAGE_VERSION } from '../shared/index.ts'
|
|
30
|
+
import { NPM_UPDATE_COMMAND, PACKAGE_VERSION, COAUTHOR_TRAILER } from '../shared/index.ts'
|
|
24
31
|
import { getPreference } from '../config/preferences'
|
|
25
32
|
import { loadCrossSessionConfig } from '../config/loader'
|
|
26
33
|
import { stripIndent } from './strip-indent.js'
|
|
@@ -818,6 +825,62 @@ const crsiProposeCmd: CommandHandler = async (ctx, args) => {
|
|
|
818
825
|
// 非 git 目录 → 回退 cwd
|
|
819
826
|
}
|
|
820
827
|
|
|
828
|
+
// ── 散文提议路径:/crsi propose --prose 用 LLM 生成改 skill 散文提议 ──
|
|
829
|
+
if (args[0] === '--prose') {
|
|
830
|
+
const skillFiles = collectSkillFiles(root)
|
|
831
|
+
if (skillFiles.length === 0) {
|
|
832
|
+
return { content: '没有可改的 skill 文件。' }
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
const signal = selectCrsiSignal(insights, metaRules)
|
|
836
|
+
if (!signal) {
|
|
837
|
+
return { content: '没有足够的失败信号来生成散文提议。' }
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
const id = proseProposalId(signal)
|
|
841
|
+
if (hasProposedProse(id)) {
|
|
842
|
+
return { content: '该失败信号已生成过散文提议(幂等去重,跳过)。' }
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const llm = ctx.engine.getLlm() ?? ctx.engine.getRegistry()
|
|
846
|
+
const { readFileSync } = await import('node:fs')
|
|
847
|
+
const { join } = await import('node:path')
|
|
848
|
+
const proposal = await produceProseProposal(signal, llm, skillFiles, (p) =>
|
|
849
|
+
readFileSync(join(root, p), 'utf-8'),
|
|
850
|
+
)
|
|
851
|
+
if (!proposal) {
|
|
852
|
+
return { content: '散文提议生成失败(LLM 未返回有效结果)。' }
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
const verdict = prefilterProposal({
|
|
856
|
+
id,
|
|
857
|
+
filePath: proposal.filePath,
|
|
858
|
+
kind: 'skill',
|
|
859
|
+
newContent: proposal.newContent,
|
|
860
|
+
})
|
|
861
|
+
if (!verdict.pass) {
|
|
862
|
+
return { content: `❌ 提议未通过预筛:${verdict.reasons.join('; ')}` }
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
const result = runCrsiModification({
|
|
866
|
+
description: proposal.description,
|
|
867
|
+
filePath: proposal.filePath,
|
|
868
|
+
newContent: proposal.newContent,
|
|
869
|
+
originalContent: proposal.originalContent,
|
|
870
|
+
})
|
|
871
|
+
if (!result.applied || result.phase === 'failed') {
|
|
872
|
+
return { content: `❌ 生成失败(phase: ${result.phase})。\n${result.error ?? ''}` }
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
appendProseProposal({ id, filePath: proposal.filePath, timestamp: new Date().toISOString() })
|
|
876
|
+
|
|
877
|
+
return {
|
|
878
|
+
content:
|
|
879
|
+
`✅ 已生成散文提议并跑过测试。审阅 diff:\n\n${result.diff}\n\n` +
|
|
880
|
+
'/crsi modify --approve 合并 | /crsi modify --reject 丢弃',
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
821
884
|
// ── 毕业路径:/crsi propose --rule 固化受管理规则(行为) ──
|
|
822
885
|
if (args[0] === '--rule') {
|
|
823
886
|
const signal = selectCrsiSignal(insights, metaRules)
|
|
@@ -900,6 +963,14 @@ const crsiEvalCmd: CommandHandler = async () => {
|
|
|
900
963
|
return { content: lines.join('\n') }
|
|
901
964
|
}
|
|
902
965
|
|
|
966
|
+
const crsiProseClearCmd: CommandHandler = () => {
|
|
967
|
+
const count = clearProseProposals()
|
|
968
|
+
if (count === 0) {
|
|
969
|
+
return { content: '散文提议 ledger 为空(无可清除记录)。' }
|
|
970
|
+
}
|
|
971
|
+
return { content: `已清空散文提议 ledger(移除 ${count} 条记录)。` }
|
|
972
|
+
}
|
|
973
|
+
|
|
903
974
|
const crsiHealthCmd: CommandHandler = async (ctx) => {
|
|
904
975
|
const engine = ctx.engine.getRuleEngine()
|
|
905
976
|
const tracker = ctx.engine.getEffectivenessTracker()
|
|
@@ -951,8 +1022,6 @@ const crsiHealthCmd: CommandHandler = async (ctx) => {
|
|
|
951
1022
|
lines.push('', '### 🛡️ SIS 自免疫子系统', '')
|
|
952
1023
|
if (db) {
|
|
953
1024
|
const stats = db.getStats()
|
|
954
|
-
const healthEmoji =
|
|
955
|
-
stats.avgSuccessRate >= 0.8 ? '🟢' : stats.avgSuccessRate >= 0.5 ? '🟡' : '🔴'
|
|
956
1025
|
|
|
957
1026
|
lines.push(`| 指标 | 值 |`)
|
|
958
1027
|
lines.push(`|------|----|`)
|
|
@@ -1175,7 +1244,7 @@ const crsiCritiqueCmd: CommandHandler = (ctx, args) => {
|
|
|
1175
1244
|
const engine = ctx.engine
|
|
1176
1245
|
const sc = engine.getSelfCritique?.()
|
|
1177
1246
|
if (!sc) {
|
|
1178
|
-
return { content: '
|
|
1247
|
+
return { content: t('commands.crsi_critique.not_init') }
|
|
1179
1248
|
}
|
|
1180
1249
|
|
|
1181
1250
|
const sub = args[0]?.toLowerCase()
|
|
@@ -1185,42 +1254,44 @@ const crsiCritiqueCmd: CommandHandler = (ctx, args) => {
|
|
|
1185
1254
|
sc.setEnabled(true)
|
|
1186
1255
|
return {
|
|
1187
1256
|
content: [
|
|
1188
|
-
'
|
|
1257
|
+
t('commands.crsi_critique.on_title'),
|
|
1189
1258
|
'',
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1259
|
+
t('commands.crsi_critique.model', { model: config.model || 'auto (fastest available)' }),
|
|
1260
|
+
t('commands.crsi_critique.threshold', { pct: (config.threshold * 100).toFixed(0) }),
|
|
1261
|
+
t('commands.crsi_critique.target_tools', { tools: config.targetTools.join(', ') }),
|
|
1193
1262
|
'',
|
|
1194
|
-
'
|
|
1195
|
-
'
|
|
1263
|
+
t('commands.crsi_critique.on_desc1'),
|
|
1264
|
+
t('commands.crsi_critique.on_desc2'),
|
|
1196
1265
|
'',
|
|
1197
|
-
'
|
|
1266
|
+
t('commands.crsi_critique.on_hint'),
|
|
1198
1267
|
].join('\n'),
|
|
1199
1268
|
}
|
|
1200
1269
|
}
|
|
1201
1270
|
|
|
1202
1271
|
if (sub === 'off' || sub === 'disable') {
|
|
1203
1272
|
sc.setEnabled(false)
|
|
1204
|
-
return {
|
|
1205
|
-
content: '## 🔍 Self-Critique: OFF\n\nTool calls will execute without pre-flight critique.',
|
|
1206
|
-
}
|
|
1273
|
+
return { content: t('commands.crsi_critique.off_title') }
|
|
1207
1274
|
}
|
|
1208
1275
|
|
|
1209
1276
|
// status (default)
|
|
1210
1277
|
const lines: string[] = [
|
|
1211
|
-
'
|
|
1278
|
+
t('commands.crsi_critique.status_title'),
|
|
1212
1279
|
'',
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1280
|
+
t('commands.crsi_critique.state', {
|
|
1281
|
+
state: config.enabled ? '🟢 Enabled' : '⚫ Disabled',
|
|
1282
|
+
}),
|
|
1283
|
+
t('commands.crsi_critique.model', { model: config.model || 'auto (fastest available)' }),
|
|
1284
|
+
t('commands.crsi_critique.threshold_detail', { pct: (config.threshold * 100).toFixed(0) }),
|
|
1285
|
+
t('commands.crsi_critique.target_tools', {
|
|
1286
|
+
tools: config.targetTools.length > 0 ? config.targetTools.join(', ') : 'all',
|
|
1287
|
+
}),
|
|
1288
|
+
t('commands.crsi_critique.timeout', { ms: String(config.timeoutMs) }),
|
|
1218
1289
|
'',
|
|
1219
1290
|
'──',
|
|
1220
|
-
'
|
|
1221
|
-
'
|
|
1291
|
+
t('commands.crsi_critique.status_on_hint'),
|
|
1292
|
+
t('commands.crsi_critique.status_off_hint'),
|
|
1222
1293
|
'',
|
|
1223
|
-
'
|
|
1294
|
+
t('commands.crsi_critique.inspired'),
|
|
1224
1295
|
]
|
|
1225
1296
|
|
|
1226
1297
|
return { content: lines.join('\n') }
|
|
@@ -1235,7 +1306,7 @@ const crsiInterpretCmd: CommandHandler = (ctx, args) => {
|
|
|
1235
1306
|
const engine = ctx.engine
|
|
1236
1307
|
const toolFilter = args[0]?.toLowerCase()
|
|
1237
1308
|
|
|
1238
|
-
const lines: string[] = ['
|
|
1309
|
+
const lines: string[] = [t('commands.crsi_interpret.title'), '']
|
|
1239
1310
|
|
|
1240
1311
|
// ── Error Signature Analysis ──
|
|
1241
1312
|
const db = engine.getErrorSignatureDB?.()
|
|
@@ -1247,23 +1318,34 @@ const crsiInterpretCmd: CommandHandler = (ctx, args) => {
|
|
|
1247
1318
|
if (sigs.length === 0) {
|
|
1248
1319
|
lines.push(
|
|
1249
1320
|
toolFilter
|
|
1250
|
-
?
|
|
1251
|
-
: '
|
|
1321
|
+
? t('commands.crsi_interpret.no_sigs_for_tool', { tool: toolFilter })
|
|
1322
|
+
: t('commands.crsi_interpret.no_sigs'),
|
|
1252
1323
|
)
|
|
1253
1324
|
} else {
|
|
1254
|
-
lines.push(
|
|
1325
|
+
lines.push(
|
|
1326
|
+
t('commands.crsi_interpret.sigs_title', {
|
|
1327
|
+
tool: toolFilter ? ` — \`${toolFilter}\`` : '',
|
|
1328
|
+
}),
|
|
1329
|
+
'',
|
|
1330
|
+
)
|
|
1255
1331
|
for (const sig of sigs.slice(0, 15)) {
|
|
1256
1332
|
const bar =
|
|
1257
1333
|
'█'.repeat(Math.round(sig.successRate * 10)) +
|
|
1258
1334
|
'░'.repeat(10 - Math.round(sig.successRate * 10))
|
|
1259
1335
|
lines.push(`- **${sig.toolName}**: \`${sig.pattern.slice(0, 60)}\``)
|
|
1260
1336
|
lines.push(
|
|
1261
|
-
|
|
1337
|
+
t('commands.crsi_interpret.sig_success', {
|
|
1338
|
+
bar,
|
|
1339
|
+
pct: String(Math.round(sig.successRate * 100)),
|
|
1340
|
+
occurrences: String(sig.occurrences),
|
|
1341
|
+
strategy: sig.fixStrategy,
|
|
1342
|
+
}),
|
|
1262
1343
|
)
|
|
1263
|
-
lines.push(
|
|
1344
|
+
lines.push(t('commands.crsi_interpret.sig_fix', { fix: sig.fixAction.slice(0, 80) }))
|
|
1264
1345
|
lines.push('')
|
|
1265
1346
|
}
|
|
1266
|
-
if (sigs.length > 15)
|
|
1347
|
+
if (sigs.length > 15)
|
|
1348
|
+
lines.push(t('commands.crsi_interpret.sigs_more', { count: String(sigs.length - 15) }), '')
|
|
1267
1349
|
}
|
|
1268
1350
|
}
|
|
1269
1351
|
|
|
@@ -1272,8 +1354,8 @@ const crsiInterpretCmd: CommandHandler = (ctx, args) => {
|
|
|
1272
1354
|
if (autoMemory) {
|
|
1273
1355
|
const count = autoMemory.sessionReflectionCount ?? 0
|
|
1274
1356
|
if (count > 0) {
|
|
1275
|
-
lines.push('
|
|
1276
|
-
lines.push(
|
|
1357
|
+
lines.push(t('commands.crsi_interpret.reflection_title'), '')
|
|
1358
|
+
lines.push(t('commands.crsi_interpret.reflections', { count: String(count) }))
|
|
1277
1359
|
lines.push('')
|
|
1278
1360
|
}
|
|
1279
1361
|
}
|
|
@@ -1282,10 +1364,16 @@ const crsiInterpretCmd: CommandHandler = (ctx, args) => {
|
|
|
1282
1364
|
const usage = engine.getUsageTracker?.()
|
|
1283
1365
|
if (usage) {
|
|
1284
1366
|
const summary = usage.getSummary()
|
|
1285
|
-
lines.push('
|
|
1286
|
-
lines.push(
|
|
1287
|
-
|
|
1288
|
-
|
|
1367
|
+
lines.push(t('commands.crsi_interpret.usage_title'), '')
|
|
1368
|
+
lines.push(
|
|
1369
|
+
t('commands.crsi_interpret.api_in', { count: summary.apiInputTokens.toLocaleString() }),
|
|
1370
|
+
)
|
|
1371
|
+
lines.push(
|
|
1372
|
+
t('commands.crsi_interpret.api_out', { count: summary.apiOutputTokens.toLocaleString() }),
|
|
1373
|
+
)
|
|
1374
|
+
lines.push(
|
|
1375
|
+
t('commands.crsi_interpret.est_tokens', { count: summary.estimatedTokens.toLocaleString() }),
|
|
1376
|
+
)
|
|
1289
1377
|
lines.push('')
|
|
1290
1378
|
}
|
|
1291
1379
|
|
|
@@ -1297,9 +1385,9 @@ const crsiInterpretCmd: CommandHandler = (ctx, args) => {
|
|
|
1297
1385
|
if (analysis.systemHealth) {
|
|
1298
1386
|
const h = analysis.systemHealth
|
|
1299
1387
|
const bar = '█'.repeat(Math.round(h.score / 10)) + '░'.repeat(10 - Math.round(h.score / 10))
|
|
1300
|
-
lines.push('
|
|
1301
|
-
lines.push(
|
|
1302
|
-
lines.push(
|
|
1388
|
+
lines.push(t('commands.crsi_interpret.health_title'), '')
|
|
1389
|
+
lines.push(t('commands.crsi_interpret.overall', { bar, score: String(h.score) }))
|
|
1390
|
+
lines.push(t('commands.crsi_interpret.assessment', { assessment: h.assessment }))
|
|
1303
1391
|
if (h.components) {
|
|
1304
1392
|
lines.push('')
|
|
1305
1393
|
for (const [comp, score] of Object.entries(h.components)) {
|
|
@@ -1323,20 +1411,25 @@ const crsiInterpretCmd: CommandHandler = (ctx, args) => {
|
|
|
1323
1411
|
const blocks = c.principles.filter((p) => p.enforce === 'block').length
|
|
1324
1412
|
const warns = c.principles.filter((p) => p.enforce === 'warn').length
|
|
1325
1413
|
const autos = c.principles.filter((p) => p.enforce === 'auto').length
|
|
1326
|
-
lines.push('
|
|
1414
|
+
lines.push(t('commands.crsi_interpret.constitution_title'), '')
|
|
1327
1415
|
lines.push(
|
|
1328
|
-
|
|
1416
|
+
t('commands.crsi_interpret.principles', {
|
|
1417
|
+
total: String(c.principles.length),
|
|
1418
|
+
block: String(blocks),
|
|
1419
|
+
warn: String(warns),
|
|
1420
|
+
auto: String(autos),
|
|
1421
|
+
}),
|
|
1329
1422
|
)
|
|
1330
|
-
lines.push(
|
|
1423
|
+
lines.push(t('commands.crsi_interpret.version', { version: c.version }))
|
|
1331
1424
|
lines.push('')
|
|
1332
1425
|
}
|
|
1333
1426
|
|
|
1334
1427
|
if (lines.length <= 2) {
|
|
1335
|
-
lines.push('
|
|
1428
|
+
lines.push(t('commands.crsi_interpret.empty'))
|
|
1336
1429
|
}
|
|
1337
1430
|
|
|
1338
1431
|
lines.push('──')
|
|
1339
|
-
lines.push('
|
|
1432
|
+
lines.push(t('commands.crsi_interpret.filter_hint'))
|
|
1340
1433
|
|
|
1341
1434
|
return { content: lines.join('\n') }
|
|
1342
1435
|
}
|
|
@@ -1353,7 +1446,7 @@ const crsiRedTeamCmd: CommandHandler = async (ctx) => {
|
|
|
1353
1446
|
const preflight = engine.getPreFlightChecker?.()
|
|
1354
1447
|
|
|
1355
1448
|
if (!constitution || !preflight) {
|
|
1356
|
-
return { content: '
|
|
1449
|
+
return { content: t('commands.crsi_red_team.not_init') }
|
|
1357
1450
|
}
|
|
1358
1451
|
|
|
1359
1452
|
const { RedTeam: RT } = await import('../../src/core/red-team.js')
|
|
@@ -1361,21 +1454,21 @@ const crsiRedTeamCmd: CommandHandler = async (ctx) => {
|
|
|
1361
1454
|
const report = redTeam.run(constitution, preflight)
|
|
1362
1455
|
|
|
1363
1456
|
const lines: string[] = [
|
|
1364
|
-
'
|
|
1457
|
+
t('commands.crsi_red_team.title'),
|
|
1365
1458
|
'',
|
|
1366
|
-
|
|
1459
|
+
t('commands.crsi_red_team.score', { score: String(report.score) }),
|
|
1367
1460
|
'',
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1461
|
+
t('commands.crsi_red_team.metric'),
|
|
1462
|
+
t('commands.crsi_red_team.metric_sep'),
|
|
1463
|
+
t('commands.crsi_red_team.total_attacks', { count: String(report.total) }),
|
|
1464
|
+
t('commands.crsi_red_team.blocked', { count: String(report.blocked) }),
|
|
1465
|
+
t('commands.crsi_red_team.passed_through', { count: String(report.passedThrough) }),
|
|
1466
|
+
t('commands.crsi_red_team.false_positives', { count: String(report.falsePositives) }),
|
|
1374
1467
|
'',
|
|
1375
1468
|
]
|
|
1376
1469
|
|
|
1377
1470
|
// Per-principle breakdown
|
|
1378
|
-
lines.push('
|
|
1471
|
+
lines.push(t('commands.crsi_red_team.by_principle'), '')
|
|
1379
1472
|
for (const [pid, stats] of Object.entries(report.byPrinciple)) {
|
|
1380
1473
|
const pct = stats.total > 0 ? Math.round((stats.blocked / stats.total) * 100) : 100
|
|
1381
1474
|
const bar = '█'.repeat(Math.round(pct / 10)) + '░'.repeat(10 - Math.round(pct / 10))
|
|
@@ -1387,11 +1480,14 @@ const crsiRedTeamCmd: CommandHandler = async (ctx) => {
|
|
|
1387
1480
|
// Detail: passed-through attacks
|
|
1388
1481
|
const gaps = report.results.filter((r) => r.attack.shouldBlock && !r.blocked)
|
|
1389
1482
|
if (gaps.length > 0) {
|
|
1390
|
-
lines.push('
|
|
1483
|
+
lines.push(t('commands.crsi_red_team.gaps_title'), '')
|
|
1391
1484
|
for (const g of gaps) {
|
|
1392
1485
|
lines.push(`- **${g.attack.principleId}**: ${g.attack.description}`)
|
|
1393
1486
|
lines.push(
|
|
1394
|
-
|
|
1487
|
+
t('commands.crsi_red_team.gap_tool', {
|
|
1488
|
+
tool: g.attack.toolName,
|
|
1489
|
+
params: JSON.stringify(g.attack.params).slice(0, 80),
|
|
1490
|
+
}),
|
|
1395
1491
|
)
|
|
1396
1492
|
}
|
|
1397
1493
|
lines.push('')
|
|
@@ -1400,21 +1496,25 @@ const crsiRedTeamCmd: CommandHandler = async (ctx) => {
|
|
|
1400
1496
|
// Detail: caught attacks
|
|
1401
1497
|
const caught = report.results.filter((r) => r.blocked)
|
|
1402
1498
|
if (caught.length > 0) {
|
|
1403
|
-
lines.push('
|
|
1499
|
+
lines.push(t('commands.crsi_red_team.blocked_title'), '')
|
|
1404
1500
|
for (const c of caught) {
|
|
1405
|
-
lines.push(
|
|
1501
|
+
lines.push(
|
|
1502
|
+
t('commands.crsi_red_team.caught_by', {
|
|
1503
|
+
principle: c.attack.principleId,
|
|
1504
|
+
desc: c.attack.description,
|
|
1505
|
+
caught: c.caughtBy ?? 'unknown',
|
|
1506
|
+
}),
|
|
1507
|
+
)
|
|
1406
1508
|
}
|
|
1407
1509
|
lines.push('')
|
|
1408
1510
|
}
|
|
1409
1511
|
|
|
1410
1512
|
if (report.score === 100) {
|
|
1411
|
-
lines.push('
|
|
1513
|
+
lines.push(t('commands.crsi_red_team.all_blocked'))
|
|
1412
1514
|
} else if (report.score >= 80) {
|
|
1413
|
-
lines.push(
|
|
1414
|
-
'⚠️ Good coverage. Review the gaps above and add audit patterns to `ai-guardrails.yml`.',
|
|
1415
|
-
)
|
|
1515
|
+
lines.push(t('commands.crsi_red_team.good_coverage'))
|
|
1416
1516
|
} else {
|
|
1417
|
-
lines.push('
|
|
1517
|
+
lines.push(t('commands.crsi_red_team.critical'))
|
|
1418
1518
|
}
|
|
1419
1519
|
|
|
1420
1520
|
return { content: lines.join('\n') }
|
|
@@ -1431,45 +1531,61 @@ const dreamCmd: CommandHandler = async (ctx, args) => {
|
|
|
1431
1531
|
|
|
1432
1532
|
const engine = ctx.engine.getDreamEngine?.()
|
|
1433
1533
|
if (!engine) {
|
|
1434
|
-
return { content: '
|
|
1534
|
+
return { content: t('commands.dream.not_init') }
|
|
1435
1535
|
}
|
|
1436
1536
|
|
|
1437
1537
|
if (status) {
|
|
1438
1538
|
const history = engine.getDreamHistory()
|
|
1439
1539
|
if (history.length === 0) {
|
|
1440
|
-
return { content: '
|
|
1540
|
+
return { content: t('commands.dream.no_history') }
|
|
1441
1541
|
}
|
|
1442
|
-
const lines: string[] = ['
|
|
1542
|
+
const lines: string[] = [t('commands.dream.history_title'), '']
|
|
1443
1543
|
for (const entry of history.slice(0, 5)) {
|
|
1444
1544
|
const ts = new Date(entry.timestamp).toLocaleString('zh-CN')
|
|
1445
1545
|
const total = entry.actions.length
|
|
1446
1546
|
const applied = entry.actions.filter((a) => a.autoApplied).length
|
|
1447
1547
|
const flagged = entry.actions.filter((a) => !a.autoApplied).length
|
|
1448
|
-
lines.push(
|
|
1548
|
+
lines.push(
|
|
1549
|
+
t('commands.dream.history_entry', {
|
|
1550
|
+
time: ts,
|
|
1551
|
+
total: String(total),
|
|
1552
|
+
applied: String(applied),
|
|
1553
|
+
flagged: String(flagged),
|
|
1554
|
+
}),
|
|
1555
|
+
)
|
|
1449
1556
|
}
|
|
1450
1557
|
return { content: lines.join('\n') }
|
|
1451
1558
|
}
|
|
1452
1559
|
|
|
1453
1560
|
const report = engine.dream({ aggressive })
|
|
1454
1561
|
const lines: string[] = [
|
|
1455
|
-
'
|
|
1562
|
+
t('commands.dream.done_title'),
|
|
1456
1563
|
'',
|
|
1457
|
-
|
|
1458
|
-
|
|
1564
|
+
t('commands.dream.integrate', {
|
|
1565
|
+
before: String(report.beforeCount),
|
|
1566
|
+
after: String(report.afterCount),
|
|
1567
|
+
}),
|
|
1568
|
+
...(report.phases.deduplicated > 0
|
|
1569
|
+
? [t('commands.dream.dedup', { count: String(report.phases.deduplicated) })]
|
|
1570
|
+
: []),
|
|
1459
1571
|
...(report.phases.contradictionsFound > 0
|
|
1460
|
-
? [
|
|
1572
|
+
? [t('commands.dream.contradiction', { count: String(report.phases.contradictionsFound) })]
|
|
1573
|
+
: []),
|
|
1574
|
+
...(report.phases.merged > 0
|
|
1575
|
+
? [t('commands.dream.merge', { count: String(report.phases.merged) })]
|
|
1461
1576
|
: []),
|
|
1462
|
-
...(report.phases.merged > 0 ? [`- 合并: ${report.phases.merged} 组`] : []),
|
|
1463
1577
|
...(report.phases.solidified > 0
|
|
1464
|
-
? [
|
|
1578
|
+
? [t('commands.dream.solidify', { count: String(report.phases.solidified) })]
|
|
1579
|
+
: []),
|
|
1580
|
+
...(report.phases.pruned > 0
|
|
1581
|
+
? [t('commands.dream.prune', { count: String(report.phases.pruned) })]
|
|
1465
1582
|
: []),
|
|
1466
|
-
...(report.phases.pruned > 0 ? [`- 清理过期: ${report.phases.pruned} 条`] : []),
|
|
1467
1583
|
'',
|
|
1468
1584
|
]
|
|
1469
1585
|
|
|
1470
1586
|
const flagged = report.actions.filter((a) => !a.autoApplied)
|
|
1471
1587
|
if (flagged.length > 0 && !aggressive) {
|
|
1472
|
-
lines.push(
|
|
1588
|
+
lines.push(t('commands.dream.review_hint', { count: String(flagged.length) }))
|
|
1473
1589
|
lines.push('')
|
|
1474
1590
|
for (const action of flagged) {
|
|
1475
1591
|
lines.push(`- [ ] **${action.type}**: ${action.description}`)
|
|
@@ -1477,7 +1593,7 @@ const dreamCmd: CommandHandler = async (ctx, args) => {
|
|
|
1477
1593
|
}
|
|
1478
1594
|
|
|
1479
1595
|
if (report.actions.length === 0) {
|
|
1480
|
-
lines.push('
|
|
1596
|
+
lines.push(t('commands.dream.clean'))
|
|
1481
1597
|
}
|
|
1482
1598
|
|
|
1483
1599
|
return { content: lines.join('\n') }
|
|
@@ -1492,7 +1608,7 @@ const constitutionCmd: CommandHandler = (ctx, args) => {
|
|
|
1492
1608
|
const engine = ctx.engine
|
|
1493
1609
|
const constitution = engine.getConstitutionLoader?.()
|
|
1494
1610
|
if (!constitution) {
|
|
1495
|
-
return { content: '
|
|
1611
|
+
return { content: t('commands.constitution.not_init') }
|
|
1496
1612
|
}
|
|
1497
1613
|
|
|
1498
1614
|
const subCmd = args[0]?.toLowerCase()
|
|
@@ -1502,11 +1618,11 @@ const constitutionCmd: CommandHandler = (ctx, args) => {
|
|
|
1502
1618
|
const c = constitution.reload()
|
|
1503
1619
|
return {
|
|
1504
1620
|
content: [
|
|
1505
|
-
'
|
|
1621
|
+
t('commands.constitution.reload_title'),
|
|
1506
1622
|
'',
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1623
|
+
t('commands.constitution.version', { version: c.version }),
|
|
1624
|
+
t('commands.constitution.principles', { count: String(c.principles.length) }),
|
|
1625
|
+
t('commands.constitution.path', { path: constitution.getPath() }),
|
|
1510
1626
|
'',
|
|
1511
1627
|
c.principles.map((p) => `- **${p.id}** [${p.enforce}]: ${p.text}`).join('\n'),
|
|
1512
1628
|
].join('\n'),
|
|
@@ -1516,9 +1632,13 @@ const constitutionCmd: CommandHandler = (ctx, args) => {
|
|
|
1516
1632
|
// /constitution view (default)
|
|
1517
1633
|
const c = constitution.load()
|
|
1518
1634
|
const lines: string[] = [
|
|
1519
|
-
'
|
|
1635
|
+
t('commands.constitution.view_title'),
|
|
1520
1636
|
'',
|
|
1521
|
-
|
|
1637
|
+
t('commands.constitution.view_summary', {
|
|
1638
|
+
version: c.version,
|
|
1639
|
+
count: String(c.principles.length),
|
|
1640
|
+
path: constitution.getPath(),
|
|
1641
|
+
}),
|
|
1522
1642
|
'',
|
|
1523
1643
|
'---',
|
|
1524
1644
|
'',
|
|
@@ -1530,20 +1650,18 @@ const constitutionCmd: CommandHandler = (ctx, args) => {
|
|
|
1530
1650
|
lines.push('')
|
|
1531
1651
|
lines.push(p.text)
|
|
1532
1652
|
if (p.rationale) lines.push(` *${p.rationale}*`)
|
|
1533
|
-
if (p.scope) lines.push(
|
|
1534
|
-
if (p.tools) lines.push(
|
|
1653
|
+
if (p.scope) lines.push(t('commands.constitution.scope', { scope: p.scope }))
|
|
1654
|
+
if (p.tools) lines.push(t('commands.constitution.tools', { tools: p.tools.join(', ') }))
|
|
1535
1655
|
lines.push('')
|
|
1536
1656
|
}
|
|
1537
1657
|
|
|
1538
1658
|
lines.push('---')
|
|
1539
1659
|
lines.push('')
|
|
1540
|
-
lines.push('
|
|
1541
|
-
lines.push('
|
|
1542
|
-
lines.push('
|
|
1660
|
+
lines.push(t('commands.constitution.reload_hint'))
|
|
1661
|
+
lines.push(t('commands.constitution.edit_hint'))
|
|
1662
|
+
lines.push(t('commands.constitution.reset_hint'))
|
|
1543
1663
|
lines.push('')
|
|
1544
|
-
lines.push(
|
|
1545
|
-
'*Inspired by Anthropic Constitutional AI. Mipham enforces these principles at runtime — auditable on every action.*',
|
|
1546
|
-
)
|
|
1664
|
+
lines.push(t('commands.constitution.inspired'))
|
|
1547
1665
|
|
|
1548
1666
|
return { content: lines.join('\n') }
|
|
1549
1667
|
}
|
|
@@ -1556,25 +1674,32 @@ const bugReportCmd: CommandHandler = async (ctx) => {
|
|
|
1556
1674
|
const t = resolveT(ctx)
|
|
1557
1675
|
const engine = ctx.engine
|
|
1558
1676
|
const lines: string[] = [
|
|
1559
|
-
'
|
|
1677
|
+
t('commands.bug_report.title'),
|
|
1560
1678
|
'',
|
|
1561
|
-
'
|
|
1679
|
+
t('commands.bug_report.hint'),
|
|
1562
1680
|
'',
|
|
1563
1681
|
'---',
|
|
1564
1682
|
'',
|
|
1565
1683
|
]
|
|
1566
1684
|
|
|
1567
1685
|
// ── Version & Runtime ──
|
|
1568
|
-
lines.push('
|
|
1569
|
-
lines.push(
|
|
1570
|
-
lines.push(
|
|
1571
|
-
lines.push(
|
|
1572
|
-
lines.push(
|
|
1686
|
+
lines.push(t('commands.bug_report.env_title'), '')
|
|
1687
|
+
lines.push(t('commands.bug_report.mipham', { version: ctx.version }))
|
|
1688
|
+
lines.push(t('commands.bug_report.session', { id: ctx.sessionId }))
|
|
1689
|
+
lines.push(t('commands.bug_report.node', { version: process.version }))
|
|
1690
|
+
lines.push(t('commands.bug_report.platform', { platform: process.platform, arch: process.arch }))
|
|
1573
1691
|
lines.push(
|
|
1574
|
-
|
|
1692
|
+
t('commands.bug_report.os', {
|
|
1693
|
+
os:
|
|
1694
|
+
process.platform === 'darwin'
|
|
1695
|
+
? 'macOS'
|
|
1696
|
+
: process.platform === 'linux'
|
|
1697
|
+
? 'Linux'
|
|
1698
|
+
: 'Windows',
|
|
1699
|
+
}),
|
|
1575
1700
|
)
|
|
1576
|
-
lines.push(
|
|
1577
|
-
lines.push(
|
|
1701
|
+
lines.push(t('commands.bug_report.provider', { provider: ctx.providerId }))
|
|
1702
|
+
lines.push(t('commands.bug_report.model', { model: ctx.modelId }))
|
|
1578
1703
|
lines.push('')
|
|
1579
1704
|
|
|
1580
1705
|
// ── SIS errors ──
|
|
@@ -1583,10 +1708,16 @@ const bugReportCmd: CommandHandler = async (ctx) => {
|
|
|
1583
1708
|
if (db) {
|
|
1584
1709
|
const active = db.getActive()
|
|
1585
1710
|
if (active.length > 0) {
|
|
1586
|
-
lines.push('
|
|
1711
|
+
lines.push(t('commands.bug_report.sigs_title'), '')
|
|
1587
1712
|
for (const sig of active.slice(0, 10)) {
|
|
1588
1713
|
lines.push(
|
|
1589
|
-
|
|
1714
|
+
t('commands.bug_report.sig_entry', {
|
|
1715
|
+
id: sig.id,
|
|
1716
|
+
pattern: sig.pattern,
|
|
1717
|
+
category: sig.category,
|
|
1718
|
+
occurrences: String(sig.occurrences),
|
|
1719
|
+
pct: (sig.successRate * 100).toFixed(0),
|
|
1720
|
+
}),
|
|
1590
1721
|
)
|
|
1591
1722
|
}
|
|
1592
1723
|
lines.push('')
|
|
@@ -1603,10 +1734,14 @@ const bugReportCmd: CommandHandler = async (ctx) => {
|
|
|
1603
1734
|
const health = hookEngine.getHookHealth()
|
|
1604
1735
|
const disabled = health.filter((h) => h.health.disabled)
|
|
1605
1736
|
if (disabled.length > 0) {
|
|
1606
|
-
lines.push('
|
|
1737
|
+
lines.push(t('commands.bug_report.disabled_hooks'), '')
|
|
1607
1738
|
for (const entry of disabled) {
|
|
1608
1739
|
lines.push(
|
|
1609
|
-
|
|
1740
|
+
t('commands.bug_report.hook_entry', {
|
|
1741
|
+
key: entry.key,
|
|
1742
|
+
failures: String(entry.health.failures),
|
|
1743
|
+
time: new Date(entry.health.disabledAt).toISOString(),
|
|
1744
|
+
}),
|
|
1610
1745
|
)
|
|
1611
1746
|
}
|
|
1612
1747
|
lines.push('')
|
|
@@ -1623,10 +1758,15 @@ const bugReportCmd: CommandHandler = async (ctx) => {
|
|
|
1623
1758
|
const history = dreamEngine.getDreamHistory()
|
|
1624
1759
|
if (history.length > 0) {
|
|
1625
1760
|
const last = history[0]!
|
|
1626
|
-
lines.push('
|
|
1627
|
-
lines.push(
|
|
1761
|
+
lines.push(t('commands.bug_report.last_dream'), '')
|
|
1762
|
+
lines.push(t('commands.bug_report.ran_at', { time: last.timestamp }))
|
|
1628
1763
|
lines.push(
|
|
1629
|
-
|
|
1764
|
+
t('commands.bug_report.actions', {
|
|
1765
|
+
total: String(last.actions.length),
|
|
1766
|
+
applied: String(
|
|
1767
|
+
last.actions.filter((a: { autoApplied: boolean }) => a.autoApplied).length,
|
|
1768
|
+
),
|
|
1769
|
+
}),
|
|
1630
1770
|
)
|
|
1631
1771
|
lines.push('')
|
|
1632
1772
|
}
|
|
@@ -1636,17 +1776,17 @@ const bugReportCmd: CommandHandler = async (ctx) => {
|
|
|
1636
1776
|
}
|
|
1637
1777
|
|
|
1638
1778
|
// ── Steps to reproduce (template) ──
|
|
1639
|
-
lines.push('
|
|
1779
|
+
lines.push(t('commands.bug_report.steps_title'), '')
|
|
1640
1780
|
lines.push('1. ')
|
|
1641
1781
|
lines.push('2. ')
|
|
1642
1782
|
lines.push('3. ')
|
|
1643
1783
|
lines.push('')
|
|
1644
|
-
lines.push('
|
|
1784
|
+
lines.push(t('commands.bug_report.expected'), '')
|
|
1645
1785
|
lines.push('')
|
|
1646
|
-
lines.push('
|
|
1786
|
+
lines.push(t('commands.bug_report.actual'), '')
|
|
1647
1787
|
lines.push('')
|
|
1648
1788
|
lines.push('---')
|
|
1649
|
-
lines.push(
|
|
1789
|
+
lines.push(t('commands.bug_report.generated', { version: ctx.version }))
|
|
1650
1790
|
|
|
1651
1791
|
return { content: lines.join('\n'), copyContent: lines.join('\n') }
|
|
1652
1792
|
}
|
|
@@ -1659,7 +1799,7 @@ const bugReportCmd: CommandHandler = async (ctx) => {
|
|
|
1659
1799
|
|
|
1660
1800
|
const changelogCmd: CommandHandler = async (ctx) => {
|
|
1661
1801
|
const t = resolveT(ctx)
|
|
1662
|
-
const lines: string[] = ['
|
|
1802
|
+
const lines: string[] = [t('commands.changelog.title'), '']
|
|
1663
1803
|
|
|
1664
1804
|
try {
|
|
1665
1805
|
const { execSync } = await import('node:child_process')
|
|
@@ -1670,11 +1810,11 @@ const changelogCmd: CommandHandler = async (ctx) => {
|
|
|
1670
1810
|
.slice(0, 15)
|
|
1671
1811
|
|
|
1672
1812
|
if (tags.length === 0) {
|
|
1673
|
-
lines.push('
|
|
1813
|
+
lines.push(t('commands.changelog.no_tags'))
|
|
1674
1814
|
return { content: lines.join('\n') }
|
|
1675
1815
|
}
|
|
1676
1816
|
|
|
1677
|
-
lines.push(
|
|
1817
|
+
lines.push(t('commands.changelog.current', { version: ctx.version }), '')
|
|
1678
1818
|
|
|
1679
1819
|
for (let i = 0; i < tags.length; i++) {
|
|
1680
1820
|
const tag = tags[i]!
|
|
@@ -1690,25 +1830,25 @@ const changelogCmd: CommandHandler = async (ctx) => {
|
|
|
1690
1830
|
.filter(Boolean)
|
|
1691
1831
|
|
|
1692
1832
|
const isCurrent = tag === `v${ctx.version}`
|
|
1693
|
-
lines.push(`### ${tag}${isCurrent ? '
|
|
1833
|
+
lines.push(`### ${tag}${isCurrent ? t('commands.changelog.current_marker') : ''}`, '')
|
|
1694
1834
|
if (log.length > 0) {
|
|
1695
1835
|
for (const entry of log) {
|
|
1696
1836
|
lines.push(`- ${entry}`)
|
|
1697
1837
|
}
|
|
1698
1838
|
} else {
|
|
1699
|
-
lines.push(
|
|
1839
|
+
lines.push(t('commands.changelog.release_only'))
|
|
1700
1840
|
}
|
|
1701
1841
|
lines.push('')
|
|
1702
1842
|
} catch {
|
|
1703
|
-
lines.push(`### ${tag}`, '', '
|
|
1843
|
+
lines.push(`### ${tag}`, '', t('commands.changelog.details_unavailable'), '')
|
|
1704
1844
|
}
|
|
1705
1845
|
}
|
|
1706
1846
|
} catch {
|
|
1707
|
-
lines.push('
|
|
1847
|
+
lines.push(t('commands.changelog.no_git'))
|
|
1708
1848
|
}
|
|
1709
1849
|
|
|
1710
1850
|
lines.push('---')
|
|
1711
|
-
lines.push(
|
|
1851
|
+
lines.push(t('commands.changelog.full_history'))
|
|
1712
1852
|
|
|
1713
1853
|
return { content: lines.join('\n') }
|
|
1714
1854
|
}
|
|
@@ -4285,10 +4425,10 @@ const forkCmd: CommandHandler = async (ctx, args) => {
|
|
|
4285
4425
|
ex(`git -C ${wtPath} add -A`, { stdio: 'ignore', timeout: 10_000 })
|
|
4286
4426
|
const st = ex(`git -C ${wtPath} status --porcelain`, { encoding: 'utf-8', timeout: 10_000 })
|
|
4287
4427
|
if (st.trim()) {
|
|
4288
|
-
ex(
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
)
|
|
4428
|
+
ex(`git -C ${wtPath} commit -m "feat: ${prompt.slice(0, 60)}\n\n${COAUTHOR_TRAILER}"`, {
|
|
4429
|
+
stdio: 'ignore',
|
|
4430
|
+
timeout: 10_000,
|
|
4431
|
+
})
|
|
4292
4432
|
ex(`git push origin ${branch}`, { stdio: 'ignore', timeout: 30_000 })
|
|
4293
4433
|
}
|
|
4294
4434
|
} catch {
|
|
@@ -4485,6 +4625,7 @@ const commandsListCmd: CommandHandler = () => {
|
|
|
4485
4625
|
'/crsi inventory': 'Tools & Skills',
|
|
4486
4626
|
'/crsi modify': 'Tools & Skills',
|
|
4487
4627
|
'/crsi propose': 'Tools & Skills',
|
|
4628
|
+
'/crsi prose-clear': 'Tools & Skills',
|
|
4488
4629
|
'/crsi eval': 'Tools & Skills',
|
|
4489
4630
|
'/crsi meta': 'Tools & Skills',
|
|
4490
4631
|
'/crsi interpret': 'Tools & Skills',
|
|
@@ -4641,6 +4782,7 @@ registry.set('/crsi health', crsiHealthCmd)
|
|
|
4641
4782
|
registry.set('/crsi inventory', crsiInventoryCmd)
|
|
4642
4783
|
registry.set('/crsi modify', crsiModifyCmd)
|
|
4643
4784
|
registry.set('/crsi propose', crsiProposeCmd)
|
|
4785
|
+
registry.set('/crsi prose-clear', crsiProseClearCmd)
|
|
4644
4786
|
registry.set('/crsi eval', crsiEvalCmd)
|
|
4645
4787
|
registry.set('/crsi meta', crsiMetaCmd)
|
|
4646
4788
|
registry.set('/crsi interpret', crsiInterpretCmd)
|
|
@@ -4819,7 +4961,9 @@ const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
|
4819
4961
|
'/crsi health': 'CRSI + SIS unified health dashboard with scoring',
|
|
4820
4962
|
'/crsi inventory': 'Live capability self-report — CRSI/SIS/constitution state',
|
|
4821
4963
|
'/crsi modify': 'Run a code self-modification through the sandbox (worktree → tests → approve)',
|
|
4822
|
-
'/crsi propose':
|
|
4964
|
+
'/crsi propose':
|
|
4965
|
+
'固化 CRSI 失败信号(默认教训 / --rule 受管理规则 / --prose 改 skill 散文),沙箱 + 人批准门控',
|
|
4966
|
+
'/crsi prose-clear': '清空散文提议去重 ledger(~/.mipham/crsi/prose-proposals.jsonl)',
|
|
4823
4967
|
'/crsi eval': 'Run the ground-truth CRSI eval harness and record the score',
|
|
4824
4968
|
'/crsi meta': 'RSI Level 3 meta-rule analysis — rules that improve the rules',
|
|
4825
4969
|
'/crsi interpret': 'Tool-call behavior dashboard — error patterns, usage, health',
|