@vibe-commit/capture 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +238 -7
- package/dist/account_not_here.d.ts +15 -0
- package/dist/account_not_here.js +25 -0
- package/dist/account_not_here.js.map +1 -0
- package/dist/agents/claude_code.js +13 -0
- package/dist/agents/claude_code.js.map +1 -1
- package/dist/agents/codex_cli.js +11 -0
- package/dist/agents/codex_cli.js.map +1 -1
- package/dist/agents/cursor.js +7 -1
- package/dist/agents/cursor.js.map +1 -1
- package/dist/agents/registry.d.ts +7 -0
- package/dist/agents/registry.js +9 -0
- package/dist/agents/registry.js.map +1 -1
- package/dist/agents/types.d.ts +32 -0
- package/dist/agents/types.js.map +1 -1
- package/dist/bounded_id.d.ts +29 -0
- package/dist/bounded_id.js +42 -0
- package/dist/bounded_id.js.map +1 -0
- package/dist/codex_folders.d.ts +340 -0
- package/dist/codex_folders.js +1448 -0
- package/dist/codex_folders.js.map +1 -0
- package/dist/commands/auth.d.ts +7 -0
- package/dist/commands/auth.js +21 -0
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/backfill.d.ts +29 -7
- package/dist/commands/backfill.js +387 -109
- package/dist/commands/backfill.js.map +1 -1
- package/dist/commands/browser_credential.d.ts +4 -2
- package/dist/commands/browser_credential.js +5 -2
- package/dist/commands/browser_credential.js.map +1 -1
- package/dist/commands/connect.d.ts +10 -1
- package/dist/commands/connect.js +14 -9
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/connect_account.d.ts +135 -0
- package/dist/commands/connect_account.js +321 -0
- package/dist/commands/connect_account.js.map +1 -0
- package/dist/commands/connect_picker.js +204 -29
- package/dist/commands/connect_picker.js.map +1 -1
- package/dist/commands/device_credential.d.ts +3 -1
- package/dist/commands/device_credential.js +1 -0
- package/dist/commands/device_credential.js.map +1 -1
- package/dist/commands/finalize.d.ts +67 -0
- package/dist/commands/finalize.js +450 -114
- package/dist/commands/finalize.js.map +1 -1
- package/dist/commands/finish_mint.d.ts +28 -0
- package/dist/commands/finish_mint.js +16 -4
- package/dist/commands/finish_mint.js.map +1 -1
- package/dist/commands/scan.d.ts +28 -0
- package/dist/commands/scan.js +11 -0
- package/dist/commands/scan.js.map +1 -1
- package/dist/commands/status.d.ts +19 -1
- package/dist/commands/status.js +123 -14
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/status_machine.d.ts +12 -3
- package/dist/commands/status_machine.js +111 -13
- package/dist/commands/status_machine.js.map +1 -1
- package/dist/commands/sync_reason.d.ts +17 -0
- package/dist/commands/sync_reason.js +25 -0
- package/dist/commands/sync_reason.js.map +1 -0
- package/dist/consent.d.ts +131 -3
- package/dist/consent.js +248 -14
- package/dist/consent.js.map +1 -1
- package/dist/copy/strings.d.ts +165 -4
- package/dist/copy/strings.js +190 -7
- package/dist/copy/strings.js.map +1 -1
- package/dist/folder_grants.d.ts +44 -0
- package/dist/folder_grants.js +101 -0
- package/dist/folder_grants.js.map +1 -0
- package/dist/git.d.ts +26 -4
- package/dist/git.js +82 -11
- package/dist/git.js.map +1 -1
- package/dist/grants_sync.d.ts +165 -0
- package/dist/grants_sync.js +289 -0
- package/dist/grants_sync.js.map +1 -0
- package/dist/grants_verb.d.ts +70 -0
- package/dist/grants_verb.js +121 -0
- package/dist/grants_verb.js.map +1 -0
- package/dist/hooks/entry.d.ts +30 -50
- package/dist/hooks/entry.js +601 -561
- package/dist/hooks/entry.js.map +1 -1
- package/dist/hooks/fire_lock.d.ts +31 -0
- package/dist/hooks/fire_lock.js +120 -12
- package/dist/hooks/fire_lock.js.map +1 -1
- package/dist/hooks/session_grants.d.ts +59 -0
- package/dist/hooks/session_grants.js +91 -0
- package/dist/hooks/session_grants.js.map +1 -0
- package/dist/hooks/session_start.d.ts +28 -7
- package/dist/hooks/session_start.js +55 -11
- package/dist/hooks/session_start.js.map +1 -1
- package/dist/index.js +22 -5
- package/dist/index.js.map +1 -1
- package/dist/machine_state.d.ts +44 -1
- package/dist/machine_state.js +75 -12
- package/dist/machine_state.js.map +1 -1
- package/dist/oauth/discovery.js +2 -1
- package/dist/oauth/discovery.js.map +1 -1
- package/dist/oauth/pkce.js +2 -1
- package/dist/oauth/pkce.js.map +1 -1
- package/dist/oauth/retire.d.ts +10 -0
- package/dist/oauth/retire.js +13 -0
- package/dist/oauth/retire.js.map +1 -1
- package/dist/paths.d.ts +54 -1
- package/dist/paths.js +88 -12
- package/dist/paths.js.map +1 -1
- package/dist/pending_revoke.d.ts +117 -0
- package/dist/pending_revoke.js +233 -0
- package/dist/pending_revoke.js.map +1 -0
- package/dist/pending_revoke_file.d.ts +55 -0
- package/dist/pending_revoke_file.js +74 -0
- package/dist/pending_revoke_file.js.map +1 -0
- package/dist/physical_path.d.ts +46 -0
- package/dist/physical_path.js +151 -0
- package/dist/physical_path.js.map +1 -0
- package/dist/picker.d.ts +82 -5
- package/dist/picker.js +183 -10
- package/dist/picker.js.map +1 -1
- package/dist/picker_checklist.d.ts +27 -3
- package/dist/picker_checklist.js +81 -6
- package/dist/picker_checklist.js.map +1 -1
- package/dist/policy.d.ts +24 -1
- package/dist/policy.js +30 -2
- package/dist/policy.js.map +1 -1
- package/dist/post.d.ts +55 -2
- package/dist/post.js +72 -22
- package/dist/post.js.map +1 -1
- package/dist/project.d.ts +89 -0
- package/dist/project.js +123 -0
- package/dist/project.js.map +1 -1
- package/dist/redact.d.ts +77 -2
- package/dist/redact.js +713 -47
- package/dist/redact.js.map +1 -1
- package/dist/session_targets.d.ts +713 -0
- package/dist/session_targets.js +2602 -0
- package/dist/session_targets.js.map +1 -0
- package/dist/spool.d.ts +12 -0
- package/dist/spool.js +29 -1
- package/dist/spool.js.map +1 -1
- package/dist/spool_union.d.ts +51 -0
- package/dist/spool_union.js +57 -0
- package/dist/spool_union.js.map +1 -0
- package/dist/state.d.ts +5 -0
- package/dist/state.js +19 -1
- package/dist/state.js.map +1 -1
- package/dist/system_message.d.ts +25 -2
- package/dist/system_message.js +29 -5
- package/dist/system_message.js.map +1 -1
- package/dist/text_tail.d.ts +8 -0
- package/dist/text_tail.js +19 -0
- package/dist/text_tail.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/dist/oauth/retire.d.ts
CHANGED
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
*/
|
|
32
32
|
import type { IngestCredential } from "../credential.js";
|
|
33
33
|
export declare const RETIRE_PATH = "/oauth/ingest-credential/retire";
|
|
34
|
+
/** One best-effort revoke of a credential `g` holds, and the bound on a verb's whole retry of the queue (`pending_revoke.ts`). */
|
|
35
|
+
export declare const REVOKE_TIMEOUT_MS = 3000;
|
|
34
36
|
export type Retire =
|
|
35
37
|
/** The server revoked the old credential. */
|
|
36
38
|
{
|
|
@@ -62,3 +64,11 @@ export declare function retireCredential(mcpEndpoint: string, replacement: Inges
|
|
|
62
64
|
* result carries nothing of the credential.
|
|
63
65
|
*/
|
|
64
66
|
export declare function selfRevokeCredential(mcpEndpoint: string, credential: IngestCredential, deps: RetireDeps): Promise<Retire>;
|
|
67
|
+
/**
|
|
68
|
+
* `selfRevokeCredential`, plus the one thing a RETRY needs to know: `gone` is a 401, the server saying it does not accept this
|
|
69
|
+
* credential — already revoked, expired or never real — so there is nothing left to revoke and a queued retry stops. Every
|
|
70
|
+
* other result is `selfRevokeCredential`'s.
|
|
71
|
+
*/
|
|
72
|
+
export declare function selfRevokeOutcome(mcpEndpoint: string, credential: IngestCredential, deps: RetireDeps): Promise<Retire | {
|
|
73
|
+
readonly kind: "gone";
|
|
74
|
+
}>;
|
package/dist/oauth/retire.js
CHANGED
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
*/
|
|
32
32
|
import { HTTP_TIMEOUT_MS } from "./signin.js";
|
|
33
33
|
export const RETIRE_PATH = "/oauth/ingest-credential/retire";
|
|
34
|
+
/** One best-effort revoke of a credential `g` holds, and the bound on a verb's whole retry of the queue (`pending_revoke.ts`). */
|
|
35
|
+
export const REVOKE_TIMEOUT_MS = 3_000;
|
|
34
36
|
export function retireUrl(mcpEndpoint) {
|
|
35
37
|
return new URL(RETIRE_PATH, mcpEndpoint).toString();
|
|
36
38
|
}
|
|
@@ -75,6 +77,15 @@ export async function retireCredential(mcpEndpoint, replacement, old, deps) {
|
|
|
75
77
|
* result carries nothing of the credential.
|
|
76
78
|
*/
|
|
77
79
|
export async function selfRevokeCredential(mcpEndpoint, credential, deps) {
|
|
80
|
+
const outcome = await selfRevokeOutcome(mcpEndpoint, credential, deps);
|
|
81
|
+
return outcome.kind === "gone" ? { kind: "failed" } : outcome;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* `selfRevokeCredential`, plus the one thing a RETRY needs to know: `gone` is a 401, the server saying it does not accept this
|
|
85
|
+
* credential — already revoked, expired or never real — so there is nothing left to revoke and a queued retry stops. Every
|
|
86
|
+
* other result is `selfRevokeCredential`'s.
|
|
87
|
+
*/
|
|
88
|
+
export async function selfRevokeOutcome(mcpEndpoint, credential, deps) {
|
|
78
89
|
const controller = new AbortController();
|
|
79
90
|
const timer = setTimeout(() => controller.abort(), deps.timeoutMs ?? HTTP_TIMEOUT_MS);
|
|
80
91
|
try {
|
|
@@ -91,6 +102,8 @@ export async function selfRevokeCredential(mcpEndpoint, credential, deps) {
|
|
|
91
102
|
});
|
|
92
103
|
if (res.status === 404)
|
|
93
104
|
return { kind: "unknown" };
|
|
105
|
+
if (res.status === 401)
|
|
106
|
+
return { kind: "gone" };
|
|
94
107
|
if (res.status !== 200)
|
|
95
108
|
return { kind: "failed" };
|
|
96
109
|
const doc = (await res.json());
|
package/dist/oauth/retire.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retire.js","sourceRoot":"","sources":["../../src/oauth/retire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,CAAC,MAAM,WAAW,GAAG,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"retire.js","sourceRoot":"","sources":["../../src/oauth/retire.ts"],"names":[],"mappings":"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"}
|
package/dist/paths.d.ts
CHANGED
|
@@ -19,11 +19,32 @@ export declare function rootDir(home: string): string;
|
|
|
19
19
|
export declare function credentialsPath(home: string): string;
|
|
20
20
|
/** The per-project consent allow list. Consulted BEFORE any transcript read (D56 §D19). */
|
|
21
21
|
export declare function projectsPath(home: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Folder grants (any-folder capture, R3): a folder whose no-repo sessions may be captured under a `local:folder:` identity.
|
|
24
|
+
* ⛔ A separate file from `projects.json` on purpose: that one is keyed by git common dir and enumerated as clones (`status`,
|
|
25
|
+
* `machine_state`), and a folder in it would be listed as one. Keyed by the folder's REALPATH. Client-side only: never synced,
|
|
26
|
+
* because the server holds no path and never refuses a `local:` slug. Absent file: no folder is granted.
|
|
27
|
+
*/
|
|
28
|
+
export declare function foldersPath(home: string): string;
|
|
22
29
|
/**
|
|
23
30
|
* The slug-keyed grant list — owners, repos, exclusions and refusals. Read next to
|
|
24
31
|
* `projects.json` by `consent.ts`'s `isCaptureAllowed`, BEFORE any transcript read.
|
|
25
32
|
*/
|
|
26
33
|
export declare function grantsPath(home: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* What the SERVER told this machine about the account, and the refusals a hook saw (slice 2, S4). ⛔ A separate file
|
|
36
|
+
* from `grants.json` on purpose: hooks write this one and never write `grants.json`, whose `updateGrants`
|
|
37
|
+
* read-modify-write has no lock — a hook racing `vibecommit off` could otherwise restore a turned-off repo. Written whole
|
|
38
|
+
* and atomically; read by `consent.ts`'s `isCaptureAllowed` next to `grants.json`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function grantsAccountPath(home: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Credentials `g` made and then removed from this machine whose revoke did not reach the server (slice 2, S4, R3-11): the next CLI
|
|
43
|
+
* verb retries each one. ⛔ **It holds a bearer token**, because a self-revoke is made with the credential itself and the local
|
|
44
|
+
* credential file was deleted. Mode 0600 like `credentials.json`, written atomically, CLI-only, and a row leaves it the moment the
|
|
45
|
+
* server says there is nothing left to revoke.
|
|
46
|
+
*/
|
|
47
|
+
export declare function pendingRevokePath(home: string): string;
|
|
27
48
|
/**
|
|
28
49
|
* The HUMAN lane's signed-in session — `CR-084d`. Mode 0600, enforced on read by
|
|
29
50
|
* the same `readSecretFile` the ingest credential goes through.
|
|
@@ -95,6 +116,12 @@ export declare function repoDayNoticePath(home: string, repoKey: string, day: st
|
|
|
95
116
|
* `day` is a UTC `YYYY-MM-DD` supplied by the caller, never read from a local clock here.
|
|
96
117
|
*/
|
|
97
118
|
export declare function machineDayNoticePath(home: string, day: string, key: string): string;
|
|
119
|
+
/**
|
|
120
|
+
* Once-per-`(machine, account epoch)` marker — slice 2, notice state 10 ("your account grants N repositories not captured on this
|
|
121
|
+
* machine yet"). The epoch is the server's version of the user's grants, so the message is spoken again only when the grants
|
|
122
|
+
* changed; a repeat per session or per day would nag about the same unchanged gap. `epoch` is a non-negative integer, `key` the state.
|
|
123
|
+
*/
|
|
124
|
+
export declare function machineEpochNoticePath(home: string, epoch: number, key: string): string;
|
|
98
125
|
/**
|
|
99
126
|
* Once-per-CLONE marker — 0.7.0, notices 6-8 and the `SessionStart` install record (eng review D4 · A).
|
|
100
127
|
*
|
|
@@ -163,6 +190,27 @@ export declare function sessionStatePath(home: string, key: SessionKey): string
|
|
|
163
190
|
* repo-less bucket, and a caller with no repo has nothing to scan.
|
|
164
191
|
*/
|
|
165
192
|
export declare function repoSessionsDir(home: string, repoKey: string): string | null;
|
|
193
|
+
/**
|
|
194
|
+
* ⛔ The directory that holds per-SESSION state which is not any one repo's: the session's target record
|
|
195
|
+
* (`session_targets.ts`) and the digest → work-tree notes.
|
|
196
|
+
*
|
|
197
|
+
* Under `state/notices/` and NOT beside the repo digests, and not a new `state/` entry, on purpose: two suites pin entry-name
|
|
198
|
+
* sets (`study-contract.test.ts` pins `state/` to `notices` and `sessions`; `agent-registry.test.ts` counts the entries of
|
|
199
|
+
* `state/sessions/` as repo digests, and the study harness binds both). `notices/` is already a mixed namespace
|
|
200
|
+
* (`machine-day`, `machine-epoch`, `clone`, `repo-day`, one directory per session id) that nothing enumerates. None of the
|
|
201
|
+
* files here has a `.json` suffix, so no scan that reads `*.json` can mistake one for a repo's session state.
|
|
202
|
+
*/
|
|
203
|
+
export declare function targetsDir(home: string): string;
|
|
204
|
+
/** Where every repo's `<digest>/` state directory lives. */
|
|
205
|
+
export declare function sessionsRoot(home: string): string;
|
|
206
|
+
/** One session's target record: scan cursors, resolved roots, targets, undecided names. Not a `.json` (see `targetsDir`). */
|
|
207
|
+
export declare function sessionTargetsPath(home: string, sessionId: string): string;
|
|
208
|
+
/** Which work tree a state digest names — written by `spool.ts` when a commit is spooled. Null for no repo key. */
|
|
209
|
+
export declare function repoKeyNotePath(home: string, repoKey: string): string | null;
|
|
210
|
+
/** The digest a work tree's state directory is named by (`repoSessionsDir`). Exposed for the spool-evidence reader. */
|
|
211
|
+
export declare function repoKeyDigest(repoKey: string): string;
|
|
212
|
+
/** The stem every file of one session is named by (`<stem>.json`, `.spool.jsonl`, …). */
|
|
213
|
+
export declare function sessionFileStem(sessionId: string): string;
|
|
166
214
|
/**
|
|
167
215
|
* Where Claude Code writes transcripts.
|
|
168
216
|
*
|
|
@@ -206,7 +254,12 @@ export declare function codexTranscriptRoot(home: string, env: NodeJS.ProcessEnv
|
|
|
206
254
|
* all**. The repository that IS one sits a directory below it, so its project
|
|
207
255
|
* key munges to that workspace's name with the child directory appended — a
|
|
208
256
|
* name with no directory under `projects/` — and a project-key-derived root
|
|
209
|
-
* would refuse the one real transcript there is.
|
|
257
|
+
* would refuse the one real transcript there is. (That is the same shape as the
|
|
258
|
+
* parent-folder sessions any-folder capture now reads: a session launched in a
|
|
259
|
+
* folder above its repos has no single repo whose key could name its transcript's
|
|
260
|
+
* directory. The boundary therefore stays registry-computed and can only refuse;
|
|
261
|
+
* WHICH repos or folder a session's bytes go to is `session_targets`' decision,
|
|
262
|
+
* made after this confinement, never an input to it.)
|
|
210
263
|
*
|
|
211
264
|
* ⇒ ⛔ **The interior shape is enforced by `isCursorTranscript` instead**, which
|
|
212
265
|
* runs AFTER the registry-computed boundary and can only refuse. Read that
|
package/dist/paths.js
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* @provenance vibecommit-schema ingest_sessions.file_key — CHECK bound 1..128, retyped
|
|
15
15
|
*/
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
|
-
import { realpathSync } from "node:fs";
|
|
18
17
|
import { join, sep } from "node:path";
|
|
18
|
+
import { physicalPath } from "./physical_path.js";
|
|
19
19
|
/** Root of the client's own state. Never Claude Code's — see the plan's keychain note. */
|
|
20
20
|
export function rootDir(home) {
|
|
21
21
|
return join(home, ".vibecommit");
|
|
@@ -28,6 +28,15 @@ export function credentialsPath(home) {
|
|
|
28
28
|
export function projectsPath(home) {
|
|
29
29
|
return join(rootDir(home), "projects.json");
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Folder grants (any-folder capture, R3): a folder whose no-repo sessions may be captured under a `local:folder:` identity.
|
|
33
|
+
* ⛔ A separate file from `projects.json` on purpose: that one is keyed by git common dir and enumerated as clones (`status`,
|
|
34
|
+
* `machine_state`), and a folder in it would be listed as one. Keyed by the folder's REALPATH. Client-side only: never synced,
|
|
35
|
+
* because the server holds no path and never refuses a `local:` slug. Absent file: no folder is granted.
|
|
36
|
+
*/
|
|
37
|
+
export function foldersPath(home) {
|
|
38
|
+
return join(rootDir(home), "folders.json");
|
|
39
|
+
}
|
|
31
40
|
/**
|
|
32
41
|
* The slug-keyed grant list — owners, repos, exclusions and refusals. Read next to
|
|
33
42
|
* `projects.json` by `consent.ts`'s `isCaptureAllowed`, BEFORE any transcript read.
|
|
@@ -35,6 +44,24 @@ export function projectsPath(home) {
|
|
|
35
44
|
export function grantsPath(home) {
|
|
36
45
|
return join(rootDir(home), "grants.json");
|
|
37
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* What the SERVER told this machine about the account, and the refusals a hook saw (slice 2, S4). ⛔ A separate file
|
|
49
|
+
* from `grants.json` on purpose: hooks write this one and never write `grants.json`, whose `updateGrants`
|
|
50
|
+
* read-modify-write has no lock — a hook racing `vibecommit off` could otherwise restore a turned-off repo. Written whole
|
|
51
|
+
* and atomically; read by `consent.ts`'s `isCaptureAllowed` next to `grants.json`.
|
|
52
|
+
*/
|
|
53
|
+
export function grantsAccountPath(home) {
|
|
54
|
+
return join(rootDir(home), "grants-account.json");
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Credentials `g` made and then removed from this machine whose revoke did not reach the server (slice 2, S4, R3-11): the next CLI
|
|
58
|
+
* verb retries each one. ⛔ **It holds a bearer token**, because a self-revoke is made with the credential itself and the local
|
|
59
|
+
* credential file was deleted. Mode 0600 like `credentials.json`, written atomically, CLI-only, and a row leaves it the moment the
|
|
60
|
+
* server says there is nothing left to revoke.
|
|
61
|
+
*/
|
|
62
|
+
export function pendingRevokePath(home) {
|
|
63
|
+
return join(rootDir(home), "pending-revoke.json");
|
|
64
|
+
}
|
|
38
65
|
/**
|
|
39
66
|
* The HUMAN lane's signed-in session — `CR-084d`. Mode 0600, enforced on read by
|
|
40
67
|
* the same `readSecretFile` the ingest credential goes through.
|
|
@@ -120,6 +147,14 @@ export function repoDayNoticePath(home, repoKey, day, state) {
|
|
|
120
147
|
export function machineDayNoticePath(home, day, key) {
|
|
121
148
|
return join(stateDir(home), "notices", "machine-day", sanitise(day), `${sanitise(key)}.json`);
|
|
122
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Once-per-`(machine, account epoch)` marker — slice 2, notice state 10 ("your account grants N repositories not captured on this
|
|
152
|
+
* machine yet"). The epoch is the server's version of the user's grants, so the message is spoken again only when the grants
|
|
153
|
+
* changed; a repeat per session or per day would nag about the same unchanged gap. `epoch` is a non-negative integer, `key` the state.
|
|
154
|
+
*/
|
|
155
|
+
export function machineEpochNoticePath(home, epoch, key) {
|
|
156
|
+
return join(stateDir(home), "notices", "machine-epoch", sanitise(String(epoch)), `${sanitise(key)}.json`);
|
|
157
|
+
}
|
|
123
158
|
/**
|
|
124
159
|
* Once-per-CLONE marker — 0.7.0, notices 6-8 and the `SessionStart` install record (eng review D4 · A).
|
|
125
160
|
*
|
|
@@ -178,6 +213,41 @@ export function repoSessionsDir(home, repoKey) {
|
|
|
178
213
|
return null;
|
|
179
214
|
return join(stateDir(home), "sessions", repoDigest(repoKey));
|
|
180
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* ⛔ The directory that holds per-SESSION state which is not any one repo's: the session's target record
|
|
218
|
+
* (`session_targets.ts`) and the digest → work-tree notes.
|
|
219
|
+
*
|
|
220
|
+
* Under `state/notices/` and NOT beside the repo digests, and not a new `state/` entry, on purpose: two suites pin entry-name
|
|
221
|
+
* sets (`study-contract.test.ts` pins `state/` to `notices` and `sessions`; `agent-registry.test.ts` counts the entries of
|
|
222
|
+
* `state/sessions/` as repo digests, and the study harness binds both). `notices/` is already a mixed namespace
|
|
223
|
+
* (`machine-day`, `machine-epoch`, `clone`, `repo-day`, one directory per session id) that nothing enumerates. None of the
|
|
224
|
+
* files here has a `.json` suffix, so no scan that reads `*.json` can mistake one for a repo's session state.
|
|
225
|
+
*/
|
|
226
|
+
export function targetsDir(home) {
|
|
227
|
+
return join(stateDir(home), "notices", "_session-targets");
|
|
228
|
+
}
|
|
229
|
+
/** Where every repo's `<digest>/` state directory lives. */
|
|
230
|
+
export function sessionsRoot(home) {
|
|
231
|
+
return join(stateDir(home), "sessions");
|
|
232
|
+
}
|
|
233
|
+
/** One session's target record: scan cursors, resolved roots, targets, undecided names. Not a `.json` (see `targetsDir`). */
|
|
234
|
+
export function sessionTargetsPath(home, sessionId) {
|
|
235
|
+
return join(targetsDir(home), `${sanitise(sessionId)}.targets`);
|
|
236
|
+
}
|
|
237
|
+
/** Which work tree a state digest names — written by `spool.ts` when a commit is spooled. Null for no repo key. */
|
|
238
|
+
export function repoKeyNotePath(home, repoKey) {
|
|
239
|
+
if (repoKey === "")
|
|
240
|
+
return null;
|
|
241
|
+
return join(targetsDir(home), `${repoDigest(repoKey)}.repo`);
|
|
242
|
+
}
|
|
243
|
+
/** The digest a work tree's state directory is named by (`repoSessionsDir`). Exposed for the spool-evidence reader. */
|
|
244
|
+
export function repoKeyDigest(repoKey) {
|
|
245
|
+
return repoDigest(repoKey);
|
|
246
|
+
}
|
|
247
|
+
/** The stem every file of one session is named by (`<stem>.json`, `.spool.jsonl`, …). */
|
|
248
|
+
export function sessionFileStem(sessionId) {
|
|
249
|
+
return sanitise(sessionId);
|
|
250
|
+
}
|
|
181
251
|
/** A fixed-length, collision-free filename component for a work-tree path. */
|
|
182
252
|
function repoDigest(repoKey) {
|
|
183
253
|
return createHash("sha256").update(repoKey).digest("hex").slice(0, 32);
|
|
@@ -237,7 +307,12 @@ export function codexTranscriptRoot(home, env) {
|
|
|
237
307
|
* all**. The repository that IS one sits a directory below it, so its project
|
|
238
308
|
* key munges to that workspace's name with the child directory appended — a
|
|
239
309
|
* name with no directory under `projects/` — and a project-key-derived root
|
|
240
|
-
* would refuse the one real transcript there is.
|
|
310
|
+
* would refuse the one real transcript there is. (That is the same shape as the
|
|
311
|
+
* parent-folder sessions any-folder capture now reads: a session launched in a
|
|
312
|
+
* folder above its repos has no single repo whose key could name its transcript's
|
|
313
|
+
* directory. The boundary therefore stays registry-computed and can only refuse;
|
|
314
|
+
* WHICH repos or folder a session's bytes go to is `session_targets`' decision,
|
|
315
|
+
* made after this confinement, never an input to it.)
|
|
241
316
|
*
|
|
242
317
|
* ⇒ ⛔ **The interior shape is enforced by `isCursorTranscript` instead**, which
|
|
243
318
|
* runs AFTER the registry-computed boundary and can only refuse. Read that
|
|
@@ -331,15 +406,11 @@ export function isTranscriptFile(_root, path) {
|
|
|
331
406
|
export function isCursorTranscript(root, path) {
|
|
332
407
|
if (!isInside(root, path))
|
|
333
408
|
return false;
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
realPath = realpathSync(path);
|
|
339
|
-
}
|
|
340
|
-
catch {
|
|
409
|
+
// C71 (3): the one resolver.
|
|
410
|
+
const realRoot = physicalPath(root, "fail");
|
|
411
|
+
const realPath = physicalPath(path, "fail");
|
|
412
|
+
if (realRoot === null || realPath === null)
|
|
341
413
|
return false;
|
|
342
|
-
}
|
|
343
414
|
if (!realPath.endsWith(TRANSCRIPT_SUFFIX))
|
|
344
415
|
return false;
|
|
345
416
|
const segments = realPath.slice(realRoot.length + 1).split(sep);
|
|
@@ -465,8 +536,13 @@ export function isInside(root, candidate) {
|
|
|
465
536
|
let realRoot;
|
|
466
537
|
let realCandidate;
|
|
467
538
|
try {
|
|
468
|
-
|
|
469
|
-
|
|
539
|
+
// C70: physical resolution (`..` after a link is the link target's parent), missing = outside, as `realpathSync` threw.
|
|
540
|
+
const rootPath = physicalPath(root, "fail");
|
|
541
|
+
const candidatePath = physicalPath(candidate, "fail");
|
|
542
|
+
if (rootPath === null || candidatePath === null)
|
|
543
|
+
return false;
|
|
544
|
+
realRoot = rootPath;
|
|
545
|
+
realCandidate = candidatePath;
|
|
470
546
|
}
|
|
471
547
|
catch {
|
|
472
548
|
return false;
|
package/dist/paths.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pending revokes (slice 2, S4, R3-11): the WRITE-AHEAD record of a credential `g` has made and not yet been told to keep.
|
|
3
|
+
*
|
|
4
|
+
* ```
|
|
5
|
+
* addPendingRevoke(home, credential, endpoint, now) at the mint, BEFORE anything else: refuses (never overwrites) when it cannot
|
|
6
|
+
* removePendingRevoke(home, token) after the revoke, or after the credential is kept: re-reads, removes ONE row
|
|
7
|
+
* revokeHeld(home, token, fetch) one best-effort revoke (3 s) of a row, to ITS recorded origin
|
|
8
|
+
* retryPendingRevokes(home, env, fetch, now) every user-facing verb, once, at its start: one 3 s bound across all rows
|
|
9
|
+
* readPendingRevokes(home) how many are waiting (for `status`'s `pending` count)
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* ## ⛔ WHY IT IS WRITE-AHEAD
|
|
13
|
+
*
|
|
14
|
+
* `g` is the one place a credential is made ahead of consent (exception 3). So the credential lives in MEMORY until the yes:
|
|
15
|
+
* `credentials.json` does not exist before it, and the row below is written the instant the server hands the token over. A kill, a
|
|
16
|
+
* second Ctrl+C, a SIGHUP at the y/N or an unexpected throw therefore leaves a ROW (which the next verb revokes), never a live
|
|
17
|
+
* credential on disk that nothing remembers. The yes commits in this order: the grants, then `credentials.json`, then the row's
|
|
18
|
+
* deletion; a retry skips and drops any row whose token IS the current credential, so a kill between the last two never revokes what
|
|
19
|
+
* the user kept.
|
|
20
|
+
*
|
|
21
|
+
* ## ⛔ THE FILE HOLDS A BEARER TOKEN — the same exposure class as `credentials.json`, held to the same rules
|
|
22
|
+
* - written mode 0600 under the 0700 directory, temp + rename;
|
|
23
|
+
* - READ through `readSecretFile`: a file or folder others can read is refused, and an insecure or unreadable file is NEVER
|
|
24
|
+
* overwritten (the writer refuses, and `g` fails closed);
|
|
25
|
+
* - never printed, logged or returned: `status` counts the rows and shows nothing else, `--json` included;
|
|
26
|
+
* - a hook never touches it (only the CLI verbs import this module; `test/connect-account.test.ts` walks the hooks' import graph).
|
|
27
|
+
*
|
|
28
|
+
* ## ⛔ A ROW IS NEVER DROPPED UNREVOKED, except by the clock
|
|
29
|
+
* - it leaves on a 2xx, a 401 (the server does not accept it: already dead) or a 404 (a server that cannot revoke);
|
|
30
|
+
* - or at `minted_at` + 91 days: a token that was never on disk was never used, and an ingest credential ends 90 days unused;
|
|
31
|
+
* - there is no row cap that drops one: at the cap `addPendingRevoke` REFUSES, and `g` fails closed.
|
|
32
|
+
*
|
|
33
|
+
* ## ⛔ THE ORIGIN IS THE ROW'S
|
|
34
|
+
*
|
|
35
|
+
* A row records the issuing server's origin and a retry goes ONLY there (https, or http on loopback: `isAllowedIngestUrl`), never to
|
|
36
|
+
* wherever `VIBECOMMIT_MCP_URL` points today.
|
|
37
|
+
*/
|
|
38
|
+
import { IngestCredential, type SecretFileRead } from "./credential.js";
|
|
39
|
+
import { type Queue } from "./pending_revoke_file.js";
|
|
40
|
+
import { REVOKE_TIMEOUT_MS } from "./oauth/retire.js";
|
|
41
|
+
export { readPendingRevokes, type PendingRevoke } from "./pending_revoke_file.js";
|
|
42
|
+
/** More rows than `g` can produce in earnest: past it `g` refuses rather than drop one. */
|
|
43
|
+
export declare const MAX_ROWS = 8;
|
|
44
|
+
/** One best-effort revoke, and the bound on a verb's whole retry. */
|
|
45
|
+
export { REVOKE_TIMEOUT_MS };
|
|
46
|
+
export type AddRevoke = {
|
|
47
|
+
readonly kind: "written";
|
|
48
|
+
}
|
|
49
|
+
/** The file is there but is not safe to read or write (others can read it, or it is not what this client wrote). It was not touched. */
|
|
50
|
+
| {
|
|
51
|
+
readonly kind: "refused";
|
|
52
|
+
readonly read: Extract<Queue, {
|
|
53
|
+
kind: "refused";
|
|
54
|
+
}>["read"];
|
|
55
|
+
}
|
|
56
|
+
/** `MAX_ROWS` unrevoked rows already wait. None was dropped. */
|
|
57
|
+
| {
|
|
58
|
+
readonly kind: "full";
|
|
59
|
+
}
|
|
60
|
+
/** The write itself failed. */
|
|
61
|
+
| {
|
|
62
|
+
readonly kind: "failed";
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Write the row for a credential that has just been made. Never overwrites a file it cannot read, never drops a row.
|
|
66
|
+
* `lease: true` is `g` holding the credential at its y/N: the row carries `{ pid, lease_until }` (30 minutes) so another verb's retry
|
|
67
|
+
* leaves it alone while it is kept; every other writer (a test, an orphaned row) has no lease and is retried at once.
|
|
68
|
+
*/
|
|
69
|
+
export declare function addPendingRevoke(home: string, credential: IngestCredential, endpoint: string, now: Date, options?: {
|
|
70
|
+
readonly lease?: boolean;
|
|
71
|
+
}): AddRevoke;
|
|
72
|
+
/** Remove ONE row, re-reading just before the write so a row queued in between survives. Deletes the file when it is empty. Never throws. */
|
|
73
|
+
export declare function removePendingRevoke(home: string, token: string): void;
|
|
74
|
+
/** Give the row up to the retry: `g` is no longer holding the credential, so the next verb may revoke it. Re-reads before it writes. */
|
|
75
|
+
export declare function releaseLease(home: string, token: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Is the row for `token` still there? `g` asks just before it commits, and the three answers are different things:
|
|
78
|
+
* - `held`: the row is in a queue this client can use;
|
|
79
|
+
* - `gone`: the queue is readable and the row is not in it — another verb settled (revoked) it;
|
|
80
|
+
* - `unusable`: the queue is insecure or unreadable. Nobody revoked anything; this client can neither keep nor settle the record.
|
|
81
|
+
*/
|
|
82
|
+
export declare function holdsRow(home: string, token: string): "held" | "gone" | "unusable";
|
|
83
|
+
/**
|
|
84
|
+
* What one best-effort revoke of the credential `g` holds came to:
|
|
85
|
+
* - `revoked`: a 2xx, a 401 or a 404 — from the row's recorded origin when a readable row is there, and otherwise from the
|
|
86
|
+
* credential IN MEMORY at the origin that minted it. Never "revoked" for any other reason;
|
|
87
|
+
* - `waiting`: a readable row is there and the revoke did not land; the next verb retries it;
|
|
88
|
+
* - `orphan`: no usable row (it is gone, or the queue became unreadable or insecure) AND the in-memory revoke did not land: the
|
|
89
|
+
* credential may be live and nothing retries it. `insecure` carries the queue file's problem to print the insecure-file block;
|
|
90
|
+
* - `unrevocable`: a 404 — the server has no revoke route, so the row ends (retrying is pointless) but the credential may still be live.
|
|
91
|
+
* It is NOT "revoked": the caller prints the orphan wording, which says where to remove it ("0.8.0 truth fixes" F7).
|
|
92
|
+
*/
|
|
93
|
+
export interface HeldRevoke {
|
|
94
|
+
readonly kind: "revoked" | "waiting" | "orphan" | "unrevocable";
|
|
95
|
+
readonly insecure: Extract<SecretFileRead, {
|
|
96
|
+
kind: "insecure-file";
|
|
97
|
+
}> | null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* `g`'s every no-grant exit: one revoke within 3 s. With a readable row it goes to the row's recorded origin and removes the row on a
|
|
101
|
+
* 2xx, 401 or 404 (a failure gives the lease up so the next verb retries). With NO usable row — missing, or the queue refused — it
|
|
102
|
+
* revokes with the in-memory credential at the MINTED origin: a missing row is never taken for "already revoked".
|
|
103
|
+
*/
|
|
104
|
+
export declare function revokeHeld(home: string, credential: IngestCredential, mintedOrigin: string, fetchImpl: typeof fetch): Promise<HeldRevoke>;
|
|
105
|
+
/**
|
|
106
|
+
* Every user-facing verb, once, at its start: one attempt at each row, and ONE 3 s bound across all of them (a row gets what is
|
|
107
|
+
* left of the bound, and none is attempted once it is spent). Silent, and needs no credential.
|
|
108
|
+
*
|
|
109
|
+
* Before EACH request it re-reads the queue and the current credential (a credential committed, or a row settled, after the loop
|
|
110
|
+
* began is never revoked on a stale view), and it
|
|
111
|
+
* - skips and DROPS a row whose token is the current credential (the user kept it; the kill came between the credential's write
|
|
112
|
+
* and the row's deletion) — compared on the file's raw token, so a mode problem does not hide a kept credential;
|
|
113
|
+
* - skips (and keeps) a LEASED row: `g` is holding it at its y/N in another process;
|
|
114
|
+
* - drops a row past `minted_at` + 91 days.
|
|
115
|
+
* Removes each row it settles as it goes, re-reading just before it writes. Returns how many rows still wait. Never throws.
|
|
116
|
+
*/
|
|
117
|
+
export declare function retryPendingRevokes(home: string, env: NodeJS.ProcessEnv, fetchImpl: typeof fetch, now: Date, deadlineMs?: number): Promise<number>;
|