ctxr-cli 0.33.0 → 0.34.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 +15 -1
- package/dist/commands/archive.d.ts +5 -4
- package/dist/commands/archive.d.ts.map +1 -1
- package/dist/commands/archive.js +7 -7
- package/dist/commands/archive.js.map +1 -1
- package/dist/commands/catalog-show.d.ts +8 -0
- package/dist/commands/catalog-show.d.ts.map +1 -1
- package/dist/commands/catalog-show.js +29 -2
- package/dist/commands/catalog-show.js.map +1 -1
- package/dist/commands/context-gather.d.ts.map +1 -1
- package/dist/commands/context-gather.js +3 -2
- package/dist/commands/context-gather.js.map +1 -1
- package/dist/commands/doctor.d.ts +5 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +4 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/graph-build.d.ts +4 -1
- package/dist/commands/graph-build.d.ts.map +1 -1
- package/dist/commands/graph-build.js +14 -5
- package/dist/commands/graph-build.js.map +1 -1
- package/dist/commands/land.d.ts +27 -7
- package/dist/commands/land.d.ts.map +1 -1
- package/dist/commands/land.js +307 -32
- package/dist/commands/land.js.map +1 -1
- package/dist/commands/publish-gather.d.ts.map +1 -1
- package/dist/commands/publish-gather.js +2 -3
- package/dist/commands/publish-gather.js.map +1 -1
- package/dist/commands/review-list.d.ts +19 -5
- package/dist/commands/review-list.d.ts.map +1 -1
- package/dist/commands/review-list.js +55 -6
- package/dist/commands/review-list.js.map +1 -1
- package/dist/commands/rollup-gather.d.ts.map +1 -1
- package/dist/commands/rollup-gather.js +2 -3
- package/dist/commands/rollup-gather.js.map +1 -1
- package/dist/commands/second-opinion.d.ts +33 -0
- package/dist/commands/second-opinion.d.ts.map +1 -0
- package/dist/commands/second-opinion.js +56 -0
- package/dist/commands/second-opinion.js.map +1 -0
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +4 -0
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/session-discard.d.ts +18 -0
- package/dist/commands/session-discard.d.ts.map +1 -0
- package/dist/commands/session-discard.js +31 -0
- package/dist/commands/session-discard.js.map +1 -0
- package/dist/commands/session-list.d.ts +17 -6
- package/dist/commands/session-list.d.ts.map +1 -1
- package/dist/commands/session-list.js +31 -11
- package/dist/commands/session-list.js.map +1 -1
- package/dist/commands/session-rebase.d.ts +18 -0
- package/dist/commands/session-rebase.d.ts.map +1 -0
- package/dist/commands/session-rebase.js +43 -0
- package/dist/commands/session-rebase.js.map +1 -0
- package/dist/commands/session-start.d.ts +8 -0
- package/dist/commands/session-start.d.ts.map +1 -1
- package/dist/commands/session-start.js +45 -5
- package/dist/commands/session-start.js.map +1 -1
- package/dist/commands/session-status.d.ts +17 -0
- package/dist/commands/session-status.d.ts.map +1 -0
- package/dist/commands/session-status.js +38 -0
- package/dist/commands/session-status.js.map +1 -0
- package/dist/commands/session-submit.d.ts +23 -0
- package/dist/commands/session-submit.d.ts.map +1 -0
- package/dist/commands/session-submit.js +42 -0
- package/dist/commands/session-submit.js.map +1 -0
- package/dist/commands/shared-stores-status.d.ts +24 -0
- package/dist/commands/shared-stores-status.d.ts.map +1 -0
- package/dist/commands/shared-stores-status.js +51 -0
- package/dist/commands/shared-stores-status.js.map +1 -0
- package/dist/commands/shared-stores-sync.d.ts +27 -0
- package/dist/commands/shared-stores-sync.d.ts.map +1 -0
- package/dist/commands/shared-stores-sync.js +115 -0
- package/dist/commands/shared-stores-sync.js.map +1 -0
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +2 -4
- package/dist/commands/verify.js.map +1 -1
- package/dist/config/schema.d.ts +16 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +32 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/core/agents-doc.d.ts +10 -0
- package/dist/core/agents-doc.d.ts.map +1 -1
- package/dist/core/agents-doc.js +26 -1
- package/dist/core/agents-doc.js.map +1 -1
- package/dist/core/approval/decision.d.ts +39 -1
- package/dist/core/approval/decision.d.ts.map +1 -1
- package/dist/core/approval/decision.js +53 -6
- package/dist/core/approval/decision.js.map +1 -1
- package/dist/core/approval/session-group.d.ts +156 -0
- package/dist/core/approval/session-group.d.ts.map +1 -0
- package/dist/core/approval/session-group.js +359 -0
- package/dist/core/approval/session-group.js.map +1 -0
- package/dist/core/approval/session-marker.d.ts +79 -0
- package/dist/core/approval/session-marker.d.ts.map +1 -0
- package/dist/core/approval/session-marker.js +146 -0
- package/dist/core/approval/session-marker.js.map +1 -0
- package/dist/core/approval/store-forges.d.ts +15 -0
- package/dist/core/approval/store-forges.d.ts.map +1 -0
- package/dist/core/approval/store-forges.js +33 -0
- package/dist/core/approval/store-forges.js.map +1 -0
- package/dist/core/browse/approve.d.ts +8 -0
- package/dist/core/browse/approve.d.ts.map +1 -1
- package/dist/core/browse/approve.js +366 -48
- package/dist/core/browse/approve.js.map +1 -1
- package/dist/core/browse/link-resolver.d.ts +9 -4
- package/dist/core/browse/link-resolver.d.ts.map +1 -1
- package/dist/core/browse/link-resolver.js +12 -7
- package/dist/core/browse/link-resolver.js.map +1 -1
- package/dist/core/browse/review.d.ts +5 -0
- package/dist/core/browse/review.d.ts.map +1 -1
- package/dist/core/browse/review.js +8 -0
- package/dist/core/browse/review.js.map +1 -1
- package/dist/core/checks/integrity-checks.d.ts.map +1 -1
- package/dist/core/checks/integrity-checks.js +7 -1
- package/dist/core/checks/integrity-checks.js.map +1 -1
- package/dist/core/checks/manifest.d.ts.map +1 -1
- package/dist/core/checks/manifest.js +2 -0
- package/dist/core/checks/manifest.js.map +1 -1
- package/dist/core/checks/shared-stores-checks.d.ts +17 -0
- package/dist/core/checks/shared-stores-checks.d.ts.map +1 -0
- package/dist/core/checks/shared-stores-checks.js +84 -0
- package/dist/core/checks/shared-stores-checks.js.map +1 -0
- package/dist/core/errors.d.ts +17 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +21 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/forge/github.d.ts +14 -0
- package/dist/core/forge/github.d.ts.map +1 -1
- package/dist/core/forge/github.js +17 -0
- package/dist/core/forge/github.js.map +1 -1
- package/dist/core/git/fast-forward.d.ts +23 -0
- package/dist/core/git/fast-forward.d.ts.map +1 -0
- package/dist/core/git/fast-forward.js +38 -0
- package/dist/core/git/fast-forward.js.map +1 -0
- package/dist/core/git/repo.d.ts +11 -0
- package/dist/core/git/repo.d.ts.map +1 -1
- package/dist/core/git/repo.js +25 -0
- package/dist/core/git/repo.js.map +1 -1
- package/dist/core/graph/model.d.ts +27 -0
- package/dist/core/graph/model.d.ts.map +1 -1
- package/dist/core/graph/model.js +68 -2
- package/dist/core/graph/model.js.map +1 -1
- package/dist/core/graph/persist.d.ts.map +1 -1
- package/dist/core/graph/persist.js +3 -2
- package/dist/core/graph/persist.js.map +1 -1
- package/dist/core/mcp/sessions.d.ts +11 -14
- package/dist/core/mcp/sessions.d.ts.map +1 -1
- package/dist/core/mcp/sessions.js +23 -43
- package/dist/core/mcp/sessions.js.map +1 -1
- package/dist/core/notes/list.d.ts.map +1 -1
- package/dist/core/notes/list.js +5 -0
- package/dist/core/notes/list.js.map +1 -1
- package/dist/core/reconcile.d.ts.map +1 -1
- package/dist/core/reconcile.js +2 -1
- package/dist/core/reconcile.js.map +1 -1
- package/dist/core/retrieval/pass.d.ts.map +1 -1
- package/dist/core/retrieval/pass.js +5 -4
- package/dist/core/retrieval/pass.js.map +1 -1
- package/dist/core/rollup.d.ts.map +1 -1
- package/dist/core/rollup.js +2 -3
- package/dist/core/rollup.js.map +1 -1
- package/dist/core/root.d.ts.map +1 -1
- package/dist/core/root.js +33 -2
- package/dist/core/root.js.map +1 -1
- package/dist/core/second-opinion/environment.d.ts +21 -0
- package/dist/core/second-opinion/environment.d.ts.map +1 -0
- package/dist/core/second-opinion/environment.js +70 -0
- package/dist/core/second-opinion/environment.js.map +1 -0
- package/dist/core/second-opinion/judge.d.ts +29 -0
- package/dist/core/second-opinion/judge.d.ts.map +1 -0
- package/dist/core/second-opinion/judge.js +55 -0
- package/dist/core/second-opinion/judge.js.map +1 -0
- package/dist/core/second-opinion/launch.d.ts +16 -0
- package/dist/core/second-opinion/launch.d.ts.map +1 -0
- package/dist/core/second-opinion/launch.js +75 -0
- package/dist/core/second-opinion/launch.js.map +1 -0
- package/dist/core/second-opinion/lineup.d.ts +82 -0
- package/dist/core/second-opinion/lineup.d.ts.map +1 -0
- package/dist/core/second-opinion/lineup.js +113 -0
- package/dist/core/second-opinion/lineup.js.map +1 -0
- package/dist/core/second-opinion/modes.d.ts +98 -0
- package/dist/core/second-opinion/modes.d.ts.map +1 -0
- package/dist/core/second-opinion/modes.js +224 -0
- package/dist/core/second-opinion/modes.js.map +1 -0
- package/dist/core/second-opinion/prompts.d.ts +18 -0
- package/dist/core/second-opinion/prompts.d.ts.map +1 -0
- package/dist/core/second-opinion/prompts.js +65 -0
- package/dist/core/second-opinion/prompts.js.map +1 -0
- package/dist/core/session/commit.d.ts +29 -0
- package/dist/core/session/commit.d.ts.map +1 -0
- package/dist/core/session/commit.js +22 -0
- package/dist/core/session/commit.js.map +1 -0
- package/dist/core/session/discard.d.ts +24 -0
- package/dist/core/session/discard.d.ts.map +1 -0
- package/dist/core/session/discard.js +68 -0
- package/dist/core/session/discard.js.map +1 -0
- package/dist/core/session/list.d.ts +48 -0
- package/dist/core/session/list.d.ts.map +1 -0
- package/dist/core/session/list.js +55 -0
- package/dist/core/session/list.js.map +1 -0
- package/dist/core/session/rebase.d.ts +34 -0
- package/dist/core/session/rebase.d.ts.map +1 -0
- package/dist/core/session/rebase.js +87 -0
- package/dist/core/session/rebase.js.map +1 -0
- package/dist/core/session/remote.d.ts +80 -0
- package/dist/core/session/remote.d.ts.map +1 -0
- package/dist/core/session/remote.js +102 -0
- package/dist/core/session/remote.js.map +1 -0
- package/dist/core/session/resolve.d.ts +41 -0
- package/dist/core/session/resolve.d.ts.map +1 -0
- package/dist/core/session/resolve.js +109 -0
- package/dist/core/session/resolve.js.map +1 -0
- package/dist/core/session/status.d.ts +47 -0
- package/dist/core/session/status.d.ts.map +1 -0
- package/dist/core/session/status.js +55 -0
- package/dist/core/session/status.js.map +1 -0
- package/dist/core/session/submit.d.ts +67 -0
- package/dist/core/session/submit.d.ts.map +1 -0
- package/dist/core/session/submit.js +254 -0
- package/dist/core/session/submit.js.map +1 -0
- package/dist/core/shared-stores-location.d.ts +17 -0
- package/dist/core/shared-stores-location.d.ts.map +1 -0
- package/dist/core/shared-stores-location.js +22 -0
- package/dist/core/shared-stores-location.js.map +1 -0
- package/dist/core/shared-stores.d.ts +69 -0
- package/dist/core/shared-stores.d.ts.map +1 -0
- package/dist/core/shared-stores.js +100 -0
- package/dist/core/shared-stores.js.map +1 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +14 -10
- package/dist/core/skills.js.map +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +122 -6
- package/dist/run.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/templates/agents/shared-stores.md +11 -0
- package/templates/approve/copies-missing.md +1 -0
- package/templates/approve/elsewhere-heading.md +1 -0
- package/templates/approve/elsewhere-intro.md +1 -0
- package/templates/approve/homed-elsewhere.md +1 -0
- package/templates/approve/not-decider.md +1 -0
- package/templates/approve/part-heading.md +1 -0
- package/templates/approve/parts-changed.md +1 -0
- package/templates/approve/session-decision-note.md +1 -0
- package/templates/approve/session-intro.md +1 -0
- package/templates/approve/session-no-decision.md +1 -0
- package/templates/approve/store-unreachable.md +1 -0
- package/templates/land/resolver.md +2 -0
- package/templates/second-opinion/poll-answer.md +7 -0
- package/templates/second-opinion/taste-panel.md +14 -0
- package/templates/session/pages/bare-route.md +2 -0
- package/templates/session/pages/block.md +8 -0
- package/templates/session/pages/condition-preview.md +1 -0
- package/templates/session/pages/condition.md +1 -0
- package/templates/session/pages/moved.md +1 -0
- package/templates/session/pages/stops-working.md +1 -0
- package/templates/session/pages/table-head-preview.md +2 -0
- package/templates/session/pages/table-head.md +2 -0
- package/templates/skills/ctxr-connection-finding.md +4 -1
- package/templates/skills/ctxr-land.md +26 -7
- package/templates/skills/ctxr-placement.md +10 -0
- package/templates/skills/ctxr-rollup.md +3 -0
- package/templates/skills/ctxr-second-opinion.md +52 -36
- package/templates/skills/ctxr-session-lifecycle.md +60 -33
- package/templates/skills/ctxr-submit.md +65 -56
- package/templates/skills/ctxr-second-opinion/run.mjs +0 -542
- /package/templates/{skills/ctxr-second-opinion → second-opinion}/critic-contract.md +0 -0
- /package/templates/{skills/ctxr-second-opinion → second-opinion}/lenses.md +0 -0
- /package/templates/{skills/ctxr-second-opinion → second-opinion}/personas/architect.md +0 -0
- /package/templates/{skills/ctxr-second-opinion → second-opinion}/personas/pragmatist.md +0 -0
- /package/templates/{skills/ctxr-second-opinion → second-opinion}/personas/skeptic.md +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type { StoreConfig } from '../../config/schema.js';
|
|
2
|
+
import type { ForgeCredentials } from '../forge/credentials.js';
|
|
3
|
+
import { type ForgeClient, type PullRequest } from '../forge/github.js';
|
|
4
|
+
import type { GitRunner } from '../git/exec.js';
|
|
5
|
+
import { type Decision, type LandingMark, type PartRef, type ReviewStateName, type SessionDecision } from './decision.js';
|
|
6
|
+
import { sessionKey, type SessionIdentity } from './session-marker.js';
|
|
7
|
+
/**
|
|
8
|
+
* approve-sessions-across-stores: a session's pull requests across the home
|
|
9
|
+
* store and the stores it mounts, and the state of its one decision.
|
|
10
|
+
*
|
|
11
|
+
* Only pull requests carrying a well-formed session marker are grouped here.
|
|
12
|
+
* A pull request without one is a session of its own and keeps today's path
|
|
13
|
+
* (`sessions.ts`), so a store whose pull requests carry no marker behaves
|
|
14
|
+
* exactly as before.
|
|
15
|
+
*/
|
|
16
|
+
/** One store a session can reach: the home store, or a present mount. */
|
|
17
|
+
export interface SessionStore {
|
|
18
|
+
/** The forge repository slug, `owner/repo`. */
|
|
19
|
+
slug: string;
|
|
20
|
+
/** null for the home store; the mount's name otherwise. */
|
|
21
|
+
mountName: string | null;
|
|
22
|
+
/** The clone's top level: the canonical clone for the home store, `shared/<name>` for a mount. */
|
|
23
|
+
root: string;
|
|
24
|
+
config: StoreConfig;
|
|
25
|
+
forge: ForgeClient;
|
|
26
|
+
/** The credential behind `forge`, for fetches and pushes against the store's remote; null keeps the transport's own. */
|
|
27
|
+
credentials: ForgeCredentials | null;
|
|
28
|
+
}
|
|
29
|
+
export interface StoreReach {
|
|
30
|
+
home: SessionStore;
|
|
31
|
+
/** Present mounts with a forge slug, in declared order. */
|
|
32
|
+
mounts: SessionStore[];
|
|
33
|
+
/** Declared mounts this run cannot read: absent, not a store, or without an `origin`. */
|
|
34
|
+
unavailable: {
|
|
35
|
+
name: string;
|
|
36
|
+
reason: string;
|
|
37
|
+
}[];
|
|
38
|
+
}
|
|
39
|
+
export type ForgeFor = (root: string, mount: boolean) => Promise<{
|
|
40
|
+
forge: ForgeClient;
|
|
41
|
+
credentials: ForgeCredentials | null;
|
|
42
|
+
}>;
|
|
43
|
+
/** The home store and every present mount, each with its own forge client. */
|
|
44
|
+
export declare function storeReach(git: GitRunner, home: {
|
|
45
|
+
root: string;
|
|
46
|
+
canonical: string;
|
|
47
|
+
config: StoreConfig;
|
|
48
|
+
forge: ForgeClient;
|
|
49
|
+
credentials?: ForgeCredentials | null;
|
|
50
|
+
}, forgeFor: ForgeFor): Promise<StoreReach | null>;
|
|
51
|
+
export declare function allStores(reach: StoreReach): SessionStore[];
|
|
52
|
+
/** A store's open pull requests, or why they could not be read. */
|
|
53
|
+
export interface StoreListing {
|
|
54
|
+
store: SessionStore;
|
|
55
|
+
pulls: PullRequest[] | null;
|
|
56
|
+
error: string | null;
|
|
57
|
+
}
|
|
58
|
+
export declare function listOpen(reach: StoreReach, homePulls?: () => Promise<PullRequest[]>): Promise<StoreListing[]>;
|
|
59
|
+
export interface OpenPart {
|
|
60
|
+
store: SessionStore;
|
|
61
|
+
pull: PullRequest;
|
|
62
|
+
}
|
|
63
|
+
export interface SessionGroup {
|
|
64
|
+
identity: SessionIdentity;
|
|
65
|
+
/** Whether this store is the session's home: only then is it decided and landed here. */
|
|
66
|
+
homedHere: boolean;
|
|
67
|
+
/** Its open pull requests, in landing order: mounted stores first (in declared order), the home store last. */
|
|
68
|
+
parts: OpenPart[];
|
|
69
|
+
/** Stores whose pull requests could not be read: the session may have parts there, so it is not decided. */
|
|
70
|
+
unreadable: string[];
|
|
71
|
+
}
|
|
72
|
+
/** Landing order: parts in mounted stores first, in declared order, then the home store's part. */
|
|
73
|
+
export declare function landingOrder<T extends {
|
|
74
|
+
store: string;
|
|
75
|
+
}>(parts: readonly T[], reach: StoreReach, homeSlug: string): T[];
|
|
76
|
+
/**
|
|
77
|
+
* Whether a pull request is read as a part of a session rather than on its own:
|
|
78
|
+
* it carries a session marker, and the session is homed in another store or
|
|
79
|
+
* the reading store declares mounts. A store with no `shared_stores` keeps
|
|
80
|
+
* today's path for its own sessions (design.md D9: nothing changes for a store
|
|
81
|
+
* that has not declared mounts); a pull request homed elsewhere is always its
|
|
82
|
+
* home's, so a mounted store never lands it.
|
|
83
|
+
*/
|
|
84
|
+
export declare function readAsSessionPart(pull: PullRequest, homeSlug: string | null, config: StoreConfig): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* write-lifecycle spec ("Every pull request of a session carries the session"):
|
|
87
|
+
* every open pull request read as a session part, grouped by the session it
|
|
88
|
+
* names. A session homed elsewhere is grouped too, so a page can show it apart.
|
|
89
|
+
* `all` also groups this store's own sessions when it declares no mounts — for
|
|
90
|
+
* `ctxr land --session`, which names one explicitly.
|
|
91
|
+
*/
|
|
92
|
+
export declare function groupSessions(reach: StoreReach, listings: readonly StoreListing[], all?: boolean): SessionGroup[];
|
|
93
|
+
/** Whether a pull request's body names a session homed in another store than `homeSlug`. */
|
|
94
|
+
export declare function homedElsewhere(pull: PullRequest, homeSlug: string): boolean;
|
|
95
|
+
export type SessionStateName = ReviewStateName | 'retrying';
|
|
96
|
+
export interface PartState {
|
|
97
|
+
ref: PartRef | null;
|
|
98
|
+
store: SessionStore | null;
|
|
99
|
+
storeSlug: string;
|
|
100
|
+
number: number;
|
|
101
|
+
/** The pull request as the forge has it now; null when its store cannot be read. */
|
|
102
|
+
pull: PullRequest | null;
|
|
103
|
+
/** Whether the decision names this part. */
|
|
104
|
+
named: boolean;
|
|
105
|
+
/** What this part contributes: ok, merged, closed, moved (head no longer the one approved), unnamed, unknown, or a landing record. */
|
|
106
|
+
status: 'ok' | 'merged' | 'closed' | 'moved' | 'unnamed' | 'unknown' | 'landing-blocked' | 'landing-needs-reapproval' | 'pending';
|
|
107
|
+
/** Whether this part carries a review of the decision (the record, or a copy) by the recording login. */
|
|
108
|
+
hasCopy: boolean;
|
|
109
|
+
landing: LandingMark | null;
|
|
110
|
+
}
|
|
111
|
+
export interface SessionState {
|
|
112
|
+
identity: SessionIdentity;
|
|
113
|
+
state: SessionStateName;
|
|
114
|
+
/** The record's decision, as on the record part. */
|
|
115
|
+
decision: Decision | null;
|
|
116
|
+
session: SessionDecision | null;
|
|
117
|
+
/** Every part: the named ones in the decision's order, then any open part it does not name. */
|
|
118
|
+
parts: PartState[];
|
|
119
|
+
/** The part and the reason behind `blocked`, `needs-reapproval` or `retrying`. */
|
|
120
|
+
reason: string | null;
|
|
121
|
+
reasonPart: string | null;
|
|
122
|
+
}
|
|
123
|
+
export interface StateInput {
|
|
124
|
+
git: GitRunner;
|
|
125
|
+
reach: StoreReach;
|
|
126
|
+
identity: SessionIdentity;
|
|
127
|
+
/**
|
|
128
|
+
* Whether the session is homed in the reading store. A session homed elsewhere may name parts on stores out of
|
|
129
|
+
* this store's reach; those are left out of its state, and its decision is read from a copy when the record is
|
|
130
|
+
* out of reach. A session homed here never ignores a part: every store it can name is in reach.
|
|
131
|
+
*/
|
|
132
|
+
homedHere: boolean;
|
|
133
|
+
/** The session's open parts, as grouped from the forge. */
|
|
134
|
+
open: readonly OpenPart[];
|
|
135
|
+
recordingLogin: string;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* change-approval spec ("A session is decided only on its home store's page,
|
|
139
|
+
* for every part it names"): the session's decision is the latest one on its
|
|
140
|
+
* record part alone, and it counts only while every part it names keeps the
|
|
141
|
+
* head it gives (or one carried over from it) and no open part carrying the
|
|
142
|
+
* marker is missing from it. A named part closed without merging blocks the
|
|
143
|
+
* session; a named part already merged counts as landed, and a session with
|
|
144
|
+
* some named parts landed and others still open is `retrying` — its landing
|
|
145
|
+
* was left unfinished and the next run goes on with it.
|
|
146
|
+
*/
|
|
147
|
+
export declare function sessionState(input: StateInput): Promise<SessionState>;
|
|
148
|
+
/**
|
|
149
|
+
* change-approval spec: a store's deciders, read from its `contexture.yaml` on its default branch on the forge at
|
|
150
|
+
* decision time (design.md D5) — never from a clone that can be behind. No `change_approval` means no deciders.
|
|
151
|
+
*/
|
|
152
|
+
export declare function decidersOnForge(git: GitRunner, store: SessionStore): Promise<string[]>;
|
|
153
|
+
/** A display name for a store in a session: its mount name, or the home store's slug. */
|
|
154
|
+
export declare function storeLabel(store: SessionStore): string;
|
|
155
|
+
export { sessionKey };
|
|
156
|
+
//# sourceMappingURL=session-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-group.d.ts","sourceRoot":"","sources":["../../../src/core/approval/session-group.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { parse as parseYaml } from 'yaml';
|
|
2
|
+
import { storePrefix } from '../graph/tree.js';
|
|
3
|
+
import { CONFIG_FILE_NAME } from '../root.js';
|
|
4
|
+
import { ContextureError } from '../errors.js';
|
|
5
|
+
import { ForgeRequestError } from '../forge/github.js';
|
|
6
|
+
import { declaresSharedStores, resolveMounts } from '../shared-stores.js';
|
|
7
|
+
import { parseDecision, parseLandingMark, partKey, recordPartOf } from './decision.js';
|
|
8
|
+
import { parseSessionMarker, repositorySlug, sessionKey, sessionsEqual } from './session-marker.js';
|
|
9
|
+
import { baseRef, carriesOver } from './sessions.js';
|
|
10
|
+
/** The home store and every present mount, each with its own forge client. */
|
|
11
|
+
export async function storeReach(git, home, forgeFor) {
|
|
12
|
+
const homeSlug = await repositorySlug(git, home.canonical);
|
|
13
|
+
if (homeSlug === null)
|
|
14
|
+
return null;
|
|
15
|
+
const mounts = [];
|
|
16
|
+
const unavailable = [];
|
|
17
|
+
for (const mount of await resolveMounts(home.root, home.config)) {
|
|
18
|
+
if (mount.state !== 'present') {
|
|
19
|
+
unavailable.push({ name: mount.name, reason: mount.state === 'absent' ? 'not cloned' : mount.reason });
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const slug = await repositorySlug(git, mount.root);
|
|
23
|
+
if (slug === null) {
|
|
24
|
+
unavailable.push({ name: mount.name, reason: 'its clone has no "origin" remote' });
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
mounts.push({ slug, mountName: mount.name, root: mount.root, config: mount.config, ...(await forgeFor(mount.root, true)) });
|
|
28
|
+
}
|
|
29
|
+
return { home: { slug: homeSlug, mountName: null, root: home.canonical, config: home.config, forge: home.forge, credentials: home.credentials ?? null }, mounts, unavailable };
|
|
30
|
+
}
|
|
31
|
+
export function allStores(reach) {
|
|
32
|
+
return [...reach.mounts, reach.home];
|
|
33
|
+
}
|
|
34
|
+
export async function listOpen(reach, homePulls) {
|
|
35
|
+
return Promise.all(allStores(reach).map(async (store) => {
|
|
36
|
+
try {
|
|
37
|
+
const pulls = store === reach.home && homePulls !== undefined ? await homePulls() : await store.forge.openPulls();
|
|
38
|
+
return { store, pulls, error: null };
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
// A mount the credential cannot reach (an App not installed there) is unreadable, like an unreachable forge.
|
|
42
|
+
if (!(err instanceof ForgeRequestError) && !(store !== reach.home && err instanceof ContextureError))
|
|
43
|
+
throw err;
|
|
44
|
+
return { store, pulls: null, error: err.message };
|
|
45
|
+
}
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
/** Landing order: parts in mounted stores first, in declared order, then the home store's part. */
|
|
49
|
+
export function landingOrder(parts, reach, homeSlug) {
|
|
50
|
+
const rank = (slug) => {
|
|
51
|
+
if (slug === homeSlug)
|
|
52
|
+
return Number.MAX_SAFE_INTEGER;
|
|
53
|
+
const i = reach.mounts.findIndex((m) => m.slug === slug);
|
|
54
|
+
return i === -1 ? Number.MAX_SAFE_INTEGER - 1 : i;
|
|
55
|
+
};
|
|
56
|
+
return [...parts].sort((x, y) => rank(x.store) - rank(y.store));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Whether a pull request is read as a part of a session rather than on its own:
|
|
60
|
+
* it carries a session marker, and the session is homed in another store or
|
|
61
|
+
* the reading store declares mounts. A store with no `shared_stores` keeps
|
|
62
|
+
* today's path for its own sessions (design.md D9: nothing changes for a store
|
|
63
|
+
* that has not declared mounts); a pull request homed elsewhere is always its
|
|
64
|
+
* home's, so a mounted store never lands it.
|
|
65
|
+
*/
|
|
66
|
+
export function readAsSessionPart(pull, homeSlug, config) {
|
|
67
|
+
const identity = parseSessionMarker(pull.body);
|
|
68
|
+
if (identity === null)
|
|
69
|
+
return false;
|
|
70
|
+
return identity.home !== homeSlug || declaresSharedStores(config);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* write-lifecycle spec ("Every pull request of a session carries the session"):
|
|
74
|
+
* every open pull request read as a session part, grouped by the session it
|
|
75
|
+
* names. A session homed elsewhere is grouped too, so a page can show it apart.
|
|
76
|
+
* `all` also groups this store's own sessions when it declares no mounts — for
|
|
77
|
+
* `ctxr land --session`, which names one explicitly.
|
|
78
|
+
*/
|
|
79
|
+
export function groupSessions(reach, listings, all = false) {
|
|
80
|
+
const groups = new Map();
|
|
81
|
+
const unreadable = listings.filter((l) => l.pulls === null).map((l) => l.store.slug);
|
|
82
|
+
for (const listing of listings) {
|
|
83
|
+
for (const pull of listing.pulls ?? []) {
|
|
84
|
+
const identity = parseSessionMarker(pull.body);
|
|
85
|
+
if (identity === null)
|
|
86
|
+
continue;
|
|
87
|
+
if (!all && !readAsSessionPart(pull, reach.home.slug, reach.home.config))
|
|
88
|
+
continue;
|
|
89
|
+
const key = sessionKey(identity);
|
|
90
|
+
let group = groups.get(key);
|
|
91
|
+
if (group === undefined) {
|
|
92
|
+
group = { identity, homedHere: identity.home === reach.home.slug, parts: [], unreadable };
|
|
93
|
+
groups.set(key, group);
|
|
94
|
+
}
|
|
95
|
+
group.parts.push({ store: listing.store, pull });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const group of groups.values()) {
|
|
99
|
+
const ordered = landingOrder(group.parts.map((p) => ({ ...p, store: p.store.slug, part: p })), reach, group.identity.home);
|
|
100
|
+
group.parts = ordered.map((o) => o.part);
|
|
101
|
+
}
|
|
102
|
+
return [...groups.values()];
|
|
103
|
+
}
|
|
104
|
+
/** Whether a pull request's body names a session homed in another store than `homeSlug`. */
|
|
105
|
+
export function homedElsewhere(pull, homeSlug) {
|
|
106
|
+
const identity = parseSessionMarker(pull.body);
|
|
107
|
+
return identity !== null && identity.home !== homeSlug;
|
|
108
|
+
}
|
|
109
|
+
function timeOf(value) {
|
|
110
|
+
const t = value === null ? Number.NaN : Date.parse(value);
|
|
111
|
+
return Number.isNaN(t) ? 0 : t;
|
|
112
|
+
}
|
|
113
|
+
/** The latest session decision for `identity` among a part's reviews by the recording login. */
|
|
114
|
+
function latestSessionDecision(reviews, recordingLogin, identity, id) {
|
|
115
|
+
let found = null;
|
|
116
|
+
for (const review of reviews) {
|
|
117
|
+
if (review.author !== recordingLogin)
|
|
118
|
+
continue;
|
|
119
|
+
const decision = parseDecision(review.body);
|
|
120
|
+
const session = decision?.session ?? null;
|
|
121
|
+
if (decision === null || session === null || !sessionsEqual(session.session, identity))
|
|
122
|
+
continue;
|
|
123
|
+
if (id !== undefined && session.id !== id)
|
|
124
|
+
continue;
|
|
125
|
+
const time = timeOf(review.submittedAt);
|
|
126
|
+
if (found === null || time >= found.time)
|
|
127
|
+
found = { decision, session, time };
|
|
128
|
+
}
|
|
129
|
+
return found;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* change-approval spec ("A session is decided only on its home store's page,
|
|
133
|
+
* for every part it names"): the session's decision is the latest one on its
|
|
134
|
+
* record part alone, and it counts only while every part it names keeps the
|
|
135
|
+
* head it gives (or one carried over from it) and no open part carrying the
|
|
136
|
+
* marker is missing from it. A named part closed without merging blocks the
|
|
137
|
+
* session; a named part already merged counts as landed, and a session with
|
|
138
|
+
* some named parts landed and others still open is `retrying` — its landing
|
|
139
|
+
* was left unfinished and the next run goes on with it.
|
|
140
|
+
*/
|
|
141
|
+
export async function sessionState(input) {
|
|
142
|
+
const { git, reach, identity, recordingLogin } = input;
|
|
143
|
+
const stores = allStores(reach);
|
|
144
|
+
const storeOf = (slug) => stores.find((s) => s.slug === slug) ?? null;
|
|
145
|
+
const reads = new Map();
|
|
146
|
+
const readPart = (store, number) => {
|
|
147
|
+
const key = partKey({ store: store.slug, number });
|
|
148
|
+
let read = reads.get(key);
|
|
149
|
+
if (read === undefined) {
|
|
150
|
+
read = Promise.all([store.forge.reviews(number), store.forge.comments(number)]).then(([reviews, comments]) => ({ reviews, comments }));
|
|
151
|
+
reads.set(key, read);
|
|
152
|
+
}
|
|
153
|
+
return read;
|
|
154
|
+
};
|
|
155
|
+
// The latest session decision on any open part points at the record part; the record alone decides.
|
|
156
|
+
const openReads = await Promise.all(input.open.map(async (p) => ({ part: p, reads: await readPart(p.store, p.pull.number) })));
|
|
157
|
+
let candidate = null;
|
|
158
|
+
for (const { reads: r } of openReads) {
|
|
159
|
+
const found = latestSessionDecision(r.reviews, recordingLogin, identity);
|
|
160
|
+
if (found !== null && (candidate === null || found.time >= candidate.time))
|
|
161
|
+
candidate = found;
|
|
162
|
+
}
|
|
163
|
+
let record = null;
|
|
164
|
+
let recordComments = [];
|
|
165
|
+
if (candidate !== null) {
|
|
166
|
+
const recordRef = recordPartOf(candidate.session);
|
|
167
|
+
const recordStore = storeOf(recordRef.store);
|
|
168
|
+
if (recordStore === null && !input.homedHere)
|
|
169
|
+
record = candidate;
|
|
170
|
+
if (recordStore !== null) {
|
|
171
|
+
try {
|
|
172
|
+
const recordReads = await readPart(recordStore, recordRef.number);
|
|
173
|
+
record = latestSessionDecision(recordReads.reviews, recordingLogin, identity);
|
|
174
|
+
recordComments = recordReads.comments;
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
if (!(err instanceof ForgeRequestError))
|
|
178
|
+
throw err;
|
|
179
|
+
record = null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const openPart = (slug, number) => input.open.find((p) => p.store.slug === slug && p.pull.number === number);
|
|
184
|
+
const unnamedOpen = (named) => input.open.filter((p) => !named.some((n) => n.store === p.store.slug && n.number === p.pull.number));
|
|
185
|
+
if (record === null) {
|
|
186
|
+
const parts = input.open.map((p) => ({
|
|
187
|
+
ref: null,
|
|
188
|
+
store: p.store,
|
|
189
|
+
storeSlug: p.store.slug,
|
|
190
|
+
number: p.pull.number,
|
|
191
|
+
pull: p.pull,
|
|
192
|
+
named: false,
|
|
193
|
+
status: 'pending',
|
|
194
|
+
hasCopy: false,
|
|
195
|
+
landing: null,
|
|
196
|
+
}));
|
|
197
|
+
return { identity, state: 'awaiting', decision: null, session: null, parts, reason: null, reasonPart: null };
|
|
198
|
+
}
|
|
199
|
+
const decided = record.session;
|
|
200
|
+
const parts = [];
|
|
201
|
+
for (const ref of decided.parts) {
|
|
202
|
+
const store = storeOf(ref.store);
|
|
203
|
+
const base = { ref, store, storeSlug: ref.store, number: ref.number, named: true };
|
|
204
|
+
if (store === null) {
|
|
205
|
+
parts.push({ ...base, pull: null, status: 'unknown', hasCopy: false, landing: null });
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
let pull;
|
|
209
|
+
let reads;
|
|
210
|
+
try {
|
|
211
|
+
pull = openPart(ref.store, ref.number)?.pull ?? (await store.forge.pull(ref.number));
|
|
212
|
+
reads = await readPart(store, ref.number);
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
if (!(err instanceof ForgeRequestError))
|
|
216
|
+
throw err;
|
|
217
|
+
parts.push({ ...base, pull: null, status: 'unknown', hasCopy: false, landing: null });
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const copy = latestSessionDecision(reads.reviews, recordingLogin, identity, decided.id);
|
|
221
|
+
const hasCopy = copy !== null;
|
|
222
|
+
if (pull.merged) {
|
|
223
|
+
parts.push({ ...base, pull, status: 'merged', hasCopy, landing: null });
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (pull.state !== 'open') {
|
|
227
|
+
parts.push({ ...base, pull, status: 'closed', hasCopy, landing: null });
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
// A landing record about this head, posted after this part's review of the decision, overrides it — as for one pull request.
|
|
231
|
+
const since = copy?.time ?? record.time;
|
|
232
|
+
let landing = null;
|
|
233
|
+
let landingTime = -1;
|
|
234
|
+
for (const comment of reads.comments) {
|
|
235
|
+
if (comment.author !== recordingLogin)
|
|
236
|
+
continue;
|
|
237
|
+
const mark = parseLandingMark(comment.body);
|
|
238
|
+
if (mark === null || mark.state === 'retrying')
|
|
239
|
+
continue;
|
|
240
|
+
const t = timeOf(comment.createdAt);
|
|
241
|
+
if (t >= landingTime) {
|
|
242
|
+
landing = mark;
|
|
243
|
+
landingTime = t;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (landing !== null && (landing.head !== pull.headSha || landingTime < since))
|
|
247
|
+
landing = null;
|
|
248
|
+
let current = pull.headSha === ref.head;
|
|
249
|
+
// A carry-over the lander recorded on this part, for this decision, names the head it carried the approval to.
|
|
250
|
+
if (!current && copy !== null && copy.decision.head === pull.headSha && copy.decision.carriedFrom !== null)
|
|
251
|
+
current = true;
|
|
252
|
+
if (!current) {
|
|
253
|
+
const base = await baseRef(git, store.root, store.config.git.default_branch);
|
|
254
|
+
current = await carriesOver(git, store.root, base, ref.head, pull.headSha);
|
|
255
|
+
}
|
|
256
|
+
const status = !current
|
|
257
|
+
? 'moved'
|
|
258
|
+
: landing?.state === 'blocked'
|
|
259
|
+
? 'landing-blocked'
|
|
260
|
+
: landing?.state === 'needs-reapproval'
|
|
261
|
+
? 'landing-needs-reapproval'
|
|
262
|
+
: 'ok';
|
|
263
|
+
parts.push({ ...base, pull, status, hasCopy, landing });
|
|
264
|
+
}
|
|
265
|
+
for (const p of unnamedOpen(decided.parts)) {
|
|
266
|
+
parts.push({ ref: null, store: p.store, storeSlug: p.store.slug, number: p.pull.number, pull: p.pull, named: false, status: 'unnamed', hasCopy: false, landing: null });
|
|
267
|
+
}
|
|
268
|
+
const name = (p) => `${p.storeSlug}#${p.number}`;
|
|
269
|
+
const result = (state, reason, part) => ({
|
|
270
|
+
identity,
|
|
271
|
+
state,
|
|
272
|
+
decision: record.decision,
|
|
273
|
+
session: decided,
|
|
274
|
+
parts,
|
|
275
|
+
reason,
|
|
276
|
+
reasonPart: part === null ? null : name(part),
|
|
277
|
+
});
|
|
278
|
+
if (record.decision.decision === 'request-changes')
|
|
279
|
+
return result('changes-requested', null, null);
|
|
280
|
+
const closed = parts.find((p) => p.status === 'closed');
|
|
281
|
+
if (closed !== undefined)
|
|
282
|
+
return result('blocked', `${name(closed)} was closed without being merged`, closed);
|
|
283
|
+
const unnamed = parts.find((p) => p.status === 'unnamed');
|
|
284
|
+
if (unnamed !== undefined)
|
|
285
|
+
return result('needs-reapproval', `${name(unnamed)} carries the session's marker but the decision does not name it`, unnamed);
|
|
286
|
+
const moved = parts.find((p) => p.status === 'moved');
|
|
287
|
+
if (moved !== undefined)
|
|
288
|
+
return result('needs-reapproval', `${name(moved)} is no longer at the head the decision approved`, moved);
|
|
289
|
+
const reapprove = parts.find((p) => p.status === 'landing-needs-reapproval');
|
|
290
|
+
if (reapprove !== undefined)
|
|
291
|
+
return result('needs-reapproval', `${name(reapprove)}: ${reapprove.landing.reason}`, reapprove);
|
|
292
|
+
const blocked = parts.find((p) => p.status === 'landing-blocked');
|
|
293
|
+
if (blocked !== undefined)
|
|
294
|
+
return result('blocked', `${name(blocked)}: ${blocked.landing.reason}`, blocked);
|
|
295
|
+
const counted = parts.filter((p) => input.homedHere || p.store !== null);
|
|
296
|
+
// A landing left unfinished for a passing reason is recorded on the record part, naming the part and why. It
|
|
297
|
+
// holds until that part lands: a later run that merges it clears it.
|
|
298
|
+
const retry = latestRetrying(recordComments, recordingLogin, record.time);
|
|
299
|
+
if (retry !== null) {
|
|
300
|
+
const held = counted.find((p) => name(p) === retry.part && p.status !== 'merged');
|
|
301
|
+
if (held !== undefined)
|
|
302
|
+
return result('retrying', `${retry.part}: ${retry.why}`, held);
|
|
303
|
+
}
|
|
304
|
+
const unknown = counted.find((p) => p.status === 'unknown');
|
|
305
|
+
if (unknown !== undefined)
|
|
306
|
+
return result('retrying', `${name(unknown)} cannot be read from its store`, unknown);
|
|
307
|
+
const merged = counted.filter((p) => p.status === 'merged').length;
|
|
308
|
+
if (merged > 0 && merged < counted.length) {
|
|
309
|
+
const next = counted.find((p) => p.status === 'ok');
|
|
310
|
+
return result('retrying', `${merged} of ${counted.length} parts landed; ${name(next)} is next`, next);
|
|
311
|
+
}
|
|
312
|
+
return result('approved', null, null);
|
|
313
|
+
}
|
|
314
|
+
/** The latest `retrying` landing record by the recording login posted after the decision: the part, and why. */
|
|
315
|
+
function latestRetrying(comments, recordingLogin, since) {
|
|
316
|
+
let found = null;
|
|
317
|
+
let foundTime = -1;
|
|
318
|
+
for (const comment of comments) {
|
|
319
|
+
if (comment.author !== recordingLogin)
|
|
320
|
+
continue;
|
|
321
|
+
const mark = parseLandingMark(comment.body);
|
|
322
|
+
if (mark === null || mark.state !== 'retrying')
|
|
323
|
+
continue;
|
|
324
|
+
const t = timeOf(comment.createdAt);
|
|
325
|
+
if (t < since || t < foundTime)
|
|
326
|
+
continue;
|
|
327
|
+
const at = mark.reason.lastIndexOf(':');
|
|
328
|
+
if (at <= 0)
|
|
329
|
+
continue;
|
|
330
|
+
found = { part: mark.reason.slice(0, at), why: mark.reason.slice(at + 1) };
|
|
331
|
+
foundTime = t;
|
|
332
|
+
}
|
|
333
|
+
return found;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* change-approval spec: a store's deciders, read from its `contexture.yaml` on its default branch on the forge at
|
|
337
|
+
* decision time (design.md D5) — never from a clone that can be behind. No `change_approval` means no deciders.
|
|
338
|
+
*/
|
|
339
|
+
export async function decidersOnForge(git, store) {
|
|
340
|
+
const prefix = await storePrefix(git, store.root);
|
|
341
|
+
const text = await store.forge.fileAt(`${prefix}${CONFIG_FILE_NAME}`, store.config.git.default_branch);
|
|
342
|
+
if (text === null)
|
|
343
|
+
return [];
|
|
344
|
+
let parsed;
|
|
345
|
+
try {
|
|
346
|
+
parsed = parseYaml(text);
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
const deciders = parsed?.change_approval?.deciders;
|
|
352
|
+
return Array.isArray(deciders) ? deciders.filter((d) => typeof d === 'string') : [];
|
|
353
|
+
}
|
|
354
|
+
/** A display name for a store in a session: its mount name, or the home store's slug. */
|
|
355
|
+
export function storeLabel(store) {
|
|
356
|
+
return store.mountName === null ? store.slug : `${store.mountName} (${store.slug})`;
|
|
357
|
+
}
|
|
358
|
+
export { sessionKey };
|
|
359
|
+
//# sourceMappingURL=session-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-group.js","sourceRoot":"","sources":["../../../src/core/approval/session-group.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { StoreConfig } from '../../config/schema.js';
|
|
2
|
+
import type { GitRunner } from '../git/exec.js';
|
|
3
|
+
/**
|
|
4
|
+
* approve-sessions-across-stores (design.md D1, D2; the second critique's
|
|
5
|
+
* revisions 2 and 3): a session's identity is its home store's forge slug
|
|
6
|
+
* (`owner/repo`) and the home session's branch. It is derived from the
|
|
7
|
+
* session's own branch, worktree and repository alone — no identity file.
|
|
8
|
+
*
|
|
9
|
+
* A joined session (one started inside a mount with `ctxr session start
|
|
10
|
+
* --joins`) carries its home in its branch, `<prefix><owner>/<repo>/<home
|
|
11
|
+
* branch without its prefix>`, and in its worktree directory, where `/` cannot
|
|
12
|
+
* appear: `<prefix as a directory name><owner>--<repo>--<home branch without
|
|
13
|
+
* its prefix>`. A GitHub owner never contains `--`, and a generated session
|
|
14
|
+
* name never does, so the directory name splits back unambiguously. The
|
|
15
|
+
* directory keeps the identity after `ctxr session submit --branch` renames
|
|
16
|
+
* the branch.
|
|
17
|
+
*
|
|
18
|
+
* The pull request marker, appended by `ctxr session submit`, is what groups a
|
|
19
|
+
* session's pull requests across stores; branch names never are.
|
|
20
|
+
*/
|
|
21
|
+
export declare const SESSION_MARKER = "ctxr-session";
|
|
22
|
+
export interface SessionIdentity {
|
|
23
|
+
/** The home store's forge repository slug, `owner/repo`. */
|
|
24
|
+
home: string;
|
|
25
|
+
/** The home session's branch, with the home store's prefix. */
|
|
26
|
+
branch: string;
|
|
27
|
+
}
|
|
28
|
+
/** One string per session, for grouping and comparison. Branches cannot contain `:`, so it is unambiguous. */
|
|
29
|
+
export declare function sessionKey(identity: SessionIdentity): string;
|
|
30
|
+
export declare function parseSessionKey(key: string): SessionIdentity | null;
|
|
31
|
+
export declare function sessionsEqual(a: SessionIdentity | null, b: SessionIdentity | null): boolean;
|
|
32
|
+
/** The marker `ctxr session submit` appends to a pull request body. */
|
|
33
|
+
export declare function sessionMarker(identity: SessionIdentity): string;
|
|
34
|
+
/**
|
|
35
|
+
* The session a pull request body names, or null — a body with no well-formed
|
|
36
|
+
* marker ending it is a session of its own (write-lifecycle spec). Like the
|
|
37
|
+
* decision marker, only a marker that ends the body counts.
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseSessionMarker(body: string): SessionIdentity | null;
|
|
40
|
+
/** Any session marker anywhere in `body`, well-formed or not — what `ctxr session submit` refuses in an agent's body. */
|
|
41
|
+
export declare function findSessionMarker(body: string): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* The forge slug of a remote URL: GitHub's `owner/repo` for a github.com URL,
|
|
44
|
+
* and otherwise the URL's last two path segments without `.git` — the same
|
|
45
|
+
* shape for a mirror, a proxy, or a test's bare repository.
|
|
46
|
+
*/
|
|
47
|
+
export declare function forgeSlugOf(remoteUrl: string): string | null;
|
|
48
|
+
/** The forge slug of the repository `cwd` is in, from its `origin`; null without one. */
|
|
49
|
+
export declare function repositorySlug(git: GitRunner, cwd: string): Promise<string | null>;
|
|
50
|
+
/** write-lifecycle spec: the joined session's branch — this store's prefix, the home slug, the home branch without its prefix. */
|
|
51
|
+
export declare function joinedBranchName(prefix: string, home: SessionIdentity, homePrefix: string): string;
|
|
52
|
+
/** The joined session's worktree directory name, which splits back into its home (see the module comment). */
|
|
53
|
+
export declare function joinedWorktreeName(prefix: string, home: SessionIdentity, homePrefix: string): string;
|
|
54
|
+
export interface IdentityInput {
|
|
55
|
+
/** The branch prefix of the store the session is in. */
|
|
56
|
+
prefix: string;
|
|
57
|
+
/** The branch prefix of the store that mounts it, when it is a mount; else the store's own. */
|
|
58
|
+
homePrefix: string;
|
|
59
|
+
/** This store's own forge slug; null without an `origin`. */
|
|
60
|
+
ownSlug: string | null;
|
|
61
|
+
/** The session worktree's directory name. */
|
|
62
|
+
worktreeName: string;
|
|
63
|
+
/** The session's current branch. */
|
|
64
|
+
branch: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A session's identity, derived from its worktree and branch alone. The
|
|
68
|
+
* worktree name decides first, because `ctxr session submit --branch` can
|
|
69
|
+
* rename the branch to anything, including a name shaped like a joined one,
|
|
70
|
+
* while the worktree keeps the name it was started with: a joined worktree
|
|
71
|
+
* name carries its home, and any other session worktree is its own home. Only
|
|
72
|
+
* a worktree whose name ctxr did not give falls back to the branch.
|
|
73
|
+
*/
|
|
74
|
+
export declare function sessionIdentityFor(input: IdentityInput): SessionIdentity | null;
|
|
75
|
+
/** The identity of the session checked out in `worktreePath`, reading only its repository and, for a mount, the mounting store's configuration. */
|
|
76
|
+
export declare function identityOfWorktree(git: GitRunner, config: StoreConfig, worktreePath: string, worktreeName: string, branch: string): Promise<SessionIdentity | null>;
|
|
77
|
+
/** The approval route name of a session homed in a store: its home branch as a worktree directory name. */
|
|
78
|
+
export declare function sessionRouteName(identity: SessionIdentity): string;
|
|
79
|
+
//# sourceMappingURL=session-marker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-marker.d.ts","sourceRoot":"","sources":["../../../src/core/approval/session-marker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMhD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;CAChB;AAKD,8GAA8G;AAC9G,wBAAgB,UAAU,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAE5D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAMnE;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,eAAe,GAAG,IAAI,EAAE,CAAC,EAAE,eAAe,GAAG,IAAI,GAAG,OAAO,CAE3F;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAMvE;AAED,yHAAyH;AACzH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG7D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY5D;AAED,yFAAyF;AACzF,wBAAsB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxF;AAMD,kIAAkI;AAClI,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAElG;AAED,8GAA8G;AAC9G,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAGpG;AAED,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,GAAG,IAAI,CAkB/E;AAED,mJAAmJ;AACnJ,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CASzK;AAED,2GAA2G;AAC3G,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAElE"}
|