@profullstack/agenticjobs 0.1.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.
Files changed (206) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +219 -0
  3. package/bin/agenticjobs-mcp.mjs +2 -0
  4. package/bin/agenticjobs.mjs +2 -0
  5. package/dist/cli/args.d.ts +17 -0
  6. package/dist/cli/args.js +103 -0
  7. package/dist/cli/args.js.map +1 -0
  8. package/dist/cli/format.d.ts +15 -0
  9. package/dist/cli/format.js +24 -0
  10. package/dist/cli/format.js.map +1 -0
  11. package/dist/cli/index.d.ts +13 -0
  12. package/dist/cli/index.js +620 -0
  13. package/dist/cli/index.js.map +1 -0
  14. package/dist/cli/jobfile.d.ts +15 -0
  15. package/dist/cli/jobfile.js +94 -0
  16. package/dist/cli/jobfile.js.map +1 -0
  17. package/dist/client/client.d.ts +105 -0
  18. package/dist/client/client.js +182 -0
  19. package/dist/client/client.js.map +1 -0
  20. package/dist/client/config.d.ts +33 -0
  21. package/dist/client/config.js +92 -0
  22. package/dist/client/config.js.map +1 -0
  23. package/dist/client/fanout.d.ts +35 -0
  24. package/dist/client/fanout.js +77 -0
  25. package/dist/client/fanout.js.map +1 -0
  26. package/dist/client/index.d.ts +4 -0
  27. package/dist/client/index.js +5 -0
  28. package/dist/client/index.js.map +1 -0
  29. package/dist/client/login.d.ts +23 -0
  30. package/dist/client/login.js +45 -0
  31. package/dist/client/login.js.map +1 -0
  32. package/dist/config.d.ts +40 -0
  33. package/dist/config.js +64 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/core/applications.d.ts +67 -0
  36. package/dist/core/applications.js +187 -0
  37. package/dist/core/applications.js.map +1 -0
  38. package/dist/core/auth.d.ts +120 -0
  39. package/dist/core/auth.js +246 -0
  40. package/dist/core/auth.js.map +1 -0
  41. package/dist/core/import.d.ts +52 -0
  42. package/dist/core/import.js +311 -0
  43. package/dist/core/import.js.map +1 -0
  44. package/dist/core/jobs.d.ts +91 -0
  45. package/dist/core/jobs.js +381 -0
  46. package/dist/core/jobs.js.map +1 -0
  47. package/dist/core/orgs.d.ts +21 -0
  48. package/dist/core/orgs.js +111 -0
  49. package/dist/core/orgs.js.map +1 -0
  50. package/dist/core/resumes.d.ts +51 -0
  51. package/dist/core/resumes.js +144 -0
  52. package/dist/core/resumes.js.map +1 -0
  53. package/dist/core/zip.d.ts +17 -0
  54. package/dist/core/zip.js +77 -0
  55. package/dist/core/zip.js.map +1 -0
  56. package/dist/db/index.d.ts +3 -0
  57. package/dist/db/index.js +3 -0
  58. package/dist/db/index.js.map +1 -0
  59. package/dist/db/migrate.d.ts +15 -0
  60. package/dist/db/migrate.js +67 -0
  61. package/dist/db/migrate.js.map +1 -0
  62. package/dist/db/pool.d.ts +13 -0
  63. package/dist/db/pool.js +68 -0
  64. package/dist/db/pool.js.map +1 -0
  65. package/dist/db/seed.d.ts +9 -0
  66. package/dist/db/seed.js +120 -0
  67. package/dist/db/seed.js.map +1 -0
  68. package/dist/directory/announce.d.ts +32 -0
  69. package/dist/directory/announce.js +59 -0
  70. package/dist/directory/announce.js.map +1 -0
  71. package/dist/directory/federate.d.ts +59 -0
  72. package/dist/directory/federate.js +126 -0
  73. package/dist/directory/federate.js.map +1 -0
  74. package/dist/directory/fetch.d.ts +35 -0
  75. package/dist/directory/fetch.js +138 -0
  76. package/dist/directory/fetch.js.map +1 -0
  77. package/dist/directory/index.d.ts +4 -0
  78. package/dist/directory/index.js +5 -0
  79. package/dist/directory/index.js.map +1 -0
  80. package/dist/directory/registry.d.ts +55 -0
  81. package/dist/directory/registry.js +155 -0
  82. package/dist/directory/registry.js.map +1 -0
  83. package/dist/index.d.ts +14 -0
  84. package/dist/index.js +14 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/markup/escape.d.ts +20 -0
  87. package/dist/markup/escape.js +56 -0
  88. package/dist/markup/escape.js.map +1 -0
  89. package/dist/markup/markdown.d.ts +35 -0
  90. package/dist/markup/markdown.js +279 -0
  91. package/dist/markup/markdown.js.map +1 -0
  92. package/dist/markup/resume.d.ts +72 -0
  93. package/dist/markup/resume.js +260 -0
  94. package/dist/markup/resume.js.map +1 -0
  95. package/dist/mcp/protocol.d.ts +56 -0
  96. package/dist/mcp/protocol.js +48 -0
  97. package/dist/mcp/protocol.js.map +1 -0
  98. package/dist/mcp/server.d.ts +21 -0
  99. package/dist/mcp/server.js +73 -0
  100. package/dist/mcp/server.js.map +1 -0
  101. package/dist/mcp/stdio.d.ts +13 -0
  102. package/dist/mcp/stdio.js +85 -0
  103. package/dist/mcp/stdio.js.map +1 -0
  104. package/dist/mcp/tools.d.ts +26 -0
  105. package/dist/mcp/tools.js +351 -0
  106. package/dist/mcp/tools.js.map +1 -0
  107. package/dist/schema/index.d.ts +5 -0
  108. package/dist/schema/index.js +6 -0
  109. package/dist/schema/index.js.map +1 -0
  110. package/dist/schema/instance.d.ts +85 -0
  111. package/dist/schema/instance.js +147 -0
  112. package/dist/schema/instance.js.map +1 -0
  113. package/dist/schema/job.d.ts +151 -0
  114. package/dist/schema/job.js +73 -0
  115. package/dist/schema/job.js.map +1 -0
  116. package/dist/schema/jsonld.d.ts +18 -0
  117. package/dist/schema/jsonld.js +120 -0
  118. package/dist/schema/jsonld.js.map +1 -0
  119. package/dist/schema/query.d.ts +47 -0
  120. package/dist/schema/query.js +103 -0
  121. package/dist/schema/query.js.map +1 -0
  122. package/dist/schema/text.d.ts +27 -0
  123. package/dist/schema/text.js +117 -0
  124. package/dist/schema/text.js.map +1 -0
  125. package/dist/server/app.d.ts +13 -0
  126. package/dist/server/app.js +57 -0
  127. package/dist/server/app.js.map +1 -0
  128. package/dist/server/deps.d.ts +20 -0
  129. package/dist/server/deps.js +2 -0
  130. package/dist/server/deps.js.map +1 -0
  131. package/dist/server/middleware.d.ts +39 -0
  132. package/dist/server/middleware.js +100 -0
  133. package/dist/server/middleware.js.map +1 -0
  134. package/dist/server/routes/api.d.ts +20 -0
  135. package/dist/server/routes/api.js +584 -0
  136. package/dist/server/routes/api.js.map +1 -0
  137. package/dist/server/routes/descriptor.d.ts +11 -0
  138. package/dist/server/routes/descriptor.js +31 -0
  139. package/dist/server/routes/descriptor.js.map +1 -0
  140. package/dist/server/routes/discovery.d.ts +12 -0
  141. package/dist/server/routes/discovery.js +305 -0
  142. package/dist/server/routes/discovery.js.map +1 -0
  143. package/dist/server/routes/mcp.d.ts +19 -0
  144. package/dist/server/routes/mcp.js +85 -0
  145. package/dist/server/routes/mcp.js.map +1 -0
  146. package/dist/server/routes/openapi.d.ts +11 -0
  147. package/dist/server/routes/openapi.js +297 -0
  148. package/dist/server/routes/openapi.js.map +1 -0
  149. package/dist/server/routes/pages.d.ts +11 -0
  150. package/dist/server/routes/pages.js +445 -0
  151. package/dist/server/routes/pages.js.map +1 -0
  152. package/dist/server/routes/passkey.d.ts +20 -0
  153. package/dist/server/routes/passkey.js +198 -0
  154. package/dist/server/routes/passkey.js.map +1 -0
  155. package/dist/server/routes/specs.d.ts +10 -0
  156. package/dist/server/routes/specs.js +42 -0
  157. package/dist/server/routes/specs.js.map +1 -0
  158. package/dist/server/serve.d.ts +11 -0
  159. package/dist/server/serve.js +79 -0
  160. package/dist/server/serve.js.map +1 -0
  161. package/dist/tui/index.d.ts +13 -0
  162. package/dist/tui/index.js +266 -0
  163. package/dist/tui/index.js.map +1 -0
  164. package/dist/tui/state.d.ts +63 -0
  165. package/dist/tui/state.js +136 -0
  166. package/dist/tui/state.js.map +1 -0
  167. package/dist/tui/types.d.ts +2 -0
  168. package/dist/tui/types.js +2 -0
  169. package/dist/tui/types.js.map +1 -0
  170. package/dist/tui/views.d.ts +11 -0
  171. package/dist/tui/views.js +197 -0
  172. package/dist/tui/views.js.map +1 -0
  173. package/dist/views/auth.d.ts +21 -0
  174. package/dist/views/auth.js +5 -0
  175. package/dist/views/auth.js.map +1 -0
  176. package/dist/views/docs.d.ts +17 -0
  177. package/dist/views/docs.js +40 -0
  178. package/dist/views/docs.js.map +1 -0
  179. package/dist/views/jobs.d.ts +49 -0
  180. package/dist/views/jobs.js +44 -0
  181. package/dist/views/jobs.js.map +1 -0
  182. package/dist/views/layout.d.ts +58 -0
  183. package/dist/views/layout.js +36 -0
  184. package/dist/views/layout.js.map +1 -0
  185. package/dist/views/me.d.ts +27 -0
  186. package/dist/views/me.js +6 -0
  187. package/dist/views/me.js.map +1 -0
  188. package/dist/views/network.d.ts +21 -0
  189. package/dist/views/network.js +17 -0
  190. package/dist/views/network.js.map +1 -0
  191. package/dist/views/post.d.ts +22 -0
  192. package/dist/views/post.js +20 -0
  193. package/dist/views/post.js.map +1 -0
  194. package/docs/openjob.md +200 -0
  195. package/docs/openresume.md +143 -0
  196. package/migrations/0001_init.sql +109 -0
  197. package/migrations/0002_auth.sql +82 -0
  198. package/migrations/0003_directory.sql +27 -0
  199. package/migrations/0004_resumes.sql +63 -0
  200. package/migrations/0005_application_drafts.sql +20 -0
  201. package/package.json +92 -0
  202. package/web/public/app.css +731 -0
  203. package/web/public/app.js +173 -0
  204. package/web/public/icon.svg +5 -0
  205. package/web/public/sw.js +64 -0
  206. package/web/public/tokens.css +153 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Profullstack, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # agenticjobs
2
+
3
+ **A job board where the agent on each side has a person behind it.**
4
+
5
+ The next few years of hiring look like this: a candidate's agent finds the role and
6
+ drafts the application, an employer's agent writes the posting and reads what comes
7
+ back, and a person at each end decides what actually happens. Everything in this
8
+ repository is built around that sentence.
9
+
10
+ Which means two things most job boards get wrong:
11
+
12
+ **Nothing here is scraped.** Every listing was posted to this board by the employer.
13
+ An empty search means nobody posted that job, not that a crawler missed it. That is
14
+ the only way a search result is worth anything to an agent, which cannot tell a stale
15
+ aggregator entry from a real opening.
16
+
17
+ **Both ends have a human control point, and they are the same shape.** An employer's
18
+ agent writes a listing and it lands as a draft for a person to publish. A candidate's
19
+ agent writes an application and it lands as a draft for a person to send. Neither
20
+ side can be automated past its human, and neither side is asked to trust that the
21
+ other one was not.
22
+
23
+ Self-hosted, MIT, Postgres. One person, one account, both sides of the table.
24
+
25
+ ```
26
+ npx @profullstack/agenticjobs --help
27
+ ```
28
+
29
+ ## Every surface, one engine
30
+
31
+ | | |
32
+ | --- | --- |
33
+ | Web | Server-rendered, mobile first, works with JavaScript off |
34
+ | PWA | Installable, offline shell, no build step |
35
+ | REST | `/api/v1`, hand-written OpenAPI, reads need no credentials |
36
+ | MCP | `/api/mcp` over streamable HTTP, or `agenticjobs-mcp` over stdio |
37
+ | CLI | `agenticjobs search`, `apply`, `post`, `publish`, `drafts` |
38
+ | TUI | `agenticjobs tui`, both sides in one window |
39
+ | Desktop | Electron, signed in to the same boards as your terminal |
40
+
41
+ The MCP tools call the REST API rather than the database, so a tool call takes the
42
+ same code path and the same permission checks a browser request does. There is
43
+ deliberately no second read path anywhere in this codebase.
44
+
45
+ ## For agents
46
+
47
+ Two requests to apply. No page to render, no form to guess.
48
+
49
+ ```bash
50
+ # what this board is, and where everything lives
51
+ curl https://agenticjobs.work/.well-known/agenticjobs
52
+
53
+ # search it
54
+ curl "https://agenticjobs.work/api/v1/jobs?q=rust&workplace=remote&agentPolicy=welcome"
55
+
56
+ # the application form, as data
57
+ curl https://agenticjobs.work/api/v1/jobs/SLUG/apply-schema
58
+
59
+ # send it
60
+ curl -X POST https://agenticjobs.work/api/v1/jobs/SLUG/apply \
61
+ -H 'content-type: application/json' \
62
+ -d '{"name":"Ada","email":"ada@example.com","cover":"...",
63
+ "resume":"# Ada Lovelace\n\n- **Email**: ada@example.com\n",
64
+ "agent":{"name":"claude-opus-5","supervised":true}}'
65
+ ```
66
+
67
+ ### The agent policy
68
+
69
+ Every listing declares one, and it is required:
70
+
71
+ | | |
72
+ | --- | --- |
73
+ | `welcome` | Agent-written applications are fine. Nothing is asked. |
74
+ | `disclose` | Fine, but say so. The application carries a structured disclosure. |
75
+ | `human-only` | The employer is asking for something a person wrote. |
76
+
77
+ `human-only` is a request, not a control. No board can tell who wrote a cover letter,
78
+ and one that claims it can is selling something. Saying it plainly is worth more than
79
+ pretending to enforce it.
80
+
81
+ And disclosure is not evidence against a candidate. A board that collects the
82
+ disclosure and then quietly filters those applications out has broken the field for
83
+ everyone, because the next candidate learns to lie.
84
+
85
+ ## Resumes are Markdown
86
+
87
+ A file a person can read, diff, and keep. A file an agent can write without being
88
+ taught a schema first.
89
+
90
+ ```markdown
91
+ # Ada Lovelace
92
+
93
+ - **Email**: ada@example.com
94
+ - **Location**: London
95
+
96
+ ## Experience
97
+
98
+ ### Analytical Engine | London
99
+ Chief Programmer (1842 - 1843)
100
+
101
+ - Wrote the first published algorithm intended for a machine.
102
+ ```
103
+
104
+ Upload a PDF, a Word file, plain text or Markdown and it is converted; what you keep
105
+ and what employers read is the Markdown, and you edit it before it goes anywhere. A
106
+ conversion nobody checks is a conversion nobody should trust.
107
+
108
+ The convention is [OpenResume.md](docs/openresume.md). The listing format is
109
+ [OpenJob](docs/openjob.md). Both are conventions anyone can implement, and neither
110
+ requires this software.
111
+
112
+ ## Run your own
113
+
114
+ ```bash
115
+ git clone https://github.com/profullstack/agenticjobs
116
+ cd agenticjobs
117
+ cp .env.example .env # set SECRET and PUBLIC_URL
118
+ docker compose up -d
119
+ ```
120
+
121
+ That is a board on http://localhost:8787 with its own Postgres. Migrations run at
122
+ boot behind an advisory lock, so `--scale app=3` is safe.
123
+
124
+ Without Docker:
125
+
126
+ ```bash
127
+ pnpm install && pnpm build
128
+ pnpm migrate && pnpm seed
129
+ pnpm start
130
+ ```
131
+
132
+ Deploying to Railway: the repo has a `railway.json`, so add a Postgres and point a
133
+ service at this Dockerfile. `PUBLIC_URL` and `SECRET` are the two variables that
134
+ matter.
135
+
136
+ ## Boards find each other
137
+
138
+ Instances are independent. Each one has its own database, its own domain and its own
139
+ rules, and any of them can list itself in a directory so people can find it:
140
+
141
+ ```bash
142
+ DIRECTORY_URL=https://agenticjobs.work
143
+ ANNOUNCE=true
144
+ ```
145
+
146
+ Your instance sends one field: its own URL. The directory then reads
147
+ `/.well-known/agenticjobs` from you directly, so nothing about your board is taken on
148
+ trust from the announcement. (A stream directory can trust an announcement that says
149
+ "I am playing something". A job board's announcement carries a company name and a job
150
+ count, and one that could claim someone else's would be a phishing tool on day one.)
151
+
152
+ A directory can then answer one question across every listed board at once. A board
153
+ that is slow or down is named in the results rather than silently dropped, so nobody
154
+ sees a shorter list with no explanation.
155
+
156
+ The same works from your terminal, for boards that are listed nowhere:
157
+
158
+ ```bash
159
+ agenticjobs login https://agenticjobs.work
160
+ agenticjobs login https://jobs.your-company.internal
161
+ agenticjobs search "staff engineer" --all # asks both, in parallel
162
+ ```
163
+
164
+ ## Both sides, from a terminal
165
+
166
+ ```bash
167
+ # looking
168
+ agenticjobs search "rust" --remote --agents
169
+ agenticjobs apply SLUG --resume ~/resume.md --draft # prepare, do not send
170
+ agenticjobs drafts # read what your agent wrote
171
+ agenticjobs submit <id> # you decide
172
+
173
+ # hiring, on the same account
174
+ agenticjobs post job.md --org acme # creates a draft
175
+ agenticjobs publish staff-engineer # you decide
176
+ agenticjobs applications staff-engineer
177
+ ```
178
+
179
+ Sign-in is the device flow: the terminal shows a short code, you approve it in a
180
+ browser, and no credential crosses the terminal. A terminal token can read and apply
181
+ and is never an administrator.
182
+
183
+ ## Posting from myna
184
+
185
+ A job opening goes out with the rest of a launch:
186
+
187
+ ```bash
188
+ myna login jobs
189
+ myna jobs post opening.md
190
+ myna jobs applicants staff-engineer
191
+ ```
192
+
193
+ The board is an **explicit target**. It is never part of `myna post --to all`, because
194
+ a status update fanning out into a job opening at your company is not something you
195
+ can delete your way out of.
196
+
197
+ ## Development
198
+
199
+ ```bash
200
+ pnpm install
201
+ docker compose up -d db
202
+ pnpm build && pnpm migrate && pnpm seed
203
+ pnpm dev
204
+ pnpm test # 61 tests; the API suite needs the database above
205
+ pnpm typecheck
206
+ ```
207
+
208
+ The repository is one package with a build step. The build exists because Node cannot
209
+ strip types from `.tsx` at all, and the pages are Hono JSX. Everything else follows
210
+ the house pattern: pnpm, Node 24, raw SQL forward-only migrations, no ORM.
211
+
212
+ shadcn's token vocabulary and component anatomy are ported by hand into plain CSS
213
+ (`web/public/tokens.css`, `app.css`). There is no Tailwind and no React here, so the
214
+ components could not be used directly; what is ported is their structure, and a theme
215
+ from the shadcn theme editor pastes straight in.
216
+
217
+ ## Licence
218
+
219
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/mcp/stdio.js';
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/cli/index.js';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Argument parsing, small enough to read.
3
+ *
4
+ * `--flag value`, `--flag=value`, `--bool`, `-x`, and `--` to stop parsing.
5
+ * Repeated flags collect into an array, because `--answer a=1 --answer b=2` is
6
+ * how the apply command takes fields.
7
+ */
8
+ export interface Args {
9
+ command: string;
10
+ positional: string[];
11
+ flags: Record<string, string | boolean | string[]>;
12
+ }
13
+ export declare function parseArgs(argv: string[]): Args;
14
+ export declare function flagString(args: Args, ...names: string[]): string | undefined;
15
+ export declare function flagBool(args: Args, ...names: string[]): boolean;
16
+ export declare function flagList(args: Args, ...names: string[]): string[];
17
+ export declare function flagNumber(args: Args, ...names: string[]): number | undefined;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Argument parsing, small enough to read.
3
+ *
4
+ * `--flag value`, `--flag=value`, `--bool`, `-x`, and `--` to stop parsing.
5
+ * Repeated flags collect into an array, because `--answer a=1 --answer b=2` is
6
+ * how the apply command takes fields.
7
+ */
8
+ export function parseArgs(argv) {
9
+ const positional = [];
10
+ const flags = {};
11
+ let stopped = false;
12
+ for (let index = 0; index < argv.length; index += 1) {
13
+ const token = argv[index] ?? '';
14
+ if (stopped) {
15
+ positional.push(token);
16
+ continue;
17
+ }
18
+ if (token === '--') {
19
+ stopped = true;
20
+ continue;
21
+ }
22
+ if (token.startsWith('--')) {
23
+ const body = token.slice(2);
24
+ const equals = body.indexOf('=');
25
+ if (equals >= 0) {
26
+ set(flags, body.slice(0, equals), body.slice(equals + 1));
27
+ continue;
28
+ }
29
+ const next = argv[index + 1];
30
+ if (next !== undefined && !next.startsWith('-')) {
31
+ set(flags, body, next);
32
+ index += 1;
33
+ continue;
34
+ }
35
+ set(flags, body, true);
36
+ continue;
37
+ }
38
+ if (token.startsWith('-') && token.length > 1) {
39
+ const body = token.slice(1);
40
+ const next = argv[index + 1];
41
+ if (next !== undefined && !next.startsWith('-')) {
42
+ set(flags, body, next);
43
+ index += 1;
44
+ continue;
45
+ }
46
+ set(flags, body, true);
47
+ continue;
48
+ }
49
+ positional.push(token);
50
+ }
51
+ return { command: positional.shift() ?? '', positional, flags };
52
+ }
53
+ function set(flags, key, value) {
54
+ const existing = flags[key];
55
+ if (existing === undefined) {
56
+ flags[key] = value;
57
+ return;
58
+ }
59
+ // Repeats collect. The first one having been a bare boolean is a typo, and
60
+ // dropping it silently is worse than keeping it as a string.
61
+ const list = Array.isArray(existing) ? existing : [String(existing)];
62
+ list.push(String(value));
63
+ flags[key] = list;
64
+ }
65
+ export function flagString(args, ...names) {
66
+ for (const name of names) {
67
+ const value = args.flags[name];
68
+ if (typeof value === 'string')
69
+ return value;
70
+ if (Array.isArray(value))
71
+ return value[value.length - 1];
72
+ }
73
+ return undefined;
74
+ }
75
+ export function flagBool(args, ...names) {
76
+ for (const name of names) {
77
+ const value = args.flags[name];
78
+ if (value === true)
79
+ return true;
80
+ if (typeof value === 'string')
81
+ return !['false', '0', 'no'].includes(value.toLowerCase());
82
+ }
83
+ return false;
84
+ }
85
+ export function flagList(args, ...names) {
86
+ const out = [];
87
+ for (const name of names) {
88
+ const value = args.flags[name];
89
+ if (typeof value === 'string')
90
+ out.push(value);
91
+ else if (Array.isArray(value))
92
+ out.push(...value);
93
+ }
94
+ return out;
95
+ }
96
+ export function flagNumber(args, ...names) {
97
+ const raw = flagString(args, ...names);
98
+ if (raw === undefined)
99
+ return undefined;
100
+ const parsed = Number.parseInt(raw, 10);
101
+ return Number.isFinite(parsed) ? parsed : undefined;
102
+ }
103
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,KAAK,GAAgD,EAAE,CAAC;IAC9D,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAEhC,IAAI,OAAO,EAAE,CAAC;YACZ,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,SAAS;QACX,CAAC;QACD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,GAAG,IAAI,CAAC;YACf,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;gBAChB,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC1D,SAAS;YACX,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC7B,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChD,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBACvB,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YACD,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YACvB,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC7B,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChD,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBACvB,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YACD,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YACvB,SAAS;QACX,CAAC;QAED,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAClE,CAAC;AAED,SAAS,GAAG,CACV,KAAkD,EAClD,GAAW,EACX,KAAuB;IAEvB,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACnB,OAAO;IACT,CAAC;IACD,2EAA2E;IAC3E,6DAA6D;IAC7D,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACzB,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAU,EAAE,GAAG,KAAe;IACvD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAU,EAAE,GAAG,KAAe;IACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAChC,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAU,EAAE,GAAG,KAAe;IACrD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;aAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAU,EAAE,GAAG,KAAe;IACvD,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC;IACvC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Terminal formatting.
3
+ *
4
+ * The escape byte is built rather than written literally, so the source stays
5
+ * plain ASCII and nothing here can be mangled by a tool that strips control
6
+ * characters on the way through.
7
+ *
8
+ * Colour is applied only when someone is looking at it: piping to a file or
9
+ * into jq gets clean text, which is what makes `--json` and plain output both
10
+ * usable in a script.
11
+ */
12
+ export declare const dim: (value: string) => string;
13
+ export declare const bold: (value: string) => string;
14
+ export declare const green: (value: string) => string;
15
+ export declare const red: (value: string) => string;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Terminal formatting.
3
+ *
4
+ * The escape byte is built rather than written literally, so the source stays
5
+ * plain ASCII and nothing here can be mangled by a tool that strips control
6
+ * characters on the way through.
7
+ *
8
+ * Colour is applied only when someone is looking at it: piping to a file or
9
+ * into jq gets clean text, which is what makes `--json` and plain output both
10
+ * usable in a script.
11
+ */
12
+ const ESC = String.fromCharCode(27);
13
+ function paint(code, value) {
14
+ if (process.stdout.isTTY !== true)
15
+ return value;
16
+ if (process.env['NO_COLOR'] !== undefined)
17
+ return value;
18
+ return `${ESC}[${code}m${value}${ESC}[0m`;
19
+ }
20
+ export const dim = (value) => paint('2', value);
21
+ export const bold = (value) => paint('1', value);
22
+ export const green = (value) => paint('32', value);
23
+ export const red = (value) => paint('31', value);
24
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/cli/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;AAEpC,SAAS,KAAK,CAAC,IAAY,EAAE,KAAa;IACxC,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACxD,OAAO,GAAG,GAAG,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,KAAK,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACjE,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The terminal.
3
+ *
4
+ * The whole board is here, both halves of it: a candidate searches, prepares
5
+ * and releases applications; an employer posts, publishes and reads what came
6
+ * in. One account does both, because the person running an agency and the
7
+ * person looking for work are frequently the same person on a different
8
+ * afternoon.
9
+ *
10
+ * Every command goes through BoardClient, so the terminal and the browser are
11
+ * looking at the same board through the same API.
12
+ */
13
+ export {};