great-cto 3.72.0 → 3.74.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 (90) hide show
  1. package/board/.claude-plugin/plugin.json +1 -1
  2. package/board/agents/accounting-reviewer.md +2 -2
  3. package/board/agents/adtech-privacy-reviewer.md +3 -3
  4. package/board/agents/ai-eval-engineer.md +3 -3
  5. package/board/agents/ai-prompt-architect.md +3 -3
  6. package/board/agents/ai-security-reviewer.md +2 -2
  7. package/board/agents/api-platform-reviewer.md +2 -2
  8. package/board/agents/app-scaffolder.md +3 -3
  9. package/board/agents/architect.md +8 -8
  10. package/board/agents/auth-engineer.md +4 -4
  11. package/board/agents/ci-resolver.md +5 -5
  12. package/board/agents/cli-reviewer.md +2 -2
  13. package/board/agents/cmmc-reviewer.md +2 -2
  14. package/board/agents/cms-reviewer.md +2 -2
  15. package/board/agents/code-reviewer.md +4 -4
  16. package/board/agents/connector-builder.md +5 -5
  17. package/board/agents/continuous-learner.md +3 -3
  18. package/board/agents/coordinator.md +4 -4
  19. package/board/agents/data-platform-reviewer.md +2 -2
  20. package/board/agents/db-migration-reviewer.md +2 -2
  21. package/board/agents/decision-scorer.md +3 -3
  22. package/board/agents/design-advisor.md +3 -3
  23. package/board/agents/devops.md +12 -12
  24. package/board/agents/devtools-reviewer.md +2 -2
  25. package/board/agents/dpdpa-reviewer.md +2 -2
  26. package/board/agents/e2e-test-engineer.md +1 -1
  27. package/board/agents/edtech-reviewer.md +3 -3
  28. package/board/agents/enterprise-saas-reviewer.md +2 -2
  29. package/board/agents/firmware-reviewer.md +2 -2
  30. package/board/agents/game-reviewer.md +2 -2
  31. package/board/agents/gdpr-reviewer.md +3 -3
  32. package/board/agents/geo-routing-engineer.md +5 -5
  33. package/board/agents/gov-reviewer.md +2 -2
  34. package/board/agents/growth-engineer.md +3 -3
  35. package/board/agents/healthcare-reviewer.md +3 -3
  36. package/board/agents/hr-ai-reviewer.md +3 -3
  37. package/board/agents/infra-provisioner.md +3 -3
  38. package/board/agents/infra-reviewer.md +2 -2
  39. package/board/agents/insurance-reviewer.md +2 -2
  40. package/board/agents/integrations-engineer.md +5 -5
  41. package/board/agents/knowledge-extractor.md +2 -2
  42. package/board/agents/l3-support.md +8 -8
  43. package/board/agents/legal-reviewer.md +3 -3
  44. package/board/agents/library-reviewer.md +2 -2
  45. package/board/agents/marketplace-reviewer.md +2 -2
  46. package/board/agents/mcp-server-reviewer.md +2 -2
  47. package/board/agents/media-pipeline-engineer.md +5 -5
  48. package/board/agents/migration-import-engineer.md +5 -5
  49. package/board/agents/mlops-reviewer.md +2 -2
  50. package/board/agents/mobile-app-builder.md +6 -6
  51. package/board/agents/mobile-store-reviewer.md +2 -2
  52. package/board/agents/msp-reviewer.md +2 -2
  53. package/board/agents/oracle-reviewer.md +2 -2
  54. package/board/agents/pci-reviewer.md +2 -2
  55. package/board/agents/performance-engineer.md +3 -3
  56. package/board/agents/pm.md +6 -6
  57. package/board/agents/procurement-reviewer.md +2 -2
  58. package/board/agents/product-owner.md +5 -5
  59. package/board/agents/project-auditor.md +6 -6
  60. package/board/agents/qa-engineer.md +11 -11
  61. package/board/agents/quant-researcher.md +2 -2
  62. package/board/agents/rcm-reviewer.md +3 -3
  63. package/board/agents/regulated-reviewer.md +2 -2
  64. package/board/agents/security-officer.md +8 -8
  65. package/board/agents/senior-dev.md +7 -7
  66. package/board/agents/smart-contract-auditor.md +4 -4
  67. package/board/agents/streaming-reviewer.md +2 -2
  68. package/board/agents/subscription-billing-engineer.md +5 -5
  69. package/board/agents/tax-reviewer.md +3 -3
  70. package/board/agents/us-ai-reviewer.md +2 -2
  71. package/board/agents/us-privacy-reviewer.md +3 -3
  72. package/board/agents/voice-ai-reviewer.md +3 -3
  73. package/board/agents/web-store-reviewer.md +2 -2
  74. package/board/scripts/codex-pipeline.mjs +42 -7
  75. package/board/scripts/lib/agent-events.mjs +5 -1
  76. package/board/scripts/lib/cost-meter.mjs +34 -2
  77. package/board/scripts/lib/cross-model-review.mjs +107 -9
  78. package/board/scripts/lib/gate-tier.mjs +1 -1
  79. package/board/scripts/lib/host-graph-bindings.mjs +15 -3
  80. package/board/scripts/lib/host-graph-events.mjs +23 -4
  81. package/board/scripts/lib/host-graph-runtime.mjs +10 -3
  82. package/board/scripts/lib/kimi-review-profile.mjs +551 -0
  83. package/board/scripts/lib/kimi-review-store.mjs +469 -0
  84. package/board/scripts/lib/system-map.mjs +4 -2
  85. package/board/scripts/lib/work-publication.mjs +10 -9
  86. package/board/scripts/skill-lint.mjs +3 -3
  87. package/dist/main.js +82 -16
  88. package/dist/release-activation.mjs +3 -1
  89. package/dist/telemetry.js +2 -2
  90. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -66,6 +66,8 @@ function parseArgs(argv) {
66
66
  version: null,
67
67
  useLlm: false,
68
68
  noLlm: false,
69
+ noTelemetry: false,
70
+ rootArgv: argv,
69
71
  host: null,
70
72
  upgradeSelf: false,
71
73
  purgeData: false,
@@ -73,8 +75,18 @@ function parseArgs(argv) {
73
75
  positional: [],
74
76
  };
75
77
  const rest = [];
78
+ const telemetryFlagIndices = new Set();
79
+ const webhookValueOptions = new Set(["--secret", "--url", "--format", "--triggers", "--events", "--routing-key"]);
76
80
  for (let i = 0; i < argv.length; i++) {
77
81
  const a = argv[i];
82
+ // Webhook values may themselves look like options. Consume each owned
83
+ // value once so it cannot claim a later standalone root refusal as data.
84
+ if (args.command === "webhook" && webhookValueOptions.has(a)) {
85
+ rest.push(a);
86
+ if (i + 1 < argv.length)
87
+ rest.push(argv[++i]);
88
+ continue;
89
+ }
78
90
  if (a === "-h" || a === "--help")
79
91
  args.command = "help";
80
92
  else if (a === "-v" || a === "--version")
@@ -99,6 +111,10 @@ function parseArgs(argv) {
99
111
  args.useLlm = true;
100
112
  else if (a === "--no-llm")
101
113
  args.noLlm = true;
114
+ else if (a === "--no-telemetry") {
115
+ args.noTelemetry = true;
116
+ telemetryFlagIndices.add(i);
117
+ }
102
118
  else if (a === "--host") {
103
119
  const v = argv[++i] ?? "";
104
120
  args.hostInput = v;
@@ -121,8 +137,6 @@ function parseArgs(argv) {
121
137
  args.command = "console";
122
138
  else if (a === "telemetry")
123
139
  args.command = "telemetry";
124
- else if (a === "--no-telemetry")
125
- continue;
126
140
  else if (a === "distribution") {
127
141
  args.command = "distribution";
128
142
  args.taskArgs = argv.slice(i + 1);
@@ -200,7 +214,7 @@ function parseArgs(argv) {
200
214
  args._fromInstall = true;
201
215
  }
202
216
  }
203
- else if (!a.startsWith("-") && args.command === "init" && i === 0) {
217
+ else if (!a.startsWith("-") && args.command === "init" && i - telemetryFlagIndices.size === 0) {
204
218
  // First positional that isn't a recognised subcommand → unknown
205
219
  args.command = "unknown";
206
220
  args.unknownToken = a;
@@ -215,6 +229,9 @@ function parseArgs(argv) {
215
229
  }
216
230
  args.dir = resolve(args.dir);
217
231
  args.positional = rest;
232
+ // A consumed option value or an early-break tail belongs to its original
233
+ // parser. Filtering by value would erase literal data in either case.
234
+ args.rootArgv = argv.filter((_, i) => !telemetryFlagIndices.has(i));
218
235
  return args;
219
236
  }
220
237
  async function runRegister(args) {
@@ -870,6 +887,9 @@ ${bold("Options:")}
870
887
  even when heuristic confidence is high
871
888
  --no-llm Skip LLM suggestion (run heuristic only)
872
889
  Or set ${cyan("GREATCTO_NO_LLM=1")}
890
+ --no-telemetry Disable telemetry for this invocation, even if opted in
891
+ Put before task/worker/codex-host/run/status/resume/statusline
892
+ Does not disable update checks or command network access
873
893
  -h, --help Show this help
874
894
  -v, --version Show great-cto CLI version
875
895
 
@@ -1249,10 +1269,12 @@ async function runInit(args) {
1249
1269
  // ── 6. install pre-push git hook ─────────────────────────
1250
1270
  installPrePushHook(args.dir);
1251
1271
  // ── 7. opt-IN telemetry prompt (default OFF) ─────────────
1252
- await promoteTelemetryOptIn({ archetype: String(archetype), cliVersion: getCliVersion(), yes: args.yes });
1272
+ if (!args.noTelemetry) {
1273
+ await promoteTelemetryOptIn({ archetype: String(archetype), cliVersion: getCliVersion(), yes: args.yes });
1274
+ }
1253
1275
  // If already enabled (prior opt-in or env var), count this (re)install toward MAU.
1254
- if (isTelemetryEnabled()) {
1255
- await sendInstallPing({ cliVersion: getCliVersion(), archetype: String(archetype), consent: true })
1276
+ if (isTelemetryEnabled(args.noTelemetry)) {
1277
+ await sendInstallPing({ cliVersion: getCliVersion(), archetype: String(archetype), consent: true, noTelemetry: args.noTelemetry })
1256
1278
  .catch(() => { });
1257
1279
  }
1258
1280
  // ── done ─────────────────────────────────────────────────
@@ -1445,9 +1467,49 @@ async function reportCodexUpgrade() {
1445
1467
  }
1446
1468
  return 0;
1447
1469
  }
1470
+ // A successful write() may still have queued pipe bytes. Complete an ordered
1471
+ // empty write before forced exit, without keeping a broken consumer alive.
1472
+ function drainOutput(stream) {
1473
+ if (stream.destroyed || stream.closed || stream.writableFinished)
1474
+ return Promise.resolve(true);
1475
+ return new Promise((resolve) => {
1476
+ let settled = false;
1477
+ const finish = (complete) => {
1478
+ if (settled)
1479
+ return;
1480
+ settled = true;
1481
+ clearTimeout(timer);
1482
+ stream.off("error", completed);
1483
+ stream.off("close", completed);
1484
+ stream.off("finish", completed);
1485
+ resolve(complete);
1486
+ };
1487
+ const completed = () => finish(true);
1488
+ const timer = setTimeout(() => finish(false), 1000);
1489
+ timer.unref();
1490
+ stream.once("error", completed);
1491
+ stream.once("close", completed);
1492
+ stream.once("finish", completed);
1493
+ if (!stream.writableEnded) {
1494
+ try {
1495
+ stream.write("", (error) => {
1496
+ // Node emits the write error after its callback; leave the listener
1497
+ // in place for that event before cleaning up a callback-only failure.
1498
+ if (error)
1499
+ queueMicrotask(completed);
1500
+ else
1501
+ completed();
1502
+ });
1503
+ }
1504
+ catch {
1505
+ completed();
1506
+ }
1507
+ }
1508
+ });
1509
+ }
1448
1510
  async function main() {
1449
- const rawArgv = process.argv.slice(2);
1450
- const args = parseArgs(rawArgv);
1511
+ const args = parseArgs(process.argv.slice(2));
1512
+ const rawArgv = args.rootArgv;
1451
1513
  // Anonymous, opt-IN usage telemetry (default OFF — see docs/PRIVACY.md). `finish`
1452
1514
  // is the single exit funnel: it fires one fire-and-forget event (command + node + os
1453
1515
  // + exit_code + duration, no PII) only when the user has opted in, then exits.
@@ -1458,13 +1520,13 @@ async function main() {
1458
1520
  // widen types at every call site.
1459
1521
  const finish = async (code) => {
1460
1522
  try {
1461
- if (!rawArgv.includes("--no-telemetry"))
1462
- await sendUsagePing({
1463
- cliVersion: getCliVersion(),
1464
- subcommand: args.command,
1465
- exitCode: code,
1466
- durationMs: Date.now() - __tStart,
1467
- });
1523
+ await sendUsagePing({
1524
+ cliVersion: getCliVersion(),
1525
+ subcommand: args.command,
1526
+ exitCode: code,
1527
+ durationMs: Date.now() - __tStart,
1528
+ noTelemetry: args.noTelemetry,
1529
+ });
1468
1530
  }
1469
1531
  catch { /* telemetry never affects the exit */ }
1470
1532
  // Update hint / prompt — printed after the command's own output, never
@@ -1479,7 +1541,11 @@ async function main() {
1479
1541
  await checkForUpdate({ currentVersion: getCliVersion(), command: args.command });
1480
1542
  }
1481
1543
  catch { /* update hint never affects the exit */ }
1482
- process.exit(code);
1544
+ // An unref deadline cannot keep an otherwise empty event loop alive.
1545
+ // Until completion is proven, even that early exit must fail closed.
1546
+ process.exitCode = code || 1;
1547
+ const completed = await Promise.all([drainOutput(process.stdout), drainOutput(process.stderr)]);
1548
+ process.exit(completed.every(Boolean) ? code : code || 1);
1483
1549
  };
1484
1550
  // `great-cto telemetry <on|off|status|whoami>` — inspect / toggle, never sends.
1485
1551
  if (args.command === "distribution") {
@@ -183,8 +183,10 @@ function safeEnvironment(tx, npmPath) {
183
183
  fs.mkdirSync(temp, { mode: 0o700 });
184
184
  const config = path.join(tx, 'empty.npmrc');
185
185
  fs.writeFileSync(config, '', { flag: 'wx', mode: 0o600 });
186
+ const globalConfig = path.join(tx, 'empty-global.npmrc');
187
+ fs.writeFileSync(globalConfig, '', { flag: 'wx', mode: 0o600 });
186
188
  return { PATH: [path.dirname(process.execPath), path.dirname(npmPath), '/usr/bin', '/bin', '/usr/sbin', '/sbin'].join(path.delimiter),
187
- HOME: home, USERPROFILE: home, TMPDIR: temp, NPM_CONFIG_USERCONFIG: config, NPM_CONFIG_GLOBALCONFIG: config,
189
+ HOME: home, USERPROFILE: home, TMPDIR: temp, NPM_CONFIG_USERCONFIG: config, NPM_CONFIG_GLOBALCONFIG: globalConfig,
188
190
  NPM_CONFIG_CACHE: path.join(tx, 'npm-cache'), NPM_CONFIG_IGNORE_SCRIPTS: 'true', NPM_CONFIG_OFFLINE: 'true',
189
191
  NPM_CONFIG_AUDIT: 'false', NPM_CONFIG_FUND: 'false', NPM_CONFIG_PACKAGE_LOCK: 'false',
190
192
  DO_NOT_TRACK: '1', GREAT_CTO_TELEMETRY: 'off', GREAT_CTO_NO_BOARD: '1', GREAT_CTO_NO_UPDATE_CHECK: '1', CI: '1' };
package/dist/telemetry.js CHANGED
@@ -150,7 +150,7 @@ async function send(evt) {
150
150
  export async function sendInstallPing(opts) {
151
151
  if (!opts.consent)
152
152
  return;
153
- if (!isTelemetryEnabled())
153
+ if (!isTelemetryEnabled(opts.noTelemetry))
154
154
  return;
155
155
  const evt = sanitize({ cliVersion: opts.cliVersion, command: "install", archetype: opts.archetype });
156
156
  if (!evt)
@@ -159,7 +159,7 @@ export async function sendInstallPing(opts) {
159
159
  }
160
160
  /** Per-command usage ping. Sent only when enabled. Fire-and-forget. */
161
161
  export async function sendUsagePing(opts) {
162
- if (!isTelemetryEnabled())
162
+ if (!isTelemetryEnabled(opts.noTelemetry))
163
163
  return;
164
164
  const evt = sanitize({
165
165
  cliVersion: opts.cliVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "3.72.0",
3
+ "version": "3.74.0",
4
4
  "description": "One command install for the great_cto Claude Code plugin. Auto-detects your stack, picks the right archetype, bootstraps PROJECT.md.",
5
5
  "keywords": [
6
6
  "claude-code",