hacklab 0.8.5 → 0.10.0-staging.16.1

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.
Files changed (57) hide show
  1. package/README.md +78 -33
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +147 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/drop.d.ts +2 -1
  7. package/dist/commands/drop.d.ts.map +1 -1
  8. package/dist/commands/drop.js +51 -11
  9. package/dist/commands/drop.js.map +1 -1
  10. package/dist/commands/hacker.d.ts.map +1 -1
  11. package/dist/commands/hacker.js +68 -6
  12. package/dist/commands/hacker.js.map +1 -1
  13. package/dist/commands/join.d.ts +1 -1
  14. package/dist/commands/join.d.ts.map +1 -1
  15. package/dist/commands/join.js +96 -184
  16. package/dist/commands/join.js.map +1 -1
  17. package/dist/commands/profile.d.ts +2 -1
  18. package/dist/commands/profile.d.ts.map +1 -1
  19. package/dist/commands/profile.js +66 -7
  20. package/dist/commands/profile.js.map +1 -1
  21. package/dist/commands/project.d.ts +19 -0
  22. package/dist/commands/project.d.ts.map +1 -1
  23. package/dist/commands/project.js +684 -27
  24. package/dist/commands/project.js.map +1 -1
  25. package/dist/commands/sync.js +7 -3
  26. package/dist/commands/sync.js.map +1 -1
  27. package/dist/commands/update.js +2 -2
  28. package/dist/commands/update.js.map +1 -1
  29. package/dist/daily-sync.d.ts +16 -1
  30. package/dist/daily-sync.d.ts.map +1 -1
  31. package/dist/daily-sync.js +66 -2
  32. package/dist/daily-sync.js.map +1 -1
  33. package/dist/index.js +18 -150
  34. package/dist/index.js.map +1 -1
  35. package/dist/project-infer.d.ts +13 -0
  36. package/dist/project-infer.d.ts.map +1 -1
  37. package/dist/project-infer.js +41 -2
  38. package/dist/project-infer.js.map +1 -1
  39. package/dist/registry.js +7 -7
  40. package/dist/registry.js.map +1 -1
  41. package/dist/scanners/index.d.ts +6 -0
  42. package/dist/scanners/index.d.ts.map +1 -1
  43. package/dist/scanners/index.js +48 -51
  44. package/dist/scanners/index.js.map +1 -1
  45. package/dist/scanners/sqlite.d.ts +18 -0
  46. package/dist/scanners/sqlite.d.ts.map +1 -0
  47. package/dist/scanners/sqlite.js +63 -0
  48. package/dist/scanners/sqlite.js.map +1 -0
  49. package/dist/share.d.ts +3 -12
  50. package/dist/share.d.ts.map +1 -1
  51. package/dist/share.js +41 -37
  52. package/dist/share.js.map +1 -1
  53. package/dist/sync.d.ts +4 -1
  54. package/dist/sync.d.ts.map +1 -1
  55. package/dist/sync.js +9 -2
  56. package/dist/sync.js.map +1 -1
  57. package/package.json +7 -3
package/README.md CHANGED
@@ -6,27 +6,49 @@ your profile with GitHub.
6
6
 
7
7
  ## Install & join
8
8
 
9
- One command:
9
+ Install, then join:
10
10
 
11
11
  ```bash
12
12
  curl -fsSL https://hacklab.so/install | sh
13
+ hacklab join
13
14
  ```
14
15
 
15
- It checks for Node 20+, installs the CLI globally (`npm install -g
16
- hacklab@latest`), then runs `hacklab join`. After that `hacklab` is a real
17
- command on your PATH. If you already have Node (incl. via a version manager),
18
- you can skip the script and do the same two steps yourself:
16
+ The script checks for Node 20+ and installs the CLI globally. After that
17
+ `hacklab` is a real command on your PATH. If you already have Node (including
18
+ through a version manager), you can skip the script:
19
19
 
20
20
  ```bash
21
- npm install -g hacklab@latest
21
+ npm i -g hacklab@latest
22
22
  hacklab join
23
23
  ```
24
24
 
25
- If this machine is already set up with a finished profile, both the installer
26
- and `hacklab join` stop early: they print who you're signed in as and how to
27
- switch (`hacklab logout` then `hacklab login`) instead of reinstalling or
28
- re-registering. A half-finished signup that authenticated but never claimed a
29
- username still falls through, so you can re-run and complete it.
25
+ ### Windows
26
+
27
+ On native Windows (PowerShell), use the `.ps1` installer instead — it checks
28
+ for Node 20+, installs the CLI globally, and (unlike the sh installer) also
29
+ runs `hacklab join` for you:
30
+
31
+ ```powershell
32
+ irm https://hacklab.so/install.ps1 | iex
33
+ ```
34
+
35
+ It reads your agents' usage from your Windows home (`%USERPROFILE%\.claude`,
36
+ `.codex`, and Cursor's native tracking DB) and registers a daily background sync
37
+ as a Task Scheduler task. If you run Claude Code or Codex **inside WSL**, install
38
+ there instead with the `curl … | sh` command above, run from your WSL shell.
39
+
40
+ The installer also enables local PowerShell scripts for your user
41
+ (`Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`) so the `hacklab` command
42
+ runs. If you install manually instead (`npm i -g hacklab@latest`) and PowerShell
43
+ says *"running scripts is disabled on this system"*, run that one line yourself,
44
+ or call `hacklab.cmd …` (which no execution policy blocks).
45
+
46
+ If this machine is already set up with a finished profile, `hacklab join` stops
47
+ early: it prints who you're signed in as and how to switch (`hacklab logout`
48
+ then `hacklab login`) instead of re-registering. A half-finished signup that
49
+ authenticated but never claimed a username still falls through, so you can
50
+ re-run and complete it. The `curl | sh` installer itself only installs — it
51
+ never touches your session.
30
52
 
31
53
  The CLI prints a one-line nudge when a newer version is published (checked at
32
54
  most once a day); update with `npm i -g hacklab@latest`.
@@ -34,7 +56,7 @@ most once a day); update with `npm i -g hacklab@latest`.
34
56
  ## The join ritual
35
57
 
36
58
  ```
37
- scan local AI usage → see your rank → pick a username → sign in with GitHub → claim → chat
59
+ scan local AI usage → see your rank → sign in with GitHub → claim a username → card → optional X share
38
60
  ```
39
61
 
40
62
  1. **Scan** — reads your local AI token usage from Claude Code, Codex, Cursor,
@@ -47,14 +69,15 @@ scan local AI usage → see your rank → pick a username → sign in with GitHu
47
69
  asked.
48
70
  3. **Rank** — shows the rank that usage would hold (`you'd be #15 of N`), with no
49
71
  account required.
50
- 4. **Username** — pick your Hacklab handle (checked for availability live).
51
- 5. **GitHub** — sign in to authenticate and link your profile + repos.
52
- 6. **Claim** — your profile goes live at `hacklab.so/<username>`. Your usage
53
- uploads in the background while you get a shareable stats card.
54
- 7. **Share** — a stats thumbnail (belt, level, rank, token breakdown) is rendered
55
- locally, copied to your clipboard, and you can post it to X in one keystroke.
56
- 8. **Chat** — finally, you're offered the live channel (default yes). Decline and
57
- you can jump in anytime with `hacklab chat`.
72
+ 4. **GitHub** — sign in to authenticate and link your profile + repos.
73
+ 5. **Username** — pick your Hacklab handle (checked for availability live).
74
+ 6. **Claim** — saves your usage, syncs pinned GitHub projects, and claims
75
+ `hacklab.so/<username>`. Bio and the first drop finish activation in the web
76
+ onboarding flow.
77
+ 7. **Card** — renders the belt, level, rank, and token breakdown directly in the
78
+ terminal. Terminals without inline images get a text version.
79
+ 8. **Share** — one optional X prompt. Saying yes saves the image to
80
+ `~/hacklab-card.png`, copies it, and opens a prefilled X post; saying no exits.
58
81
 
59
82
  ## Commands
60
83
 
@@ -64,7 +87,9 @@ scan local AI usage → see your rank → pick a username → sign in with GitHu
64
87
  `hacklab login` to switch accounts.
65
88
  - `hacklab sync` — re-scan local AI usage and sync it to your profile.
66
89
  - `hacklab whoami` — show who you're logged in as.
67
- - `hacklab drop "message"` — post a drop to your feed (`-u <url>` to attach a link).
90
+ - `hacklab drop "message"` — post a drop to your feed (`-u <url>` to attach a
91
+ link). Human output prints its profile URL; `--json` returns a stable envelope
92
+ (`schemaVersion`, `id`, `path`, full `url`).
68
93
  - `hacklab chat` — open the live channel (typing posts; this is the default, so
69
94
  bare `hacklab chat` and `hacklab chat live` are the same). Other subcommands:
70
95
  `tail`, `post`, `history`, `dms`, `dm <handle>`, `flag`. Author handles are
@@ -74,15 +99,31 @@ scan local AI usage → see your rank → pick a username → sign in with GitHu
74
99
  - `hacklab logout` — clear your saved session on this machine.
75
100
  - `hacklab config <key> <value>` — set config (`cursor-api-key`, `cursor-email`).
76
101
  Bare `hacklab config` prints the effective values and where each came from.
77
- - `hacklab project` — publish the repo you're standing in as a project. No
78
- manifest: it reads the git remote, README, and package.json, shows a preview,
79
- and publishes on confirm (`--yes` to skip, `--json` for agents). Re-running
80
- refreshes the same project (slug derives from the repo name) without losing
81
- its publish date or screenshots; if the live site (package.json `homepage` or
82
- `--live <url>`) has an `og:image`, that becomes the screenshot. Override any
83
- inferred field with `--title`, `--description`, `--live`, `--tags a,b,c`,
84
- `--slug`. Manage the set with `hacklab project list` and
85
- `hacklab project delete <slug>`.
102
+ - `hacklab project` — publish the repo you're standing in as a project. It reads
103
+ the git remote, README, and package.json, shows a preview, and publishes on
104
+ confirm (`--yes` to skip, `--json` for agents). Publish a project with no repo
105
+ using `project add --no-repo --title "…"`, and set the long-form page content
106
+ with `--content <md>` or `--content-file <file>`. Agents can publish every
107
+ field at once from a manifest with `project apply project.yaml --yes --json`,
108
+ including up to five remote PNG, JPEG, or WebP screenshots (max 3MB each) that
109
+ Hacklab downloads and hosts. Re-running `add`/`apply` refreshes the same slug
110
+ without losing its publish date. Manage the set with `hacklab project list`,
111
+ `project view <slug>`, `project edit <slug> --title/--desc/--url/--tags`, and
112
+ `project delete <slug>`.
113
+
114
+ ```yaml
115
+ title: My project
116
+ repoUrl: https://github.com/me/my-project
117
+ liveUrl: https://my-project.dev
118
+ description: The short profile-card summary.
119
+ content: |
120
+ ## Why I built it
121
+ Long-form markdown for the project page.
122
+ tags: [ai, typescript]
123
+ screenshots:
124
+ - url: https://my-project.dev/thumbnail.webp
125
+ caption: Main screen
126
+ ```
86
127
  - `hacklab org` — hub for company management. If you already own a company, pick
87
128
  a field, type the new value, and it saves as you go. If you don't own one yet,
88
129
  it offers to claim or create. Subcommands: `hacklab org claim` (take ownership
@@ -91,10 +132,14 @@ scan local AI usage → see your rank → pick a username → sign in with GitHu
91
132
  - `hacklab profile` — view and edit your own profile. Bare `profile` (or
92
133
  `profile view`) shows it; `profile edit` is an org-style autosave editor;
93
134
  `profile set <field> <value>` writes one field (`--clear` unsets, handles like
94
- `x mattbratos` become full links); `profile apply profile.yaml` writes many
95
- fields in one shot — handy for agents setting up your profile. Fields: `name`,
96
- `bio`, `website`, `blog`, `x`, `youtube`, `instagram`, `rss`, `open-to-work`.
135
+ `x mattbratos` become full links); `profile set readme --file profile.md`
136
+ writes a long Markdown README without shell quoting; `profile apply
137
+ profile.yaml` writes many fields in one shot. Fields: `name`, `bio`, `readme`,
138
+ `website`, `blog`, `x`, `youtube`, `instagram`, `rss`, `open-to-work`.
97
139
  Add `--json` to `view`/`set`/`apply` for machine-readable output.
140
+ - `hacklab hacker view [handle] --json` — read the rich agent profile including
141
+ links, counts, skills, recent projects, essays, and drops. Use
142
+ `hacklab hacker list --newest --json` to discover recently activated members.
98
143
  - `hacklab --version` / `hacklab --help`.
99
144
 
100
145
  ## Cursor usage
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,147 @@
1
+ // The real CLI. Loaded via a dynamic import from index.ts *after* its Node
2
+ // version guard passes — so the Node 20+ APIs these imports reach (e.g.
3
+ // @clack/core's `styleText` from node:util) never link on an unsupported Node.
4
+ import { createRequire } from 'node:module';
5
+ import { clearSyncPaused, readSyncPaused } from './daily-sync.js';
6
+ import { captureException, maybePrintTelemetryNotice, shutdownTelemetry, } from './posthog.js';
7
+ import { COMMANDS, findCommand } from './registry.js';
8
+ import { resolveCommand } from './resolve-command.js';
9
+ import { HACKLAB_ENVIRONMENTS, loadSession, resolveHacklabEnv, } from './session.js';
10
+ import { banner, bold, dim } from './ui.js';
11
+ import { notifyIfOutdated } from './utils/updateCheck.js';
12
+ // Single source of the published version: read it from package.json (one level
13
+ // up from this module in both `dist/` and `src/`) instead of hardcoding a string
14
+ // that silently drifts from the real package version. `createRequire` resolves
15
+ // JSON the same way under tsx (dev) and the compiled bin.
16
+ const require = createRequire(import.meta.url);
17
+ const { version: VERSION } = require('../package.json');
18
+ /**
19
+ * The global flags, each mapping onto the env var the rest of the CLI already
20
+ * reads. Going through the env is what makes precedence fall out for free: the
21
+ * flag overwrites any inherited value, and the readers (getAppUrl,
22
+ * resolveCursorAuth) prefer the env over the config file. It also means a value
23
+ * passed once on the command line reaches anything the command shells out to.
24
+ */
25
+ const GLOBAL_FLAGS = {
26
+ '--env': (value) => {
27
+ const env = resolveHacklabEnv(value);
28
+ if (!env) {
29
+ console.error(`--env must be one of: ${Object.keys(HACKLAB_ENVIRONMENTS).join(', ')} (abbreviations like dev/prod/stag work)`);
30
+ process.exit(1);
31
+ }
32
+ process.env.HACKLAB_APP_URL = HACKLAB_ENVIRONMENTS[env];
33
+ },
34
+ '--cursor-api-key': (value) => {
35
+ process.env.CURSOR_API_KEY = value;
36
+ },
37
+ '--cursor-email': (value) => {
38
+ process.env.CURSOR_EMAIL = value;
39
+ },
40
+ };
41
+ /**
42
+ * Pull the global flags out of argv and apply them, returning the remaining args
43
+ * so per-command parsing never sees them. Both `--flag value` and `--flag=value`
44
+ * spellings work.
45
+ */
46
+ function applyGlobalFlags(argv) {
47
+ const rest = [];
48
+ for (let i = 0; i < argv.length; i++) {
49
+ const arg = argv[i];
50
+ const eq = arg.indexOf('=');
51
+ const name = eq === -1 ? arg : arg.slice(0, eq);
52
+ const apply = GLOBAL_FLAGS[name];
53
+ if (!apply) {
54
+ rest.push(arg);
55
+ continue;
56
+ }
57
+ const value = eq === -1 ? argv[++i] : arg.slice(eq + 1);
58
+ if (!value) {
59
+ console.error(`${name} requires a value`);
60
+ process.exit(1);
61
+ }
62
+ apply(value);
63
+ }
64
+ return rest;
65
+ }
66
+ const [cmd, ...args] = applyGlobalFlags(process.argv.slice(2));
67
+ function printHelp() {
68
+ banner();
69
+ console.log('');
70
+ console.log(bold('usage:'));
71
+ // Align the descriptions: pad to the widest `name + args` so the summaries
72
+ // line up no matter how the registry grows.
73
+ const rows = COMMANDS.map((c) => ({
74
+ label: c.args ? `${c.name} ${c.args}` : c.name,
75
+ summary: c.summary,
76
+ }));
77
+ const width = Math.max(...rows.map((r) => r.label.length));
78
+ for (const { label, summary } of rows) {
79
+ console.log(` hacklab ${dim(label)}${' '.repeat(width - label.length)} ${summary}`);
80
+ }
81
+ console.log('');
82
+ console.log(` ${dim('--env')} ${dim('<production|staging|development>')} pick the backend (default: production)`);
83
+ console.log(` ${dim('--cursor-api-key')} ${dim('<key>')} exact Cursor usage (or ${dim('CURSOR_API_KEY')})`);
84
+ console.log(` ${dim('--cursor-email')} ${dim('<email>')} scope a Cursor team key to you (or ${dim('CURSOR_EMAIL')})`);
85
+ console.log('');
86
+ }
87
+ // Node-version guard (T9). The CLI uses modern Node APIs (global fetch,
88
+ // AbortSignal.timeout). Fail fast with a clear message instead of a cryptic
89
+ // runtime error on an old runtime. The nvm hint matters because a piped
90
+ async function main() {
91
+ // Bare `hacklab` (no command) prints help, same as `--help`/`-h`. Runs before
92
+ // the update nudge so it reads as plain help, matching the `--help` path.
93
+ if (!cmd || cmd === '--help' || cmd === '-h') {
94
+ printHelp();
95
+ process.exit(0);
96
+ }
97
+ if (cmd === '--version' || cmd === '-v') {
98
+ console.log(VERSION);
99
+ process.exit(0);
100
+ }
101
+ // One-time anonymous-telemetry notice (interactive only, shown once). Before
102
+ // the update nudge so, on the very first run, consent is disclosed above any
103
+ // other output.
104
+ await maybePrintTelemetryNotice();
105
+ // One-line nudge if a newer hacklab is published (interactive only, cached
106
+ // daily, timeout-guarded). Must run before any command output so it reads as
107
+ // a header, not buried in results.
108
+ await notifyIfOutdated(VERSION);
109
+ // Resolve a possibly-abbreviated command to its full name (e.g. `sy` -> sync,
110
+ // `or` -> org). Exact matches always win; an ambiguous prefix is
111
+ // rejected with the candidates so the user can disambiguate.
112
+ const resolution = resolveCommand(cmd);
113
+ if (resolution.kind === 'ambiguous') {
114
+ console.error(`ambiguous command "${cmd}": ${resolution.matches.join(' or ')}?`);
115
+ process.exit(1);
116
+ }
117
+ const command = resolution.kind === 'match' ? findCommand(resolution.name) : undefined;
118
+ if (!command) {
119
+ console.error(`unknown command: ${cmd}`);
120
+ console.error('run hacklab --help for usage');
121
+ process.exit(1);
122
+ }
123
+ // Surface a paused daily background sync (e.g. the session expired while the
124
+ // machine was off) once, then clear the marker. Skipped for the auth commands
125
+ // that fix it (login/join), so we never nag mid-fix.
126
+ if (process.stdout.isTTY &&
127
+ command.name !== 'login' &&
128
+ command.name !== 'join') {
129
+ const paused = await readSyncPaused();
130
+ if (paused) {
131
+ console.error(dim(`paused: daily background sync — ${paused}`));
132
+ await clearSyncPaused();
133
+ }
134
+ }
135
+ await command.run(args);
136
+ // Best-effort final flush for the happy path. Per-event captures already flush
137
+ // eagerly (flushAt: 1), so this mainly drains any autocaptured exception.
138
+ await shutdownTelemetry();
139
+ }
140
+ main().catch(async (err) => {
141
+ console.error(err instanceof Error ? err.message : String(err));
142
+ const session = await loadSession().catch(() => null);
143
+ await captureException(err, session?.handle);
144
+ await shutdownTelemetry();
145
+ process.exit(1);
146
+ });
147
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@
6
6
  export declare function parseDropArgs(args: string[]): {
7
7
  text: string;
8
8
  url?: string;
9
+ json: boolean;
9
10
  };
10
- export declare function drop(content: string, url?: string): Promise<void>;
11
+ export declare function drop(content: string, url?: string, json?: boolean): Promise<void>;
11
12
  //# sourceMappingURL=drop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"drop.d.ts","sourceRoot":"","sources":["../../src/commands/drop.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAyB5E;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,iBAmCvD"}
1
+ {"version":3,"file":"drop.d.ts","sourceRoot":"","sources":["../../src/commands/drop.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;CACd,CA4BA;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,UAAQ,iBAgFrE"}
@@ -1,3 +1,4 @@
1
+ import { emitJsonError } from '../api-client.js';
1
2
  import { captureEvent } from '../posthog.js';
2
3
  import { loadSession, resolveAppUrl } from '../session.js';
3
4
  import { dim, error, info, success } from '../ui.js';
@@ -8,6 +9,7 @@ import { dim, error, info, success } from '../ui.js';
8
9
  */
9
10
  export function parseDropArgs(args) {
10
11
  let url;
12
+ let json = false;
11
13
  const words = [];
12
14
  for (let i = 0; i < args.length; i++) {
13
15
  const arg = args[i];
@@ -15,6 +17,9 @@ export function parseDropArgs(args) {
15
17
  url = args[i + 1];
16
18
  i++;
17
19
  }
20
+ else if (arg === '--json') {
21
+ json = true;
22
+ }
18
23
  else if (arg.startsWith('-')) {
19
24
  console.error(`unknown flag: ${arg}`);
20
25
  process.exit(1);
@@ -28,33 +33,68 @@ export function parseDropArgs(args) {
28
33
  console.error('usage: hacklab drop your message here');
29
34
  process.exit(1);
30
35
  }
31
- return { text, url };
36
+ return { text, url, json };
32
37
  }
33
- export async function drop(content, url) {
38
+ export async function drop(content, url, json = false) {
34
39
  const session = await loadSession();
35
40
  if (!session) {
41
+ if (json)
42
+ emitJsonError('unauthorized', 'not logged in');
36
43
  error('not logged in');
37
44
  info(`run ${dim('hacklab login')} first`);
38
45
  process.exit(1);
39
46
  }
40
47
  if (content.length > 1000) {
48
+ if (json)
49
+ emitJsonError('invalid_fields', `too long — ${content.length}/1000 chars`);
41
50
  error(`too long — ${content.length}/1000 chars`);
42
51
  process.exit(1);
43
52
  }
44
- const res = await fetch(`${resolveAppUrl(session)}/api/drops`, {
45
- method: 'POST',
46
- headers: {
47
- 'Content-Type': 'application/json',
48
- Authorization: `Bearer ${session.token}`,
49
- },
50
- body: JSON.stringify({ content, url }),
51
- });
53
+ let res;
54
+ try {
55
+ res = await fetch(`${resolveAppUrl(session)}/api/drops`, {
56
+ method: 'POST',
57
+ headers: {
58
+ 'Content-Type': 'application/json',
59
+ Authorization: `Bearer ${session.token}`,
60
+ },
61
+ body: JSON.stringify({ content, url }),
62
+ });
63
+ }
64
+ catch (err) {
65
+ const message = err instanceof Error ? err.message : String(err);
66
+ if (json)
67
+ emitJsonError('network', `couldn't reach hacklab: ${message}`);
68
+ error(`couldn't reach hacklab: ${message}`);
69
+ process.exit(1);
70
+ }
52
71
  if (!res.ok) {
53
72
  const data = await res.json().catch(() => null);
73
+ if (json)
74
+ emitJsonError('request_failed', data?.error ?? `failed (${res.status})`);
54
75
  error(data?.error ?? `failed (${res.status})`);
55
76
  process.exit(1);
56
77
  }
57
- success('dropped.');
78
+ const result = (await res.json().catch(() => null));
79
+ if (!result?.id) {
80
+ if (json)
81
+ emitJsonError('bad_response', 'got a malformed response from hacklab');
82
+ error('got a malformed response from hacklab');
83
+ process.exit(1);
84
+ }
85
+ // Only `id` is load-bearing. Older servers respond without path/url —
86
+ // during a CLI-publish/deploy skew the drop still succeeded, so degrade
87
+ // gracefully instead of reporting a false failure (agents would retry and
88
+ // post duplicates).
89
+ const dropPath = result.path ?? `/${session.handle}?tab=drops#drop-${result.id}`;
90
+ const dropUrl = result.url ?? `${resolveAppUrl(session).replace(/\/$/, '')}${dropPath}`;
91
+ if (json) {
92
+ console.log(JSON.stringify({ schemaVersion: 1, id: result.id, path: dropPath, url: dropUrl }, null, 2));
93
+ }
94
+ else {
95
+ success('dropped.');
96
+ info(dropUrl);
97
+ }
58
98
  await captureEvent(session.handle, 'cli_drop_posted', {
59
99
  content_length: content.length,
60
100
  has_url: url !== undefined,
@@ -1 +1 @@
1
- {"version":3,"file":"drop.js","sourceRoot":"","sources":["../../src/commands/drop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"drop.js","sourceRoot":"","sources":["../../src/commands/drop.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"hacker.d.ts","sourceRoot":"","sources":["../../src/commands/hacker.ts"],"names":[],"mappings":"AAyBA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAe1D"}
1
+ {"version":3,"file":"hacker.d.ts","sourceRoot":"","sources":["../../src/commands/hacker.ts"],"names":[],"mappings":"AA4BA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB1D"}
@@ -2,16 +2,19 @@ import { apiErrorMessage, emitJsonError, requireSession, } from '../api-client.j
2
2
  import { renderCard } from '../card.js';
3
3
  import { resolveCommand } from '../resolve-command.js';
4
4
  import { fetchApi } from '../sync.js';
5
- import { dim, error, info } from '../ui.js';
6
- // `hacklab hacker view [handle]` — the auth-gated terminal card, `--json` for
7
- // agents. With no handle it views your own profile (the authenticated user);
5
+ import { bold, dim, error, info } from '../ui.js';
6
+ // `hacklab hacker view [handle]` — an auth-gated terminal card for humans and
7
+ // a rich agent profile in JSON. `list --newest` provides bounded discovery.
8
+ // With no handle it views your own profile (the authenticated user);
8
9
  // managing that profile is `hacklab profile`'s job — this command is the
9
10
  // window, that one is the mirror. Noun-verb so an identifier never sits in a
10
11
  // verb slot (a handle can be any word). Subcommands resolve by shortest
11
12
  // unambiguous prefix, so `hacklab h v isomiki` works via resolveCommand.
12
- const SUBCOMMANDS = ['view'];
13
+ const SUBCOMMANDS = ['view', 'list'];
13
14
  function usage() {
14
- error('usage: hacklab hacker view [handle]');
15
+ error('usage: hacklab hacker [view|list]');
16
+ info(` hacklab hacker ${dim('view [handle] [--json]')}`);
17
+ info(` hacklab hacker ${dim('list --newest [--limit 20] [--json]')}`);
15
18
  process.exit(1);
16
19
  }
17
20
  export async function hacker(args) {
@@ -29,6 +32,64 @@ export async function hacker(args) {
29
32
  }
30
33
  if (resolved.name === 'view')
31
34
  return hackerView(rest);
35
+ if (resolved.name === 'list')
36
+ return hackerList(rest);
37
+ }
38
+ async function hackerList(args) {
39
+ const json = args.includes('--json');
40
+ if (!args.includes('--newest')) {
41
+ if (json)
42
+ return emitJsonError('invalid_fields', 'pass --newest');
43
+ error('pass --newest');
44
+ usage();
45
+ }
46
+ const limitIndex = args.indexOf('--limit');
47
+ const rawLimit = limitIndex === -1 ? undefined : args[limitIndex + 1];
48
+ const limit = rawLimit === undefined ? 20 : Number(rawLimit);
49
+ if ((limitIndex !== -1 && rawLimit === undefined) ||
50
+ !Number.isInteger(limit) ||
51
+ limit < 1 ||
52
+ limit > 50) {
53
+ if (json)
54
+ return emitJsonError('invalid_fields', '--limit must be 1-50');
55
+ error('--limit must be 1-50');
56
+ process.exit(1);
57
+ }
58
+ const session = await requireSession(json);
59
+ let res;
60
+ try {
61
+ res = await fetchApi(session, `/api/hackers/newest?src=cli&limit=${limit}`, { headers: { Authorization: `Bearer ${session.token}` } });
62
+ }
63
+ catch (err) {
64
+ const message = err instanceof Error ? err.message : String(err);
65
+ if (json)
66
+ return emitJsonError('network', message);
67
+ error(message);
68
+ process.exit(1);
69
+ }
70
+ if (!res.ok)
71
+ return handleError(res, 'newest hackers', json, session);
72
+ const body = (await res.json().catch(() => null));
73
+ if (!body?.hackers) {
74
+ if (json)
75
+ return emitJsonError('bad_response', 'malformed response');
76
+ error('got a malformed response from hacklab');
77
+ process.exit(1);
78
+ }
79
+ if (json) {
80
+ console.log(JSON.stringify(body, null, 2));
81
+ return;
82
+ }
83
+ if (!body.hackers.length) {
84
+ info('no new hackers yet');
85
+ return;
86
+ }
87
+ for (const hacker of body.hackers) {
88
+ const name = hacker.displayName ? ` ${hacker.displayName}` : '';
89
+ console.log(` ${bold(hacker.handle)}${dim(name)}`);
90
+ if (hacker.bio)
91
+ console.log(` ${dim(hacker.bio)}`);
92
+ }
32
93
  }
33
94
  async function hackerView(args) {
34
95
  const json = args.includes('--json');
@@ -47,7 +108,8 @@ async function hackerView(args) {
47
108
  }
48
109
  let res;
49
110
  try {
50
- res = await fetchApi(session, `/api/hackers/${encodeURIComponent(handle)}?src=cli`, { headers: { Authorization: `Bearer ${session.token}` } });
111
+ const format = json ? '&format=agent' : '';
112
+ res = await fetchApi(session, `/api/hackers/${encodeURIComponent(handle)}?src=cli${format}`, { headers: { Authorization: `Bearer ${session.token}` } });
51
113
  }
52
114
  catch (err) {
53
115
  // fetchApi rethrows a friendly "couldn't reach hacklab" message.
@@ -1 +1 @@
1
- {"version":3,"file":"hacker.js","sourceRoot":"","sources":["../../src/commands/hacker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hacker.js","sourceRoot":"","sources":["../../src/commands/hacker.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The hero command: the guided join ritual.
3
3
  *
4
- * scan → anonymous rank → GitHub OAuth → pick username + fields → claim
4
+ * scan → anonymous rank → GitHub OAuth → pick username → claim → card
5
5
  *
6
6
  * Value (rank) is shown before any account exists. GitHub auth comes right
7
7
  * after the rank and before the username, so we know whether the account
@@ -1 +1 @@
1
- {"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../src/commands/join.ts"],"names":[],"mappings":"AA2CA;;;;;;;;;;GAUG;AACH,wBAAsB,IAAI,CAAC,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,iBA6Y1D"}
1
+ {"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../src/commands/join.ts"],"names":[],"mappings":"AA0CA;;;;;;;;;;GAUG;AACH,wBAAsB,IAAI,CAAC,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,iBA+U1D"}