@youdie006/prodex 0.16.7 → 0.16.9

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.
@@ -867,16 +867,28 @@ export function proSubmenuExpanderRectExpression() {
867
867
  export function projectItemRectExpression(name) {
868
868
  return `(() => {${CLICK_POINT_SNIPPET}
869
869
  // Korean: "<name> 프로젝트 옵션 열기"; English: "Open project options for <name>".
870
- const opt = [...document.querySelectorAll('[aria-label*="프로젝트 옵션"],[aria-label*="project options" i]')].find((b) => (b.getAttribute("aria-label") || "").includes(${JSON.stringify(name)}));
870
+ const wanted = ${JSON.stringify(name)};
871
+ const optionButtons = [...document.querySelectorAll('[aria-label*="프로젝트 옵션"],[aria-label*="project options" i]')];
872
+ let opt = optionButtons.find((b) => (b.getAttribute("aria-label") || "").includes(wanted));
873
+ if (!opt) {
874
+ // Case-insensitive fallback: sidebar names are user-typed ("Codex") and
875
+ // an agent asking for "codex" should still resolve when unambiguous.
876
+ // Ambiguity fails loudly rather than guessing.
877
+ const ci = optionButtons.filter((b) => (b.getAttribute("aria-label") || "").toLowerCase().includes(wanted.toLowerCase()));
878
+ if (ci.length === 1) opt = ci[0];
879
+ else if (ci.length > 1) return { ok: false, reason: "project name matches multiple sidebar projects case-insensitively; use the exact name" };
880
+ }
871
881
  let target = opt ? (opt.closest('a,[role="link"],li') || opt.parentElement) : null;
872
882
  if (!target) {
873
883
  const icons = [...document.querySelectorAll('[data-testid="project-folder-icon"]')];
874
884
  for (const ic of icons) {
875
885
  const row = ic.closest('a,li,[role="link"]') || ic.parentElement?.parentElement;
876
- if (row && (row.textContent || "").includes(${JSON.stringify(name)})) { target = row; break; }
886
+ if (row && (row.textContent || "").includes(wanted)) { target = row; break; }
877
887
  }
878
888
  }
879
- if (!target) return { ok: false, reason: "project not found in sidebar" };
889
+ if (!target) {
890
+ return { ok: false, reason: "project not found in sidebar (" + optionButtons.length + " projects visible; names are matched exactly first, then case-insensitively - check the exact sidebar spelling)" };
891
+ }
880
892
  // 2026-07 ChatGPT update: the project row (li) is no longer a link - the
881
893
  // navigation affordance is a dedicated "Open project home" button inside
882
894
  // the row (verified live: clicking the row does nothing, clicking the home
package/dist/cli-pro.js CHANGED
@@ -692,10 +692,17 @@ export async function runAskProCommand(rest, io) {
692
692
  }
693
693
  const answerArtifactText = formatProConsultArtifact(consult);
694
694
  const persistenceWarnings = [...consult.warnings];
695
+ // A send with no model selection at all (no per-ask flag, no saved
696
+ // default) silently uses whatever the ChatGPT UI last had selected -
697
+ // after the 2026-07 update reset that to Medium, consults meant for Pro
698
+ // quietly ran on a mid-tier model. Warn loudly and record it.
699
+ if (!selectionModel && !selectionProMode && !selectionEffort) {
700
+ persistenceWarnings.push("model_selection_warning: no model/effort was selected for this send (no per-ask flag, no saved default), so it used whatever the ChatGPT UI last had selected. Pin one with `prodex setup --model Pro` or pass --model/--effort.");
701
+ }
695
702
  // Truncation and other send warnings must be visible at runtime, not
696
703
  // only inside the persisted receipt: a caller who never opens .bridge
697
704
  // would otherwise treat a cut-off answer as complete.
698
- for (const warning of consult.warnings)
705
+ for (const warning of persistenceWarnings)
699
706
  io.stderr(warning);
700
707
  let answerArtifactPath;
701
708
  const answerArtifactBytes = Buffer.byteLength(answerArtifactText, "utf8");
package/dist/config.js CHANGED
@@ -76,9 +76,14 @@ export async function writeLocalConfig(cwd, input = {}) {
76
76
  const now = new Date().toISOString();
77
77
  const host = normalizeLoopbackHttpHost(input.host ?? "127.0.0.1");
78
78
  const port = input.port ?? 8787;
79
- const token = input.token ?? randomBytes(24).toString("hex");
80
- const tokenExpiresAt = computeTokenExpiresAt(input.tokenTtlHours, now);
81
79
  const existing = await readExistingConfig(cwd);
80
+ // A setup re-run that only adjusts defaults/host/port must NOT rotate the
81
+ // token - that would silently 401 every client holding the old MCP URL.
82
+ // Rotation happens only when the caller explicitly asks for a token
83
+ // (--token) or a fresh expiry (--token-ttl-hours).
84
+ const tokenExplicitlyRequested = input.token !== undefined || input.tokenTtlHours !== undefined;
85
+ const token = input.token ?? (tokenExplicitlyRequested ? undefined : existing?.token) ?? randomBytes(24).toString("hex");
86
+ const tokenExpiresAt = tokenExplicitlyRequested || !existing ? computeTokenExpiresAt(input.tokenTtlHours, now) : existing.token_expires_at;
82
87
  const browserDefaults = mergeBrowserDefaults(existing?.browser_defaults, input.browserDefaults);
83
88
  const config = LocalConfigSchema.parse({
84
89
  schema_version: SCHEMA_VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdie006/prodex",
3
- "version": "0.16.7",
3
+ "version": "0.16.9",
4
4
  "description": "Local receipt bus for coordinating Codex execution with ChatGPT Pro/Projects consultation.",
5
5
  "author": "youdie006",
6
6
  "license": "MIT",