hacklab 0.7.5 → 0.9.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/README.md +20 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +147 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/book.d.ts +14 -0
- package/dist/commands/book.d.ts.map +1 -0
- package/dist/commands/book.js +90 -0
- package/dist/commands/book.js.map +1 -0
- package/dist/commands/chat.d.ts +1 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +3 -0
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/hacker.js +18 -9
- package/dist/commands/hacker.js.map +1 -1
- package/dist/commands/join.d.ts +4 -2
- package/dist/commands/join.d.ts.map +1 -1
- package/dist/commands/join.js +78 -45
- package/dist/commands/join.js.map +1 -1
- package/dist/commands/keys.d.ts +2 -0
- package/dist/commands/keys.d.ts.map +1 -0
- package/dist/commands/keys.js +138 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +3 -6
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/org.d.ts +7 -7
- package/dist/commands/org.d.ts.map +1 -1
- package/dist/commands/org.js +407 -32
- package/dist/commands/org.js.map +1 -1
- package/dist/commands/profile.d.ts.map +1 -1
- package/dist/commands/profile.js +1 -5
- package/dist/commands/profile.js.map +1 -1
- package/dist/commands/scout.d.ts +18 -0
- package/dist/commands/scout.d.ts.map +1 -0
- package/dist/commands/scout.js +232 -0
- package/dist/commands/scout.js.map +1 -0
- package/dist/daily-sync.d.ts +16 -1
- package/dist/daily-sync.d.ts.map +1 -1
- package/dist/daily-sync.js +66 -2
- package/dist/daily-sync.js.map +1 -1
- package/dist/field-normalize.d.ts +4 -0
- package/dist/field-normalize.d.ts.map +1 -0
- package/dist/field-normalize.js +8 -0
- package/dist/field-normalize.js.map +1 -0
- package/dist/index.js +18 -143
- package/dist/index.js.map +1 -1
- package/dist/machine.d.ts +15 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +64 -0
- package/dist/machine.js.map +1 -0
- package/dist/org-fields.d.ts +57 -0
- package/dist/org-fields.d.ts.map +1 -0
- package/dist/org-fields.js +167 -0
- package/dist/org-fields.js.map +1 -0
- package/dist/posthog.d.ts +34 -5
- package/dist/posthog.d.ts.map +1 -1
- package/dist/posthog.js +217 -13
- package/dist/posthog.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +25 -4
- package/dist/registry.js.map +1 -1
- package/dist/scanners/index.d.ts +6 -0
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +48 -51
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/sqlite.d.ts +18 -0
- package/dist/scanners/sqlite.d.ts.map +1 -0
- package/dist/scanners/sqlite.js +63 -0
- package/dist/scanners/sqlite.js.map +1 -0
- package/dist/sync.d.ts +3 -0
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +7 -0
- package/dist/sync.js.map +1 -1
- package/dist/ui.d.ts +1 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +5 -0
- package/dist/ui.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -1,149 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* The global flags, each mapping onto the env var the rest of the CLI already
|
|
18
|
-
* reads. Going through the env is what makes precedence fall out for free: the
|
|
19
|
-
* flag overwrites any inherited value, and the readers (getAppUrl,
|
|
20
|
-
* resolveCursorAuth) prefer the env over the config file. It also means a value
|
|
21
|
-
* passed once on the command line reaches anything the command shells out to.
|
|
22
|
-
*/
|
|
23
|
-
const GLOBAL_FLAGS = {
|
|
24
|
-
'--env': (value) => {
|
|
25
|
-
const env = resolveHacklabEnv(value);
|
|
26
|
-
if (!env) {
|
|
27
|
-
console.error(`--env must be one of: ${Object.keys(HACKLAB_ENVIRONMENTS).join(', ')} (abbreviations like dev/prod/stag work)`);
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
process.env.HACKLAB_APP_URL = HACKLAB_ENVIRONMENTS[env];
|
|
31
|
-
},
|
|
32
|
-
'--cursor-api-key': (value) => {
|
|
33
|
-
process.env.CURSOR_API_KEY = value;
|
|
34
|
-
},
|
|
35
|
-
'--cursor-email': (value) => {
|
|
36
|
-
process.env.CURSOR_EMAIL = value;
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* Pull the global flags out of argv and apply them, returning the remaining args
|
|
41
|
-
* so per-command parsing never sees them. Both `--flag value` and `--flag=value`
|
|
42
|
-
* spellings work.
|
|
43
|
-
*/
|
|
44
|
-
function applyGlobalFlags(argv) {
|
|
45
|
-
const rest = [];
|
|
46
|
-
for (let i = 0; i < argv.length; i++) {
|
|
47
|
-
const arg = argv[i];
|
|
48
|
-
const eq = arg.indexOf('=');
|
|
49
|
-
const name = eq === -1 ? arg : arg.slice(0, eq);
|
|
50
|
-
const apply = GLOBAL_FLAGS[name];
|
|
51
|
-
if (!apply) {
|
|
52
|
-
rest.push(arg);
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
const value = eq === -1 ? argv[++i] : arg.slice(eq + 1);
|
|
56
|
-
if (!value) {
|
|
57
|
-
console.error(`${name} requires a value`);
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
60
|
-
apply(value);
|
|
61
|
-
}
|
|
62
|
-
return rest;
|
|
63
|
-
}
|
|
64
|
-
const [cmd, ...args] = applyGlobalFlags(process.argv.slice(2));
|
|
65
|
-
function printHelp() {
|
|
66
|
-
banner();
|
|
67
|
-
console.log('');
|
|
68
|
-
console.log(bold('usage:'));
|
|
69
|
-
// Align the descriptions: pad to the widest `name + args` so the summaries
|
|
70
|
-
// line up no matter how the registry grows.
|
|
71
|
-
const rows = COMMANDS.map((c) => ({
|
|
72
|
-
label: c.args ? `${c.name} ${c.args}` : c.name,
|
|
73
|
-
summary: c.summary,
|
|
74
|
-
}));
|
|
75
|
-
const width = Math.max(...rows.map((r) => r.label.length));
|
|
76
|
-
for (const { label, summary } of rows) {
|
|
77
|
-
console.log(` hacklab ${dim(label)}${' '.repeat(width - label.length)} ${summary}`);
|
|
78
|
-
}
|
|
79
|
-
console.log('');
|
|
80
|
-
console.log(` ${dim('--env')} ${dim('<production|staging|development>')} pick the backend (default: production)`);
|
|
81
|
-
console.log(` ${dim('--cursor-api-key')} ${dim('<key>')} exact Cursor usage (or ${dim('CURSOR_API_KEY')})`);
|
|
82
|
-
console.log(` ${dim('--cursor-email')} ${dim('<email>')} scope a Cursor team key to you (or ${dim('CURSOR_EMAIL')})`);
|
|
83
|
-
console.log('');
|
|
84
|
-
}
|
|
85
|
-
// Node-version guard (T9). The CLI uses modern Node APIs (global fetch,
|
|
86
|
-
// AbortSignal.timeout). Fail fast with a clear message instead of a cryptic
|
|
87
|
-
// runtime error on an old runtime. The nvm hint matters because a piped
|
|
88
|
-
// `curl | sh` install runs in a non-interactive shell where nvm isn't sourced,
|
|
89
|
-
// so version-manager users are told to run npx directly in their own shell.
|
|
90
|
-
function enforceNodeVersion() {
|
|
91
|
-
const major = Number(process.versions.node.split('.')[0]);
|
|
92
|
-
if (Number.isFinite(major) && major < 20) {
|
|
93
|
-
console.error(`hacklab requires Node 20 or newer (you have ${process.versions.node}).`);
|
|
94
|
-
console.error('Using a version manager (nvm/fnm/volta)? Activate Node 20+ in your shell, then: npm install -g hacklab@latest');
|
|
95
|
-
process.exit(1);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
async function main() {
|
|
99
|
-
enforceNodeVersion();
|
|
100
|
-
// Bare `hacklab` (no command) prints help, same as `--help`/`-h`. Runs before
|
|
101
|
-
// the update nudge so it reads as plain help, matching the `--help` path.
|
|
102
|
-
if (!cmd || cmd === '--help' || cmd === '-h') {
|
|
103
|
-
printHelp();
|
|
104
|
-
process.exit(0);
|
|
105
|
-
}
|
|
106
|
-
if (cmd === '--version' || cmd === '-v') {
|
|
107
|
-
console.log(VERSION);
|
|
108
|
-
process.exit(0);
|
|
109
|
-
}
|
|
110
|
-
// One-line nudge if a newer hacklab is published (interactive only, cached
|
|
111
|
-
// daily, timeout-guarded). Must run before any command output so it reads as
|
|
112
|
-
// a header, not buried in results.
|
|
113
|
-
await notifyIfOutdated(VERSION);
|
|
114
|
-
// Resolve a possibly-abbreviated command to its full name (e.g. `sy` -> sync,
|
|
115
|
-
// `or` -> org). Exact matches always win; an ambiguous prefix is
|
|
116
|
-
// rejected with the candidates so the user can disambiguate.
|
|
117
|
-
const resolution = resolveCommand(cmd);
|
|
118
|
-
if (resolution.kind === 'ambiguous') {
|
|
119
|
-
console.error(`ambiguous command "${cmd}": ${resolution.matches.join(' or ')}?`);
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
const command = resolution.kind === 'match' ? findCommand(resolution.name) : undefined;
|
|
123
|
-
if (!command) {
|
|
124
|
-
console.error(`unknown command: ${cmd}`);
|
|
125
|
-
console.error('run hacklab --help for usage');
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
128
|
-
// Surface a paused daily background sync (e.g. the session expired while the
|
|
129
|
-
// machine was off) once, then clear the marker. Skipped for the auth commands
|
|
130
|
-
// that fix it (login/join), so we never nag mid-fix.
|
|
131
|
-
if (process.stdout.isTTY &&
|
|
132
|
-
command.name !== 'login' &&
|
|
133
|
-
command.name !== 'join') {
|
|
134
|
-
const paused = await readSyncPaused();
|
|
135
|
-
if (paused) {
|
|
136
|
-
console.error(dim(`paused: daily background sync — ${paused}`));
|
|
137
|
-
await clearSyncPaused();
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
await command.run(args);
|
|
2
|
+
// Minimal launcher. It checks the Node version using ONLY built-ins, then
|
|
3
|
+
// dynamically imports the real CLI — so nothing that needs a Node 20+ API is
|
|
4
|
+
// even *linked* until the guard passes. The real entry (cli.ts) pulls in
|
|
5
|
+
// @clack/core, which statically imports `styleText` from node:util (Node 20.12+);
|
|
6
|
+
// on Node 18 that fails to link with a cryptic SyntaxError *before* any code
|
|
7
|
+
// runs, so the version check has to happen here, ahead of that import graph.
|
|
8
|
+
//
|
|
9
|
+
// npm only warns (doesn't block) on an `engines` mismatch, and version-manager
|
|
10
|
+
// users can switch to an old Node after installing — so this runtime guard is
|
|
11
|
+
// the real gate, not package.json.
|
|
12
|
+
const major = Number(process.versions.node.split('.')[0]);
|
|
13
|
+
if (Number.isFinite(major) && major < 20) {
|
|
14
|
+
console.error(`hacklab requires Node 20 or newer (you have ${process.versions.node}).`);
|
|
15
|
+
console.error('Using a version manager (nvm/fnm/volta)? Activate Node 20+ in your shell, then: npm install -g hacklab@latest');
|
|
16
|
+
process.exit(1);
|
|
141
17
|
}
|
|
142
|
-
|
|
18
|
+
// Defer the real CLI (and its Node 20+ import graph) until after the guard.
|
|
19
|
+
import('./cli.js').catch((err) => {
|
|
143
20
|
console.error(err instanceof Error ? err.message : String(err));
|
|
144
|
-
const session = await loadSession().catch(() => null);
|
|
145
|
-
posthog.captureException(err, session?.handle);
|
|
146
|
-
await posthog.flush();
|
|
147
21
|
process.exit(1);
|
|
148
22
|
});
|
|
23
|
+
export {};
|
|
149
24
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,0EAA0E;AAC1E,6EAA6E;AAC7E,yEAAyE;AACzE,kFAAkF;AAClF,6EAA6E;AAC7E,6EAA6E;AAC7E,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,mCAAmC;AAEnC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AACzD,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;IACzC,OAAO,CAAC,KAAK,CACX,+CAA+C,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,CACzE,CAAA;IACD,OAAO,CAAC,KAAK,CACX,+GAA+G,CAChH,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACxC,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function getMachinePath(): string;
|
|
2
|
+
export type MachineIdentity = {
|
|
3
|
+
machineId: string;
|
|
4
|
+
/** Best-effort hostname for a friendlier "synced from N machines" UI later. */
|
|
5
|
+
machineName: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Load this machine's id, generating and persisting one on first use. Uses an
|
|
9
|
+
* exclusive create so two concurrent syncs (e.g. the daily daemon racing an
|
|
10
|
+
* interactive run) can't each mint a different id — the loser reads back the
|
|
11
|
+
* winner's file. Falls back to an ephemeral id only if the file can't be
|
|
12
|
+
* written at all, so sync never hard-fails on a read-only home directory.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getMachineIdentity(): Promise<MachineIdentity>;
|
|
15
|
+
//# sourceMappingURL=machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../src/machine.ts"],"names":[],"mappings":"AAoBA,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAyBD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CAoBnE"}
|
package/dist/machine.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir, hostname } from 'node:os';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
/**
|
|
6
|
+
* Stable per-machine identity for token sync.
|
|
7
|
+
*
|
|
8
|
+
* The backend sums token usage across a user's machines and needs each machine
|
|
9
|
+
* to be distinguishable so a re-run from one machine is idempotent (it replaces
|
|
10
|
+
* that machine's contribution) while a second machine adds on top. We identify a
|
|
11
|
+
* machine with a random id generated once and persisted here.
|
|
12
|
+
*
|
|
13
|
+
* The id is deliberately env-independent — a machine is one machine whether you
|
|
14
|
+
* `hacklab sync --env prod` or `--env dev`; each backend tracks that same id in
|
|
15
|
+
* its own database. So this lives next to the session, not per-backend.
|
|
16
|
+
*/
|
|
17
|
+
const MACHINE_PATH = join(homedir(), '.hacklab', 'machine.json');
|
|
18
|
+
export function getMachinePath() {
|
|
19
|
+
return process.env.HACKLAB_MACHINE_PATH ?? MACHINE_PATH;
|
|
20
|
+
}
|
|
21
|
+
function isValid(data) {
|
|
22
|
+
return (typeof data === 'object' &&
|
|
23
|
+
data !== null &&
|
|
24
|
+
typeof data.machineId === 'string' &&
|
|
25
|
+
data.machineId.length > 0);
|
|
26
|
+
}
|
|
27
|
+
async function readMachineId(path) {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
30
|
+
return isValid(parsed) ? parsed.machineId : null;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Load this machine's id, generating and persisting one on first use. Uses an
|
|
38
|
+
* exclusive create so two concurrent syncs (e.g. the daily daemon racing an
|
|
39
|
+
* interactive run) can't each mint a different id — the loser reads back the
|
|
40
|
+
* winner's file. Falls back to an ephemeral id only if the file can't be
|
|
41
|
+
* written at all, so sync never hard-fails on a read-only home directory.
|
|
42
|
+
*/
|
|
43
|
+
export async function getMachineIdentity() {
|
|
44
|
+
const path = getMachinePath();
|
|
45
|
+
const existing = await readMachineId(path);
|
|
46
|
+
if (existing)
|
|
47
|
+
return { machineId: existing, machineName: hostname() };
|
|
48
|
+
const machineId = randomUUID();
|
|
49
|
+
const body = `${JSON.stringify({ machineId, createdAt: new Date().toISOString() }, null, 2)}\n`;
|
|
50
|
+
try {
|
|
51
|
+
await mkdir(dirname(path), { recursive: true });
|
|
52
|
+
// 'wx' fails if another process created it first; re-read to adopt theirs.
|
|
53
|
+
await writeFile(path, body, { encoding: 'utf8', flag: 'wx' });
|
|
54
|
+
return { machineId, machineName: hostname() };
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
const raced = await readMachineId(path);
|
|
58
|
+
return {
|
|
59
|
+
machineId: raced ?? machineId,
|
|
60
|
+
machineName: hostname(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine.js","sourceRoot":"","sources":["../src/machine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEzC;;;;;;;;;;;GAWG;AAEH,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,cAAc,CAAC,CAAA;AAEhE,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,YAAY,CAAA;AACzD,CAAC;AAaD,SAAS,OAAO,CAAC,IAAa;IAC5B,OAAO,CACL,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,KAAK,IAAI;QACb,OAAQ,IAAgC,CAAC,SAAS,KAAK,QAAQ;QAC9D,IAA8B,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CACrD,CAAA;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,IAAY;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CAAA;QAClE,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,IAAI,GAAG,cAAc,EAAE,CAAA;IAE7B,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;IAC1C,IAAI,QAAQ;QAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,CAAA;IAErE,MAAM,SAAS,GAAG,UAAU,EAAE,CAAA;IAC9B,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAwB,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAA;IACrH,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC/C,2EAA2E;QAC3E,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,CAAA;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QACvC,OAAO;YACL,SAAS,EAAE,KAAK,IAAI,SAAS;YAC7B,WAAW,EAAE,QAAQ,EAAE;SACxB,CAAA;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export type OrgFieldType = 'text' | 'url' | 'number' | 'boolean' | 'list';
|
|
2
|
+
export type OrgFieldSpec = {
|
|
3
|
+
/** API key sent to /api/cli/org. */
|
|
4
|
+
key: string;
|
|
5
|
+
/** CLI-facing name (`hacklab org set <name> …`). */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Label shown in the interactive editor. */
|
|
8
|
+
label: string;
|
|
9
|
+
type: OrgFieldType;
|
|
10
|
+
};
|
|
11
|
+
export declare const ORG_FIELDS: OrgFieldSpec[];
|
|
12
|
+
export declare const ORG_FIELD_NAMES: string[];
|
|
13
|
+
export type OrgValue = string | number | boolean | string[] | null;
|
|
14
|
+
export type NormalizedOrgValue = {
|
|
15
|
+
ok: true;
|
|
16
|
+
value: OrgValue;
|
|
17
|
+
} | {
|
|
18
|
+
ok: false;
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Shape one raw CLI string into the value the API expects. Empty clears the
|
|
23
|
+
* field (except name/slug, which are required). URLs get https:// prepended
|
|
24
|
+
* when the scheme is missing; lists split on commas. Real validation (slug
|
|
25
|
+
* pattern, lengths, URL syntax) stays server-side.
|
|
26
|
+
*/
|
|
27
|
+
export declare function normalizeOrgFieldValue(spec: OrgFieldSpec, raw: string): NormalizedOrgValue;
|
|
28
|
+
/**
|
|
29
|
+
* Map a parsed yaml/json document to API fields for `org apply`. Keys may be
|
|
30
|
+
* CLI names (`long-description`, `hiring`) or API keys (`longDescription`,
|
|
31
|
+
* `isHiring`); unknown keys fail loudly so a typo can't silently drop a field.
|
|
32
|
+
* Lists accept real arrays or comma-separated strings.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseOrgDocument(doc: unknown): {
|
|
35
|
+
ok: true;
|
|
36
|
+
fields: Record<string, OrgValue>;
|
|
37
|
+
} | {
|
|
38
|
+
ok: false;
|
|
39
|
+
error: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Pick the org a view/set/apply targets. `--org <slug>` wins; with no flag,
|
|
43
|
+
* exactly one managed org is the target, zero or several is a typed error the
|
|
44
|
+
* caller renders (JSON gets the code, humans get the message — which always
|
|
45
|
+
* names the way out).
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveTargetOrg<T extends {
|
|
48
|
+
slug: string;
|
|
49
|
+
}>(organizations: T[], slugFlag: string | undefined): {
|
|
50
|
+
ok: true;
|
|
51
|
+
org: T;
|
|
52
|
+
} | {
|
|
53
|
+
ok: false;
|
|
54
|
+
code: 'no_org' | 'ambiguous_org' | 'not_found';
|
|
55
|
+
error: string;
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=org-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-fields.d.ts","sourceRoot":"","sources":["../src/org-fields.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAA;AAEzE,MAAM,MAAM,YAAY,GAAG;IACzB,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAA;IACX,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,YAAY,CAAA;CACnB,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,YAAY,EA4BpC,CAAA;AAED,eAAO,MAAM,eAAe,UAAgC,CAAA;AAK5D,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,GAAG,IAAI,CAAA;AAElE,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAShC;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,YAAY,EAClB,GAAG,EAAE,MAAM,GACV,kBAAkB,CA+BpB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GACzC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CAAE,GAC9C;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;CACd,CAqDJ;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACzD,aAAa,EAAE,CAAC,EAAE,EAClB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAE1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,CAAC,CAAA;CAAE,GACpB;IACE,EAAE,EAAE,KAAK,CAAA;IACT,IAAI,EAAE,QAAQ,GAAG,eAAe,GAAG,WAAW,CAAA;IAC9C,KAAK,EAAE,MAAM,CAAA;CACd,CA+BJ"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { ensureScheme, FALSE_WORDS, TRUE_WORDS } from './field-normalize.js';
|
|
2
|
+
export const ORG_FIELDS = [
|
|
3
|
+
{ key: 'name', name: 'name', label: 'Name', type: 'text' },
|
|
4
|
+
{ key: 'slug', name: 'slug', label: 'Slug (URL handle)', type: 'text' },
|
|
5
|
+
{ key: 'logoUrl', name: 'logo', label: 'Logo URL', type: 'url' },
|
|
6
|
+
{ key: 'website', name: 'website', label: 'Website', type: 'url' },
|
|
7
|
+
{
|
|
8
|
+
key: 'description',
|
|
9
|
+
name: 'description',
|
|
10
|
+
label: 'Short description',
|
|
11
|
+
type: 'text',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
key: 'longDescription',
|
|
15
|
+
name: 'long-description',
|
|
16
|
+
label: 'Long description',
|
|
17
|
+
type: 'text',
|
|
18
|
+
},
|
|
19
|
+
{ key: 'ycBatch', name: 'yc-batch', label: 'YC batch', type: 'text' },
|
|
20
|
+
{ key: 'ycSlug', name: 'yc-slug', label: 'YC slug', type: 'text' },
|
|
21
|
+
{ key: 'ycUrl', name: 'yc-url', label: 'YC URL', type: 'url' },
|
|
22
|
+
{ key: 'waasUrl', name: 'waas', label: 'WaaS URL', type: 'url' },
|
|
23
|
+
{ key: 'teamSize', name: 'team-size', label: 'Team size', type: 'number' },
|
|
24
|
+
{ key: 'status', name: 'status', label: 'Status', type: 'text' },
|
|
25
|
+
{ key: 'stage', name: 'stage', label: 'Stage', type: 'text' },
|
|
26
|
+
{ key: 'isHiring', name: 'hiring', label: 'Hiring?', type: 'boolean' },
|
|
27
|
+
{ key: 'industries', name: 'industries', label: 'Industries', type: 'list' },
|
|
28
|
+
{ key: 'tags', name: 'tags', label: 'Tags', type: 'list' },
|
|
29
|
+
{ key: 'locations', name: 'locations', label: 'Locations', type: 'list' },
|
|
30
|
+
];
|
|
31
|
+
export const ORG_FIELD_NAMES = ORG_FIELDS.map((f) => f.name);
|
|
32
|
+
// name and slug are notNull columns — a blank must fail loudly, not clear.
|
|
33
|
+
const REQUIRED_KEYS = new Set(['name', 'slug']);
|
|
34
|
+
function splitList(raw) {
|
|
35
|
+
return raw
|
|
36
|
+
.split(',')
|
|
37
|
+
.map((s) => s.trim())
|
|
38
|
+
.filter(Boolean);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Shape one raw CLI string into the value the API expects. Empty clears the
|
|
42
|
+
* field (except name/slug, which are required). URLs get https:// prepended
|
|
43
|
+
* when the scheme is missing; lists split on commas. Real validation (slug
|
|
44
|
+
* pattern, lengths, URL syntax) stays server-side.
|
|
45
|
+
*/
|
|
46
|
+
export function normalizeOrgFieldValue(spec, raw) {
|
|
47
|
+
const trimmed = raw.trim();
|
|
48
|
+
if (!trimmed) {
|
|
49
|
+
if (REQUIRED_KEYS.has(spec.key)) {
|
|
50
|
+
return { ok: false, error: `${spec.name} can't be empty` };
|
|
51
|
+
}
|
|
52
|
+
return { ok: true, value: null };
|
|
53
|
+
}
|
|
54
|
+
if (spec.type === 'boolean') {
|
|
55
|
+
const word = trimmed.toLowerCase();
|
|
56
|
+
if (TRUE_WORDS.has(word))
|
|
57
|
+
return { ok: true, value: true };
|
|
58
|
+
if (FALSE_WORDS.has(word))
|
|
59
|
+
return { ok: true, value: false };
|
|
60
|
+
return { ok: false, error: `${spec.name} must be yes or no` };
|
|
61
|
+
}
|
|
62
|
+
if (spec.type === 'number') {
|
|
63
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
64
|
+
return { ok: false, error: `${spec.name} must be a whole number` };
|
|
65
|
+
}
|
|
66
|
+
return { ok: true, value: Number(trimmed) };
|
|
67
|
+
}
|
|
68
|
+
if (spec.type === 'list') {
|
|
69
|
+
const items = splitList(trimmed);
|
|
70
|
+
return { ok: true, value: items.length ? items : null };
|
|
71
|
+
}
|
|
72
|
+
if (spec.type === 'url')
|
|
73
|
+
return { ok: true, value: ensureScheme(trimmed) };
|
|
74
|
+
return { ok: true, value: trimmed };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Map a parsed yaml/json document to API fields for `org apply`. Keys may be
|
|
78
|
+
* CLI names (`long-description`, `hiring`) or API keys (`longDescription`,
|
|
79
|
+
* `isHiring`); unknown keys fail loudly so a typo can't silently drop a field.
|
|
80
|
+
* Lists accept real arrays or comma-separated strings.
|
|
81
|
+
*/
|
|
82
|
+
export function parseOrgDocument(doc) {
|
|
83
|
+
if (typeof doc !== 'object' || doc === null || Array.isArray(doc)) {
|
|
84
|
+
return { ok: false, error: 'expected a mapping of fields to values' };
|
|
85
|
+
}
|
|
86
|
+
const fields = {};
|
|
87
|
+
for (const [rawKey, rawValue] of Object.entries(doc)) {
|
|
88
|
+
const spec = ORG_FIELDS.find((f) => f.name === rawKey || f.key === rawKey);
|
|
89
|
+
if (!spec) {
|
|
90
|
+
return {
|
|
91
|
+
ok: false,
|
|
92
|
+
error: `unknown field "${rawKey}" (fields: ${ORG_FIELD_NAMES.join(', ')})`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (rawValue === null) {
|
|
96
|
+
if (REQUIRED_KEYS.has(spec.key)) {
|
|
97
|
+
return { ok: false, error: `${spec.name} can't be empty` };
|
|
98
|
+
}
|
|
99
|
+
fields[spec.key] = null;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (typeof rawValue === 'boolean') {
|
|
103
|
+
if (spec.type !== 'boolean') {
|
|
104
|
+
return { ok: false, error: `${spec.name}: expected a string value` };
|
|
105
|
+
}
|
|
106
|
+
fields[spec.key] = rawValue;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (Array.isArray(rawValue)) {
|
|
110
|
+
if (spec.type !== 'list') {
|
|
111
|
+
return { ok: false, error: `${spec.name}: expected a single value` };
|
|
112
|
+
}
|
|
113
|
+
const items = rawValue.map((v) => String(v).trim()).filter(Boolean);
|
|
114
|
+
fields[spec.key] = items.length ? items : null;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (typeof rawValue !== 'string' && typeof rawValue !== 'number') {
|
|
118
|
+
return { ok: false, error: `${spec.name}: expected a string value` };
|
|
119
|
+
}
|
|
120
|
+
const normalized = normalizeOrgFieldValue(spec, String(rawValue));
|
|
121
|
+
if (!normalized.ok)
|
|
122
|
+
return normalized;
|
|
123
|
+
fields[spec.key] = normalized.value;
|
|
124
|
+
}
|
|
125
|
+
if (Object.keys(fields).length === 0) {
|
|
126
|
+
return { ok: false, error: 'no fields to apply' };
|
|
127
|
+
}
|
|
128
|
+
return { ok: true, fields };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Pick the org a view/set/apply targets. `--org <slug>` wins; with no flag,
|
|
132
|
+
* exactly one managed org is the target, zero or several is a typed error the
|
|
133
|
+
* caller renders (JSON gets the code, humans get the message — which always
|
|
134
|
+
* names the way out).
|
|
135
|
+
*/
|
|
136
|
+
export function resolveTargetOrg(organizations, slugFlag) {
|
|
137
|
+
if (slugFlag) {
|
|
138
|
+
const found = organizations.find((o) => o.slug === slugFlag);
|
|
139
|
+
if (found)
|
|
140
|
+
return { ok: true, org: found };
|
|
141
|
+
const yours = organizations.map((o) => o.slug).join(', ');
|
|
142
|
+
return {
|
|
143
|
+
ok: false,
|
|
144
|
+
code: 'not_found',
|
|
145
|
+
error: organizations.length
|
|
146
|
+
? `you don't manage "${slugFlag}" (you manage: ${yours})`
|
|
147
|
+
: `you don't manage "${slugFlag}" — claim or create it first`,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (organizations.length === 0) {
|
|
151
|
+
return {
|
|
152
|
+
ok: false,
|
|
153
|
+
code: 'no_org',
|
|
154
|
+
error: "you don't manage a company yet — run `hacklab org claim <slug>` or `hacklab org create`",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (organizations.length > 1) {
|
|
158
|
+
const slugs = organizations.map((o) => o.slug).join(', ');
|
|
159
|
+
return {
|
|
160
|
+
ok: false,
|
|
161
|
+
code: 'ambiguous_org',
|
|
162
|
+
error: `you manage ${organizations.length} companies — pass --org <slug> (${slugs})`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return { ok: true, org: organizations[0] };
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=org-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-fields.js","sourceRoot":"","sources":["../src/org-fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAmB5E,MAAM,CAAC,MAAM,UAAU,GAAmB;IACxC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;IAC1D,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE;IACvE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE;IAChE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE;IAClE;QACE,GAAG,EAAE,aAAa;QAClB,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,mBAAmB;QAC1B,IAAI,EAAE,MAAM;KACb;IACD;QACE,GAAG,EAAE,iBAAiB;QACtB,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,kBAAkB;QACzB,IAAI,EAAE,MAAM;KACb;IACD,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE;IACrE,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE;IAClE,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE;IAC9D,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE;IAChE,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC1E,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;IAChE,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE;IAC7D,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IACtE,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE;IAC5E,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;IAC1D,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;CAC1E,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;AAE5D,2EAA2E;AAC3E,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAQ/C,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,GAAG;SACP,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CAAA;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAkB,EAClB,GAAW;IAEX,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;IAC1B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,iBAAiB,EAAE,CAAA;QAC5D,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IAClC,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;QAClC,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;QAC1D,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;QAC5D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,oBAAoB,EAAE,CAAA;IAC/D,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,yBAAyB,EAAE,CAAA;QACpE,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAA;IAC7C,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;QAChC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACzD,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,CAAA;IAE1E,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AACrC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAM3C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAA;IACvE,CAAC;IAED,MAAM,MAAM,GAA6B,EAAE,CAAA;IAC3C,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,CAAA;QAC1E,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,kBAAkB,MAAM,cAAc,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;aAC3E,CAAA;QACH,CAAC;QAED,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,iBAAiB,EAAE,CAAA;YAC5D,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAA;YACvB,SAAQ;QACV,CAAC;QAED,IAAI,OAAO,QAAQ,KAAK,SAAS,EAAE,CAAC;YAClC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,2BAA2B,EAAE,CAAA;YACtE,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAA;YAC3B,SAAQ;QACV,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,2BAA2B,EAAE,CAAA;YACtE,CAAC;YACD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACnE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;YAC9C,SAAQ;QACV,CAAC;QAED,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,2BAA2B,EAAE,CAAA;QACtE,CAAC;QAED,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;QACjE,IAAI,CAAC,UAAU,CAAC,EAAE;YAAE,OAAO,UAAU,CAAA;QACrC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,KAAK,CAAA;IACrC,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAA;IACnD,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AAC7B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,aAAkB,EAClB,QAA4B;IAQ5B,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAA;QAC5D,IAAI,KAAK;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,CAAA;QAC1C,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,WAAW;YACjB,KAAK,EAAE,aAAa,CAAC,MAAM;gBACzB,CAAC,CAAC,qBAAqB,QAAQ,kBAAkB,KAAK,GAAG;gBACzD,CAAC,CAAC,qBAAqB,QAAQ,8BAA8B;SAChE,CAAA;IACH,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,QAAQ;YACd,KAAK,EACH,yFAAyF;SAC5F,CAAA;IACH,CAAC;IACD,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,eAAe;YACrB,KAAK,EAAE,cAAc,aAAa,CAAC,MAAM,mCAAmC,KAAK,GAAG;SACrF,CAAA;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC,CAAE,EAAE,CAAA;AAC7C,CAAC"}
|
package/dist/posthog.d.ts
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
|
-
import { PostHog } from 'posthog-node';
|
|
2
|
-
export declare const posthog: PostHog;
|
|
3
1
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Telemetry is opt-OUT. It's off when the user sets `HACKLAB_NO_TELEMETRY`
|
|
3
|
+
* (mirrors `HACKLAB_NO_UPDATE_CHECK`) or the cross-tool `DO_NOT_TRACK` standard
|
|
4
|
+
* (https://consoledonottrack.com). Checked at every entry point, so a disabled
|
|
5
|
+
* CLI never constructs a client, phones home, or installs exception handlers.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isTelemetryDisabled(): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Capture an event and flush it. Falls back to the anonymous device id when no
|
|
10
|
+
* handle is given, so pre-auth usage is still counted (and later stitched onto
|
|
11
|
+
* the user via `identifyUser`). Fire-and-forget: gated on opt-out, wrapped so it
|
|
12
|
+
* can never slow down or break the command that called it.
|
|
7
13
|
*/
|
|
8
14
|
export declare function captureEvent(distinctId: string | undefined, event: string, properties?: Record<string, unknown>): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Identify the logged-in user and merge any anonymous pre-login history onto
|
|
17
|
+
* them. `properties` is passed straight through (callers set `$set` /
|
|
18
|
+
* `$set_once`). Opt-out gated and fully wrapped.
|
|
19
|
+
*/
|
|
20
|
+
export declare function identifyUser(handle: string, properties: Record<string, unknown>): Promise<void>;
|
|
21
|
+
/** Report an unhandled error to PostHog. Opt-out gated and wrapped. */
|
|
22
|
+
export declare function captureException(error: unknown, distinctId?: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Final drain before the process exits. No-op if telemetry never initialized.
|
|
25
|
+
* Uses flush(), not shutdown(): shutdown() routes a failed flush to a hardcoded
|
|
26
|
+
* console.error (a network stack trace in the user's terminal), whereas flush()
|
|
27
|
+
* rejects into our own catch and stays silent. There are no background timers to
|
|
28
|
+
* clear (flushInterval is 0), so flush() is a complete drain here.
|
|
29
|
+
*/
|
|
30
|
+
export declare function shutdownTelemetry(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* One-time, one-line notice that the CLI collects anonymous usage, with the
|
|
33
|
+
* opt-out. Interactive only (never in pipes / CI / the quiet daily run), shown
|
|
34
|
+
* once per machine (flagged in telemetry.json). Mirrors the update-check nudge:
|
|
35
|
+
* stderr, TTY-gated, and wrapped so it can never break or delay a command.
|
|
36
|
+
*/
|
|
37
|
+
export declare function maybePrintTelemetryNotice(): Promise<void>;
|
|
9
38
|
//# sourceMappingURL=posthog.d.ts.map
|
package/dist/posthog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog.d.ts","sourceRoot":"","sources":["../src/posthog.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"posthog.d.ts","sourceRoot":"","sources":["../src/posthog.ts"],"names":[],"mappings":"AAkCA;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAI7C;AAgGD;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,uEAAuE;AACvE,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,OAAO,EACd,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOvD;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmB/D"}
|