ctxr-cli 0.33.0 → 0.35.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 +40 -6
- 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/plugin-build.d.ts +33 -0
- package/dist/commands/plugin-build.d.ts.map +1 -0
- package/dist/commands/plugin-build.js +51 -0
- package/dist/commands/plugin-build.js.map +1 -0
- package/dist/commands/publish-check.d.ts.map +1 -1
- package/dist/commands/publish-check.js +35 -4
- package/dist/commands/publish-check.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 +14 -2
- 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 +52 -38
- 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/fs/atomic.d.ts +3 -2
- package/dist/core/fs/atomic.d.ts.map +1 -1
- package/dist/core/fs/atomic.js +3 -2
- package/dist/core/fs/atomic.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/cli-runner.d.ts +41 -0
- package/dist/core/mcp/cli-runner.d.ts.map +1 -0
- package/dist/core/mcp/cli-runner.js +81 -0
- package/dist/core/mcp/cli-runner.js.map +1 -0
- package/dist/core/mcp/jsonrpc.d.ts +13 -1
- package/dist/core/mcp/jsonrpc.d.ts.map +1 -1
- package/dist/core/mcp/jsonrpc.js +1 -1
- package/dist/core/mcp/jsonrpc.js.map +1 -1
- package/dist/core/mcp/member-sessions.d.ts +48 -0
- package/dist/core/mcp/member-sessions.d.ts.map +1 -0
- package/dist/core/mcp/member-sessions.js +85 -0
- package/dist/core/mcp/member-sessions.js.map +1 -0
- package/dist/core/mcp/ownership.d.ts +51 -0
- package/dist/core/mcp/ownership.d.ts.map +1 -0
- package/dist/core/mcp/ownership.js +101 -0
- package/dist/core/mcp/ownership.js.map +1 -0
- package/dist/core/mcp/paths.d.ts +48 -0
- package/dist/core/mcp/paths.d.ts.map +1 -0
- package/dist/core/mcp/paths.js +111 -0
- package/dist/core/mcp/paths.js.map +1 -0
- package/dist/core/mcp/sessions.d.ts +25 -50
- package/dist/core/mcp/sessions.d.ts.map +1 -1
- package/dist/core/mcp/sessions.js +31 -123
- package/dist/core/mcp/sessions.js.map +1 -1
- package/dist/core/mcp/tool-map.d.ts +94 -0
- package/dist/core/mcp/tool-map.d.ts.map +1 -0
- package/dist/core/mcp/tool-map.js +211 -0
- package/dist/core/mcp/tool-map.js.map +1 -0
- package/dist/core/mcp/tools/capture.d.ts +7 -2
- package/dist/core/mcp/tools/capture.d.ts.map +1 -1
- package/dist/core/mcp/tools/capture.js +69 -18
- package/dist/core/mcp/tools/capture.js.map +1 -1
- package/dist/core/mcp/tools/cli.d.ts +97 -0
- package/dist/core/mcp/tools/cli.d.ts.map +1 -0
- package/dist/core/mcp/tools/cli.js +271 -0
- package/dist/core/mcp/tools/cli.js.map +1 -0
- package/dist/core/mcp/tools/edit.d.ts +62 -28
- package/dist/core/mcp/tools/edit.d.ts.map +1 -1
- package/dist/core/mcp/tools/edit.js +182 -153
- package/dist/core/mcp/tools/edit.js.map +1 -1
- package/dist/core/mcp/tools/files.d.ts +37 -11
- package/dist/core/mcp/tools/files.d.ts.map +1 -1
- package/dist/core/mcp/tools/files.js +122 -100
- package/dist/core/mcp/tools/files.js.map +1 -1
- package/dist/core/mcp/tools/index.d.ts +12 -3
- package/dist/core/mcp/tools/index.d.ts.map +1 -1
- package/dist/core/mcp/tools/index.js +161 -58
- package/dist/core/mcp/tools/index.js.map +1 -1
- package/dist/core/mcp/tools/sessions.d.ts +145 -0
- package/dist/core/mcp/tools/sessions.d.ts.map +1 -0
- package/dist/core/mcp/tools/sessions.js +226 -0
- package/dist/core/mcp/tools/sessions.js.map +1 -0
- 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/plugin/build.d.ts +70 -0
- package/dist/core/plugin/build.d.ts.map +1 -0
- package/dist/core/plugin/build.js +159 -0
- package/dist/core/plugin/build.js.map +1 -0
- package/dist/core/plugin/routes.d.ts +35 -0
- package/dist/core/plugin/routes.d.ts.map +1 -0
- package/dist/core/plugin/routes.js +77 -0
- package/dist/core/plugin/routes.js.map +1 -0
- package/dist/core/plugin/zip.d.ts +17 -0
- package/dist/core/plugin/zip.d.ts.map +1 -0
- package/dist/core/plugin/zip.js +75 -0
- package/dist/core/plugin/zip.js.map +1 -0
- 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/start.d.ts +46 -0
- package/dist/core/session/start.d.ts.map +1 -0
- package/dist/core/session/start.js +33 -0
- package/dist/core/session/start.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 +20 -2
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +70 -13
- package/dist/core/skills.js.map +1 -1
- package/dist/run.d.ts +12 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +194 -55
- 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/mcp/Delete.md +6 -0
- package/templates/mcp/Edit.md +6 -5
- package/templates/mcp/Glob.md +2 -2
- package/templates/mcp/Grep.md +2 -1
- package/templates/mcp/Move.md +7 -0
- package/templates/mcp/Read.md +4 -4
- package/templates/mcp/Write.md +4 -4
- package/templates/mcp/ctxr.md +7 -0
- package/templates/mcp/ctxr_write.md +8 -0
- package/templates/mcp/server-instructions.md +11 -3
- package/templates/mcp/session_discard.md +4 -0
- package/templates/mcp/session_list.md +7 -0
- package/templates/mcp/session_rebase.md +5 -0
- package/templates/mcp/session_start.md +7 -0
- package/templates/mcp/session_status.md +3 -0
- package/templates/mcp/session_submit.md +8 -0
- package/templates/plugin/README.md +13 -0
- package/templates/plugin/chatgpt-mcp.json +19 -0
- package/templates/plugin/chatgpt-plugin.json +13 -0
- package/templates/plugin/claude-mcp.json +8 -0
- package/templates/plugin/claude-plugin.json +6 -0
- package/templates/plugin/page.html +47 -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-publish.md +2 -1
- 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/mcp/_preamble.md +44 -0
- package/dist/core/mcp/drafts.d.ts +0 -30
- package/dist/core/mcp/drafts.d.ts.map +0 -1
- package/dist/core/mcp/drafts.js +0 -52
- package/dist/core/mcp/drafts.js.map +0 -1
- 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,224 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { SecondOpinionUsageError } from '../errors.js';
|
|
5
|
+
import { childEnvironment, PASS_ENV_VARIABLE, protectedPassThroughNames } from './environment.js';
|
|
6
|
+
import { judgeCritique } from './judge.js';
|
|
7
|
+
import { firstLines, runCli } from './launch.js';
|
|
8
|
+
import { ALL_CLIS, buildInvocation, FLAGS_USED, MAX_ARGV_BYTES, normalize, QUORUM, ROLE_CLI, ROLES, TIERS, tiers } from './lineup.js';
|
|
9
|
+
import { critiquePrompt, pollPrompt } from './prompts.js';
|
|
10
|
+
/** Every refusal happens here, before any CLI launches. */
|
|
11
|
+
function resolve(ctx, opts, needQuorum) {
|
|
12
|
+
const tier = (opts.tier ?? 'strong');
|
|
13
|
+
if (!TIERS.includes(tier))
|
|
14
|
+
throw new SecondOpinionUsageError('--tier is strong or fast');
|
|
15
|
+
const timeout = opts.timeout === undefined ? 600 : Number(opts.timeout);
|
|
16
|
+
if (!Number.isFinite(timeout) || timeout <= 0)
|
|
17
|
+
throw new SecondOpinionUsageError('--timeout must be a positive number of seconds');
|
|
18
|
+
let clis = [...ALL_CLIS];
|
|
19
|
+
if (opts.only !== undefined) {
|
|
20
|
+
const named = opts.only.split(',').map((c) => c.trim()).filter(Boolean);
|
|
21
|
+
const bad = named.filter((c) => !ALL_CLIS.includes(c));
|
|
22
|
+
if (bad.length)
|
|
23
|
+
throw new SecondOpinionUsageError(`unknown CLI in --only: ${bad.join(', ')} (valid: ${ALL_CLIS.join(', ')})`);
|
|
24
|
+
clis = [...new Set(named)];
|
|
25
|
+
}
|
|
26
|
+
if (needQuorum && clis.length < QUORUM) {
|
|
27
|
+
throw new SecondOpinionUsageError(`--only names ${clis.length} CLI; a second opinion needs at least ${QUORUM}`);
|
|
28
|
+
}
|
|
29
|
+
// D3 and Revisions after critique 1: the protected prefixes win over the pass-through, and naming one stops the run.
|
|
30
|
+
const refused = protectedPassThroughNames(ctx.source);
|
|
31
|
+
if (refused.length) {
|
|
32
|
+
throw new SecondOpinionUsageError(`${PASS_ENV_VARIABLE} names ${refused.join(', ')}; forge and contexture variables are never passed to a model CLI`, { variables: refused });
|
|
33
|
+
}
|
|
34
|
+
const { env, withheld } = childEnvironment(ctx.source, ctx.home);
|
|
35
|
+
return { tier, timeout, clis, env, withheld };
|
|
36
|
+
}
|
|
37
|
+
export async function preflight(ctx, opts) {
|
|
38
|
+
const r = resolve(ctx, opts, false);
|
|
39
|
+
const results = await Promise.all(r.clis.map(async (cli) => {
|
|
40
|
+
const spec = FLAGS_USED[cli];
|
|
41
|
+
const help = await runCli(cli, spec.helpArgs, '', 30, r.env);
|
|
42
|
+
if (!help.ok)
|
|
43
|
+
return { cli, ok: false, detail: help.cause ?? 'failed' };
|
|
44
|
+
const helpText = help.stdout + help.stderr;
|
|
45
|
+
const missing = spec.flags.filter((f) => !helpText.includes(f));
|
|
46
|
+
// The ping runs at the tier the run will use. A fixed tier left the other tier's model untested, so a
|
|
47
|
+
// model name agy no longer accepted passed preflight and failed the critique (2026-10-13).
|
|
48
|
+
const inv = buildInvocation(cli, 'say PONG only', r.tier, ctx.source);
|
|
49
|
+
const ping = await runCli(inv.cmd, inv.args, inv.stdin, Math.min(r.timeout, 60), r.env);
|
|
50
|
+
if (!ping.ok)
|
|
51
|
+
return { cli, ok: false, detail: ping.cause ?? 'failed' };
|
|
52
|
+
const { text } = normalize(cli, ping);
|
|
53
|
+
if (!/pong/i.test(text))
|
|
54
|
+
return { cli, ok: false, detail: `unexpected reply: ${firstLines(text, 2)}` };
|
|
55
|
+
if (missing.length)
|
|
56
|
+
return { cli, ok: false, detail: `answers, but its --help no longer lists: ${missing.join(' ')}` };
|
|
57
|
+
const model = tiers(ctx.source)[r.tier][cli].model;
|
|
58
|
+
return { cli, ok: true, detail: model ? `PONG (${model})` : 'PONG' };
|
|
59
|
+
}));
|
|
60
|
+
const ok = results.every((x) => x.ok);
|
|
61
|
+
const lines = results.map((x) => `[${x.ok ? 'OK ' : 'DOWN'}] ${x.cli.padEnd(7)} ${x.detail}`);
|
|
62
|
+
if (!ok) {
|
|
63
|
+
lines.push('', 'At least one CLI is down. Re-authenticate it, or run with --only on the ones that are up.');
|
|
64
|
+
// D3: a variable the allowlist dropped may be what a CLI needed. Names only, never values.
|
|
65
|
+
if (r.withheld.length) {
|
|
66
|
+
lines.push(`Withheld from the CLIs: ${r.withheld.join(', ')}. To pass one through, name it in ${PASS_ENV_VARIABLE}.`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { tier: r.tier, ok, clis: results, ...(ok ? {} : { withheld: r.withheld }), lines };
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Input and output.
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
async function readInput(ctx, file, flag) {
|
|
75
|
+
if (file !== undefined) {
|
|
76
|
+
const absolute = path.resolve(ctx.cwd, file);
|
|
77
|
+
try {
|
|
78
|
+
return readFileSync(absolute, 'utf8');
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
throw new SecondOpinionUsageError(`cannot read ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const piped = await ctx.readStdin();
|
|
85
|
+
if (piped !== null && piped.trim())
|
|
86
|
+
return piped;
|
|
87
|
+
throw new SecondOpinionUsageError(`no input: pass ${flag} PATH or pipe it on stdin`);
|
|
88
|
+
}
|
|
89
|
+
function outDir(ctx, out) {
|
|
90
|
+
const dir = out !== undefined ? path.resolve(ctx.cwd, out) : mkdtempSync(path.join(tmpdir(), 'ctxr-second-opinion-out-'));
|
|
91
|
+
mkdirSync(path.join(dir, 'raw'), { recursive: true });
|
|
92
|
+
return dir;
|
|
93
|
+
}
|
|
94
|
+
function rng(seed) {
|
|
95
|
+
if (seed === null || Number.isNaN(seed))
|
|
96
|
+
return Math.random;
|
|
97
|
+
let a = seed >>> 0; // mulberry32: deterministic, for tests
|
|
98
|
+
return () => {
|
|
99
|
+
a = (a + 0x6d2b79f5) >>> 0;
|
|
100
|
+
let t = a;
|
|
101
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
102
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
103
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function shuffled(items, random) {
|
|
107
|
+
const a = [...items];
|
|
108
|
+
for (let i = a.length - 1; i > 0; i--) {
|
|
109
|
+
const j = Math.floor(random() * (i + 1));
|
|
110
|
+
[a[i], a[j]] = [a[j], a[i]];
|
|
111
|
+
}
|
|
112
|
+
return a;
|
|
113
|
+
}
|
|
114
|
+
const tooLong = (prompt, cause) => Buffer.byteLength(prompt) > MAX_ARGV_BYTES ? { ok: false, stdout: '', stderr: '', cause } : null;
|
|
115
|
+
export async function critique(ctx, opts) {
|
|
116
|
+
const r = resolve(ctx, opts, true);
|
|
117
|
+
const seed = opts.seed === undefined ? null : Number(opts.seed);
|
|
118
|
+
const plan = await readInput(ctx, opts.planFile, '--plan-file');
|
|
119
|
+
const roles = ROLES.filter((role) => r.clis.includes(ROLE_CLI[role]));
|
|
120
|
+
const dir = outDir(ctx, opts.out);
|
|
121
|
+
ctx.progress(`plan: ${plan.length} characters (about ${Math.ceil(plan.length / 4)} tokens) · tier: ${r.tier} · critics: ${roles.length} · each may take 1-3 minutes`);
|
|
122
|
+
const runs = await Promise.all(roles.map(async (role) => {
|
|
123
|
+
const cli = ROLE_CLI[role];
|
|
124
|
+
const prompt = critiquePrompt(role, plan);
|
|
125
|
+
const started = Date.now();
|
|
126
|
+
let raw;
|
|
127
|
+
const refused = cli === 'agy' ? tooLong(prompt, `prompt is ${Buffer.byteLength(prompt)} bytes; agy takes it as one argument and the limit is ${MAX_ARGV_BYTES}`) : null;
|
|
128
|
+
if (refused)
|
|
129
|
+
raw = refused;
|
|
130
|
+
else {
|
|
131
|
+
const inv = buildInvocation(cli, prompt, r.tier, ctx.source);
|
|
132
|
+
raw = await runCli(inv.cmd, inv.args, inv.stdin, r.timeout, r.env);
|
|
133
|
+
}
|
|
134
|
+
writeFileSync(path.join(dir, 'raw', `${role}-${cli}.txt`), `${raw.stdout}\n--- stderr ---\n${raw.stderr}\n`);
|
|
135
|
+
const base = { role, cli, duration_ms: Date.now() - started };
|
|
136
|
+
if (!raw.ok)
|
|
137
|
+
return { ...base, status: 'failed', cause: raw.cause ?? null, model: null, text: '', verdict: null, findings: 0, veto: false };
|
|
138
|
+
const { text, model } = normalize(cli, raw);
|
|
139
|
+
const judged = judgeCritique(text, plan);
|
|
140
|
+
return { ...base, status: judged.status, cause: judged.cause, model, text, verdict: judged.verdict, findings: judged.findings.length, veto: judged.veto };
|
|
141
|
+
}));
|
|
142
|
+
// Letters go to every critique that produced text (valid or blind), in an order that does not follow the roster.
|
|
143
|
+
const answered = runs.filter((x) => x.status !== 'failed');
|
|
144
|
+
const letters = shuffled(answered, rng(seed)).map((x, i) => ({ ...x, letter: String.fromCharCode(65 + i) }));
|
|
145
|
+
for (const x of letters)
|
|
146
|
+
writeFileSync(path.join(dir, `critique-${x.letter}.md`), `${x.text}\n`);
|
|
147
|
+
const valid = runs.filter((x) => x.status === 'valid').length;
|
|
148
|
+
const manifest = {
|
|
149
|
+
mode: 'critique',
|
|
150
|
+
tier: r.tier,
|
|
151
|
+
quorum: QUORUM,
|
|
152
|
+
critiques: runs.map((x) => ({
|
|
153
|
+
letter: letters.find((l) => l.role === x.role)?.letter ?? null,
|
|
154
|
+
role: x.role,
|
|
155
|
+
cli: x.cli,
|
|
156
|
+
model_reported: x.model,
|
|
157
|
+
status: x.status,
|
|
158
|
+
cause: x.cause,
|
|
159
|
+
verdict: x.verdict,
|
|
160
|
+
findings: x.findings,
|
|
161
|
+
veto: x.veto,
|
|
162
|
+
duration_ms: x.duration_ms,
|
|
163
|
+
})),
|
|
164
|
+
valid,
|
|
165
|
+
partial: valid < QUORUM,
|
|
166
|
+
};
|
|
167
|
+
writeFileSync(path.join(dir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
168
|
+
// stdout names letters, never roles or models; a failed critic has no letter and is named by CLI, since that is what to fix.
|
|
169
|
+
const lines = [`out: ${dir}`, `valid: ${valid} blind: ${runs.filter((x) => x.status === 'blind').length} failed: ${runs.filter((x) => x.status === 'failed').length}`];
|
|
170
|
+
for (const x of [...letters].sort((a, b) => a.letter.localeCompare(b.letter))) {
|
|
171
|
+
lines.push(` ${x.letter} ${x.status} ${x.verdict ?? '-'} findings=${x.findings}${x.veto ? ' veto' : ''}`);
|
|
172
|
+
}
|
|
173
|
+
for (const x of runs.filter((y) => y.status === 'failed'))
|
|
174
|
+
lines.push(` failed ${x.cli} ${x.cause}`);
|
|
175
|
+
if (manifest.partial)
|
|
176
|
+
lines.push(`PARTIAL: fewer than ${QUORUM} valid critiques. Report this as a partial result, not a consensus.`);
|
|
177
|
+
lines.push(`Read the critique files first; open ${path.join(dir, 'manifest.json')} last.`);
|
|
178
|
+
return { out: dir, manifest, lines };
|
|
179
|
+
}
|
|
180
|
+
export async function poll(ctx, opts) {
|
|
181
|
+
const r = resolve(ctx, opts, true);
|
|
182
|
+
const question = await readInput(ctx, opts.promptFile, '--prompt-file');
|
|
183
|
+
const prompt = pollPrompt(question, { lens: opts.lens, wrap: opts.wrap !== false });
|
|
184
|
+
const dir = outDir(ctx, opts.out);
|
|
185
|
+
ctx.progress(`question: ${question.length} characters · tier: ${r.tier} · models: ${r.clis.length}${opts.lens ? ` · lenses: ${opts.lens}` : ''}`);
|
|
186
|
+
const runs = await Promise.all(r.clis.map(async (cli) => {
|
|
187
|
+
let raw;
|
|
188
|
+
const refused = cli === 'agy' ? tooLong(prompt, `prompt exceeds the ${MAX_ARGV_BYTES}-byte argument limit`) : null;
|
|
189
|
+
if (refused)
|
|
190
|
+
raw = refused;
|
|
191
|
+
else {
|
|
192
|
+
const inv = buildInvocation(cli, prompt, r.tier, ctx.source);
|
|
193
|
+
raw = await runCli(inv.cmd, inv.args, inv.stdin, r.timeout, r.env);
|
|
194
|
+
}
|
|
195
|
+
writeFileSync(path.join(dir, 'raw', `poll-${cli}.txt`), `${raw.stdout}\n--- stderr ---\n${raw.stderr}\n`);
|
|
196
|
+
if (!raw.ok)
|
|
197
|
+
return { cli, status: 'failed', cause: raw.cause ?? null, model: null, text: '' };
|
|
198
|
+
const { text, model } = normalize(cli, raw);
|
|
199
|
+
if (!text)
|
|
200
|
+
return { cli, status: 'failed', cause: 'empty output', model, text };
|
|
201
|
+
return { cli, status: 'valid', cause: null, model, text };
|
|
202
|
+
}));
|
|
203
|
+
// A poll is read model against model (the lens grid's columns are models), so files are named by model here.
|
|
204
|
+
for (const x of runs.filter((y) => y.status === 'valid'))
|
|
205
|
+
writeFileSync(path.join(dir, `poll-${x.cli}.md`), `${x.text}\n`);
|
|
206
|
+
const valid = runs.filter((x) => x.status === 'valid').length;
|
|
207
|
+
const manifest = {
|
|
208
|
+
mode: 'poll',
|
|
209
|
+
tier: r.tier,
|
|
210
|
+
lens: opts.lens ?? null,
|
|
211
|
+
quorum: QUORUM,
|
|
212
|
+
valid,
|
|
213
|
+
partial: valid < QUORUM,
|
|
214
|
+
answers: runs.map(({ text: _text, ...rest }) => rest),
|
|
215
|
+
};
|
|
216
|
+
writeFileSync(path.join(dir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
217
|
+
const lines = [`out: ${dir}`, `valid: ${valid} failed: ${runs.length - valid}`];
|
|
218
|
+
for (const x of runs)
|
|
219
|
+
lines.push(` ${x.cli} ${x.status}${x.cause ? ` ${x.cause}` : ''}${x.model ? ` model=${x.model}` : ''}`);
|
|
220
|
+
if (manifest.partial)
|
|
221
|
+
lines.push(`PARTIAL: fewer than ${QUORUM} answers. Report it as a partial result.`);
|
|
222
|
+
return { out: dir, manifest, lines };
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=modes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modes.js","sourceRoot":"","sources":["../../../src/core/second-opinion/modes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Role } from './lineup.js';
|
|
2
|
+
export declare function critiquePrompt(role: Role, plan: string): string;
|
|
3
|
+
/** The built-in lenses, by name, from the roster's `- **name** — description` lines. */
|
|
4
|
+
export declare function lensRoster(): Map<string, string>;
|
|
5
|
+
/**
|
|
6
|
+
* Splits `--lens` into one string per lens. Lenses are comma-separated, but an inline description may itself
|
|
7
|
+
* contain commas: a fragment starts a NEW lens only when it is exactly a roster name or begins `Name:`;
|
|
8
|
+
* any other fragment continues the lens before it. So `minimalist,House taste:blunt, anti-slogan` is two
|
|
9
|
+
* lenses, and a description must not contain a colon (that would read as the start of another lens).
|
|
10
|
+
*/
|
|
11
|
+
export declare function splitLenses(spec: string, roster: ReadonlyMap<string, string>): string[];
|
|
12
|
+
/** One `- name — description` line per lens; refuses an unknown lens and a count outside two to three. */
|
|
13
|
+
export declare function lensLines(spec: string): string[];
|
|
14
|
+
export declare function pollPrompt(question: string, opts: {
|
|
15
|
+
lens?: string;
|
|
16
|
+
wrap: boolean;
|
|
17
|
+
}): string;
|
|
18
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/core/second-opinion/prompts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAUxC,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wFAAwF;AACxF,wBAAgB,UAAU,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAIhD;AAID;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAQvF;AAED,0GAA0G;AAC1G,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAehD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAM3F"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SecondOpinionUsageError } from '../errors.js';
|
|
2
|
+
import { packagedTemplate, substituteBlock } from '../templates.js';
|
|
3
|
+
/**
|
|
4
|
+
* run-the-second-opinion-from-the-cli D4: the critic contract, the persona
|
|
5
|
+
* mandates, the lens roster and the poll scaffolds are package templates
|
|
6
|
+
* under `templates/second-opinion/`, reviewable as markdown. This module only
|
|
7
|
+
* assembles them; it carries no prompt prose of its own.
|
|
8
|
+
*/
|
|
9
|
+
const template = (name) => packagedTemplate('second-opinion', name);
|
|
10
|
+
export function critiquePrompt(role, plan) {
|
|
11
|
+
return `${template('critic-contract').trimEnd()}\n\n---\n${template(`personas/${role}`).trimEnd()}\n\nPLAN:\n${plan}\n`;
|
|
12
|
+
}
|
|
13
|
+
/** The built-in lenses, by name, from the roster's `- **name** — description` lines. */
|
|
14
|
+
export function lensRoster() {
|
|
15
|
+
const roster = new Map();
|
|
16
|
+
for (const m of template('lenses').matchAll(/^- \*\*([a-z-]+)\*\* — (.+)$/gm))
|
|
17
|
+
roster.set(m[1], m[2].trim());
|
|
18
|
+
return roster;
|
|
19
|
+
}
|
|
20
|
+
const INLINE_LENS = /^[^:,]{1,40}:/;
|
|
21
|
+
/**
|
|
22
|
+
* Splits `--lens` into one string per lens. Lenses are comma-separated, but an inline description may itself
|
|
23
|
+
* contain commas: a fragment starts a NEW lens only when it is exactly a roster name or begins `Name:`;
|
|
24
|
+
* any other fragment continues the lens before it. So `minimalist,House taste:blunt, anti-slogan` is two
|
|
25
|
+
* lenses, and a description must not contain a colon (that would read as the start of another lens).
|
|
26
|
+
*/
|
|
27
|
+
export function splitLenses(spec, roster) {
|
|
28
|
+
const lenses = [];
|
|
29
|
+
for (const fragment of spec.split(',').map((f) => f.trim()).filter(Boolean)) {
|
|
30
|
+
const startsLens = roster.has(fragment.toLowerCase()) || INLINE_LENS.test(fragment);
|
|
31
|
+
if (startsLens || lenses.length === 0)
|
|
32
|
+
lenses.push(fragment);
|
|
33
|
+
else
|
|
34
|
+
lenses[lenses.length - 1] += `, ${fragment}`;
|
|
35
|
+
}
|
|
36
|
+
return lenses;
|
|
37
|
+
}
|
|
38
|
+
/** One `- name — description` line per lens; refuses an unknown lens and a count outside two to three. */
|
|
39
|
+
export function lensLines(spec) {
|
|
40
|
+
const roster = lensRoster();
|
|
41
|
+
const described = [];
|
|
42
|
+
for (const s of splitLenses(spec, roster)) {
|
|
43
|
+
const known = roster.get(s.toLowerCase());
|
|
44
|
+
if (known !== undefined)
|
|
45
|
+
described.push(`- ${s.toLowerCase()} — ${known}`);
|
|
46
|
+
else if (INLINE_LENS.test(s)) {
|
|
47
|
+
const [name, ...rest] = s.split(':');
|
|
48
|
+
described.push(`- ${name.trim()} — ${rest.join(':').trim()}`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
throw new SecondOpinionUsageError(`unknown lens "${s}" (known: ${[...roster.keys()].join(', ')}; or pass "Name:description")`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (described.length < 2 || described.length > 3)
|
|
55
|
+
throw new SecondOpinionUsageError('--lens takes two or three lenses; keep them orthogonal');
|
|
56
|
+
return described;
|
|
57
|
+
}
|
|
58
|
+
export function pollPrompt(question, opts) {
|
|
59
|
+
if (opts.lens) {
|
|
60
|
+
const withLenses = substituteBlock(template('taste-panel'), '__LENSES__', lensLines(opts.lens));
|
|
61
|
+
return `${substituteBlock(withLenses, '__QUESTION__', question.split('\n'))}\n`;
|
|
62
|
+
}
|
|
63
|
+
return opts.wrap ? `${question}\n\n${template('poll-answer')}` : question;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/core/second-opinion/prompts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { GitResult, GitRunner } from '../git/exec.js';
|
|
2
|
+
/**
|
|
3
|
+
* bring-the-session-lifecycle-into-the-cli D4: one commit call for both
|
|
4
|
+
* surfaces. Locally it commits as the clone's own git identity, exactly as a
|
|
5
|
+
* hand-run `git commit` does. The MCP surface passes an author override (the
|
|
6
|
+
* member's verified email) with a trailer naming them, and the recording
|
|
7
|
+
* login as committer when the host has no identity of its own — the same
|
|
8
|
+
* fallback `ctxr land` uses. The store's hooks run either way.
|
|
9
|
+
*/
|
|
10
|
+
export interface CommitOptions {
|
|
11
|
+
message: string;
|
|
12
|
+
/** The commit's author, in place of the clone's identity. */
|
|
13
|
+
author?: {
|
|
14
|
+
name: string;
|
|
15
|
+
email: string;
|
|
16
|
+
};
|
|
17
|
+
/** A trailer paragraph, e.g. `Edited-by: <email>`. */
|
|
18
|
+
trailer?: {
|
|
19
|
+
key: string;
|
|
20
|
+
value: string;
|
|
21
|
+
};
|
|
22
|
+
/** The committer when neither git config nor the environment names one; omitted, git decides. */
|
|
23
|
+
fallbackCommitter?: string;
|
|
24
|
+
}
|
|
25
|
+
/** The committer: the host's git identity when it has one, else the given login's noreply address. */
|
|
26
|
+
export declare function committerEnv(git: GitRunner, cwd: string, env: Readonly<Record<string, string | undefined>>, login: string): Promise<Record<string, string>>;
|
|
27
|
+
/** Commits what is staged in `cwd`. Resolves with git's result; the caller decides what a refusal means on its surface. */
|
|
28
|
+
export declare function commitStaged(git: GitRunner, cwd: string, env: Readonly<Record<string, string | undefined>>, opts: CommitOptions): Promise<GitResult>;
|
|
29
|
+
//# sourceMappingURL=commit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../../src/core/session/commit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,sDAAsD;IACtD,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,iGAAiG;IACjG,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,sGAAsG;AACtG,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAKjK;AAED,2HAA2H;AAC3H,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAQ1J"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** The committer: the host's git identity when it has one, else the given login's noreply address. */
|
|
2
|
+
export async function committerEnv(git, cwd, env, login) {
|
|
3
|
+
const email = (await git.run(['config', '--get', 'user.email'], { cwd, allowFailure: true })).stdout.trim();
|
|
4
|
+
if (email !== '' || env.GIT_COMMITTER_EMAIL || env.EMAIL)
|
|
5
|
+
return {};
|
|
6
|
+
const address = `${login.replace(/\[bot\]$/, '')}@users.noreply.github.com`;
|
|
7
|
+
return { GIT_COMMITTER_NAME: login, GIT_COMMITTER_EMAIL: address };
|
|
8
|
+
}
|
|
9
|
+
/** Commits what is staged in `cwd`. Resolves with git's result; the caller decides what a refusal means on its surface. */
|
|
10
|
+
export async function commitStaged(git, cwd, env, opts) {
|
|
11
|
+
const identity = {};
|
|
12
|
+
if (opts.fallbackCommitter !== undefined)
|
|
13
|
+
Object.assign(identity, await committerEnv(git, cwd, env, opts.fallbackCommitter));
|
|
14
|
+
if (opts.author !== undefined)
|
|
15
|
+
Object.assign(identity, { GIT_AUTHOR_NAME: opts.author.name, GIT_AUTHOR_EMAIL: opts.author.email });
|
|
16
|
+
const args = ['commit', '--quiet', '-m', opts.message];
|
|
17
|
+
if (opts.trailer !== undefined)
|
|
18
|
+
args.push('-m', `${opts.trailer.key}: ${opts.trailer.value}`);
|
|
19
|
+
const overridden = Object.keys(identity).length > 0;
|
|
20
|
+
return git.run(args, { cwd, allowFailure: true, ...(overridden ? { env: { ...env, ...identity } } : {}) });
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../../src/core/session/commit.ts"],"names":[],"mappings":"AAoBA,sGAAsG;AACtG,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAc,EAAE,GAAW,EAAE,GAAiD,EAAE,KAAa;IAC9H,MAAM,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC5G,IAAI,KAAK,KAAK,EAAE,IAAI,GAAG,CAAC,mBAAmB,IAAI,GAAG,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACpE,MAAM,OAAO,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,2BAA2B,CAAC;IAC5E,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,CAAC;AACrE,CAAC;AAED,2HAA2H;AAC3H,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAc,EAAE,GAAW,EAAE,GAAiD,EAAE,IAAmB;IACpI,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS;QAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC7H,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACnI,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9F,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACpD,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,GAAG,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7G,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type RemoteDeps } from './remote.js';
|
|
2
|
+
import { type SessionRef } from './resolve.js';
|
|
3
|
+
/**
|
|
4
|
+
* write-lifecycle spec (*`ctxr session discard` removes only a session, and
|
|
5
|
+
* only clean unless forced*): #31's `abandon` could force-remove any worktree
|
|
6
|
+
* (bring-the-session-lifecycle-into-the-cli D1, point 4). `resolveSession`
|
|
7
|
+
* has already refused anything that is not a session; this refuses, without
|
|
8
|
+
* `--force`, a session whose removal would lose work — uncommitted changes, or
|
|
9
|
+
* commits its remote branch lacks — and closes a pull request only when asked.
|
|
10
|
+
*/
|
|
11
|
+
export interface DiscardResult {
|
|
12
|
+
session: string;
|
|
13
|
+
worktree: string;
|
|
14
|
+
branch: string;
|
|
15
|
+
removed: boolean;
|
|
16
|
+
forced: boolean;
|
|
17
|
+
/** The pull request `--close-pull-request` closed; null when none was asked for or none was open. */
|
|
18
|
+
closed_pull_request: number | null;
|
|
19
|
+
}
|
|
20
|
+
export declare function discardSession(deps: RemoteDeps, session: SessionRef, opts?: {
|
|
21
|
+
force?: boolean;
|
|
22
|
+
closePullRequest?: boolean;
|
|
23
|
+
}): Promise<DiscardResult>;
|
|
24
|
+
//# sourceMappingURL=discard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discard.d.ts","sourceRoot":"","sources":["../../../src/core/session/discard.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgD,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/D;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,qGAAqG;IACrG,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAiCD,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAqC9J"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { baseRef, forgeRead } from '../approval/sessions.js';
|
|
2
|
+
import { SessionRefusedError } from '../errors.js';
|
|
3
|
+
import { ExitCode } from '../exit-codes.js';
|
|
4
|
+
import { ForgeRequestError } from '../forge/github.js';
|
|
5
|
+
import { removeSession, remoteTip, SessionRemoteError } from './remote.js';
|
|
6
|
+
import { workingChanges } from './resolve.js';
|
|
7
|
+
/**
|
|
8
|
+
* The session's commits that are on no remote ref: not on its remote branch,
|
|
9
|
+
* nor any other this clone has fetched. A session whose pull request was
|
|
10
|
+
* squash-merged and whose branch was then deleted carries commits on no
|
|
11
|
+
* remote ref, so a merged pull request at exactly this head counts as published.
|
|
12
|
+
*/
|
|
13
|
+
async function unpublishedCommits(deps, session) {
|
|
14
|
+
const run = (args) => deps.git.run(args, { cwd: session.path, allowFailure: true });
|
|
15
|
+
const tip = (await run(['rev-parse', 'HEAD'])).stdout.trim();
|
|
16
|
+
let remote = null;
|
|
17
|
+
try {
|
|
18
|
+
remote = await remoteTip(deps, session.path, session.branch);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
if (!(err instanceof SessionRemoteError))
|
|
22
|
+
throw err;
|
|
23
|
+
}
|
|
24
|
+
if (remote === tip)
|
|
25
|
+
return 0;
|
|
26
|
+
const exclude = remote !== null && (await run(['cat-file', '-e', `${remote}^{commit}`])).exitCode === 0 ? [`^${remote}`] : [];
|
|
27
|
+
// The default branch itself never counts: a session's base is already on it.
|
|
28
|
+
const base = await baseRef(deps.git, session.path, deps.config.git.default_branch);
|
|
29
|
+
const counted = await run(['rev-list', '--count', 'HEAD', ...exclude, `^${base}`, '--not', '--remotes=origin']);
|
|
30
|
+
const count = counted.exitCode === 0 ? Number.parseInt(counted.stdout.trim(), 10) || 0 : 0;
|
|
31
|
+
if (count === 0)
|
|
32
|
+
return 0;
|
|
33
|
+
try {
|
|
34
|
+
const pulls = await deps.forge.pullsForHead(session.branch);
|
|
35
|
+
if (pulls.some((p) => p.merged && p.headSha === tip))
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
if (!(err instanceof ForgeRequestError))
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
return count;
|
|
43
|
+
}
|
|
44
|
+
export async function discardSession(deps, session, opts = {}) {
|
|
45
|
+
const force = opts.force === true;
|
|
46
|
+
if (!force) {
|
|
47
|
+
const dirty = await workingChanges(deps.git, session.path);
|
|
48
|
+
if (dirty.length > 0) {
|
|
49
|
+
throw new SessionRefusedError(ExitCode.CheckFailed, 'discard_uncommitted', `"${session.name}" has uncommitted changes (${dirty.map((c) => c.path).join(', ')}); discarding it would destroy them. Pass --force to discard them anyway.`, { session: session.name, paths: dirty.map((c) => c.path) }, session.name);
|
|
50
|
+
}
|
|
51
|
+
const unpublished = await unpublishedCommits(deps, session);
|
|
52
|
+
if (unpublished > 0) {
|
|
53
|
+
throw new SessionRefusedError(ExitCode.CheckFailed, 'discard_unpushed', `"${session.name}" carries ${unpublished} commit(s) its remote branch lacks; discarding it would destroy them. Pass --force to discard them anyway.`, { session: session.name, commits: unpublished }, session.name);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
let closed = null;
|
|
57
|
+
if (opts.closePullRequest === true) {
|
|
58
|
+
// Before anything is removed, so a forge that cannot be reached leaves the session as it was.
|
|
59
|
+
const open = (await forgeRead(() => deps.forge.pullsForHead(session.branch))).find((p) => p.state === 'open');
|
|
60
|
+
if (open !== undefined) {
|
|
61
|
+
await forgeRead(() => deps.forge.updatePull(open.number, { state: 'closed' }));
|
|
62
|
+
closed = open.number;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
await removeSession(deps.git, session.canonical, session);
|
|
66
|
+
return { session: session.name, worktree: session.path, branch: session.branch, removed: true, forced: force, closed_pull_request: closed };
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=discard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discard.js","sourceRoot":"","sources":["../../../src/core/session/discard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,kBAAkB,EAAmB,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,cAAc,EAAmB,MAAM,cAAc,CAAC;AAoB/D;;;;;GAKG;AACH,KAAK,UAAU,kBAAkB,CAAC,IAAgB,EAAE,OAAmB;IACrE,MAAM,GAAG,GAAG,CAAC,IAAuB,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IACvG,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC7D,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,GAAG,YAAY,kBAAkB,CAAC;YAAE,MAAM,GAAG,CAAC;IACtD,CAAC;IACD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAG,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,MAAM,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9H,6EAA6E;IAC7E,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACnF,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAChH,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3F,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5D,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,KAAK,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,GAAG,YAAY,iBAAiB,CAAC;YAAE,MAAM,GAAG,CAAC;IACrD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAgB,EAAE,OAAmB,EAAE,IAAI,GAAoD,EAAE;IACpI,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC;IAClC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3D,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,mBAAmB,CAC3B,QAAQ,CAAC,WAAW,EACpB,qBAAqB,EACrB,IAAI,OAAO,CAAC,IAAI,8BAA8B,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,2EAA2E,EAC5J,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAC1D,OAAO,CAAC,IAAI,CACb,CAAC;QACJ,CAAC;QACD,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5D,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,mBAAmB,CAC3B,QAAQ,CAAC,WAAW,EACpB,kBAAkB,EAClB,IAAI,OAAO,CAAC,IAAI,aAAa,WAAW,4GAA4G,EACpJ,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,EAC/C,OAAO,CAAC,IAAI,CACb,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;QACnC,8FAA8F;QAC9F,MAAM,IAAI,GAAG,CAAC,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;QAC9G,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;YAC/E,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACvB,CAAC;IACH,CAAC;IAED,MAAM,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC1D,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC;AAC9I,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { StoreConfig } from '../../config/schema.js';
|
|
2
|
+
import type { ReviewStateName } from '../approval/decision.js';
|
|
3
|
+
import { type ForgeClient } from '../forge/github.js';
|
|
4
|
+
import type { GitRunner } from '../git/exec.js';
|
|
5
|
+
/**
|
|
6
|
+
* write-lifecycle spec (*`ctxr session list` reports each session's state*):
|
|
7
|
+
* each session's branch, worktree, head, uncommitted state and commits ahead,
|
|
8
|
+
* all read locally. With `review`, each one's open pull request and, when the
|
|
9
|
+
* store declares change approval, the decision `ctxr review list` reports for
|
|
10
|
+
* it. The forge stays behind the option so a plain list never waits on the
|
|
11
|
+
* network; an unreachable forge reads `unknown`, because the list is an
|
|
12
|
+
* inventory, not a check (bring-the-session-lifecycle-into-the-cli D3,
|
|
13
|
+
* revision 1).
|
|
14
|
+
*/
|
|
15
|
+
export interface SessionListEntry {
|
|
16
|
+
/** The worktree's directory name: what the other session commands take. */
|
|
17
|
+
name: string;
|
|
18
|
+
branch: string;
|
|
19
|
+
worktree: string;
|
|
20
|
+
head: string;
|
|
21
|
+
uncommitted: boolean;
|
|
22
|
+
ahead: number;
|
|
23
|
+
/** `review` only: the open pull request, null when none is open. */
|
|
24
|
+
pull_request?: {
|
|
25
|
+
number: number | null;
|
|
26
|
+
state: 'open' | 'unknown';
|
|
27
|
+
url: string | null;
|
|
28
|
+
} | null;
|
|
29
|
+
/** `review` with change approval declared: the decision on the open pull request. */
|
|
30
|
+
review?: {
|
|
31
|
+
state: ReviewStateName | 'unknown';
|
|
32
|
+
comment: string | null;
|
|
33
|
+
} | null;
|
|
34
|
+
}
|
|
35
|
+
export interface ListReview {
|
|
36
|
+
forge: ForgeClient;
|
|
37
|
+
/** `change_approval.recording_login`; null when the store declares no change approval. */
|
|
38
|
+
recordingLogin: string | null;
|
|
39
|
+
}
|
|
40
|
+
export interface SessionList {
|
|
41
|
+
sessions: SessionListEntry[];
|
|
42
|
+
/** `review` only: whether the forge answered. */
|
|
43
|
+
forge_reachable?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare function listSessions(git: GitRunner, storeRoot: string, config: StoreConfig, opts?: {
|
|
46
|
+
review?: ListReview;
|
|
47
|
+
}): Promise<SessionList>;
|
|
48
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/core/session/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EAAqB,KAAK,WAAW,EAAoB,MAAM,oBAAoB,CAAC;AAC3F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/F,qFAAqF;IACrF,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CAChF;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,0FAA0F;IAC1F,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,iDAAiD;IACjD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAWD,wBAAsB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CA0CnJ"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { baseRef, reviewStateOf, sessionWorktrees } from '../approval/sessions.js';
|
|
2
|
+
import { ForgeRequestError } from '../forge/github.js';
|
|
3
|
+
import { commitsAhead, workingChanges } from './resolve.js';
|
|
4
|
+
async function forgeOr(call) {
|
|
5
|
+
try {
|
|
6
|
+
return await call();
|
|
7
|
+
}
|
|
8
|
+
catch (err) {
|
|
9
|
+
if (err instanceof ForgeRequestError)
|
|
10
|
+
return 'unknown';
|
|
11
|
+
throw err;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function listSessions(git, storeRoot, config, opts = {}) {
|
|
15
|
+
const worktrees = await sessionWorktrees(git, storeRoot, config);
|
|
16
|
+
const base = await baseRef(git, storeRoot, config.git.default_branch);
|
|
17
|
+
const sessions = await Promise.all(worktrees.map(async (w) => ({
|
|
18
|
+
name: w.name,
|
|
19
|
+
branch: w.branch,
|
|
20
|
+
worktree: w.path,
|
|
21
|
+
head: (await git.run(['rev-parse', 'HEAD'], { cwd: w.path, allowFailure: true })).stdout.trim(),
|
|
22
|
+
uncommitted: (await workingChanges(git, w.path)).length > 0,
|
|
23
|
+
ahead: await commitsAhead(git, w.path, base),
|
|
24
|
+
})));
|
|
25
|
+
if (opts.review === undefined)
|
|
26
|
+
return { sessions };
|
|
27
|
+
const { forge, recordingLogin } = opts.review;
|
|
28
|
+
const open = await forgeOr(() => forge.openPulls());
|
|
29
|
+
let reachable = open !== 'unknown';
|
|
30
|
+
await Promise.all(sessions.map(async (entry) => {
|
|
31
|
+
if (open === 'unknown') {
|
|
32
|
+
entry.pull_request = { number: null, state: 'unknown', url: null };
|
|
33
|
+
if (recordingLogin !== null)
|
|
34
|
+
entry.review = { state: 'unknown', comment: null };
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const pull = open.find((p) => p.headRef === entry.branch);
|
|
38
|
+
entry.pull_request = pull === undefined ? null : { number: pull.number, state: 'open', url: pull.url };
|
|
39
|
+
if (recordingLogin === null)
|
|
40
|
+
return;
|
|
41
|
+
if (pull === undefined) {
|
|
42
|
+
entry.review = null;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const review = await forgeOr(() => reviewStateOf(git, entry.worktree, base, forge, recordingLogin, pull));
|
|
46
|
+
if (review === 'unknown') {
|
|
47
|
+
reachable = false;
|
|
48
|
+
entry.review = { state: 'unknown', comment: null };
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
entry.review = { state: review.state, comment: review.state === 'changes-requested' ? (review.decision?.comment ?? null) : null };
|
|
52
|
+
}));
|
|
53
|
+
return { sessions, forge_reachable: reachable };
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=list.js.map
|