@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/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', 'strict'];
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', 'spot'];
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
- /** strict: share of steps that also get a random Opus reviewer spot check. */
342
- const STRICT_SPOT_RATE = 1 / 3;
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 the mode loosen (fast) or tighten (strict).
348
- * opts: { mode, score, verifiable, reversible, publish, dependents, seed }
349
- * Returns { verify_plan, verify_reason, verify_floor: string[], test_scope: 'selective'|'full' }.
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 (!core.MODES.includes(mode)) throw new Error(`--mode phải là ${core.MODES.join('|')}`);
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 một lần trước cổng 3`, 'selective');
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`, 'full')
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)`, 'full');
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 === 'strict') {
373
- const u = makeRng(opts.seed === undefined || opts.seed === null || opts.seed === true ? undefined : `spot:${opts.seed}`)();
374
- if (u < STRICT_SPOT_RATE) return out('spot', 'strict: verifier độc lập chặn + reviewer Opus kiểm ngẫu nhiên (1/3), luôn chạy cả suite', 'full');
375
- return out('independent-blocking', 'strict: verifier độc lập chặn, luôn chạy cả suite', 'full');
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`, 'full');
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.MODES.includes(opts.mode)) {
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 = [];