@vibe-commit/capture 0.2.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -2
- package/dist/agent_hooks.d.ts +53 -8
- package/dist/agent_hooks.js +180 -19
- package/dist/agent_hooks.js.map +1 -1
- package/dist/agent_install.d.ts +0 -17
- package/dist/agent_install.js +1 -24
- package/dist/agent_install.js.map +1 -1
- package/dist/agents/cursor.js +54 -18
- package/dist/agents/cursor.js.map +1 -1
- package/dist/commands/auth.d.ts +24 -9
- package/dist/commands/auth.js +38 -10
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/browser_credential.d.ts +89 -0
- package/dist/commands/browser_credential.js +181 -0
- package/dist/commands/browser_credential.js.map +1 -0
- package/dist/commands/connect.d.ts +26 -9
- package/dist/commands/connect.js +52 -90
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/finalize.d.ts +35 -0
- package/dist/commands/finalize.js +283 -0
- package/dist/commands/finalize.js.map +1 -0
- package/dist/commands/status.js +56 -2
- package/dist/commands/status.js.map +1 -1
- package/dist/copy/index.d.ts +1 -1
- package/dist/copy/index.js +1 -1
- package/dist/copy/index.js.map +1 -1
- package/dist/copy/strings.d.ts +81 -2
- package/dist/copy/strings.js +94 -1
- package/dist/copy/strings.js.map +1 -1
- package/dist/exit.d.ts +7 -0
- package/dist/exit.js +7 -0
- package/dist/exit.js.map +1 -1
- package/dist/hooks/entry.d.ts +83 -0
- package/dist/hooks/entry.js +117 -28
- package/dist/hooks/entry.js.map +1 -1
- package/dist/hooks/post_rewrite.js +20 -3
- package/dist/hooks/post_rewrite.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -1
- package/dist/oauth/mint.d.ts +97 -0
- package/dist/oauth/mint.js +120 -0
- package/dist/oauth/mint.js.map +1 -0
- package/dist/oauth/signin.d.ts +25 -0
- package/dist/oauth/signin.js +30 -0
- package/dist/oauth/signin.js.map +1 -1
- package/dist/post.d.ts +53 -0
- package/dist/post.js +73 -5
- package/dist/post.js.map +1 -1
- package/dist/spool.d.ts +37 -0
- package/dist/spool.js +244 -36
- package/dist/spool.js.map +1 -1
- package/dist/state.d.ts +152 -0
- package/dist/state.js +255 -2
- package/dist/state.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/commands/auth.d.ts
CHANGED
|
@@ -36,19 +36,27 @@
|
|
|
36
36
|
* that discipline theatre. It is refused loudly rather than quietly ignored,
|
|
37
37
|
* because a user who typed it needs to be told it is now in their history.
|
|
38
38
|
*
|
|
39
|
-
* ##
|
|
39
|
+
* ## ⚠ Browser FIRST since `CR-226`; the paste is the fallback, not gone
|
|
40
40
|
*
|
|
41
|
-
*
|
|
42
|
-
* `vibecommit-mcp`
|
|
43
|
-
* plaintext
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
41
|
+
* This note used to say the verb "is not sign-in, and it does not mint", because
|
|
42
|
+
* `mintIngestCredential` in `vibecommit-mcp` had no route in front of it and the
|
|
43
|
+
* only plaintext producer was the web app's `POST /api/ingest-credentials`. The
|
|
44
|
+
* route now exists (`POST /oauth/ingest-credential`), so on a terminal this verb
|
|
45
|
+
* signs in through the browser and mints the credential there
|
|
46
|
+
* (`browser_credential.ts`). The paste below is unchanged and still reached:
|
|
47
47
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
48
|
+
* - `--stdin`, or no TTY — the CI shape. Never a browser, exactly as before.
|
|
49
|
+
* - `--paste` — a human who already holds a credential from the dashboard.
|
|
50
|
+
* - any browser step failing — its reason is printed, then the prompt runs.
|
|
51
|
+
*
|
|
52
|
+
* ⚠ So there is no path on which `CR-226` makes the pre-existing flow worse:
|
|
53
|
+
* every failure lands on the prompt that was the whole verb before it.
|
|
54
|
+
*
|
|
55
|
+
* @provenance vibecommit-mcp src/transport/server.ts — POST /oauth/ingest-credential is the mint route, verified
|
|
56
|
+
* @provenance vibecommit-web app/api/ingest-credentials/route.ts — the dashboard producer the paste path still serves, verified
|
|
50
57
|
*/
|
|
51
58
|
import type { CommandContext } from "./context.js";
|
|
59
|
+
import type { BrowserCredential, Retry } from "./browser_credential.js";
|
|
52
60
|
export interface AuthDeps {
|
|
53
61
|
/**
|
|
54
62
|
* Read the secret from a terminal WITHOUT ECHOING IT. Injected for the same
|
|
@@ -62,5 +70,12 @@ export interface AuthDeps {
|
|
|
62
70
|
readonly readSecret?: (prompt: string) => Promise<string>;
|
|
63
71
|
/** Read the whole of stdin. The pipe path, and the only path on a non-TTY. */
|
|
64
72
|
readonly readStdin?: () => Promise<string>;
|
|
73
|
+
/**
|
|
74
|
+
* The browser mint — `CR-226`. Injected like the two readers above, and for
|
|
75
|
+
* the same reason: left out, this verb is the paste-only verb it was before,
|
|
76
|
+
* so a test that forgot to stub it cannot reach a server or open a browser.
|
|
77
|
+
* `src/index.ts` passes the real one.
|
|
78
|
+
*/
|
|
79
|
+
readonly browser?: (ctx: CommandContext, retry: Retry) => Promise<BrowserCredential>;
|
|
65
80
|
}
|
|
66
81
|
export declare function auth(ctx: CommandContext, argv: readonly string[], deps?: AuthDeps): Promise<number>;
|
package/dist/commands/auth.js
CHANGED
|
@@ -36,29 +36,38 @@
|
|
|
36
36
|
* that discipline theatre. It is refused loudly rather than quietly ignored,
|
|
37
37
|
* because a user who typed it needs to be told it is now in their history.
|
|
38
38
|
*
|
|
39
|
-
* ##
|
|
39
|
+
* ## ⚠ Browser FIRST since `CR-226`; the paste is the fallback, not gone
|
|
40
40
|
*
|
|
41
|
-
*
|
|
42
|
-
* `vibecommit-mcp`
|
|
43
|
-
* plaintext
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
41
|
+
* This note used to say the verb "is not sign-in, and it does not mint", because
|
|
42
|
+
* `mintIngestCredential` in `vibecommit-mcp` had no route in front of it and the
|
|
43
|
+
* only plaintext producer was the web app's `POST /api/ingest-credentials`. The
|
|
44
|
+
* route now exists (`POST /oauth/ingest-credential`), so on a terminal this verb
|
|
45
|
+
* signs in through the browser and mints the credential there
|
|
46
|
+
* (`browser_credential.ts`). The paste below is unchanged and still reached:
|
|
47
47
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
48
|
+
* - `--stdin`, or no TTY — the CI shape. Never a browser, exactly as before.
|
|
49
|
+
* - `--paste` — a human who already holds a credential from the dashboard.
|
|
50
|
+
* - any browser step failing — its reason is printed, then the prompt runs.
|
|
51
|
+
*
|
|
52
|
+
* ⚠ So there is no path on which `CR-226` makes the pre-existing flow worse:
|
|
53
|
+
* every failure lands on the prompt that was the whole verb before it.
|
|
54
|
+
*
|
|
55
|
+
* @provenance vibecommit-mcp src/transport/server.ts — POST /oauth/ingest-credential is the mint route, verified
|
|
56
|
+
* @provenance vibecommit-web app/api/ingest-credentials/route.ts — the dashboard producer the paste path still serves, verified
|
|
50
57
|
*/
|
|
51
58
|
import { AUTH, URLS } from "../copy/index.js";
|
|
52
59
|
import { writeLines } from "./context.js";
|
|
53
60
|
import { EXIT } from "../exit.js";
|
|
54
61
|
import { INGEST_TOKEN_PREFIX, IngestCredential, saveCredential } from "../credential.js";
|
|
55
62
|
import { credentialsPath } from "../paths.js";
|
|
56
|
-
import { renderErrorBlock, tildePath } from "../term.js";
|
|
63
|
+
import { paint, renderErrorBlock, tildePath, wrap } from "../term.js";
|
|
57
64
|
/**
|
|
58
65
|
* `--stdin` forces the pipe even on a terminal — the CI shape, where a job may
|
|
59
66
|
* well have a TTY attached and must not start prompting because of it.
|
|
60
67
|
*/
|
|
61
68
|
const STDIN_FLAG = "--stdin";
|
|
69
|
+
/** `CR-226`. Skip the browser and go straight to the prompt. */
|
|
70
|
+
const PASTE_FLAG = "--paste";
|
|
62
71
|
export async function auth(ctx, argv, deps = {}) {
|
|
63
72
|
// ⛔ THE ARGV REFUSAL COMES FIRST, before stdin is read, resumed or opened.
|
|
64
73
|
// Anything else would mean the secret in `argv` had already been accepted by
|
|
@@ -75,6 +84,21 @@ export async function auth(ctx, argv, deps = {}) {
|
|
|
75
84
|
return EXIT.usage;
|
|
76
85
|
}
|
|
77
86
|
const piped = argv.includes(STDIN_FLAG) || !ctx.stdinIsTty;
|
|
87
|
+
// ── `CR-226`: the browser, first, on a terminal only. ──────────────────────
|
|
88
|
+
if (!piped && !argv.includes(PASTE_FLAG) && deps.browser !== undefined) {
|
|
89
|
+
const minted = await deps.browser(ctx, "auth");
|
|
90
|
+
if (minted.kind === "saved")
|
|
91
|
+
return saved(ctx);
|
|
92
|
+
// The reason is already on stderr. The documented fallback is the paste
|
|
93
|
+
// this verb has always had, with the page that mints one named first.
|
|
94
|
+
writeLines(ctx.stdout, [
|
|
95
|
+
"",
|
|
96
|
+
...wrap(AUTH.pasteInsteadLabel, 2),
|
|
97
|
+
// `accent` on a URL — §13.1's one exception, one colour on the line.
|
|
98
|
+
` ${paint(ctx.colour, "accent", URLS.settings)}`,
|
|
99
|
+
"",
|
|
100
|
+
]);
|
|
101
|
+
}
|
|
78
102
|
const raw = piped
|
|
79
103
|
? await (deps.readStdin ?? (() => Promise.resolve("")))()
|
|
80
104
|
: await (deps.readSecret ?? (() => Promise.resolve("")))(AUTH.prompt);
|
|
@@ -107,6 +131,10 @@ export async function auth(ctx, argv, deps = {}) {
|
|
|
107
131
|
return EXIT.failure;
|
|
108
132
|
}
|
|
109
133
|
saveCredential(ctx.home, new IngestCredential(secret, "file"));
|
|
134
|
+
return saved(ctx);
|
|
135
|
+
}
|
|
136
|
+
/** The one confirmation, whichever path wrote the file. */
|
|
137
|
+
function saved(ctx) {
|
|
110
138
|
writeLines(ctx.stdout, renderErrorBlock({
|
|
111
139
|
kind: "ok",
|
|
112
140
|
what: AUTH.savedWhat,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser beats — sign in, then buy this machine's ingest credential with
|
|
3
|
+
* that sign-in. `CR-084d` wrote the first; `CR-226` adds the second.
|
|
4
|
+
*
|
|
5
|
+
* ## Why these live together, and outside `connect`
|
|
6
|
+
*
|
|
7
|
+
* Sign-in used to be `connect`'s private beat, reachable only behind
|
|
8
|
+
* `--sign-in`, for a reason its own note gave: *"sign-in cannot mint the
|
|
9
|
+
* credential the rest of `connect` is about."* `CR-226` put a route in front of
|
|
10
|
+
* the minter, so that sentence stopped being true — and two verbs now need the
|
|
11
|
+
* pair. `auth` runs it first and falls back to the paste it has always had;
|
|
12
|
+
* `connect` runs it when a fresh machine reaches the credential beat with a
|
|
13
|
+
* human at the terminal. One copy of the sequence, two callers.
|
|
14
|
+
*
|
|
15
|
+
* ## ⚠ Browser FIRST, never browser ONLY (FOUNDER_OAUTH_PROPOSAL decision 2)
|
|
16
|
+
*
|
|
17
|
+
* Every failure here returns `failed` and leaves the machine exactly as it was:
|
|
18
|
+
* no half-written file, no deleted session. The caller then offers the paste
|
|
19
|
+
* path, which is the path that worked before this module existed. There is no
|
|
20
|
+
* outcome of this function that makes the pre-`CR-226` state worse, and that is
|
|
21
|
+
* the property that made it safe to wire a mechanism that had never run.
|
|
22
|
+
*
|
|
23
|
+
* ## ⚠ And never for a machine that already has a credential
|
|
24
|
+
*
|
|
25
|
+
* `VIBECOMMIT_TOKEN` is read before the file (D56) and still is; this module
|
|
26
|
+
* does not read either. It is the CALLER's job to reach it only when there is
|
|
27
|
+
* nothing to use — `connect` gates on `absent`, and `auth` is the verb a user
|
|
28
|
+
* types precisely to replace what is there.
|
|
29
|
+
*/
|
|
30
|
+
import { type IngestCredential } from "../credential.js";
|
|
31
|
+
import { type CommandContext } from "./context.js";
|
|
32
|
+
/**
|
|
33
|
+
* The network and the browser, injectable. Defaults are the real ones; a test
|
|
34
|
+
* supplies a `fetch` aimed at a stand-in server and an `openBrowser` that follows
|
|
35
|
+
* the authorize redirect itself.
|
|
36
|
+
*/
|
|
37
|
+
export interface BrowserDeps {
|
|
38
|
+
readonly fetch?: typeof fetch;
|
|
39
|
+
readonly openBrowser?: (url: string) => boolean;
|
|
40
|
+
/** The machine's name, for the credential's label. */
|
|
41
|
+
readonly hostname?: () => string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Which verb a failed step tells the user to run again.
|
|
45
|
+
*
|
|
46
|
+
* ⚠ A NAME, NOT THE COMMAND STRING, and that is for `test/copy-width.test.ts`.
|
|
47
|
+
* Its fix-line width gate DERIVES every string that can reach a `fixes:` array
|
|
48
|
+
* by reading the array literals; a `fixes: [retry]` holding a runtime string is
|
|
49
|
+
* invisible to it, which would quietly drop `COMMANDS.signIn` out of the set it
|
|
50
|
+
* checks. The conditional in `signInError` names all three copy paths inline,
|
|
51
|
+
* where the gate can see them.
|
|
52
|
+
*/
|
|
53
|
+
export type Retry = "auth" | "connect" | "sign-in";
|
|
54
|
+
export interface SignInBeatOptions extends BrowserDeps {
|
|
55
|
+
/** The verb a failed sign-in's fix line tells the user to run again. */
|
|
56
|
+
readonly retry: Retry;
|
|
57
|
+
/**
|
|
58
|
+
* Sign in even though a session file loads. Only for a session the server has
|
|
59
|
+
* already REFUSED to renew — see `browserCredential` — never to second-guess a
|
|
60
|
+
* working one.
|
|
61
|
+
*/
|
|
62
|
+
readonly replace?: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The browser sign-in beat — `CR-084d`.
|
|
66
|
+
*
|
|
67
|
+
* Opt-in inside `connect` (`--sign-in`) for the read lane, and the first half of
|
|
68
|
+
* `browserCredential` below. When a session already exists it is a no-op that
|
|
69
|
+
* says so; it never replaces a working session.
|
|
70
|
+
*/
|
|
71
|
+
export declare function signInBeat(ctx: CommandContext, options: SignInBeatOptions): Promise<number>;
|
|
72
|
+
export type BrowserCredential =
|
|
73
|
+
/** Minted AND written to `credentials.json`. The caller confirms it on screen. */
|
|
74
|
+
{
|
|
75
|
+
readonly kind: "saved";
|
|
76
|
+
readonly credential: IngestCredential;
|
|
77
|
+
}
|
|
78
|
+
/** Nothing was written. The reason is already on stderr; the caller offers the paste. */
|
|
79
|
+
| {
|
|
80
|
+
readonly kind: "failed";
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Sign in if needed, mint this machine's credential, save it — `CR-226`.
|
|
84
|
+
*
|
|
85
|
+
* Prints its own progress and its own failure; prints NOTHING on success,
|
|
86
|
+
* because what comes next differs by caller (`auth` ends, `connect` goes on to
|
|
87
|
+
* capture) and a confirmation here would be a second one.
|
|
88
|
+
*/
|
|
89
|
+
export declare function browserCredential(ctx: CommandContext, retry: Retry, deps?: BrowserDeps): Promise<BrowserCredential>;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser beats — sign in, then buy this machine's ingest credential with
|
|
3
|
+
* that sign-in. `CR-084d` wrote the first; `CR-226` adds the second.
|
|
4
|
+
*
|
|
5
|
+
* ## Why these live together, and outside `connect`
|
|
6
|
+
*
|
|
7
|
+
* Sign-in used to be `connect`'s private beat, reachable only behind
|
|
8
|
+
* `--sign-in`, for a reason its own note gave: *"sign-in cannot mint the
|
|
9
|
+
* credential the rest of `connect` is about."* `CR-226` put a route in front of
|
|
10
|
+
* the minter, so that sentence stopped being true — and two verbs now need the
|
|
11
|
+
* pair. `auth` runs it first and falls back to the paste it has always had;
|
|
12
|
+
* `connect` runs it when a fresh machine reaches the credential beat with a
|
|
13
|
+
* human at the terminal. One copy of the sequence, two callers.
|
|
14
|
+
*
|
|
15
|
+
* ## ⚠ Browser FIRST, never browser ONLY (FOUNDER_OAUTH_PROPOSAL decision 2)
|
|
16
|
+
*
|
|
17
|
+
* Every failure here returns `failed` and leaves the machine exactly as it was:
|
|
18
|
+
* no half-written file, no deleted session. The caller then offers the paste
|
|
19
|
+
* path, which is the path that worked before this module existed. There is no
|
|
20
|
+
* outcome of this function that makes the pre-`CR-226` state worse, and that is
|
|
21
|
+
* the property that made it safe to wire a mechanism that had never run.
|
|
22
|
+
*
|
|
23
|
+
* ## ⚠ And never for a machine that already has a credential
|
|
24
|
+
*
|
|
25
|
+
* `VIBECOMMIT_TOKEN` is read before the file (D56) and still is; this module
|
|
26
|
+
* does not read either. It is the CALLER's job to reach it only when there is
|
|
27
|
+
* nothing to use — `connect` gates on `absent`, and `auth` is the verb a user
|
|
28
|
+
* types precisely to replace what is there.
|
|
29
|
+
*/
|
|
30
|
+
import { hostname as osHostname } from "node:os";
|
|
31
|
+
import { AUTH, COMMANDS, SIGNIN } from "../copy/index.js";
|
|
32
|
+
import { saveCredential } from "../credential.js";
|
|
33
|
+
import { EXIT } from "../exit.js";
|
|
34
|
+
import { mcpUrl } from "../oauth/discovery.js";
|
|
35
|
+
import { machineLabel } from "../oauth/mint.js";
|
|
36
|
+
import { loadSession } from "../oauth/session.js";
|
|
37
|
+
import { HTTP_TIMEOUT_MS, mintWithSession, openBrowser as platformOpenBrowser, signIn, } from "../oauth/signin.js";
|
|
38
|
+
import { paint, renderErrorBlock, wrap } from "../term.js";
|
|
39
|
+
import { writeLines } from "./context.js";
|
|
40
|
+
/**
|
|
41
|
+
* The browser sign-in beat — `CR-084d`.
|
|
42
|
+
*
|
|
43
|
+
* Opt-in inside `connect` (`--sign-in`) for the read lane, and the first half of
|
|
44
|
+
* `browserCredential` below. When a session already exists it is a no-op that
|
|
45
|
+
* says so; it never replaces a working session.
|
|
46
|
+
*/
|
|
47
|
+
export async function signInBeat(ctx, options) {
|
|
48
|
+
if (options.replace !== true && loadSession(ctx.home).kind === "ok") {
|
|
49
|
+
writeLines(ctx.stdout, wrap(SIGNIN.alreadySignedIn, 2));
|
|
50
|
+
return EXIT.ok;
|
|
51
|
+
}
|
|
52
|
+
const endpoint = mcpUrl(ctx.env);
|
|
53
|
+
if (endpoint === null) {
|
|
54
|
+
writeLines(ctx.stderr, signInError(ctx, options.retry, SIGNIN.noServerWhat, SIGNIN.noServerRefusedWhy));
|
|
55
|
+
return EXIT.failure;
|
|
56
|
+
}
|
|
57
|
+
const outcome = await signIn({
|
|
58
|
+
home: ctx.home,
|
|
59
|
+
mcpEndpoint: endpoint,
|
|
60
|
+
fetch: options.fetch ?? fetch,
|
|
61
|
+
nowMs: () => ctx.now().getTime(),
|
|
62
|
+
openBrowser: options.openBrowser ?? platformOpenBrowser,
|
|
63
|
+
onAuthorizeUrl: (url, opened) => {
|
|
64
|
+
writeLines(ctx.stdout, [
|
|
65
|
+
"",
|
|
66
|
+
...wrap(opened ? SIGNIN.opening : SIGNIN.manualLabel, 2),
|
|
67
|
+
// `accent` on a URL is §13.1's one exception, and the line carries no
|
|
68
|
+
// second colour. Printed on BOTH paths: a user who wants to open it in a
|
|
69
|
+
// different browser than the default should not have to guess it.
|
|
70
|
+
` ${paint(ctx.colour, "accent", url)}`,
|
|
71
|
+
...(opened ? wrap(SIGNIN.waiting, 2) : []),
|
|
72
|
+
]);
|
|
73
|
+
},
|
|
74
|
+
page: { done: SIGNIN.browserDone, refused: SIGNIN.browserRefused },
|
|
75
|
+
});
|
|
76
|
+
if (outcome.kind === "ok") {
|
|
77
|
+
writeLines(ctx.stdout, ["", ...wrap(SIGNIN.done, 2)]);
|
|
78
|
+
return EXIT.ok;
|
|
79
|
+
}
|
|
80
|
+
writeLines(ctx.stderr, ["", ...signInFailure(ctx, options.retry, outcome)]);
|
|
81
|
+
return EXIT.failure;
|
|
82
|
+
}
|
|
83
|
+
/** §13.6's shape for a sign-in failure. One renderer, six outcomes. */
|
|
84
|
+
function signInFailure(ctx, retry, outcome) {
|
|
85
|
+
switch (outcome.kind) {
|
|
86
|
+
case "no-server":
|
|
87
|
+
return signInError(ctx, retry, SIGNIN.noServerWhat, outcome.detail === "unreachable"
|
|
88
|
+
? SIGNIN.noServerUnreachableWhy
|
|
89
|
+
: SIGNIN.noServerMalformedWhy, SIGNIN.noServerFix);
|
|
90
|
+
case "denied":
|
|
91
|
+
return signInError(ctx, retry, SIGNIN.deniedWhat, SIGNIN.deniedWhy, SIGNIN.deniedFix);
|
|
92
|
+
case "timeout":
|
|
93
|
+
return signInError(ctx, retry, SIGNIN.timeoutWhat, SIGNIN.timeoutWhy, SIGNIN.timeoutFix);
|
|
94
|
+
case "rejected":
|
|
95
|
+
return signInError(ctx, retry, SIGNIN.rejectedWhat, SIGNIN.rejectedWhy, SIGNIN.rejectedFix);
|
|
96
|
+
case "unreachable":
|
|
97
|
+
return signInError(ctx, retry, SIGNIN.unreachableWhat, SIGNIN.unreachableWhy, SIGNIN.unreachableFix);
|
|
98
|
+
case "malformed":
|
|
99
|
+
return signInError(ctx, retry, SIGNIN.malformedWhat, SIGNIN.malformedWhy, SIGNIN.malformedFix);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function signInError(ctx, retry, what, why, fixLabel = SIGNIN.noServerFix) {
|
|
103
|
+
return renderErrorBlock({
|
|
104
|
+
kind: "bad",
|
|
105
|
+
what,
|
|
106
|
+
why: [why],
|
|
107
|
+
fixLabel,
|
|
108
|
+
fixes: [
|
|
109
|
+
retry === "auth" ? COMMANDS.auth : retry === "connect" ? COMMANDS.connect : COMMANDS.signIn,
|
|
110
|
+
],
|
|
111
|
+
}, ctx.colour);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Sign in if needed, mint this machine's credential, save it — `CR-226`.
|
|
115
|
+
*
|
|
116
|
+
* Prints its own progress and its own failure; prints NOTHING on success,
|
|
117
|
+
* because what comes next differs by caller (`auth` ends, `connect` goes on to
|
|
118
|
+
* capture) and a confirmation here would be a second one.
|
|
119
|
+
*/
|
|
120
|
+
export async function browserCredential(ctx, retry, deps = {}) {
|
|
121
|
+
// Resolved ONCE and handed to both halves, so the session and the credential
|
|
122
|
+
// cannot come from two different servers.
|
|
123
|
+
const endpoint = mcpUrl(ctx.env);
|
|
124
|
+
if (endpoint === null) {
|
|
125
|
+
writeLines(ctx.stderr, signInError(ctx, retry, SIGNIN.noServerWhat, SIGNIN.noServerRefusedWhy));
|
|
126
|
+
return { kind: "failed" };
|
|
127
|
+
}
|
|
128
|
+
if ((await signInBeat(ctx, { ...deps, retry })) !== EXIT.ok)
|
|
129
|
+
return { kind: "failed" };
|
|
130
|
+
const label = machineLabel((deps.hostname ?? osHostname)());
|
|
131
|
+
writeLines(ctx.stdout, ["", ...wrap(AUTH.minting(label), 2)]);
|
|
132
|
+
const fetchImpl = deps.fetch ?? fetch;
|
|
133
|
+
const mint = () => mintWithSession(endpoint, label, {
|
|
134
|
+
home: ctx.home,
|
|
135
|
+
fetch: fetchImpl,
|
|
136
|
+
nowMs: () => ctx.now().getTime(),
|
|
137
|
+
mint: { fetch: fetchImpl, timeoutMs: HTTP_TIMEOUT_MS },
|
|
138
|
+
});
|
|
139
|
+
let outcome = await mint();
|
|
140
|
+
// ⚠ A SESSION THE SERVER WILL NOT RENEW IS OVER, and a stored file that loads
|
|
141
|
+
// is not the same as a session that works. `signInBeat` above declines to
|
|
142
|
+
// replace any session that LOADS — correct for the read lane, and a dead end
|
|
143
|
+
// here: the user would be told to sign in by a verb that then says "already
|
|
144
|
+
// signed in". So an `expired` (the refresh grant was refused) gets exactly one
|
|
145
|
+
// fresh sign-in and one more mint. Nothing else does: a `busy` lock or an
|
|
146
|
+
// unreachable server is not fixed by a browser.
|
|
147
|
+
if (outcome.kind === "not-authorized" && outcome.authorized.kind === "expired") {
|
|
148
|
+
if ((await signInBeat(ctx, { ...deps, retry, replace: true })) !== EXIT.ok) {
|
|
149
|
+
return { kind: "failed" };
|
|
150
|
+
}
|
|
151
|
+
outcome = await mint();
|
|
152
|
+
}
|
|
153
|
+
if (outcome.kind === "ok") {
|
|
154
|
+
// Through the CR-216 writer, so the 0700/0600 double-chmod and the
|
|
155
|
+
// wrong-class refusal apply exactly as they do to a pasted credential.
|
|
156
|
+
saveCredential(ctx.home, outcome.credential);
|
|
157
|
+
return { kind: "saved", credential: outcome.credential };
|
|
158
|
+
}
|
|
159
|
+
writeLines(ctx.stderr, ["", ...renderErrorBlock({ kind: "bad", what: AUTH.mintFailedWhat, why: [mintWhy(outcome)] }, ctx.colour)]);
|
|
160
|
+
return { kind: "failed" };
|
|
161
|
+
}
|
|
162
|
+
/** One `why` per way the mint can fail. No status codes on screen (§13.6). */
|
|
163
|
+
function mintWhy(outcome) {
|
|
164
|
+
switch (outcome.kind) {
|
|
165
|
+
case "not-authorized":
|
|
166
|
+
case "unauthorized":
|
|
167
|
+
case "wrong-client":
|
|
168
|
+
return AUTH.mintSessionWhy;
|
|
169
|
+
case "refused":
|
|
170
|
+
if (outcome.error === "not_a_member")
|
|
171
|
+
return AUTH.mintNotMemberWhy;
|
|
172
|
+
if (outcome.error === "rate_limited")
|
|
173
|
+
return AUTH.mintRateLimitedWhy;
|
|
174
|
+
return AUTH.mintRefusedWhy;
|
|
175
|
+
case "unreachable":
|
|
176
|
+
return AUTH.mintUnreachableWhy;
|
|
177
|
+
case "malformed":
|
|
178
|
+
return AUTH.mintMalformedWhy;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=browser_credential.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser_credential.js","sourceRoot":"","sources":["../../src/commands/browser_credential.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,17 +12,22 @@
|
|
|
12
12
|
* - `CR-025` owns the ending: capture the current session and print the live
|
|
13
13
|
* `/app/commits/<sha>` URL. The seam is marked below.
|
|
14
14
|
*
|
|
15
|
-
* `CR-084d`
|
|
16
|
-
* token for the READ lane) behind `--sign-in
|
|
17
|
-
*
|
|
18
|
-
* credential**, so it cannot replace the beat below. No route in
|
|
19
|
-
* `vibecommit-mcp` mints a `vcik_` — `mintIngestCredential` exists and has no
|
|
20
|
-
* call site outside that repo's own tests — so `VIBECOMMIT_TOKEN` remains the
|
|
21
|
-
* supported path for capture, exactly as before.
|
|
15
|
+
* `CR-084d` landed the browser sign-in beat (PKCE loopback → a user-principal
|
|
16
|
+
* token for the READ lane) behind `--sign-in`, opt-in because sign-in did not
|
|
17
|
+
* produce an ingest credential.
|
|
22
18
|
*
|
|
23
|
-
*
|
|
19
|
+
* ⚠ `CR-226` CHANGED THAT, AND THIS NOTE USED TO SAY THE OPPOSITE. The server
|
|
20
|
+
* now has a route in front of `mintIngestCredential`, so a fresh machine that
|
|
21
|
+
* reaches the credential beat with a human at the terminal signs in through the
|
|
22
|
+
* browser and mints its own credential there (`browser_credential.ts`) — browser
|
|
23
|
+
* FIRST, with the old warning pointing at `vibecommit auth` as the fallback when
|
|
24
|
+
* any step fails. `--sign-in` keeps its meaning (sign in for the read lane even
|
|
25
|
+
* when a credential exists), and `VIBECOMMIT_TOKEN` still wins over everything.
|
|
26
|
+
*
|
|
27
|
+
* @provenance vibecommit-mcp src/transport/server.ts — POST /oauth/ingest-credential now mints one, verified
|
|
24
28
|
*/
|
|
25
29
|
import { type CommandContext } from "./context.js";
|
|
30
|
+
import { type BrowserCredential, type Retry } from "./browser_credential.js";
|
|
26
31
|
/**
|
|
27
32
|
* What `connect` was asked to do beyond the default.
|
|
28
33
|
*
|
|
@@ -33,4 +38,16 @@ export interface ConnectOptions {
|
|
|
33
38
|
/** `--sign-in`. Off by default — see the module note for why. */
|
|
34
39
|
readonly signIn?: boolean;
|
|
35
40
|
}
|
|
36
|
-
|
|
41
|
+
/**
|
|
42
|
+
* The browser beat, INJECTED — `CR-226`. `src/index.ts` passes the real
|
|
43
|
+
* `browserCredential`; left out, the credential beat behaves exactly as it did
|
|
44
|
+
* before the route existed and never opens a browser. That default is the same
|
|
45
|
+
* one `auth` takes for its readers, and for the same reason: a suite that
|
|
46
|
+
* forgot to stub it must not reach a real server or launch a real browser.
|
|
47
|
+
* `test/cli-wiring.test.ts` asserts the boot path supplies it, so "forgot" is
|
|
48
|
+
* caught where it matters.
|
|
49
|
+
*/
|
|
50
|
+
export interface ConnectDeps {
|
|
51
|
+
readonly browser?: (ctx: CommandContext, retry: Retry) => Promise<BrowserCredential>;
|
|
52
|
+
}
|
|
53
|
+
export declare function connect(ctx: CommandContext, options?: ConnectOptions, deps?: ConnectDeps): Promise<number>;
|