great-cto 2.32.0 → 2.33.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/dist/companion.js CHANGED
@@ -42,7 +42,11 @@ function isAlreadyInstalled(name) {
42
42
  return null;
43
43
  try {
44
44
  const versions = readdirSync(base).filter((v) => /\S/.test(v));
45
- return versions.length > 0 ? versions[0] : null;
45
+ if (versions.length === 0)
46
+ return null;
47
+ // Return the highest version, not filesystem order — matches
48
+ // upgrade.ts/installer.ts which both sort before picking.
49
+ return versions.sort(semverDescending)[0];
46
50
  }
47
51
  catch {
48
52
  return null;
package/dist/detect.js CHANGED
@@ -1118,7 +1118,7 @@ function mineReadmeKeywords(dir) {
1118
1118
  if (terms.some((t) => text.includes(t)))
1119
1119
  kws.add(bucket);
1120
1120
  }
1121
- // Wave 1-3 pack-trigger raw terms — emitted verbatim so packs.ts
1121
+ // Wave 1-4 pack-trigger raw terms — emitted verbatim so packs.ts
1122
1122
  // can substring-match them. Keep in sync with packs.ts SIGNALS.keywords.
1123
1123
  // Single tokens + multi-word phrases supported.
1124
1124
  const packTerms = [
@@ -1163,6 +1163,19 @@ function mineReadmeKeywords(dir) {
1163
1163
  "glp", "gmp", "gxp", "preclinical", "lims", "eln", "annex 11", "alcoa",
1164
1164
  "lab automation", "robotic biology", "liquid handler", "hamilton", "tecan",
1165
1165
  "beckman", "opentrons", "plate reader", "sequencer", "hplc", "mass spec", "sila",
1166
+ // digital-health-pack (Wave 4) — keep in sync with packs.ts SIGNALS.keywords
1167
+ "wearable", "apple watch", "apple health", "healthkit", "health connect",
1168
+ "garmin", "samsung health", "google fit", "fitbit", "heart rate", "hrv",
1169
+ "heart rate variability", "spo2", "sleep tracking", "sleep stages",
1170
+ "biometric sensor", "stress score", "activity tracking", "ecg wearable",
1171
+ "mental health", "mental wellness", "wellbeing", "mindfulness ai",
1172
+ "stress detection", "burnout detection", "mood tracking", "anxiety ai",
1173
+ "depression ai", "phq-9", "gad-7", "digital therapeutics", "dtx",
1174
+ "cbt app", "dbt app", "therapy ai", "personalised training",
1175
+ "personalized training", "fitness ai", "nutrition ai",
1176
+ "supplement recommendation", "supplement ai", "diet ai", "meal plan ai",
1177
+ "macro ai", "physician review", "physician hitl", "doctor in the loop",
1178
+ "clinical review workflow", "remote patient monitoring", "rpm", "teleconsultation",
1166
1179
  ];
1167
1180
  for (const term of packTerms) {
1168
1181
  if (text.includes(term))
package/dist/main.js CHANGED
@@ -915,8 +915,11 @@ async function main() {
915
915
  if (args.command === "serve") {
916
916
  try {
917
917
  const { runServe } = await import("./serve.js");
918
+ const explicitPort = rawArgv.some((a) => a === "--port" || a.startsWith("--port="));
918
919
  const code = await runServe({
919
- port: args.boardPort === 3141 ? 3142 : args.boardPort,
920
+ // serve defaults to 3142 (board uses 3141). Honor an explicit --port
921
+ // of any value, including 3141 — only fall back to 3142 when unset.
922
+ port: explicitPort ? args.boardPort : 3142,
920
923
  noLog: rawArgv.includes("--no-log"),
921
924
  insecure: rawArgv.includes("--insecure"),
922
925
  });
package/dist/report.js CHANGED
@@ -45,10 +45,14 @@ function readAllVerdicts() {
45
45
  return out.sort((a, b) => a.ts.localeCompare(b.ts));
46
46
  }
47
47
  function periodToCutoff(period) {
48
- const m = period.match(/^(\d+)d$/);
49
- if (!m)
48
+ // "all" intentionally returns "" → every verdict passes the `ts >= cutoff`
49
+ // filter (no lower bound).
50
+ if (period === "all")
50
51
  return "";
51
- const days = parseInt(m[1], 10);
52
+ // Malformed input (e.g. "30" without the "d", "1w") must NOT silently fall
53
+ // through to all-time — fall back to the documented 30d default instead.
54
+ const m = period.match(/^(\d+)d$/);
55
+ const days = m ? parseInt(m[1], 10) : 30;
52
56
  return new Date(Date.now() - days * 86_400_000).toISOString();
53
57
  }
54
58
  // ── Cost report ────────────────────────────────────────────────────────────
package/dist/upgrade.js CHANGED
@@ -37,6 +37,19 @@ export async function upgradePlugin(plugin) {
37
37
  const { name, repoUrl } = plugin;
38
38
  const currentVersion = getInstalledVersion(name);
39
39
  const latestTag = detectLatestTag(repoUrl);
40
+ // Could not reach the remote (offline / rate-limited / git error).
41
+ // If we already have a working install, keep it — never delete a good
42
+ // version because of a transient network failure (upgrade is documented
43
+ // as idempotent and safe to run any time).
44
+ if (latestTag === null && currentVersion) {
45
+ return {
46
+ name,
47
+ status: "skipped",
48
+ fromVersion: currentVersion,
49
+ toVersion: currentVersion,
50
+ reason: "could not reach remote to check latest version — kept existing install",
51
+ };
52
+ }
40
53
  const latestVersion = latestTag ?? "main";
41
54
  // Already on latest — just re-apply overlays in case they were missing
42
55
  if (currentVersion && currentVersion === latestVersion) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "2.32.0",
3
+ "version": "2.33.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",