@uptomic/career-mentor-cli 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.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,319 @@
1
+ # `@uptomic/career-mentor-cli`
2
+
3
+ Official JSON-first command-line client for the hosted Career Mentor Capability API. It is designed
4
+ for people, scripts, coding agents, and MCP-adjacent automation that should not need the web UI.
5
+
6
+ The CLI uses the generated `@uptomic/career-mentor` transport and bundles that runtime into the published
7
+ artifact. It never imports the Career Mentor backend, opens a database connection, or implements a
8
+ second capability path.
9
+
10
+ ## Install and run
11
+
12
+ ```sh
13
+ npm install --global @uptomic/career-mentor-cli
14
+ cm help
15
+ ```
16
+
17
+ `career-mentor` is the long alias for `cm`. The package runs on Node.js 20+ and Bun 1.2+.
18
+ Using Bun is also supported: `bun add --global @uptomic/career-mentor-cli`.
19
+
20
+ Without a global install:
21
+
22
+ ```sh
23
+ bunx @uptomic/career-mentor-cli help
24
+ ```
25
+
26
+ ## Authentication
27
+
28
+ Authorize the CLI with your Career Mentor account:
29
+
30
+ ```sh
31
+ cm auth login
32
+ cm auth status
33
+ cm doctor
34
+ ```
35
+
36
+ `auth login` starts a loopback listener on `127.0.0.1`, opens the Career Mentor authorization page,
37
+ and uses PKCE to exchange a one-time authorization code for a scoped capability token. The raw token
38
+ is never placed in a URL, browser history, referrer, stdout, or stderr. Only the authorization code and
39
+ state return through the loopback redirect. The CLI then writes the token atomically to
40
+ `~/.career-mentor/capability-token` with `0600` permissions.
41
+
42
+ Browser authorization is the only CLI workflow that opens the web app. After login, capability
43
+ discovery, invocation, run inspection, and event streaming work without the UI. In a headless
44
+ environment where the browser can reach the same loopback listener, print the authorization URL as a
45
+ structured stderr diagnostic instead of opening a browser:
46
+
47
+ ```sh
48
+ cm auth login --no-open
49
+ ```
50
+
51
+ For an SSH host, select a fixed `--port` and configure loopback port forwarding before opening the URL;
52
+ the redirect deliberately cannot target a non-loopback host.
53
+
54
+ Request an explicit scope set or expiry when needed; omitting scopes lets Career Mentor apply the
55
+ account-safe defaults. Those defaults deliberately omit `account:write` and `actions:confirm`, so
56
+ request either one explicitly, alongside the exact domain scopes needed, only for access-key
57
+ management or reviewed commit approval:
58
+
59
+ ```sh
60
+ cm auth login --scopes 'profile:read,jobs:read' --expires-in-days 7
61
+ ```
62
+
63
+ `cm auth status` reports only whether a credential exists and which source won. It never prints the
64
+ token or a token prefix. Credential precedence is `--token`, then
65
+ `CAREER_MENTOR_CAPABILITY_TOKEN`, then the managed file. Override the managed file location with
66
+ `--credential-file` or `CAREER_MENTOR_CAPABILITY_TOKEN_FILE`.
67
+
68
+ `--token` remains available for ephemeral execution, but command arguments can be stored in shell
69
+ history and process listings. To remove the local managed credential without touching neighboring
70
+ files:
71
+
72
+ ```sh
73
+ cm auth logout
74
+ ```
75
+
76
+ Logout is deliberately local-only. Revoke an active token from the Career Mentor agent-access page
77
+ or entirely through the CLI when server-side invalidation is required. Revocation requires a token
78
+ authorized with `account:write`:
79
+
80
+ ```sh
81
+ cm invoke list_capability_tokens --input '{}'
82
+ cm invoke revoke_capability_token --input '{"tokenId":"<token-id>"}'
83
+ cm auth logout
84
+ ```
85
+
86
+ The same privileged CLI session can mint a least-privilege child token. The new secret is returned
87
+ exactly once:
88
+
89
+ ```sh
90
+ cm invoke create_capability_token \
91
+ --input '{"name":"job-search-agent","scopes":["capabilities:read","jobs:read"],"expiresInDays":30}'
92
+ ```
93
+
94
+ The production API origin defaults to `https://app.uptomic.com`. Override it for another environment:
95
+
96
+ ```sh
97
+ export CAREER_MENTOR_API_URL='https://staging.uptomic.com'
98
+ ```
99
+
100
+ The value is an origin or deployment base URL. The SDK appends the canonical `/api/v1` capability
101
+ paths.
102
+
103
+ ## Discover capabilities
104
+
105
+ ```sh
106
+ cm capabilities list
107
+ cm capabilities describe search_jobs
108
+ ```
109
+
110
+ `describe` returns the published manifest, including the exact input and output JSON schemas, scopes,
111
+ risk, explicit destructive behavior, side effects, confirmation policy, idempotency behavior, and
112
+ bounded-sync or durable-run execution contract.
113
+
114
+ ## Invoke a capability
115
+
116
+ Inline JSON:
117
+
118
+ ```sh
119
+ cm invoke search_jobs \
120
+ --input '{"query":"staff engineer","limit":10}' \
121
+ --request-id 'agent-run-42-search' \
122
+ --agent-session-id 'agent-run-42' \
123
+ --idempotency-key 'agent-run-42-search-attempt-1'
124
+ ```
125
+
126
+ An idempotency key names one caller operation. The same key and validated input replay safely; changed
127
+ input under that key exits with the API's conflict result. Do not configure one global key for
128
+ unrelated invocations. Chat and skill-interview commands execute every keyless call as a distinct turn,
129
+ so pass a key only when retrying the same turn. When a manifest sets
130
+ `executionContract.requiresIdempotencyKey` to true, the key is mandatory for non-dry-run execution and
131
+ reconnects request retries to one persisted operation.
132
+
133
+ Read a JSON object from a file or stdin:
134
+
135
+ ```sh
136
+ cm invoke save_job --input-file ./save-job.json
137
+ printf '%s' '{"jobId":"job-id","careerPathId":"path-id"}' \
138
+ | cm invoke save_job --input-file -
139
+ ```
140
+
141
+ The CLI returns HTTP `202` capability envelopes immediately. It never polls a long-running workflow.
142
+ Use the returned run/event references with the documented event surface.
143
+
144
+ ## Upload Career Vault files
145
+
146
+ Upload and register a local file without opening the web UI:
147
+
148
+ ```sh
149
+ cm artifacts upload ./resume.pdf
150
+ ```
151
+
152
+ The command accepts PDF, DOC, DOCX, JPEG, PNG, WebP, Markdown, and plain-text files up to 10 MiB. It
153
+ uses the published `initiate_artifact_upload` and `register_artifact_upload` capabilities around one
154
+ size- and content-type-bound PUT with a three-minute authorization. `--idempotency-key` identifies the
155
+ authorization attempt; registration and optional artifact creation keep their payload-bound
156
+ identities. Rerunning after the authorization expires therefore obtains a fresh URL and storage key
157
+ without reusing that key against changed registration input. The PUT carries no capability token, and
158
+ stdout never includes the
159
+ temporary upload URL or storage key.
160
+
161
+ File registration does not create a Career Vault artifact implicitly. Request creation and canonical
162
+ Mastra analysis explicitly:
163
+
164
+ ```sh
165
+ cm artifacts upload ./resume.pdf --create --type resume --name 'Primary resume'
166
+ ```
167
+
168
+ Supported artifact types are `resume`, `certificate`, `portfolio`, `recommendation`,
169
+ `performance_review`, `award`, `course_completion`, `project`, `publication`, and `other`. `--name`
170
+ defaults to the filename without its extension. Successful output is one JSON object containing the
171
+ safe registered `file` projection and, only with `--create`, the new `artifact` and queue state.
172
+
173
+ ## Manage profile photos and registered files
174
+
175
+ Profile photos attach only from a registered current-user image file. The upload response above
176
+ contains the required `fileId`; no photo command accepts a storage URL or object key.
177
+
178
+ ```sh
179
+ cm artifacts upload ./portrait.jpg
180
+ cm photos add <registered-file-id>
181
+ cm photos list
182
+ cm photos default <photo-id>
183
+ cm photos reorder <photo-id-2> <photo-id-1>
184
+ ```
185
+
186
+ `photos reorder` replaces the complete order and therefore requires every current photo ID exactly
187
+ once. Repeating `photos add` with the same registered file is idempotent.
188
+
189
+ Photo and standalone registered-file deletion always start with a reviewed proposal:
190
+
191
+ ```sh
192
+ cm photos delete <photo-id>
193
+ cm files delete <registered-file-id>
194
+ ```
195
+
196
+ These commands do not auto-confirm. Inspect the returned preview, then invoke its named commit
197
+ capability with the exact pending action ID and payload hash. Standalone file deletion is refused
198
+ while a Career Vault artifact, resume parse, onboarding resume run, or profile photo references the
199
+ file. Photo deletion removes the registered object only when no other authoritative reference
200
+ remains.
201
+
202
+ ## Observe asynchronous runs
203
+
204
+ Get current status or replay a bounded page of events:
205
+
206
+ ```sh
207
+ cm runs get 019f5074-5680-7000-8000-000000000001
208
+ cm runs events 019f5074-5680-7000-8000-000000000001 --after 0-0 --limit 100
209
+ ```
210
+
211
+ Wait for exactly one terminal event:
212
+
213
+ ```sh
214
+ cm runs wait 019f5074-5680-7000-8000-000000000001 \
215
+ --last-event-id 17-0 \
216
+ --timeout-ms 600000
217
+ ```
218
+
219
+ `runs wait` prints exactly one terminal JSON document. It never polls. When the server normally closes
220
+ a bounded SSE session before terminal state, it applies bounded backoff and reconnects from the last
221
+ validated event ID. `--timeout-ms` is one overall budget across every stream and reconnect delay;
222
+ Ctrl-C aborts the entire wait. A succeeded terminal event exits `0`, failed exits `8`, and cancelled
223
+ exits `9`. All three terminal envelopes stay on stdout and stderr remains empty.
224
+
225
+ Subscribe without polling:
226
+
227
+ ```sh
228
+ cm runs watch 019f5074-5680-7000-8000-000000000001 \
229
+ --last-event-id 17-0 \
230
+ --timeout-ms 30000
231
+ ```
232
+
233
+ `runs watch` is the one streaming output exception: it writes one validated event JSON object per
234
+ line (JSON Lines) as SSE frames arrive. It ignores heartbeat comments and stops when the server emits
235
+ a terminal event, the bounded SSE session closes, the timeout expires, or the caller interrupts it.
236
+ Timeout/network failures use exit `6`; Ctrl-C/caller abort uses exit `130` and writes the normal
237
+ sanitized error JSON to stderr.
238
+
239
+ `runs watch` does not reconnect invisibly. Record the last printed `id` and pass it through
240
+ `--last-event-id` to resume; this becomes the HTTP `Last-Event-ID` header. `--after` is the replay
241
+ query cursor and may also seed a watch, while `--last-event-id` takes precedence when both are set.
242
+ A nonterminal bounded-session close exits successfully, so the caller decides if and when to reconnect.
243
+
244
+ ## Agent transport controls
245
+
246
+ Every API command supports these flags and environment defaults:
247
+
248
+ | Flag | Environment variable | Purpose |
249
+ |---|---|---|
250
+ | `--endpoint` | `CAREER_MENTOR_API_URL` | Hosted API origin/base URL |
251
+ | `--token` | `CAREER_MENTOR_CAPABILITY_TOKEN` | Scoped user capability token |
252
+ | `--credential-file` | `CAREER_MENTOR_CAPABILITY_TOKEN_FILE` | Managed token file used after flag/environment lookup |
253
+ | `--timeout-ms` | `CAREER_MENTOR_TIMEOUT_MS` | Positive request timeout in milliseconds |
254
+ | `--request-id` | `CAREER_MENTOR_REQUEST_ID` | Per-request correlation ID |
255
+ | `--agent-session-id` | `CAREER_MENTOR_AGENT_SESSION_ID` | Agent-session correlation ID |
256
+ | `--idempotency-key` | `CAREER_MENTOR_IDEMPOTENCY_KEY` | Invocation idempotency key |
257
+
258
+ Flags take precedence over their environment defaults. `--idempotency-key` is accepted by `invoke`,
259
+ `artifacts upload`, `photos`, and `files`. Run event commands additionally accept `--after` and
260
+ `--limit`; `runs wait` and `runs watch` also accept `--last-event-id`.
261
+
262
+ ## Output and exit contract
263
+
264
+ Non-streaming command results are one JSON document on stdout. `runs wait` keeps its terminal envelope
265
+ on stdout even when failed or cancelled returns a nonzero outcome code. `runs watch` emits JSON Lines,
266
+ one event per line. Transport, API, configuration, and input errors are one sanitized JSON document on
267
+ stderr. `auth login` additionally emits a structured browser-handoff diagnostic on stderr, and
268
+ `doctor` always emits its complete report on stdout even when a check fails. The CLI emits no
269
+ unstructured banners, progress indicators, or log noise, so agents can parse the declared stream
270
+ directly.
271
+
272
+ ```json
273
+ {"ok":false,"error":{"code":"UNAUTHORIZED","message":"Capability token is invalid.","exitCode":3,"status":401,"requestId":"request-id"}}
274
+ ```
275
+
276
+ Exit codes are stable public behavior:
277
+
278
+ | Code | Meaning |
279
+ |---:|---|
280
+ | `0` | Success |
281
+ | `1` | Unexpected internal CLI error |
282
+ | `2` | Invalid command, configuration, or capability input |
283
+ | `3` | Authentication or authorization failure |
284
+ | `4` | Capability/resource not found |
285
+ | `5` | Conflict, in-progress idempotent request, or rate limit |
286
+ | `6` | Network error, timeout, or unavailable service |
287
+ | `7` | Other API error |
288
+ | `8` | Capability run reached terminal `failed` state |
289
+ | `9` | Capability run reached terminal `cancelled` state |
290
+ | `130` | Caller interruption/abort |
291
+
292
+ The token is redacted if any upstream error echoes it. Server payloads, stack traces, and transport
293
+ causes are never printed.
294
+
295
+ ## Package development and release
296
+
297
+ From this package directory:
298
+
299
+ ```sh
300
+ bun run test
301
+ bun run typecheck
302
+ bun run build
303
+ bun run test:package # pack, install in isolation, run both installed binaries
304
+ bun run release:dry-run
305
+ ```
306
+
307
+ Publication has one trigger: run `.github/workflows/publish-agentic-packages.yml` from the exact
308
+ `agentic-vX.Y.Z` tag. Its tag-restricted `npm-production` environment gates the publish job, which loads
309
+ the npm credential from Infisical at runtime. The workflow runs the full release gate, publishes the
310
+ already-verified SDK and CLI tarballs in order, and installs the registry artifacts under Node.js 20.
311
+
312
+ The Bun token-publish workflow does not generate npm provenance. Accepting that release explicitly or
313
+ moving to a public-repository npm trusted-publisher workflow is a product-owner decision; neither path
314
+ is inferred by the package build.
315
+
316
+ ## License
317
+
318
+ Apache-2.0. Copyright 2026 Uptomic. This grant applies to the published Career Mentor CLI package,
319
+ not to the private Career Mentor backend or the rest of its monorepo.
package/dist/auth.d.ts ADDED
@@ -0,0 +1,86 @@
1
+ export declare const CAPABILITY_TOKEN_ENV = "CAREER_MENTOR_CAPABILITY_TOKEN";
2
+ export declare const CAPABILITY_TOKEN_FILE_ENV = "CAREER_MENTOR_CAPABILITY_TOKEN_FILE";
3
+ export declare const AUTH_APP_URL_ENV = "CAREER_MENTOR_AUTH_APP_URL";
4
+ export declare const DEFAULT_AUTH_APP_URL = "https://app.uptomic.com";
5
+ export declare const DEFAULT_AUTH_EXPIRES_IN_DAYS = 7;
6
+ export declare const DEFAULT_AUTH_TIMEOUT_MS: number;
7
+ export type BrowserAuthErrorCode = 'AUTH_ABORTED' | 'AUTH_BROWSER_OPEN_FAILED' | 'AUTH_CALLBACK_FAILED' | 'AUTH_CREDENTIAL_INVALID' | 'AUTH_FILE_INVALID' | 'AUTH_FILE_PERMISSIONS' | 'AUTH_INPUT_INVALID' | 'AUTH_SERVER_FAILED' | 'AUTH_STATE_MISMATCH' | 'AUTH_TIMEOUT';
8
+ export declare class BrowserAuthError extends Error {
9
+ readonly code: BrowserAuthErrorCode;
10
+ constructor(code: BrowserAuthErrorCode, message: string);
11
+ }
12
+ export type ResolvedCredential = {
13
+ source: '--token' | 'CAREER_MENTOR_CAPABILITY_TOKEN' | 'managed_file';
14
+ token: string;
15
+ };
16
+ type CapturedAuthToken = {
17
+ code: string;
18
+ };
19
+ export type LoopbackCallbackServer = {
20
+ close: () => Promise<void>;
21
+ port: number;
22
+ redirectUri: string;
23
+ waitForCallback: Promise<CapturedAuthToken>;
24
+ };
25
+ export type BrowserAuthLaunch = {
26
+ authorizationUrl: string;
27
+ openBrowser: boolean;
28
+ redirectUri: string;
29
+ };
30
+ export type BrowserAuthLoginOptions = {
31
+ appUrl: string;
32
+ clientName: string;
33
+ credentialFile: string;
34
+ expiresInDays: number;
35
+ onLaunch: (launch: BrowserAuthLaunch) => Promise<void>;
36
+ openBrowser: boolean;
37
+ port?: number;
38
+ scopes: string[];
39
+ signal?: AbortSignal;
40
+ timeoutMs: number;
41
+ };
42
+ export type BrowserAuthLoginResult = {
43
+ credentialFile: string;
44
+ expiresAt: string;
45
+ scopes: string[];
46
+ };
47
+ export type BrowserAuthOverrides = {
48
+ fetch?: typeof globalThis.fetch;
49
+ generateCodeVerifier?: () => string;
50
+ generateState?: () => string;
51
+ openUrl?: (url: string) => Promise<void>;
52
+ };
53
+ export declare function defaultCredentialFile(): string;
54
+ export declare function resolveCredentialFile(explicitPath: string | undefined, environmentPath: string | undefined): string;
55
+ export declare function parseRequestedScopes(value: string | undefined): string[];
56
+ export declare function buildAgentAuthUrl(params: {
57
+ appUrl: string;
58
+ clientName: string;
59
+ codeChallenge: string;
60
+ expiresInDays: number;
61
+ redirectUri: string;
62
+ scopes: readonly string[];
63
+ state: string;
64
+ }): string;
65
+ export declare function resolveCredential(params: {
66
+ credentialFile: string;
67
+ envToken?: string;
68
+ flagToken?: string;
69
+ }): Promise<ResolvedCredential | undefined>;
70
+ export declare function writeCredentialFile(filePath: string, token: string): Promise<void>;
71
+ export declare function logoutCredential(filePath: string): Promise<{
72
+ removed: boolean;
73
+ }>;
74
+ export declare function startLoopbackCallbackServer(params: {
75
+ port?: number;
76
+ signal?: AbortSignal;
77
+ state: string;
78
+ timeoutMs: number;
79
+ }): Promise<LoopbackCallbackServer>;
80
+ export declare function browserLaunchCommand(url: string, platform?: NodeJS.Platform): {
81
+ args: string[];
82
+ command: string;
83
+ };
84
+ export declare function openUrlInBrowser(url: string): Promise<void>;
85
+ export declare function runBrowserAuthLogin(options: BrowserAuthLoginOptions, overrides?: BrowserAuthOverrides): Promise<BrowserAuthLoginResult>;
86
+ export {};
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from './index.js';
3
+
4
+ const controller = new AbortController();
5
+ const abort = () => controller.abort();
6
+ process.once('SIGINT', abort);
7
+ process.once('SIGTERM', abort);
8
+ try {
9
+ process.exitCode = await runCli(process.argv.slice(2), { signal: controller.signal });
10
+ } finally {
11
+ process.removeListener('SIGINT', abort);
12
+ process.removeListener('SIGTERM', abort);
13
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ import { type BrowserAuthOverrides } from './auth.ts';
2
+ export declare const CLI_VERSION = "0.1.0";
3
+ export declare const DEFAULT_API_URL = "https://app.uptomic.com";
4
+ export declare const CLI_EXIT_CODE: Readonly<{
5
+ readonly SUCCESS: 0;
6
+ readonly INTERNAL: 1;
7
+ readonly USAGE: 2;
8
+ readonly AUTH: 3;
9
+ readonly NOT_FOUND: 4;
10
+ readonly CONFLICT_OR_LIMIT: 5;
11
+ readonly UNAVAILABLE: 6;
12
+ readonly API_ERROR: 7;
13
+ readonly RUN_FAILED: 8;
14
+ readonly RUN_CANCELLED: 9;
15
+ readonly INTERRUPTED: 130;
16
+ }>;
17
+ type Env = Record<string, string | undefined>;
18
+ type Write = (text: string) => void;
19
+ type FlagValue = boolean | string;
20
+ type Flags = Record<string, FlagValue>;
21
+ export interface CliOptions {
22
+ browserAuth?: BrowserAuthOverrides;
23
+ env?: Env;
24
+ fetch?: typeof globalThis.fetch;
25
+ readBinaryFile?: (path: string) => Promise<Uint8Array>;
26
+ readFile?: (path: string) => Promise<string>;
27
+ readStdin?: () => Promise<string>;
28
+ signal?: AbortSignal;
29
+ stderr?: Write;
30
+ stdout?: Write;
31
+ }
32
+ export interface ParsedArgs {
33
+ flags: Flags;
34
+ positionals: string[];
35
+ }
36
+ export declare function parseArgs(argv: readonly string[]): ParsedArgs;
37
+ export declare function runCli(argv: readonly string[], options?: CliOptions): Promise<number>;
38
+ export {};
@@ -0,0 +1 @@
1
+ export { CLI_EXIT_CODE, CLI_VERSION, DEFAULT_API_URL, parseArgs, runCli, type CliOptions, type ParsedArgs, } from './cli.ts';