@kienntpixon/dieu-phoi 0.7.2 → 0.7.4
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 +33 -0
- package/agents/dp-exec.md +6 -1
- package/agents/dp-helper.md +6 -0
- package/agents/dp-scout.md +7 -1
- package/agents/dp-verify.md +6 -0
- package/bin/dieu-phoi.cjs +29 -13
- package/hook.cjs +854 -154
- package/lib/aggregate.cjs +20 -2
- package/lib/args.cjs +1 -1
- package/lib/cbm.cjs +8 -2
- package/lib/choose.cjs +27 -22
- package/lib/commands.cjs +448 -39
- package/lib/deps.cjs +162 -0
- package/lib/knowledge.cjs +47 -4
- package/lib/load.cjs +332 -0
- package/lib/procs.cjs +200 -1
- package/lib/prune.cjs +91 -8
- package/lib/setup.cjs +28 -5
- package/lib/worktree.cjs +250 -19
- package/package.json +1 -1
- package/profile/lessons.md +2 -1
package/lib/aggregate.cjs
CHANGED
|
@@ -574,9 +574,27 @@ function analyze(events, opts) {
|
|
|
574
574
|
};
|
|
575
575
|
}
|
|
576
576
|
|
|
577
|
+
/**
|
|
578
|
+
* core 0.7.4 (s1): one sample per task that has a first exec attempt (excluded tasks left out). `model`/`effort` are
|
|
579
|
+
* that attempt's (the cell buildCells uses), `handoff` = some segment of that attempt's chain ended on an auto-handoff,
|
|
580
|
+
* `total_cost` = the task's cost over all segments. Only plan-table's TÁCH? warning reads these; it is advice, not a gate.
|
|
581
|
+
*/
|
|
582
|
+
function handoffSamples(events) {
|
|
583
|
+
const { agents, userVerdicts, autoVerdicts } = buildAgents(withoutDiscarded(events));
|
|
584
|
+
return buildTasks(agents, userVerdicts, autoVerdicts)
|
|
585
|
+
.filter((t) => t.first && !t.excluded)
|
|
586
|
+
.map((t) => ({
|
|
587
|
+
task_type: t.task_type,
|
|
588
|
+
model: t.first.model,
|
|
589
|
+
effort: t.first.effort,
|
|
590
|
+
handoff: t.first_chain.some((a) => a.handoff),
|
|
591
|
+
total_cost: t.total_cost,
|
|
592
|
+
}));
|
|
593
|
+
}
|
|
594
|
+
|
|
577
595
|
module.exports = {
|
|
578
596
|
MIN_N, FAIL_OUTCOMES, HEAVY_STEERS, ABORTED, QUOTA_REASON_RE, HANDOFF_REASON_RE, discardedTaskIds, withoutDiscarded, CANONICAL_CELL_FIELDS, normalizeVerdict, isSelf, isInternalComplete, buildAgents, buildTasks,
|
|
579
|
-
buildCells, buildSteers, canonicalCells, isBatchVerify, batchVerifyCells, orchestrationSummary, analyze, cellKey, mean, percentile, tsOf, steerIdOf,
|
|
597
|
+
buildCells, buildSteers, canonicalCells, isBatchVerify, batchVerifyCells, orchestrationSummary, analyze, handoffSamples, cellKey, mean, percentile, tsOf, steerIdOf,
|
|
580
598
|
};
|
|
581
599
|
|
|
582
600
|
// ------------------------------------------------------------------ core 0.7.0 (s2): stats split by mode
|
|
@@ -584,7 +602,7 @@ module.exports = {
|
|
|
584
602
|
// Kept apart from the canonical cells (not part of the CLI <-> sink parity yet). A task's mode = `mode` of its first
|
|
585
603
|
// exec dispatch; tasks dispatched before modes existed (no `mode`) count as normal.
|
|
586
604
|
|
|
587
|
-
const MODE_KEYS = ['fast', 'normal'
|
|
605
|
+
const MODE_KEYS = ['fast', 'normal']; // legacy 'strict' dispatches count as normal (0.7.4)
|
|
588
606
|
const NO_CATCH_VERIFY = new Set(['self', 'none']);
|
|
589
607
|
|
|
590
608
|
/**
|
package/lib/args.cjs
CHANGED
|
@@ -4,7 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const core = require('../hook.cjs');
|
|
6
6
|
|
|
7
|
-
const BOOLEAN_FLAGS = new Set(['json', 'help', 'h', 'purge', 'version', 'v', 'dry-run', 'no-sync', 'approve', 'yes', 'force', 'follow', 'remove', 'dirty', 'no-cache', 'untagged', 'no-knowledge', 'net', 'with-codebase-memory', 'cbm', 'allow-custom-source', 'auto', 'include-local']);
|
|
7
|
+
const BOOLEAN_FLAGS = new Set(['json', 'help', 'h', 'purge', 'version', 'v', 'dry-run', 'no-sync', 'approve', 'yes', 'force', 'follow', 'remove', 'dirty', 'no-cache', 'untagged', 'no-knowledge', 'net', 'with-codebase-memory', 'cbm', 'allow-custom-source', 'auto', 'include-local', 'orphans']);
|
|
8
8
|
|
|
9
9
|
/** Minimal argv parser: positionals, --k v, --k=v, boolean flags. */
|
|
10
10
|
function parseArgs(argv) {
|
package/lib/cbm.cjs
CHANGED
|
@@ -117,9 +117,15 @@ function binArgv(bin, args) {
|
|
|
117
117
|
return /\.c?js$/i.test(bin) ? [process.execPath, [bin, ...args]] : [bin, args];
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
/** Timeout (ms) of a cbm sub-process; env override DIEU_PHOI_CBM_<name>_TIMEOUT_MS (tests under heavy load), default unchanged. */
|
|
121
|
+
function cbmTimeout(name, dflt) {
|
|
122
|
+
const n = Number(process.env[`DIEU_PHOI_CBM_${name}_TIMEOUT_MS`]);
|
|
123
|
+
return Number.isFinite(n) && n > 0 ? n : dflt;
|
|
124
|
+
}
|
|
125
|
+
|
|
120
126
|
function probeVersion(bin, timeoutMs) {
|
|
121
127
|
const [cmd, args] = binArgv(bin, ['--version']);
|
|
122
|
-
const r = cp.spawnSync(cmd, args, { encoding: 'utf8', timeout: timeoutMs || 3000, windowsHide: true });
|
|
128
|
+
const r = cp.spawnSync(cmd, args, { encoding: 'utf8', timeout: timeoutMs || cbmTimeout('PROBE', 3000), windowsHide: true });
|
|
123
129
|
if (r.error || r.status !== 0) return null;
|
|
124
130
|
const m = /(\d+\.\d+\.\d+)/.exec(`${r.stdout || ''}`);
|
|
125
131
|
return m ? m[1] : null;
|
|
@@ -275,7 +281,7 @@ function doctorChecks({ claudeDir, repo, net, deep, cacheFile, env, now }) {
|
|
|
275
281
|
const version = probeVersion(found.path);
|
|
276
282
|
const wantDaemon = !!(deep || net);
|
|
277
283
|
const cached = wantDaemon ? null : readDaemonCache(cacheFile, found.path, version, nowMs);
|
|
278
|
-
const daemonP = wantDaemon ? daemonStatus(found.path, 5000) : Promise.resolve(null);
|
|
284
|
+
const daemonP = wantDaemon ? daemonStatus(found.path, cbmTimeout('DAEMON', 5000)) : Promise.resolve(null);
|
|
279
285
|
const latestP = net ? latestVersion(e).then((v) => ({ v }), (err) => ({ err: err.message })) : Promise.resolve(null);
|
|
280
286
|
return (async () => {
|
|
281
287
|
add(!!version && regs.length > 0, 'codebase-memory', `${version ? `v${version}` : 'không chạy được `--version`'} tại ${toSlash(found.path)} (${found.source})${regs.length
|
package/lib/choose.cjs
CHANGED
|
@@ -145,6 +145,7 @@ function loadProfile(skillDir) {
|
|
|
145
145
|
return {
|
|
146
146
|
source, dept: r.dept || null, priors, lambda, explore_rate: explore, time_cap_min: timeCap, extra_task_types: extra,
|
|
147
147
|
orch_ctx_soft_cap: softCap, tier_floor: tierFloor,
|
|
148
|
+
batch_verify_normal: r.batch_verify_normal !== false,
|
|
148
149
|
};
|
|
149
150
|
}
|
|
150
151
|
|
|
@@ -334,23 +335,26 @@ function resolveTaskType(raw, profile) {
|
|
|
334
335
|
|
|
335
336
|
// ------------------------------------------------------------------ verify plan (core 0.7.0, mode per request)
|
|
336
337
|
|
|
337
|
-
const VERIFY_PLANS = ['independent-blocking', 'independent-nonblocking', 'self+batch'
|
|
338
|
+
const VERIFY_PLANS = ['independent-blocking', 'independent-nonblocking', 'self+batch'];
|
|
338
339
|
/** fast: highest score still allowed to drop its own blocking verifier (s<=6 self+batch, s7-8 independent-nonblocking). */
|
|
339
340
|
const FAST_SELF_MAX = 6;
|
|
340
341
|
const FAST_SOFT_MAX = 8;
|
|
341
|
-
/**
|
|
342
|
-
const
|
|
343
|
-
|
|
342
|
+
/** normal (0.7.4, user decision Q1): s<=4 with no step depending on it -> self+batch (one verifier per group, not per step). */
|
|
343
|
+
const NORMAL_BATCH_MAX = 4;
|
|
344
344
|
/**
|
|
345
345
|
* How one exec step is checked, from the request mode and the step's rubric inputs.
|
|
346
346
|
* The safety floor is evaluated FIRST and wins in every mode: reversible=n, publish/deploy, verifiable=n, score>=9
|
|
347
|
-
* always get an independent blocking verifier. Only after that does
|
|
348
|
-
*
|
|
349
|
-
*
|
|
347
|
+
* always get an independent blocking verifier. Only after that does fast loosen it, and normal batch the s<=4 steps.
|
|
348
|
+
* Legacy mode `strict` (removed 0.7.4) reads as normal.
|
|
349
|
+
* opts: { mode, score, verifiable, reversible, publish, dependents, batchNormal, seed }
|
|
350
|
+
* batchNormal === false (profile.batch_verify_normal=false) switches the normal batch off (rollback switch).
|
|
351
|
+
* Returns { verify_plan, verify_reason, verify_floor: string[], test_scope: 'full' | 'selective' }. Step verification (exec, independent
|
|
352
|
+
* verifier, batch verifier) always runs the touched-module tests; the full suite runs once at the release gate, not here.
|
|
353
|
+
* test_scope is 'full' only for a publish/deploy step (that step is the release gate's trigger); every other step is 'selective'.
|
|
350
354
|
*/
|
|
351
355
|
function verifyPlanFor(opts) {
|
|
352
|
-
const mode = opts.mode || core.DEFAULT_MODE;
|
|
353
|
-
if (!
|
|
356
|
+
const mode = core.normMode(opts.mode || core.DEFAULT_MODE);
|
|
357
|
+
if (!mode) throw new Error(`--mode phải là ${core.MODES.join('|')}`);
|
|
354
358
|
const score = Number(opts.score);
|
|
355
359
|
const floor = [];
|
|
356
360
|
if (opts.reversible === false) floor.push('khó hoàn tác');
|
|
@@ -358,23 +362,24 @@ function verifyPlanFor(opts) {
|
|
|
358
362
|
if (opts.verifiable === false) floor.push('không kiểm chứng bằng máy');
|
|
359
363
|
if (score >= 9) floor.push(`score ${score}≥9`);
|
|
360
364
|
const out = (plan, reason, scope) => ({ verify_plan: plan, verify_reason: reason, verify_floor: floor, test_scope: scope });
|
|
361
|
-
if (floor.length) return out('independent-blocking', `sàn an toàn (${floor.join(', ')}) → verifier độc lập chặn bước, mọi mode`, 'full');
|
|
365
|
+
if (floor.length) return out('independent-blocking', `sàn an toàn (${floor.join(', ')}) → verifier độc lập chặn bước, mọi mode`, opts.publish === true ? 'full' : 'selective');
|
|
362
366
|
if (mode === 'fast') {
|
|
363
367
|
if (score <= FAST_SELF_MAX) {
|
|
364
|
-
return out('self+batch', `fast, s${score}≤${FAST_SELF_MAX}: exec tự kiểm (test chọn lọc theo file đổi, --verify self); verifier gộp chạy cả suite
|
|
368
|
+
return out('self+batch', `fast, s${score}≤${FAST_SELF_MAX}: exec tự kiểm (test chọn lọc theo file đổi, --verify self); verifier gộp chạy test chọn lọc của các file cả nhóm đã đụng; full suite chỉ ở cổng phát hành`, 'selective');
|
|
365
369
|
}
|
|
366
370
|
if (score <= FAST_SOFT_MAX) {
|
|
367
371
|
return opts.dependents === true
|
|
368
|
-
? out('independent-blocking', `fast, s${score}: bước sau phụ thuộc (depends_on) vào bước này → verifier độc lập vẫn chặn`, '
|
|
369
|
-
: out('independent-nonblocking', `fast, s${score}: verifier độc lập nhưng không chặn bước sau (không bước nào depends_on)`, '
|
|
372
|
+
? out('independent-blocking', `fast, s${score}: bước sau phụ thuộc (depends_on) vào bước này → verifier độc lập vẫn chặn`, 'selective')
|
|
373
|
+
: out('independent-nonblocking', `fast, s${score}: verifier độc lập nhưng không chặn bước sau (không bước nào depends_on)`, 'selective');
|
|
370
374
|
}
|
|
371
375
|
}
|
|
372
|
-
if (mode === '
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
+
if (mode === 'normal' && score <= NORMAL_BATCH_MAX && opts.batchNormal !== false) {
|
|
377
|
+
if (opts.dependents !== true) {
|
|
378
|
+
return out('self+batch', `normal, s${score}≤${NORMAL_BATCH_MAX}, không bước nào phụ thuộc: exec tự kiểm (test chọn lọc theo file đổi, --verify self); verifier gộp chạy test chọn lọc của các file cả nhóm đã đụng (một lần cuối nhóm, trước cổng 3); full suite chỉ ở cổng phát hành`, 'selective');
|
|
379
|
+
}
|
|
380
|
+
return out('independent-blocking', `normal, s${score}: bước sau phụ thuộc (depends_on) vào bước này → verifier độc lập chặn`, 'selective');
|
|
376
381
|
}
|
|
377
|
-
return out('independent-blocking', `${mode}: verifier độc lập chặn bước`, '
|
|
382
|
+
return out('independent-blocking', `${mode}: verifier độc lập chặn bước`, 'selective');
|
|
378
383
|
}
|
|
379
384
|
|
|
380
385
|
// ------------------------------------------------------------------ choose
|
|
@@ -412,14 +417,14 @@ function choose(opts) {
|
|
|
412
417
|
}
|
|
413
418
|
const reversible = opts.reversible !== false;
|
|
414
419
|
const verifiable = opts.verifiable !== false;
|
|
415
|
-
if (opts.mode !== undefined && opts.mode !== null && !core.
|
|
420
|
+
if (opts.mode !== undefined && opts.mode !== null && !core.normMode(opts.mode)) {
|
|
416
421
|
throw new Error(`--mode phải là ${core.MODES.join('|')} (nhận "${opts.mode}")`);
|
|
417
422
|
}
|
|
418
|
-
const mode = opts.mode || core.DEFAULT_MODE;
|
|
423
|
+
const mode = core.normMode(opts.mode || core.DEFAULT_MODE);
|
|
424
|
+
const profile = opts.profile || loadProfile(null);
|
|
419
425
|
const vp = role === 'exec'
|
|
420
|
-
? verifyPlanFor({ mode, score, verifiable, reversible, publish: opts.publish === true, dependents: opts.dependents === true, seed: opts.seed })
|
|
426
|
+
? verifyPlanFor({ mode, score, verifiable, reversible, publish: opts.publish === true, dependents: opts.dependents === true, batchNormal: profile.batch_verify_normal, seed: opts.seed })
|
|
421
427
|
: null;
|
|
422
|
-
const profile = opts.profile || loadProfile(null);
|
|
423
428
|
const lambda = profile.lambda[urgency];
|
|
424
429
|
const rng = makeRng(opts.seed);
|
|
425
430
|
const notes = [];
|