@dench.com/cli 0.4.3 → 0.4.4
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/chat.ts +33 -8
- package/crm.ts +388 -17
- package/dench +4 -0
- package/dench.mjs +4 -0
- package/dench.ts +24 -0
- package/fs-daemon.ts +1 -0
- package/home-sync +10 -0
- package/home-sync-lib.ts +185 -0
- package/home-sync.ts +231 -0
- package/lib/crm-enrichment.ts +431 -0
- package/lib/enrichment-gateway.ts +279 -0
- package/lib/load-dev-env.mjs +102 -0
- package/package.json +6 -2
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// When `./dench` (or `./dench.mjs`) runs through Node from inside the
|
|
2
|
+
// dench.com source tree, Node does not auto-load workspace `.env` files
|
|
3
|
+
// the way Bun does for `bun run`. That made every gateway-backed
|
|
4
|
+
// subcommand (`dench apps`, `dench tool …`, the enrichment helpers,
|
|
5
|
+
// etc.) silently default to production
|
|
6
|
+
// (`https://gateway.merseoriginals.com`), because `cli/tools.ts`
|
|
7
|
+
// resolves the gateway URL purely from `process.env`. A dev-issued
|
|
8
|
+
// `DENCH_API_KEY` then 401'd against prod with `invalid_api_key`.
|
|
9
|
+
//
|
|
10
|
+
// This helper detects the dench.com source tree (via the parent
|
|
11
|
+
// `package.json` name) and loads `.env` then `.env.local` from the repo
|
|
12
|
+
// root. Globally-installed and sandbox-baked CLI installs never see
|
|
13
|
+
// that marker, so this is a no-op there. Existing `process.env` values
|
|
14
|
+
// always win, so explicit shell exports (e.g.
|
|
15
|
+
// `GATEWAY_URL=… ./dench …`) still take precedence over file values.
|
|
16
|
+
|
|
17
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
18
|
+
import { dirname, join } from "node:path";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
|
|
21
|
+
const WORKSPACE_PACKAGE_NAME = "ironclaw-cloud";
|
|
22
|
+
const ENV_FILES = [".env", ".env.local"];
|
|
23
|
+
|
|
24
|
+
export function loadDevEnv(callerUrl) {
|
|
25
|
+
try {
|
|
26
|
+
const here = dirname(fileURLToPath(callerUrl));
|
|
27
|
+
const repoRoot = dirname(here);
|
|
28
|
+
const pkgPath = join(repoRoot, "package.json");
|
|
29
|
+
if (!existsSync(pkgPath)) return;
|
|
30
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
31
|
+
if (pkg?.name !== WORKSPACE_PACKAGE_NAME) return;
|
|
32
|
+
|
|
33
|
+
for (const filename of ENV_FILES) {
|
|
34
|
+
const path = join(repoRoot, filename);
|
|
35
|
+
if (!existsSync(path)) continue;
|
|
36
|
+
const text = readFileSync(path, "utf8");
|
|
37
|
+
for (const [key, value] of parseEnv(text)) {
|
|
38
|
+
if (key in process.env) continue;
|
|
39
|
+
process.env[key] = value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
// Never break the CLI just because env loading failed.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Minimal `.env` parser: handles `KEY=value`, `KEY="value"`, `KEY='value'`,
|
|
48
|
+
// `export KEY=value`, comments, blank lines, and multi-line double-quoted
|
|
49
|
+
// values (e.g. JWT_PRIVATE_KEY="-----BEGIN ... -----END ..."). Skips lines
|
|
50
|
+
// that don't match the shape rather than throwing.
|
|
51
|
+
function* parseEnv(text) {
|
|
52
|
+
let i = 0;
|
|
53
|
+
while (i < text.length) {
|
|
54
|
+
while (i < text.length && /\s/.test(text[i])) i++;
|
|
55
|
+
if (i >= text.length) break;
|
|
56
|
+
if (text[i] === "#") {
|
|
57
|
+
while (i < text.length && text[i] !== "\n") i++;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (text.startsWith("export ", i)) i += 7;
|
|
61
|
+
while (i < text.length && (text[i] === " " || text[i] === "\t")) i++;
|
|
62
|
+
|
|
63
|
+
const keyStart = i;
|
|
64
|
+
while (i < text.length && /[A-Za-z0-9_]/.test(text[i])) i++;
|
|
65
|
+
const key = text.slice(keyStart, i);
|
|
66
|
+
if (!key || text[i] !== "=") {
|
|
67
|
+
while (i < text.length && text[i] !== "\n") i++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
i++;
|
|
71
|
+
|
|
72
|
+
let value;
|
|
73
|
+
if (text[i] === '"' || text[i] === "'") {
|
|
74
|
+
const quote = text[i++];
|
|
75
|
+
const valStart = i;
|
|
76
|
+
while (i < text.length && text[i] !== quote) {
|
|
77
|
+
if (quote === '"' && text[i] === "\\" && i + 1 < text.length) {
|
|
78
|
+
i += 2;
|
|
79
|
+
} else {
|
|
80
|
+
i++;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
value = text.slice(valStart, i);
|
|
84
|
+
if (quote === '"') {
|
|
85
|
+
value = value
|
|
86
|
+
.replace(/\\n/g, "\n")
|
|
87
|
+
.replace(/\\r/g, "\r")
|
|
88
|
+
.replace(/\\t/g, "\t")
|
|
89
|
+
.replace(/\\"/g, '"')
|
|
90
|
+
.replace(/\\\\/g, "\\");
|
|
91
|
+
}
|
|
92
|
+
if (text[i] === quote) i++;
|
|
93
|
+
} else {
|
|
94
|
+
const valStart = i;
|
|
95
|
+
while (i < text.length && text[i] !== "\n" && text[i] !== "#") i++;
|
|
96
|
+
value = text.slice(valStart, i).trim();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
while (i < text.length && text[i] !== "\n") i++;
|
|
100
|
+
yield [key, value];
|
|
101
|
+
}
|
|
102
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dench.com/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "Dench agent workspace CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"dench": "dench",
|
|
8
|
-
"dench-fs-daemon": "fs-daemon"
|
|
8
|
+
"dench-fs-daemon": "fs-daemon",
|
|
9
|
+
"dench-home-sync": "home-sync"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|
|
11
12
|
"dench",
|
|
@@ -16,6 +17,9 @@
|
|
|
16
17
|
"fs-daemon-binary.ts",
|
|
17
18
|
"fs-daemon-flush.ts",
|
|
18
19
|
"fs-daemon-mount.ts",
|
|
20
|
+
"home-sync",
|
|
21
|
+
"home-sync.ts",
|
|
22
|
+
"home-sync-lib.ts",
|
|
19
23
|
"agent.ts",
|
|
20
24
|
"chat.ts",
|
|
21
25
|
"chat-spawn.ts",
|