@event4u/agent-config 9.35.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +95 -142
  3. package/agents/templates/.ai-council.yml.example +31 -51
  4. package/dist/agent-src/commands/analyze/conformance.md +15 -4
  5. package/dist/agent-src/commands/analyze/reference-repo.md +135 -42
  6. package/dist/agent-src/contexts/augment-infrastructure.md +1 -1
  7. package/dist/agent-src/rules/design-review-after-ui-write.md +53 -6
  8. package/dist/agent-src/rules/improve-before-implement.md +1 -1
  9. package/dist/agent-src/rules/session-canary.md +28 -0
  10. package/dist/agent-src/rules/ui-audit-gate.md +35 -0
  11. package/dist/agent-src/skills/design-system-capture/SKILL.md +2 -2
  12. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +1 -1
  13. package/dist/agent-src/skills/fe-design/SKILL.md +84 -12
  14. package/dist/agent-src/skills/fe-design/evals/triggers.json +11 -3
  15. package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +5 -5
  16. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  17. package/dist/agent-src/skills/skill-writing/SKILL.md +24 -0
  18. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +29 -0
  19. package/dist/agent-src/templates/AGENTS.md +1 -1
  20. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  21. package/dist/cli-delegate/{chunk-2TGMGLBL.js → chunk-2H5SE7DU.js} +35 -5
  22. package/dist/cli-delegate/{chunk-DS6BLDMG.js → chunk-3JUTT26I.js} +8 -3
  23. package/dist/cli-delegate/{chunk-ZAXH3ZWU.js → chunk-HJSKTMIF.js} +14 -13
  24. package/dist/cli-delegate/{chunk-QEEB4LHO.js → chunk-LRXJK6GN.js} +1 -1
  25. package/dist/cli-delegate/{chunk-736JCWLM.js → chunk-M2DPGFZ4.js} +10 -0
  26. package/dist/cli-delegate/{chunk-H6F2CQFI.js → chunk-NX5AXSLD.js} +3 -3
  27. package/dist/cli-delegate/{chunk-AG47LAGQ.js → chunk-TVGXH7VA.js} +1 -1
  28. package/dist/cli-delegate/{chunk-55RI5UXK.js → chunk-XT2YTJCZ.js} +22 -18
  29. package/dist/cli-delegate/{chunk-JEJABGKB.js → chunk-XTC5ARB6.js} +16 -12
  30. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  31. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  32. package/dist/cli-delegate/cmd_conformance.js +1038 -197
  33. package/dist/cli-delegate/cmd_doctor.js +4 -4
  34. package/dist/cli-delegate/cmd_explain.js +2 -2
  35. package/dist/cli-delegate/cmd_export.js +4 -4
  36. package/dist/cli-delegate/cmd_handoff.js +3 -3
  37. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  38. package/dist/cli-delegate/cmd_migrate.js +2 -2
  39. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  40. package/dist/cli-delegate/cmd_prune.js +4 -4
  41. package/dist/cli-delegate/cmd_refresh.js +1 -1
  42. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  43. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  44. package/dist/cli-delegate/cmd_session_recycle.js +9 -2
  45. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  46. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  47. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  48. package/dist/cli-delegate/cmd_sync.js +4 -4
  49. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  50. package/dist/cli-delegate/cmd_update.js +1 -1
  51. package/dist/cli-delegate/cmd_upgrade.js +2 -2
  52. package/dist/cli-delegate/cmd_validate.js +4 -4
  53. package/dist/cli-delegate/cmd_versions.js +1 -1
  54. package/dist/discovery/deprecation-report.md +1 -1
  55. package/dist/discovery/discovery-manifest.json +14 -14
  56. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  57. package/dist/discovery/discovery-manifest.summary.md +1 -1
  58. package/dist/discovery/dormancy-report.md +1 -1
  59. package/dist/discovery/orphan-report.md +1 -1
  60. package/dist/discovery/packs.json +2 -2
  61. package/dist/discovery/trust-report.md +1 -1
  62. package/dist/discovery/workspaces.json +2 -2
  63. package/dist/hooks/dispatch.js +654 -411
  64. package/dist/install/install.mjs +39 -29
  65. package/dist/mcp/registry-manifest.json +1 -1
  66. package/dist/mcp/server.json +2 -2
  67. package/dist/mcp/server.mjs +1580 -617
  68. package/dist/router.json +1 -1
  69. package/dist/scripts/_lib/agent_settings.js +39 -25
  70. package/dist/scripts/_lib/agent_settings.js.map +1 -1
  71. package/dist/scripts/condense.js +15 -2
  72. package/dist/scripts/condense.js.map +1 -1
  73. package/dist/server/routes/wizard.js +23 -3
  74. package/dist/server/routes/wizard.js.map +1 -1
  75. package/dist/server/schemas/settings.js +11 -6
  76. package/dist/server/schemas/settings.js.map +1 -1
  77. package/docs/contracts/settings-classes.md +16 -9
  78. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +46 -4
  79. package/package.json +2 -2
  80. package/src/agent-src/templates/AGENTS.md +1 -1
  81. package/src/config/agent-settings.template.yml +38 -36
  82. package/src/config/ci-local-parity.yml +44 -0
  83. package/src/config/gate-coverage.yml +12 -0
  84. package/src/scripts/_cli/cmd_doctor.ts +32 -0
  85. package/src/scripts/_cli/cmd_migrate.ts +26 -3
  86. package/src/scripts/_cli/cmd_refresh.ts +29 -0
  87. package/src/scripts/_cli/cmd_session_recycle.ts +40 -2
  88. package/src/scripts/_lib/agent_settings.ts +39 -25
  89. package/src/scripts/_lib/environment_detector.ts +52 -1
  90. package/src/scripts/_lib/hook_settings.ts +79 -0
  91. package/src/scripts/_lib/ui_surface.ts +97 -0
  92. package/src/scripts/ai_council/config.ts +62 -24
  93. package/src/scripts/before_complete_hook.ts +39 -0
  94. package/src/scripts/capture_skill_catalogue.ts +483 -0
  95. package/src/scripts/check_bridge_derivation.ts +89 -3
  96. package/src/scripts/check_ci_local_parity.ts +74 -0
  97. package/src/scripts/check_references.ts +15 -1
  98. package/src/scripts/condense.ts +16 -2
  99. package/src/scripts/conformance_scan.ts +200 -9
  100. package/src/scripts/council_cli.ts +95 -3
  101. package/src/scripts/hook_manifest.yaml +30 -9
  102. package/src/scripts/hooks/block_no_verify.ts +82 -9
  103. package/src/scripts/hooks/concern_registry.ts +2 -0
  104. package/src/scripts/hooks/design_slop_hook.ts +1 -1
  105. package/src/scripts/hooks/turn_end_gate_hook.ts +138 -105
  106. package/src/scripts/hooks/ui_route_nudge_hook.ts +250 -0
  107. package/src/scripts/lint_roadmap_complexity.ts +60 -0
  108. package/src/scripts/lint_rule_skill_pack_reach.ts +263 -0
  109. package/src/scripts/probe_promissory_closing.ts +180 -0
  110. package/src/scripts/probe_session_canary.ts +180 -0
  111. package/src/scripts/report_consultation_rate.ts +358 -0
  112. package/src/scripts/report_skill_activation.ts +5 -1
  113. package/src/server/schemas/settings.ts +14 -13
  114. /package/dist/agent-src/skills/design-system-capture/{reference → references}/design-system-json.md +0 -0
  115. /package/dist/agent-src/skills/prediction-pool-optimizer/{reference → references}/ev-fixtures.md +0 -0
  116. /package/dist/agent-src/skills/prediction-pool-optimizer/{reference → references}/odds-and-bonus.md +0 -0
  117. /package/dist/agent-src/skills/react-shadcn-ui/{reference → references}/registry.md +0 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * ui_surface — the ONE definition of "this path is a UI surface".
3
+ *
4
+ * Three consumers need the same answer and were about to disagree about it:
5
+ * the anti-slop PreToolUse hook (which had the only copy), the UI-turn
6
+ * definition the catalogue analyzer counts against, and the route nudge.
7
+ * A UI-turn rate measured against one extension set and a nudge fired against
8
+ * another would produce a consultation rate that no fix could ever move,
9
+ * because the denominator and the trigger would be different populations.
10
+ *
11
+ * `.blade.php` is deliberately part of the set and was absent from the hook's
12
+ * original regex: a two-part extension does not match a `\.(…)$` alternation,
13
+ * so every Blade template — the single largest UI surface in a Laravel
14
+ * consumer — read as a non-UI file. That is why `isUiPath` matches on the
15
+ * path tail rather than on `path.extname`, which returns `.php` for
16
+ * `page.blade.php` and would silently reproduce the same hole.
17
+ */
18
+
19
+ /** Single-segment UI extensions, without the leading dot. */
20
+ export const UI_EXTENSIONS = [
21
+ 'html',
22
+ 'htm',
23
+ 'css',
24
+ 'scss',
25
+ 'sass',
26
+ 'less',
27
+ 'vue',
28
+ 'svelte',
29
+ 'astro',
30
+ 'jsx',
31
+ 'tsx',
32
+ ] as const;
33
+
34
+ /**
35
+ * Multi-segment UI suffixes. These cannot be expressed as an extension
36
+ * alternation — `path.extname('x.blade.php')` is `.php`.
37
+ */
38
+ export const UI_COMPOUND_SUFFIXES = ['.blade.php'] as const;
39
+
40
+ /** Equivalent to the historical hook regex, plus the compound suffixes. */
41
+ export const UI_EXT = new RegExp(
42
+ `(\\.(${UI_EXTENSIONS.join('|')})|${UI_COMPOUND_SUFFIXES.map((s) => s.replace(/\./g, '\\.')).join('|')})$`,
43
+ 'i',
44
+ );
45
+
46
+ /** True when `p` names a file on a UI surface. Case-insensitive. */
47
+ export function isUiPath(p: string): boolean {
48
+ return UI_EXT.test(p);
49
+ }
50
+
51
+ /**
52
+ * Directory fragments that mark a UI tree across frameworks. The two UI rules
53
+ * carried only the Laravel pair (`resources/views/`, `resources/js/`), so a
54
+ * React, Vue, Next or Svelte consumer writing to `src/components/` matched no
55
+ * path trigger at all. Kept as fragments, not anchored prefixes: a consumer's
56
+ * UI tree is rarely at the repo root.
57
+ *
58
+ * `app/` is deliberately NOT in this list although it is the Next.js router
59
+ * directory. In a Laravel consumer `app/` is the entire backend, so the
60
+ * fragment would fire on every controller, model and job — a trigger that
61
+ * over-fires on the largest directory of a whole ecosystem is worse than the
62
+ * gap it closes. Next.js route files are caught by extension instead
63
+ * (`page.tsx`, `layout.tsx` match `isUiPath`), which is the precise signal.
64
+ */
65
+ export const UI_PATH_FRAGMENTS = [
66
+ 'resources/views/',
67
+ 'resources/js/',
68
+ // `components/` already subsumes `src/components/` under substring
69
+ // matching — listing both here would be dead weight. The rules' own
70
+ // `path_prefix` list keeps both because matching there is anchored.
71
+ 'components/',
72
+ 'pages/',
73
+ ] as const;
74
+
75
+ /**
76
+ * Fragments that sit INSIDE a UI tree and are not UI. Checked first, because a
77
+ * substring fragment cannot express "pages/ but not pages/api/" on its own —
78
+ * and `pages/api/` is server-only Next.js code, the exact over-fire the `app/`
79
+ * exclusion above exists to avoid. Leaving it in would have put backend files
80
+ * in the pre-registered UI-turn denominator, which is worse than the nudge
81
+ * firing on them: a rate is harder to un-break than a warning.
82
+ */
83
+ export const UI_TREE_EXCLUSIONS = ['pages/api/'] as const;
84
+
85
+ /**
86
+ * True when `p` sits inside a conventional UI tree.
87
+ *
88
+ * Note this does NOT require a UI extension — that is the point: a `.js` file
89
+ * under `resources/js/` is UI. The cost is that a non-code file in a UI tree
90
+ * (a README, a fixture) also matches; callers that need the narrower answer
91
+ * combine this with `isUiPath`.
92
+ */
93
+ export function isUiTreePath(p: string): boolean {
94
+ const normalized = p.replace(/\\/g, '/').toLowerCase();
95
+ if (UI_TREE_EXCLUSIONS.some((fragment) => normalized.includes(fragment))) return false;
96
+ return UI_PATH_FRAGMENTS.some((fragment) => normalized.includes(fragment));
97
+ }
@@ -639,6 +639,20 @@ export interface CouncilConfig {
639
639
  readonly low_impact: LowImpactConfig;
640
640
  readonly lens_overrides: LensOverridesConfig;
641
641
  readonly source_path: PathLike | null;
642
+ /**
643
+ * Transport keys the config file still carries and the loader deliberately
644
+ * IGNORED — dotted paths, e.g. `defaults.mode`, `members.anthropic.mode`.
645
+ *
646
+ * Transport is resolved per machine per invocation, never configured: the
647
+ * chain is `cli → api → unavailable`, and an airgapped host forces the
648
+ * `api` rung. Deleting the keys from the schema outright would have made
649
+ * every pre-existing installation fail to load, so a stale key is
650
+ * accepted, ignored, and reported once — the migration IS the ignore.
651
+ *
652
+ * Empty on a config that never carried one, which is the shape the current
653
+ * template ships.
654
+ */
655
+ readonly ignored_transport_keys: readonly string[];
642
656
  }
643
657
 
644
658
  // ── default factories (dataclass defaults) ─────────────────────────
@@ -796,7 +810,11 @@ export function _build_config(raw: Dict, source_path: PathLike): CouncilConfig {
796
810
  throw new CouncilConfigError('`enabled` must be a bool.');
797
811
  }
798
812
 
799
- const defaults = _build_defaults(_asDict(_getOr(raw, 'defaults', {})));
813
+ const ignored_transport_keys: string[] = [];
814
+ const defaults = _build_defaults(
815
+ _asDict(_getOr(raw, 'defaults', {})),
816
+ ignored_transport_keys,
817
+ );
800
818
  const cost_budget = _build_cost_budget(
801
819
  _asDict(_getOr(raw, 'cost_budget', {})),
802
820
  );
@@ -809,7 +827,12 @@ export function _build_config(raw: Dict, source_path: PathLike): CouncilConfig {
809
827
  for (const [name, cfg] of Object.entries(members_raw)) {
810
828
  members.set(
811
829
  name,
812
- _build_member(name, _asDict(_orEmpty(cfg)), defaults.mode),
830
+ _build_member(
831
+ name,
832
+ _asDict(_orEmpty(cfg)),
833
+ defaults.mode,
834
+ ignored_transport_keys,
835
+ ),
813
836
  );
814
837
  }
815
838
 
@@ -920,6 +943,7 @@ export function _build_config(raw: Dict, source_path: PathLike): CouncilConfig {
920
943
  low_impact,
921
944
  lens_overrides,
922
945
  source_path,
946
+ ignored_transport_keys,
923
947
  };
924
948
  }
925
949
 
@@ -1508,23 +1532,36 @@ function _build_consensus_scoring(d: Dict): ConsensusScoringConfig {
1508
1532
 
1509
1533
  const _VALID_MEMBER_MODES: ReadonlySet<string> = new Set(['cli', 'api']);
1510
1534
 
1511
- function _build_defaults(d: Dict): DefaultsConfig {
1535
+ function _build_defaults(d: Dict, ignored: string[] = []): DefaultsConfig {
1512
1536
  if (!_isDict(d)) {
1513
1537
  throw new CouncilConfigError('`defaults` must be a mapping.');
1514
1538
  }
1515
- // road-to-always-on-orchestration Phase 3.1: CLI-first is the shipped
1516
- // default (was `api`) — see the module docstring rule 2. `manual` and a
1517
- // pinned `api`/`cli` remain valid overrides at every layer resolve_mode
1518
- // checks; this only changes what a config that never sets `mode` gets.
1519
- const mode = _get(d, 'mode', 'auto');
1520
- if (!(_isStr(mode) && _VALID_MODES.has(mode))) {
1521
- throw new CouncilConfigError(
1522
- `defaults.mode=${_pyRepr(mode)} not in ${_sortedListRepr(_VALID_MODES)}.`,
1523
- );
1524
- }
1539
+ // Transport is RESOLVED, never configured.
1540
+ //
1541
+ // The CLI-first flip (road-to-always-on-orchestration Phase 3.1) changed
1542
+ // only what a config that OMITS `mode` receives. Every installation that
1543
+ // spelled the key out — which the wizard did, and which every pre-flip
1544
+ // template shipped — kept its old `api` value forever, silently, and went
1545
+ // on paying per token while a subscription CLI sat unused on the same
1546
+ // machine. A default that only fires on an absent key does not migrate
1547
+ // anybody; it just makes the docs read better than the behaviour.
1548
+ //
1549
+ // So the key is no longer read. `auto` is the only value this loader
1550
+ // produces, and `transport_resolver` picks the concrete rung per machine
1551
+ // per invocation (`cli → api → unavailable`, airgap forcing `api`). A file
1552
+ // still carrying `mode:` loads fine and is reported via
1553
+ // `ignored_transport_keys` — see `CouncilConfig`.
1554
+ // `null` as the sentinel, not `undefined`: `_get`'s default parameter is
1555
+ // typed `Json`, which excludes `undefined`. A config spelling `mode: null`
1556
+ // is indistinguishable from an absent key here, and that is correct — a
1557
+ // null transport is not a pin worth reporting.
1558
+ if (_get(d, 'mode', null) !== null) {
1559
+ ignored.push('defaults.mode');
1560
+ }
1561
+ const mode = 'auto';
1525
1562
  // `member_mode` (step-9 P8 · U1) — global preference for solo /
1526
- // CLI-mode invocations. Narrower set than `defaults.mode` because
1527
- // `manual` makes no sense as a per-member dispatch default.
1563
+ // CLI-mode invocations. Narrower set than the retired `defaults.mode`
1564
+ // because `manual` makes no sense as a per-member dispatch default.
1528
1565
  const member_mode = _get(d, 'member_mode', 'cli');
1529
1566
  if (!(_isStr(member_mode) && _VALID_MEMBER_MODES.has(member_mode))) {
1530
1567
  throw new CouncilConfigError(
@@ -1726,6 +1763,7 @@ function _build_member(
1726
1763
  // a future caller that omits the third argument observes the same
1727
1764
  // doctrine rather than silently reverting to the retired `api` default.
1728
1765
  default_mode = 'auto',
1766
+ ignored: string[] = [],
1729
1767
  ): MemberConfig {
1730
1768
  if (!_VALID_PROVIDERS.has(name)) {
1731
1769
  throw new CouncilConfigError(
@@ -1738,15 +1776,15 @@ function _build_member(
1738
1776
  const model = _pyTruthy(modelVal) ? (modelVal as string) : '';
1739
1777
  const api_key_ref_raw = _get(cfg, 'api_key_ref', null);
1740
1778
  const api_key_ref = api_key_ref_raw === undefined ? null : api_key_ref_raw;
1741
- const member_mode_raw = _get(cfg, 'mode', null);
1742
- const member_mode = member_mode_raw === undefined ? null : member_mode_raw;
1743
- if (member_mode !== null && !(_isStr(member_mode) && _VALID_MODES.has(member_mode))) {
1744
- throw new CouncilConfigError(
1745
- `members.${name}.mode=${_pyRepr(member_mode)} not in ` +
1746
- `${_sortedListRepr(_VALID_MODES)}.`,
1747
- );
1748
- }
1749
- const effective_mode = member_mode !== null ? (member_mode as string) : default_mode;
1779
+ // Per-member transport is no longer configurable either — same reasoning
1780
+ // as `_build_defaults`. A member that pinned `mode: api` would reintroduce
1781
+ // exactly the silent-spend path the global key was removed for, one
1782
+ // provider at a time. Recorded as ignored, never read.
1783
+ if (_get(cfg, 'mode', null) !== null) {
1784
+ ignored.push(`members.${name}.mode`);
1785
+ }
1786
+ const member_mode: string | null = null;
1787
+ const effective_mode = default_mode;
1750
1788
  const binary_raw = _get(cfg, 'binary', null);
1751
1789
  const binary = binary_raw === undefined ? null : binary_raw;
1752
1790
  if (binary !== null) {
@@ -113,6 +113,14 @@ function _empty_state(): StateDict {
113
113
  verified_this_turn: false,
114
114
  ci_saw_pending: false,
115
115
  nonevidence_this_turn: 0,
116
+ // Round 7 § Phase 1 — the last CI read, SESSION-scoped on purpose. Every
117
+ // other counter here is turn-scoped because a stale POSITIVE would wrongly
118
+ // vouch ("I verified"). This one is a NEGATIVE ("CI was not settled"), and a
119
+ // stale negative only ever refuses more often — so surviving the turn
120
+ // boundary preserves the freshness invariant rather than bypassing it. It
121
+ // has to survive it: the measured failure is a completion claim in a LATER
122
+ // turn than the poll it rests on.
123
+ ci_last: null,
116
124
  checked_at: _now(),
117
125
  };
118
126
  }
@@ -303,6 +311,16 @@ function _update(state: StateDict, event: string, envelope: StateDict): StateDic
303
311
  // Session boundary — reset session-scoped counters.
304
312
  state["session_id"] = session_id;
305
313
  state["verifications_this_session"] = 0;
314
+ // R2 finding 1 (high). `ci_last` is SESSION-scoped, and until this line
315
+ // nothing cleared it: `_reset_turn` clears the turn-scoped witness,
316
+ // `_empty_state` sets it null only for a state file that does not exist yet,
317
+ // and `_load_state` merges the persisted value over that default. So session
318
+ // A polled CI, saw pending, and ended; session B — a doc-only session that
319
+ // never touched CI — said "Fertig" and was REFUSED, contradicting both the
320
+ // consumer's own comment ("a session that never polled CI must never be
321
+ // refused for it") and the negative case the roadmap pinned. Session-scoped
322
+ // has to mean cleared at the boundary, or it means never cleared.
323
+ state["ci_last"] = null;
306
324
  state = _reset_turn(state, session_id);
307
325
  }
308
326
 
@@ -338,6 +356,27 @@ function _update(state: StateDict, event: string, envelope: StateDict): StateDic
338
356
  } else {
339
357
  counts = false; // unrecognised or unreadable — never read as settled
340
358
  }
359
+ // Round 7 § 1.1 — the session-scoped negative the turn-end consumer reads.
360
+ //
361
+ // R2 finding 3 (medium), and it was the sharpest one: this said `settled:
362
+ // pending === 0` and CLAIMED "the same discrimination `counts` makes
363
+ // above". It was not. `counts` requires `!vacuous && ci_saw_pending`;
364
+ // `pending === 0` alone drops both. A post-push poll that reads a stale
365
+ // all-pass table returns pending 0 — verbatim the FC-3b failure documented
366
+ // twenty lines up — and recorded `settled: true`, so the completion
367
+ // detector went SILENT in exactly the premature-claim case it exists for.
368
+ // A detector defeated by the false settle it was built to catch is worse
369
+ // than no detector, because it reports coverage.
370
+ //
371
+ // Now it reuses `counts` itself, which is that discrimination rather than
372
+ // a paraphrase of it. `pending === null` (unreadable, and "no checks
373
+ // reported") stays not-a-settle by construction.
374
+ state["ci_last"] = {
375
+ at: _now(),
376
+ command: cmd.slice(0, 512),
377
+ pending,
378
+ settled: pending === 0 && counts === true,
379
+ };
341
380
  }
342
381
 
343
382
  state["last_verification"] = {