@jhizzard/termdeck 1.0.11 → 1.0.13
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/README.md +4 -0
- package/package.json +1 -1
- package/packages/cli/src/doctor.js +72 -7
- package/packages/cli/src/index.js +115 -2
- package/packages/cli/src/init-mnestra.js +14 -5
- package/packages/cli/src/stack.js +39 -10
- package/packages/client/public/app.js +164 -5
- package/packages/client/public/graph.js +19 -1
- package/packages/client/public/style.css +5 -0
- package/packages/server/src/agent-adapters/claude.js +28 -1
- package/packages/server/src/config.js +4 -2
- package/packages/server/src/flashback-diag.js +79 -0
- package/packages/server/src/graph-routes.js +142 -25
- package/packages/server/src/index.js +111 -7
- package/packages/server/src/rag-mode.js +43 -0
- package/packages/server/src/setup/dotenv-io.js +12 -3
- package/packages/server/src/setup/supabase-url.js +39 -8
- package/packages/server/src/spawn-shell.js +27 -0
|
@@ -9,6 +9,26 @@
|
|
|
9
9
|
// - init-rumen needs the project ref to run `supabase link --project-ref`
|
|
10
10
|
// and to substitute into the pg_cron schedule SQL.
|
|
11
11
|
|
|
12
|
+
// Brad #2 (Sprint 59) — strip ONE pair of matched surrounding single OR
|
|
13
|
+
// double quotes from a string. Idempotent: a value with no quotes returns
|
|
14
|
+
// unchanged, mismatched quotes (`"foo'`, `bar"`) return unchanged. The
|
|
15
|
+
// dotenv parsers in config.js / dotenv-io.js / launcher.js already strip
|
|
16
|
+
// at file-read time, but Brad's reproducer ships the literal-quoted value
|
|
17
|
+
// through process.env (shell `export DATABASE_URL="\"$URL\""`), bypassing
|
|
18
|
+
// the file parsers entirely. Adding the strip here defends the validator
|
|
19
|
+
// boundary so any caller that hands us a quoted env-var value gets the
|
|
20
|
+
// same handling as a quoted secrets.env line.
|
|
21
|
+
function stripSurroundingQuotes(value) {
|
|
22
|
+
if (typeof value !== 'string') return value;
|
|
23
|
+
if (value.length < 2) return value;
|
|
24
|
+
const first = value[0];
|
|
25
|
+
const last = value[value.length - 1];
|
|
26
|
+
if ((first === '"' || first === "'") && first === last) {
|
|
27
|
+
return value.slice(1, -1);
|
|
28
|
+
}
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
|
|
12
32
|
// A Supabase project URL looks like:
|
|
13
33
|
// https://<project-ref>.supabase.co
|
|
14
34
|
// The ref is 20 characters of lowercase alphanumerics, but we accept anything
|
|
@@ -17,7 +37,7 @@ function parseProjectUrl(url) {
|
|
|
17
37
|
if (!url || typeof url !== 'string') {
|
|
18
38
|
return { ok: false, error: 'empty url' };
|
|
19
39
|
}
|
|
20
|
-
const trimmed = url.trim().replace(/\/+$/, '');
|
|
40
|
+
const trimmed = stripSurroundingQuotes(url.trim()).replace(/\/+$/, '');
|
|
21
41
|
let u;
|
|
22
42
|
try {
|
|
23
43
|
u = new URL(trimmed);
|
|
@@ -82,9 +102,10 @@ function looksLikeAnthropicKey(key) {
|
|
|
82
102
|
// and direct connection URLs (`postgres://postgres:...@db.<ref>.supabase.co:5432/postgres`).
|
|
83
103
|
function looksLikePostgresUrl(url) {
|
|
84
104
|
if (!url || typeof url !== 'string') return 'empty';
|
|
105
|
+
const stripped = stripSurroundingQuotes(url.trim());
|
|
85
106
|
let u;
|
|
86
107
|
try {
|
|
87
|
-
u = new URL(
|
|
108
|
+
u = new URL(stripped);
|
|
88
109
|
} catch (_err) {
|
|
89
110
|
return 'not a valid URL';
|
|
90
111
|
}
|
|
@@ -137,16 +158,25 @@ function isTransactionPoolerUrl(parsedUrl) {
|
|
|
137
158
|
// because validation is the caller's job (looksLikePostgresUrl handles that).
|
|
138
159
|
function normalizeDatabaseUrl(url) {
|
|
139
160
|
if (!url || typeof url !== 'string') return { url, modified: false };
|
|
161
|
+
// Brad #2: strip surrounding quotes silently — `modified` stays scoped
|
|
162
|
+
// to "appended pgbouncer params" so the caller's user-facing message
|
|
163
|
+
// ("Detected transaction pooler URL — appending ...") doesn't fire for
|
|
164
|
+
// a no-op quote strip. The strip itself is reflected in the returned
|
|
165
|
+
// `url` so downstream `new URL(normalized.url)` / pg.Pool consumers
|
|
166
|
+
// don't re-throw.
|
|
167
|
+
const stripped = stripSurroundingQuotes(url.trim());
|
|
140
168
|
let u;
|
|
141
169
|
try {
|
|
142
|
-
u = new URL(
|
|
170
|
+
u = new URL(stripped);
|
|
143
171
|
} catch (_err) {
|
|
144
|
-
return { url, modified: false };
|
|
172
|
+
return { url: stripped, modified: false };
|
|
145
173
|
}
|
|
146
|
-
if (!isTransactionPoolerUrl(u)) return { url, modified: false };
|
|
174
|
+
if (!isTransactionPoolerUrl(u)) return { url: stripped, modified: false };
|
|
147
175
|
|
|
148
|
-
// Already has pgbouncer set? Don't touch
|
|
149
|
-
|
|
176
|
+
// Already has pgbouncer set? Don't touch — but still return the stripped URL,
|
|
177
|
+
// not the original (Sprint 59 T4-CODEX residual fix: pre-fix returned `url`,
|
|
178
|
+
// which would re-leak surrounding quotes from a quoted-pgbouncer-URL secrets.env).
|
|
179
|
+
if (u.searchParams.has('pgbouncer')) return { url: stripped, modified: false };
|
|
150
180
|
|
|
151
181
|
u.searchParams.set('pgbouncer', 'true');
|
|
152
182
|
// Set connection_limit only if not already set — preserve user intent.
|
|
@@ -171,5 +201,6 @@ module.exports = {
|
|
|
171
201
|
looksLikePostgresUrl,
|
|
172
202
|
isTransactionPoolerUrl,
|
|
173
203
|
normalizeDatabaseUrl,
|
|
174
|
-
maskSecret
|
|
204
|
+
maskSecret,
|
|
205
|
+
stripSurroundingQuotes
|
|
175
206
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Sprint 59 T2 — PTY shell fallback chain helper (Brad #5).
|
|
2
|
+
//
|
|
3
|
+
// Pre-Sprint-59 the call site at packages/server/src/index.js:958 was:
|
|
4
|
+
// const spawnShell = isPlainShell ? cmdTrim : (config.shell || '/bin/zsh');
|
|
5
|
+
// Three failure modes converged on minimal Linux: (a) config.shell empty/unread
|
|
6
|
+
// because the YAML key was wiped or never set, (b) $SHELL ignored entirely,
|
|
7
|
+
// (c) /bin/zsh absent on the host. Result was a silent
|
|
8
|
+
// `execvp(3) failed: No such file or directory` from pty.spawn. The user's
|
|
9
|
+
// login shell was bypassed.
|
|
10
|
+
//
|
|
11
|
+
// /bin/sh is universally present on POSIX; /bin/zsh is not. The chain is:
|
|
12
|
+
// explicit cmdTrim → user's config.shell → $SHELL → /bin/sh universal floor.
|
|
13
|
+
// Caller (index.js) still owns the isPlainShell vs. -c branching; this helper
|
|
14
|
+
// only resolves the FALLBACK chain for the !isPlainShell branch (and for any
|
|
15
|
+
// future caller that wants a single-source-of-truth shell pick).
|
|
16
|
+
//
|
|
17
|
+
// The function intentionally treats "" and undefined identically — both
|
|
18
|
+
// participate in the falsy-OR chain. That matches how config.shell ends up
|
|
19
|
+
// empty when the user has `shell:` (no value) in ~/.termdeck/config.yaml,
|
|
20
|
+
// and how process.env.SHELL is undefined on container-like environments
|
|
21
|
+
// that strip the inherited shell var.
|
|
22
|
+
|
|
23
|
+
function resolveSpawnShell(cmdTrim, configShell, envShell) {
|
|
24
|
+
return cmdTrim || configShell || envShell || '/bin/sh';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { resolveSpawnShell };
|