vouchington-tooling 0.45.0 → 0.46.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 +10 -52
- package/dist/agent-blackboard/feedback-audit-source.d.mts +4 -10
- package/dist/agent-blackboard/feedback-audit-source.mjs +7 -18
- package/dist/agent-blackboard/feedback-compose-audit.mjs +6 -14
- package/dist/agent-blackboard/feedback-compose.d.mts +1 -4
- package/dist/agent-blackboard/feedback-compose.mjs +2 -5
- package/dist/agent-blackboard/feedback-fields.mjs +1 -1
- package/dist/agent-blackboard/feedback-identity.mjs +1 -1
- package/dist/agent-blackboard/feedback-journal-audit.d.mts +6 -8
- package/dist/agent-blackboard/feedback-journal-audit.mjs +9 -10
- package/dist/agent-blackboard/feedback-journal-sandbox.d.mts +2 -2
- package/dist/agent-blackboard/feedback-journal-sandbox.mjs +2 -2
- package/dist/agent-blackboard/feedback-outbox-rejected.mjs +1 -1
- package/dist/agent-blackboard/feedback-outbox.mjs +2 -2
- package/dist/agent-blackboard/index.d.mts +1 -1
- package/dist/audit-journal/ci-failures.d.mts +6 -0
- package/dist/{session-friction → audit-journal}/ci-failures.mjs +3 -9
- package/dist/{session-friction → audit-journal}/journal.d.mts +0 -1
- package/dist/{session-friction → audit-journal}/journal.mjs +1 -1
- package/dist/audit-journal/session-id.d.mts +1 -0
- package/dist/{session-friction → audit-journal}/session-id.mjs +0 -5
- package/dist/{session-friction → audit-journal}/text.d.mts +1 -4
- package/dist/{session-friction → audit-journal}/text.mjs +4 -22
- package/dist/audit-journal/types.d.mts +17 -0
- package/dist/cli/commands/gha-runtime-audit.mjs +2 -0
- package/dist/gh-cli/env.d.mts +9 -0
- package/dist/gh-cli/env.mjs +12 -0
- package/dist/gh-cli/exec.d.mts +7 -4
- package/dist/gh-cli/exec.mjs +7 -5
- package/dist/gh-cli/index.d.mts +1 -0
- package/dist/gh-cli/index.mjs +1 -0
- package/dist/gha-post-review/github.mjs +2 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/mcp-server/context.d.mts +2 -0
- package/dist/mcp-server/dispatch.d.mts +2 -0
- package/dist/mcp-server/dispatch.mjs +1 -0
- package/dist/mcp-server/harness.test-helpers.d.mts +1 -0
- package/dist/mcp-server/harness.test-helpers.mjs +1 -0
- package/dist/mcp-server/pr-agent.d.mts +12 -0
- package/dist/mcp-server/pr-agent.mjs +34 -0
- package/dist/mcp-server/pr-body.d.mts +2 -0
- package/dist/mcp-server/pr-body.mjs +1 -2
- package/dist/mcp-server/pr-gh.mjs +2 -1
- package/dist/mcp-server/pr-input.d.mts +2 -1
- package/dist/mcp-server/pr-input.mjs +1 -1
- package/dist/mcp-server/pr-live.d.mts +1 -0
- package/dist/mcp-server/pr-live.mjs +1 -1
- package/dist/mcp-server/pr-prepare.mjs +25 -4
- package/dist/mcp-server/server.mjs +1 -0
- package/dist/mcp-server/tools-pr.mjs +8 -12
- package/dist/{session-friction → private-files}/lock.mjs +3 -2
- package/dist/private-files/log-file.d.mts +3 -0
- package/dist/private-files/log-file.mjs +53 -0
- package/dist/{session-friction → private-files}/utf8.mjs +1 -1
- package/dist/retrospective-facts/exec.mjs +2 -1
- package/docs/mcp-server.md +18 -4
- package/package.json +1 -6
- package/dist/session-friction/ci-failures.d.mts +0 -13
- package/dist/session-friction/classify.d.mts +0 -2
- package/dist/session-friction/classify.mjs +0 -98
- package/dist/session-friction/command-segments.d.mts +0 -3
- package/dist/session-friction/command-segments.mjs +0 -94
- package/dist/session-friction/coverage-ledger.d.mts +0 -10
- package/dist/session-friction/coverage-ledger.mjs +0 -75
- package/dist/session-friction/directory.d.mts +0 -1
- package/dist/session-friction/directory.mjs +0 -71
- package/dist/session-friction/index.d.mts +0 -6
- package/dist/session-friction/index.mjs +0 -5
- package/dist/session-friction/log-file.d.mts +0 -7
- package/dist/session-friction/log-file.mjs +0 -95
- package/dist/session-friction/log.d.mts +0 -8
- package/dist/session-friction/log.mjs +0 -163
- package/dist/session-friction/normalize.d.mts +0 -1
- package/dist/session-friction/normalize.mjs +0 -81
- package/dist/session-friction/report.d.mts +0 -16
- package/dist/session-friction/report.mjs +0 -91
- package/dist/session-friction/sandbox.d.mts +0 -3
- package/dist/session-friction/sandbox.mjs +0 -43
- package/dist/session-friction/session-id.d.mts +0 -2
- package/dist/session-friction/types.d.mts +0 -80
- /package/dist/{session-friction → audit-journal}/audit-block.d.mts +0 -0
- /package/dist/{session-friction → audit-journal}/audit-block.mjs +0 -0
- /package/dist/{session-friction → audit-journal}/audit-fit.d.mts +0 -0
- /package/dist/{session-friction → audit-journal}/audit-fit.mjs +0 -0
- /package/dist/{session-friction → audit-journal}/types.mjs +0 -0
- /package/dist/{session-friction → private-files}/lock.d.mts +0 -0
- /package/dist/{session-friction → private-files}/utf8.d.mts +0 -0
package/dist/gh-cli/exec.d.mts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/** A text-mode command runner: argv in, stdout out. Rejects on a non-zero exit. */
|
|
2
2
|
export type RunTextCommand = (args: string[]) => Promise<string>;
|
|
3
3
|
/** The `child_process.execFile` shape `createCommandRunner` wraps — injectable for tests. */
|
|
4
|
-
export type ExecFileText = (command: string, args: string[]
|
|
4
|
+
export type ExecFileText = (command: string, args: string[], options?: {
|
|
5
|
+
env: NodeJS.ProcessEnv;
|
|
6
|
+
}) => Promise<{
|
|
5
7
|
stdout: string;
|
|
6
8
|
}>;
|
|
7
9
|
/**
|
|
8
10
|
* Builds a `RunTextCommand` bound to a fixed binary. The default `exec` wraps `execFile` via
|
|
9
11
|
* `promisify` so a test can inject a fake without spawning a real process; `runGh`/`runGit` below
|
|
10
|
-
* are this factory applied to the two binaries this module cares about.
|
|
12
|
+
* are this factory applied to the two binaries this module cares about. `buildEnv` maps the
|
|
13
|
+
* parent environment to the one the child is spawned with (identity by default).
|
|
11
14
|
*/
|
|
12
|
-
export declare function createCommandRunner(command: string, exec?: ExecFileText): RunTextCommand;
|
|
13
|
-
/** Runs `gh` and returns its stdout. */
|
|
15
|
+
export declare function createCommandRunner(command: string, exec?: ExecFileText, buildEnv?: (env: NodeJS.ProcessEnv) => NodeJS.ProcessEnv): RunTextCommand;
|
|
16
|
+
/** Runs `gh` and returns its stdout, with `CLICOLOR_FORCE` removed so `--json` output stays plain. */
|
|
14
17
|
export declare const runGh: RunTextCommand;
|
|
15
18
|
/** Runs `git` and returns its stdout. */
|
|
16
19
|
export declare const runGit: RunTextCommand;
|
package/dist/gh-cli/exec.mjs
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
|
+
import { ghSpawnEnv } from "./env.mjs";
|
|
3
4
|
const execFileAsync = promisify(execFile);
|
|
4
5
|
/**
|
|
5
6
|
* Builds a `RunTextCommand` bound to a fixed binary. The default `exec` wraps `execFile` via
|
|
6
7
|
* `promisify` so a test can inject a fake without spawning a real process; `runGh`/`runGit` below
|
|
7
|
-
* are this factory applied to the two binaries this module cares about.
|
|
8
|
+
* are this factory applied to the two binaries this module cares about. `buildEnv` maps the
|
|
9
|
+
* parent environment to the one the child is spawned with (identity by default).
|
|
8
10
|
*/
|
|
9
|
-
export function createCommandRunner(command, exec = (cmd, args) => execFileAsync(cmd, args)) {
|
|
11
|
+
export function createCommandRunner(command, exec = (cmd, args, options) => execFileAsync(cmd, args, { ...options, encoding: 'utf8' }), buildEnv = (env) => env) {
|
|
10
12
|
return async (args) => {
|
|
11
|
-
const { stdout } = await exec(command, args);
|
|
13
|
+
const { stdout } = await exec(command, args, { env: buildEnv(process.env) });
|
|
12
14
|
return stdout;
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
|
-
/** Runs `gh` and returns its stdout. */
|
|
16
|
-
export const runGh = createCommandRunner('gh');
|
|
17
|
+
/** Runs `gh` and returns its stdout, with `CLICOLOR_FORCE` removed so `--json` output stays plain. */
|
|
18
|
+
export const runGh = createCommandRunner('gh', undefined, ghSpawnEnv);
|
|
17
19
|
/** Runs `git` and returns its stdout. */
|
|
18
20
|
export const runGit = createCommandRunner('git');
|
package/dist/gh-cli/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createCommandRunner, runGh, runGit } from './exec.mts';
|
|
2
|
+
export { ghSpawnEnv } from './env.mts';
|
|
2
3
|
export type { ExecFileText, RunTextCommand } from './exec.mts';
|
|
3
4
|
export { DiffCommandError, processDiffCommand } from './diff.mts';
|
|
4
5
|
export type { DiffBlockCallback, DiffCommand } from './diff.mts';
|
package/dist/gh-cli/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createCommandRunner, runGh, runGit } from "./exec.mjs";
|
|
2
|
+
export { ghSpawnEnv } from "./env.mjs";
|
|
2
3
|
export { DiffCommandError, processDiffCommand } from "./diff.mjs";
|
|
3
4
|
export { GITHUB_BODY_MAX_CHARACTERS, validateGitHubBodyLength } from "./body-length.mjs";
|
|
4
5
|
export { assertHeadPushed, buildGhPrCreateArgs, createPullRequest, DetachedHeadError, HeadNotPushedError, HeadOutOfDateError, resolveHeadBranch, } from "./pr-create.mjs";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
2
|
import { appendFileSync } from 'node:fs';
|
|
3
|
+
import { ghSpawnEnv } from "../gh-cli/env.mjs";
|
|
3
4
|
import { ReviewPayloadError } from "../gha-review-payload/index.mjs";
|
|
4
5
|
import { readRegularReviewPayload } from "../gha-review-payload/index.mjs";
|
|
5
6
|
import { createActionsClaudeTokenIo, withClaudeAppToken } from "./claude-token.mjs";
|
|
@@ -11,7 +12,7 @@ export function createGhExec(exec = execFileSync) {
|
|
|
11
12
|
return (args, options) => exec('gh', [...args], {
|
|
12
13
|
encoding: 'utf8',
|
|
13
14
|
input: options?.input,
|
|
14
|
-
env: options?.env ?? process.env,
|
|
15
|
+
env: ghSpawnEnv(options?.env ?? process.env),
|
|
15
16
|
}).trim();
|
|
16
17
|
}
|
|
17
18
|
export function writePostedOutput(posted, commentCount, outputPath = process.env.GITHUB_OUTPUT) {
|
package/dist/index.d.mts
CHANGED
|
@@ -8,8 +8,8 @@ export { runRetrospectiveFacts } from './retrospective-facts/index.mts';
|
|
|
8
8
|
export type { CommandExecutor, CommandResult, RetrospectiveFactsOptions, } from './retrospective-facts/index.mts';
|
|
9
9
|
export { appendJournal, assertSessionId, cleanupSnapshotPartitions, partitionSnapshot, probeBlackboard, readJournal, resolveBlackboardConnection, } from './agent-blackboard/index.mts';
|
|
10
10
|
export type { BlackboardConnection, SnapshotChecksum, SnapshotCleanupReceipt, SnapshotCleanupOptions, SnapshotCounts, SnapshotManifest, SnapshotPartition, SnapshotPartitionOptions, SnapshotPartitionResult, SnapshotSelection, } from './agent-blackboard/index.mts';
|
|
11
|
-
export {
|
|
12
|
-
export type {
|
|
11
|
+
export { isConformingCiFailureBlock } from './audit-journal/ci-failures.mts';
|
|
12
|
+
export type { JournalEntry, JournalLoader, JournalLoadResult } from './audit-journal/types.mts';
|
|
13
13
|
export { EphemeralListenerAttemptsExhaustedError, isRunnerReservedPort, listenOnRunnerUnreservedEphemeralPort, loadRunnerPortPolicy, runnerPortPolicy, validateRunnerPortPolicy, } from './runner-port-policy/index.mts';
|
|
14
14
|
export type { EphemeralListenerOptions, RunnerPortPolicy } from './runner-port-policy/index.mts';
|
|
15
15
|
export { extractCreateTableMetadata, extractDefaultFunction, extractFuncCallArgColumnNames, initSqlAst, lineOfUtf8ByteOffset, MissingSqlAstParserError, parseSql, } from './sql-ast/index.mts';
|
|
@@ -95,7 +95,7 @@ export { validateResolvedPinDelta } from './swift-resolved-pin-delta/index.mts';
|
|
|
95
95
|
export type { ResolvedDocument, ResolvedPin, ValidateResolvedPinDeltaOptions, } from './swift-resolved-pin-delta/index.mts';
|
|
96
96
|
export { DEFAULT_MAX_DIAGNOSTIC_REPORTS, DEFAULT_MAX_FORMATTED_DIAGNOSTIC_REPORTS, formatDiagnosticReportSummaries, HARD_MAX_DIAGNOSTIC_REPORTS, readDiagnosticReportSummaries, summarizeDiagnosticReport, } from './vitest-diagnostics/index.mts';
|
|
97
97
|
export type { DiagnosticReportLimitOptions, DiagnosticReportSummary, } from './vitest-diagnostics/index.mts';
|
|
98
|
-
export { createCommandRunner, runGh, runGit } from './gh-cli/index.mts';
|
|
98
|
+
export { createCommandRunner, ghSpawnEnv, runGh, runGit } from './gh-cli/index.mts';
|
|
99
99
|
export type { ExecFileText, RunTextCommand } from './gh-cli/index.mts';
|
|
100
100
|
export { DiffCommandError, processDiffCommand } from './gh-cli/index.mts';
|
|
101
101
|
export type { DiffBlockCallback, DiffCommand } from './gh-cli/index.mts';
|
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ export { HARNESS_IDS, inspectHarnessEnvironment, selectHarnessSession, } from ".
|
|
|
4
4
|
export { codexChildren, codexIdentity, computeTranscriptFacts, formatTranscriptFacts, formatUnavailable, resolveTranscriptFile, runRetrospectiveTranscript, } from "./retrospective-transcript/index.mjs";
|
|
5
5
|
export { runRetrospectiveFacts } from "./retrospective-facts/index.mjs";
|
|
6
6
|
export { appendJournal, assertSessionId, cleanupSnapshotPartitions, partitionSnapshot, probeBlackboard, readJournal, resolveBlackboardConnection, } from "./agent-blackboard/index.mjs";
|
|
7
|
-
export {
|
|
7
|
+
export { isConformingCiFailureBlock } from "./audit-journal/ci-failures.mjs";
|
|
8
8
|
export { EphemeralListenerAttemptsExhaustedError, isRunnerReservedPort, listenOnRunnerUnreservedEphemeralPort, loadRunnerPortPolicy, runnerPortPolicy, validateRunnerPortPolicy, } from "./runner-port-policy/index.mjs";
|
|
9
9
|
export { extractCreateTableMetadata, extractDefaultFunction, extractFuncCallArgColumnNames, initSqlAst, lineOfUtf8ByteOffset, MissingSqlAstParserError, parseSql, } from "./sql-ast/index.mjs";
|
|
10
10
|
export { dollarQuoteEnd, lineOf, maskSqlQuotedText, readDollarQuoteDelimiter, readStringLiteral, splitSqlStatements, sqlFragments, stripSqlComments, } from "./sql-scanner/index.mjs";
|
|
@@ -52,7 +52,7 @@ export { normalizeSwiftSource } from "./swift-semantic-equal/index.mjs";
|
|
|
52
52
|
export { isSwiftCodeOffset, parseUniqueSwiftBinaryTargetChecksum, } from "./swift-source-offset/index.mjs";
|
|
53
53
|
export { validateResolvedPinDelta } from "./swift-resolved-pin-delta/index.mjs";
|
|
54
54
|
export { DEFAULT_MAX_DIAGNOSTIC_REPORTS, DEFAULT_MAX_FORMATTED_DIAGNOSTIC_REPORTS, formatDiagnosticReportSummaries, HARD_MAX_DIAGNOSTIC_REPORTS, readDiagnosticReportSummaries, summarizeDiagnosticReport, } from "./vitest-diagnostics/index.mjs";
|
|
55
|
-
export { createCommandRunner, runGh, runGit } from "./gh-cli/index.mjs";
|
|
55
|
+
export { createCommandRunner, ghSpawnEnv, runGh, runGit } from "./gh-cli/index.mjs";
|
|
56
56
|
export { DiffCommandError, processDiffCommand } from "./gh-cli/index.mjs";
|
|
57
57
|
export { GITHUB_BODY_MAX_CHARACTERS, validateGitHubBodyLength } from "./gh-cli/index.mjs";
|
|
58
58
|
export { assertHeadPushed, buildGhPrCreateArgs, createPullRequest, DetachedHeadError, HeadNotPushedError, HeadOutOfDateError, resolveHeadBranch, } from "./gh-cli/index.mjs";
|
|
@@ -21,6 +21,8 @@ export type ToolContext = {
|
|
|
21
21
|
runGit: RunTextCommand;
|
|
22
22
|
/** Test seam: replaces locating and running gh. */
|
|
23
23
|
runGh?: GhRunner;
|
|
24
|
+
/** The connected MCP client's `clientInfo.name`, once `initialize` has completed. */
|
|
25
|
+
clientName?: () => string | undefined;
|
|
24
26
|
/** Test seam: replaces the operating system user and host name. */
|
|
25
27
|
device?: () => {
|
|
26
28
|
user: string;
|
|
@@ -16,6 +16,8 @@ export type ServerEnvironment = {
|
|
|
16
16
|
spawnPolicy?: PolicySpawner;
|
|
17
17
|
/** Test seam: replaces locating and running gh. */
|
|
18
18
|
runGh?: GhRunner;
|
|
19
|
+
/** The connected MCP client's `clientInfo.name`, once `initialize` has completed. */
|
|
20
|
+
clientName?: () => string | undefined;
|
|
19
21
|
/** Test seam: replaces the operating system user and host name. */
|
|
20
22
|
device?: () => {
|
|
21
23
|
user: string;
|
|
@@ -67,6 +67,7 @@ export async function callTool(name, rawArguments, environment) {
|
|
|
67
67
|
runGit: environment.runGit,
|
|
68
68
|
snapshots: environment.snapshots ?? PROCESS_SNAPSHOTS,
|
|
69
69
|
...(environment.runGh === undefined ? {} : { runGh: environment.runGh }),
|
|
70
|
+
...(environment.clientName === undefined ? {} : { clientName: environment.clientName }),
|
|
70
71
|
...(environment.device === undefined ? {} : { device: environment.device }),
|
|
71
72
|
...(environment.spawnPolicy === undefined ? {} : { spawnPolicy: environment.spawnPolicy }),
|
|
72
73
|
// The client resolves from this package's install, like the SDK, never from the worktree.
|
|
@@ -23,6 +23,7 @@ export declare function harness(fixture: RepoFixture, options?: FakeOptions & {
|
|
|
23
23
|
host: string;
|
|
24
24
|
};
|
|
25
25
|
snapshots?: SnapshotRegistry;
|
|
26
|
+
clientName?: () => string | undefined;
|
|
26
27
|
}): Harness;
|
|
27
28
|
export declare function textOf(result: ToolCallResult): string;
|
|
28
29
|
export declare function jsonOf(result: ToolCallResult): Record<string, unknown>;
|
|
@@ -28,6 +28,7 @@ export function harness(fixture, options = {}) {
|
|
|
28
28
|
...(options.runGh === undefined ? {} : { runGh: options.runGh }),
|
|
29
29
|
...(options.device === undefined ? {} : { device: options.device }),
|
|
30
30
|
...(options.snapshots === undefined ? {} : { snapshots: options.snapshots }),
|
|
31
|
+
...(options.clientName === undefined ? {} : { clientName: options.clientName }),
|
|
31
32
|
};
|
|
32
33
|
return { fake, call: (name, args) => callTool(name, args, environment) };
|
|
33
34
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type HarnessId } from '../agent-harness-identity/index.mts';
|
|
2
|
+
/**
|
|
3
|
+
* The harness that launched this server, from the launch environment first and the MCP client's
|
|
4
|
+
* `initialize` `clientInfo.name` second. Neither comes from a tool argument.
|
|
5
|
+
*/
|
|
6
|
+
export declare function deriveAgent(env: NodeJS.ProcessEnv, clientName?: string): HarnessId | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* The text of the `Agent:` line before the session. The agent is the derived harness; a caller
|
|
9
|
+
* `agent` that does not name it, or any `model`, is shown as caller-claimed and never replaces it.
|
|
10
|
+
* With nothing derivable the agent is `unknown`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function agentLabel(derived: HarnessId | undefined, claimedAgent: string | undefined, claimedModel: string | undefined): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { inspectHarnessEnvironment } from "../agent-harness-identity/index.mjs";
|
|
2
|
+
const PRECEDENCE = ['codex', 'claude', 'cursor', 'grok'];
|
|
3
|
+
/**
|
|
4
|
+
* The harness that launched this server, from the launch environment first and the MCP client's
|
|
5
|
+
* `initialize` `clientInfo.name` second. Neither comes from a tool argument.
|
|
6
|
+
*/
|
|
7
|
+
export function deriveAgent(env, clientName) {
|
|
8
|
+
const found = inspectHarnessEnvironment(env);
|
|
9
|
+
const present = {
|
|
10
|
+
codex: Boolean(found.codex.sessionId),
|
|
11
|
+
claude: found.claude.compatMode || Boolean(found.claude.sessionId),
|
|
12
|
+
cursor: found.cursor.agentMarker || Boolean(found.cursor.sessionId),
|
|
13
|
+
grok: found.grok.agentMarker || found.grok.hookEvent || Boolean(found.grok.sessionId),
|
|
14
|
+
};
|
|
15
|
+
const fromEnv = PRECEDENCE.find((id) => present[id]);
|
|
16
|
+
if (fromEnv !== undefined)
|
|
17
|
+
return fromEnv;
|
|
18
|
+
const name = clientName?.toLowerCase() ?? '';
|
|
19
|
+
return PRECEDENCE.find((id) => name.includes(id));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The text of the `Agent:` line before the session. The agent is the derived harness; a caller
|
|
23
|
+
* `agent` that does not name it, or any `model`, is shown as caller-claimed and never replaces it.
|
|
24
|
+
* With nothing derivable the agent is `unknown`.
|
|
25
|
+
*/
|
|
26
|
+
export function agentLabel(derived, claimedAgent, claimedModel) {
|
|
27
|
+
const notes = [];
|
|
28
|
+
const claim = claimedAgent?.trim();
|
|
29
|
+
if (claim && !(derived !== undefined && claim.toLowerCase().includes(derived)))
|
|
30
|
+
notes.push(`caller-claimed agent: ${claim}`);
|
|
31
|
+
if (claimedModel)
|
|
32
|
+
notes.push(`caller-claimed model: ${claimedModel}`);
|
|
33
|
+
return `${derived ?? 'unknown'}${notes.length ? ` (${notes.join('; ')})` : ''}`;
|
|
34
|
+
}
|
|
@@ -7,6 +7,8 @@ export type PullRequestProvenance = {
|
|
|
7
7
|
host: string;
|
|
8
8
|
/** The checkout label, see {@link worktreeLabel}. */
|
|
9
9
|
worktree: string;
|
|
10
|
+
/** The Agent line text before the session, see `agentLabel`. */
|
|
11
|
+
agent: string;
|
|
10
12
|
};
|
|
11
13
|
/**
|
|
12
14
|
* The pull request body: the Summary, Impact, Related issues and Details sections followed by the
|
|
@@ -21,7 +21,6 @@ export function renderPullRequestBody(input, provenance, noSourceStatement) {
|
|
|
21
21
|
? '- None'
|
|
22
22
|
: (noSourceStatement ?? defaultNoSourceStatement(input.noSourceIssue.reason)),
|
|
23
23
|
];
|
|
24
|
-
const agent = input.model === undefined ? input.agent : `${input.agent} (${input.model})`;
|
|
25
24
|
return [
|
|
26
25
|
'## Summary',
|
|
27
26
|
'',
|
|
@@ -40,7 +39,7 @@ export function renderPullRequestBody(input, provenance, noSourceStatement) {
|
|
|
40
39
|
input.details.join('\n\n'),
|
|
41
40
|
'',
|
|
42
41
|
`Workspace setup: ${input.workspaceSetup}`,
|
|
43
|
-
`Agent: ${agent} session ${provenance.sessionId}`,
|
|
42
|
+
`Agent: ${provenance.agent} session ${provenance.sessionId}`,
|
|
44
43
|
`Device: ${provenance.user}@${provenance.host.toLowerCase()}`,
|
|
45
44
|
`Worktree: ${provenance.worktree}`,
|
|
46
45
|
'',
|
|
@@ -3,6 +3,7 @@ import { constants } from 'node:fs';
|
|
|
3
3
|
import { access, stat } from 'node:fs/promises';
|
|
4
4
|
import { delimiter, isAbsolute, join } from 'node:path';
|
|
5
5
|
import { promisify } from 'node:util';
|
|
6
|
+
import { ghSpawnEnv } from "../gh-cli/env.mjs";
|
|
6
7
|
const execFileAsync = promisify(execFile);
|
|
7
8
|
const FALLBACKS = ['/opt/homebrew/bin/gh', '/usr/local/bin/gh', '/usr/bin/gh'];
|
|
8
9
|
const MAX_BUFFER_BYTES = 16_000_000;
|
|
@@ -36,7 +37,7 @@ export async function locateGh(env, fallbacks = FALLBACKS) {
|
|
|
36
37
|
* GH_REPO, which would point gh at a repository other than the validated worktree's.
|
|
37
38
|
*/
|
|
38
39
|
export function ghEnvironment(env) {
|
|
39
|
-
const { AGENT_BLACKBOARD_URL: _url, AGENT_BLACKBOARD_TOKEN: _token, GH_REPO: _repo, ...rest } = env;
|
|
40
|
+
const { AGENT_BLACKBOARD_URL: _url, AGENT_BLACKBOARD_TOKEN: _token, GH_REPO: _repo, ...rest } = ghSpawnEnv(env);
|
|
40
41
|
return rest;
|
|
41
42
|
}
|
|
42
43
|
/** A runner that locates gh once, on first use, from the server's environment. */
|
|
@@ -16,7 +16,8 @@ export type PullRequestInput = {
|
|
|
16
16
|
};
|
|
17
17
|
details: string[];
|
|
18
18
|
base: string;
|
|
19
|
-
|
|
19
|
+
/** The caller's claim only; the rendered Agent line comes from `agentLabel`. */
|
|
20
|
+
agent?: string;
|
|
20
21
|
model?: string;
|
|
21
22
|
/** The trusted mode, see {@link trustedMode}; never the caller's word alone. */
|
|
22
23
|
mode: PullRequestMode;
|
|
@@ -70,7 +70,7 @@ export function readPullRequestInput(args, env) {
|
|
|
70
70
|
...(noSourceIssue === undefined ? {} : { noSourceIssue }),
|
|
71
71
|
details: readDetails(args),
|
|
72
72
|
base: optionalString(args, 'base') ?? 'main',
|
|
73
|
-
agent: singleLine(args, 'agent'),
|
|
73
|
+
...(args.agent === undefined ? {} : { agent: singleLine(args, 'agent') }),
|
|
74
74
|
...(model === undefined ? {} : { model }),
|
|
75
75
|
mode: trustedMode(env, requested),
|
|
76
76
|
// It renders on its own provenance line; a newline would forge the lines after it.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findShepherdJournal } from "./pr-journal.mjs";
|
|
2
|
-
const FIELDS = ['body', 'headRefName', 'baseRefName', 'state'];
|
|
2
|
+
const FIELDS = ['body', 'headRefName', 'headRefOid', 'baseRefName', 'state'];
|
|
3
3
|
/** The live pull request as gh reports it, whatever its state. */
|
|
4
4
|
export async function readLivePullRequest(gh, pr) {
|
|
5
5
|
const output = await gh(['pr', 'view', String(pr), '--json', FIELDS.join(',')]);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { hostname, userInfo } from 'node:os';
|
|
2
2
|
import { validateGitHubBodyLength } from "../gh-cli/body-length.mjs";
|
|
3
3
|
import { assertPolicyAllowed } from "./context.mjs";
|
|
4
|
+
import { agentLabel, deriveAgent } from "./pr-agent.mjs";
|
|
4
5
|
import { renderPullRequestBody, worktreeLabel } from "./pr-body.mjs";
|
|
5
6
|
import { createGhRunner, ghEnvironment } from "./pr-gh.mjs";
|
|
6
7
|
import { checkTitleLength, readPullRequestInput } from "./pr-input.mjs";
|
|
@@ -41,6 +42,20 @@ async function liveFor(kind, context, pr) {
|
|
|
41
42
|
? livePullRequest(ghIn(context), pr)
|
|
42
43
|
: readLivePullRequest(ghIn(context), pr);
|
|
43
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The head to validate. An update accepts the worktree branch, or an alias branch whose HEAD is
|
|
47
|
+
* the live head commit, and then uses the live head name; anything else is rejected.
|
|
48
|
+
*/
|
|
49
|
+
async function headFor(kind, git, live, pr, worktreeHead) {
|
|
50
|
+
if (worktreeHead === undefined)
|
|
51
|
+
return live.headRefName;
|
|
52
|
+
if (live === undefined || kind !== 'update' || live.headRefName === worktreeHead)
|
|
53
|
+
return worktreeHead;
|
|
54
|
+
const sha = (await git(['rev-parse', 'HEAD'])).trim();
|
|
55
|
+
if (sha !== live.headRefOid)
|
|
56
|
+
throw new Error(`pull request ${pr} has head ${live.headRefName} at ${live.headRefOid}, not the worktree branch ${worktreeHead} at ${sha}`);
|
|
57
|
+
return live.headRefName;
|
|
58
|
+
}
|
|
44
59
|
/** Renders the body, preserves the live journal for an update, and runs the policy validator. */
|
|
45
60
|
export async function prepare(args, context, kind, pr) {
|
|
46
61
|
assertPolicyAllowed(context);
|
|
@@ -53,14 +68,15 @@ export async function prepare(args, context, kind, pr) {
|
|
|
53
68
|
const live = await liveFor(kind, context, pr);
|
|
54
69
|
// A read-only validation of an existing pull request judges the head that pull request has.
|
|
55
70
|
const worktreeHead = live !== undefined && kind === 'validate' ? undefined : await currentBranch(git);
|
|
56
|
-
|
|
71
|
+
// The local branch is checked before any diagnostic or alias resolution can echo or drop it.
|
|
72
|
+
if (worktreeHead !== undefined && secrets.some((secret) => worktreeHead.includes(secret)))
|
|
73
|
+
throw new Error('the worktree branch name contains a server credential: rename the branch');
|
|
74
|
+
const head = await headFor(kind, git, live, pr, worktreeHead);
|
|
57
75
|
// Branch names are refs passed to gh as is: redacting one would name a branch that does not exist.
|
|
58
76
|
if (secrets.some((secret) => head.includes(secret)))
|
|
59
77
|
throw new Error('the worktree branch name contains a server credential: rename the branch');
|
|
60
78
|
if (secrets.some((secret) => args.base?.includes(secret)))
|
|
61
79
|
throw new Error('base contains a server credential: use another base branch');
|
|
62
|
-
if (live !== undefined && kind === 'update' && live.headRefName !== head)
|
|
63
|
-
throw new Error(`pull request ${pr} has head ${live.headRefName}, not the worktree branch ${head}`);
|
|
64
80
|
const base = live === undefined
|
|
65
81
|
? given.base
|
|
66
82
|
: liveBase(pr, live, redactCredentials(args.base, secrets));
|
|
@@ -70,7 +86,12 @@ export async function prepare(args, context, kind, pr) {
|
|
|
70
86
|
throw new Error(`head branch ${head} must differ from base ${base}`);
|
|
71
87
|
const device = (context.device ?? (() => ({ user: userInfo().username, host: hostname() })))();
|
|
72
88
|
const statement = await noSourceStatement(policyFor(context), input);
|
|
73
|
-
let body = renderPullRequestBody(input, {
|
|
89
|
+
let body = renderPullRequestBody(input, {
|
|
90
|
+
sessionId: context.sessionId,
|
|
91
|
+
...device,
|
|
92
|
+
worktree: await label(context, git),
|
|
93
|
+
agent: agentLabel(deriveAgent(context.env, context.clientName?.()), input.agent, input.model),
|
|
94
|
+
}, statement);
|
|
74
95
|
if (live !== undefined)
|
|
75
96
|
body = preserveShepherdJournal(body, live.body);
|
|
76
97
|
body = redactCredentials(body, secrets);
|
|
@@ -15,6 +15,7 @@ const INSTRUCTIONS = 'Journals agent-blackboard feedback for a vouchington consu
|
|
|
15
15
|
*/
|
|
16
16
|
export function createMcpServer(sdk, environment, version) {
|
|
17
17
|
const mcp = new sdk.McpServer({ name: SERVER_NAME, version }, { instructions: INSTRUCTIONS });
|
|
18
|
+
environment.clientName ??= () => mcp.server.getClientVersion()?.name;
|
|
18
19
|
mcp.server.registerCapabilities({ tools: {} });
|
|
19
20
|
mcp.server.setRequestHandler(sdk.ListToolsRequestSchema, async () => ({ tools: [...TOOLS] }));
|
|
20
21
|
mcp.server.setRequestHandler(sdk.CallToolRequestSchema, async (request) => callTool(request.params.name, request.params.arguments, environment));
|
|
@@ -41,8 +41,12 @@ const FIELDS = {
|
|
|
41
41
|
description: 'Markdown paragraphs or bullets, joined by blank lines.',
|
|
42
42
|
},
|
|
43
43
|
base: { type: 'string', minLength: 1, description: 'Base branch. Default: main.' },
|
|
44
|
-
agent: text('
|
|
45
|
-
|
|
44
|
+
agent: text('Optional, and never trusted. The server derives the Agent line from its own launch ' +
|
|
45
|
+
'environment (harness markers) and the MCP client name; a value that does not name the ' +
|
|
46
|
+
'derived agent is rendered as "caller-claimed", and with nothing derivable the agent is ' +
|
|
47
|
+
'"unknown".'),
|
|
48
|
+
model: text('Optional, and never trusted. The server cannot derive the model, so it is rendered as ' +
|
|
49
|
+
'"caller-claimed model: <model>" in parentheses after the agent.'),
|
|
46
50
|
mode: {
|
|
47
51
|
enum: ['interactive', 'autonomous'],
|
|
48
52
|
description: 'Optional. The server derives the mode from its own launch environment and fails closed: ' +
|
|
@@ -51,15 +55,7 @@ const FIELDS = {
|
|
|
51
55
|
},
|
|
52
56
|
workspaceSetup: text('Text for the Workspace setup line, such as how the worktree was prepared.'),
|
|
53
57
|
};
|
|
54
|
-
const REQUIRED = [
|
|
55
|
-
'title',
|
|
56
|
-
'summary',
|
|
57
|
-
'impact',
|
|
58
|
-
'relatedIssues',
|
|
59
|
-
'details',
|
|
60
|
-
'agent',
|
|
61
|
-
'workspaceSetup',
|
|
62
|
-
];
|
|
58
|
+
const REQUIRED = ['title', 'summary', 'impact', 'relatedIssues', 'details', 'workspaceSetup'];
|
|
63
59
|
const RENDERING = 'The server renders the body from the structured input (Summary, Impact, Related issues, ' +
|
|
64
60
|
'Details, then Workspace setup, Agent, Device and Worktree lines) and runs the checkout ' +
|
|
65
61
|
'policy validatePullRequest export in a child process; the head branch is the ' +
|
|
@@ -79,7 +75,7 @@ export const PR_TOOLS = [
|
|
|
79
75
|
"repository's stack tooling. Returns { number, url, warnings }.", openWorld(ADDITIVE), FIELDS, REQUIRED),
|
|
80
76
|
tool('pr_update', "Replaces an open pull request's title and body. " +
|
|
81
77
|
RENDERING +
|
|
82
|
-
"The pull request's head branch must be the
|
|
78
|
+
"The pull request's head must be the worktree branch, or the worktree HEAD must be the pull request's head commit (an alias branch); the live head name is then used. The live Shepherd Journal is " +
|
|
83
79
|
'preserved and nothing else is carried over from the live body. Validation errors block ' +
|
|
84
80
|
'the update. Returns { number, url, warnings }.', openWorld(MUTATING), { ...FIELDS, pr: PR_NUMBER }, [...REQUIRED, 'pr']),
|
|
85
81
|
];
|
|
@@ -131,6 +131,7 @@ function removeStaleLock(lockPath) {
|
|
|
131
131
|
return true;
|
|
132
132
|
}
|
|
133
133
|
catch {
|
|
134
|
+
/* v8 ignore next -- requires an unexpected filesystem failure during stale-lock recovery. */
|
|
134
135
|
return false;
|
|
135
136
|
}
|
|
136
137
|
});
|
|
@@ -174,7 +175,7 @@ export function withFileLock(path, action) {
|
|
|
174
175
|
throw statusError;
|
|
175
176
|
}
|
|
176
177
|
if (!lockStatus.isFile())
|
|
177
|
-
throw new Error('
|
|
178
|
+
throw new Error('log lock must be a regular file');
|
|
178
179
|
if (removeStaleLock(lockPath))
|
|
179
180
|
continue;
|
|
180
181
|
waitForLock();
|
|
@@ -189,5 +190,5 @@ export function withFileLock(path, action) {
|
|
|
189
190
|
unlinkSync(lockPath);
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
|
-
throw new Error(`could not acquire
|
|
193
|
+
throw new Error(`could not acquire file lock for ${basename(path)}`);
|
|
193
194
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { closeSync, constants, fstatSync, openSync, readSync, writeSync } from 'node:fs';
|
|
2
|
+
import { decodeUtf8 } from "./utf8.mjs";
|
|
3
|
+
export function openLogFile(path, flags) {
|
|
4
|
+
let descriptor;
|
|
5
|
+
try {
|
|
6
|
+
descriptor = openSync(path, flags | constants.O_NOFOLLOW | constants.O_NONBLOCK, 0o600);
|
|
7
|
+
}
|
|
8
|
+
catch (error) {
|
|
9
|
+
if (error &&
|
|
10
|
+
typeof error === 'object' &&
|
|
11
|
+
'code' in error &&
|
|
12
|
+
(error.code === 'ELOOP' || error.code === 'EISDIR' || error.code === 'ENOTDIR'))
|
|
13
|
+
throw new Error('log file must be a regular file');
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const status = fstatSync(descriptor);
|
|
18
|
+
if (!status.isFile() || status.nlink !== 1)
|
|
19
|
+
throw new Error('log file must be a regular file');
|
|
20
|
+
return descriptor;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
closeSync(descriptor);
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function readLogContent(descriptor, maximumBytes) {
|
|
28
|
+
if (fstatSync(descriptor).size > maximumBytes)
|
|
29
|
+
throw new Error('log file is too large');
|
|
30
|
+
const buffer = Buffer.alloc(maximumBytes + 1);
|
|
31
|
+
let length = 0;
|
|
32
|
+
while (length < buffer.length) {
|
|
33
|
+
const bytes = readSync(descriptor, buffer, length, buffer.length - length, length);
|
|
34
|
+
if (bytes === 0)
|
|
35
|
+
break;
|
|
36
|
+
length += bytes;
|
|
37
|
+
}
|
|
38
|
+
/* v8 ignore next -- detects external growth after the descriptor size check. */
|
|
39
|
+
if (length > maximumBytes)
|
|
40
|
+
throw new Error('log file is too large');
|
|
41
|
+
return decodeUtf8(buffer.subarray(0, length));
|
|
42
|
+
}
|
|
43
|
+
export function writeAll(descriptor, value) {
|
|
44
|
+
const buffer = Buffer.from(value);
|
|
45
|
+
let offset = 0;
|
|
46
|
+
while (offset < buffer.length) {
|
|
47
|
+
const written = writeSync(descriptor, buffer, offset, buffer.length - offset);
|
|
48
|
+
/* v8 ignore next -- a zero-byte synchronous file write is an external I/O failure. */
|
|
49
|
+
if (written === 0)
|
|
50
|
+
throw new Error('log file write made no progress');
|
|
51
|
+
offset += written;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
+
import { ghSpawnEnv } from "../gh-cli/env.mjs";
|
|
2
3
|
export const shell = (command, args) => new Promise((resolve) => {
|
|
3
|
-
const child = spawn(command, args);
|
|
4
|
+
const child = command === 'gh' ? spawn(command, args, { env: ghSpawnEnv() }) : spawn(command, args);
|
|
4
5
|
let stdout = '';
|
|
5
6
|
let stderr = '';
|
|
6
7
|
child.stdout.setEncoding('utf8');
|
package/docs/mcp-server.md
CHANGED
|
@@ -287,7 +287,7 @@ retrospective tools. All three take `sessionId` (required) and `worktree` (optio
|
|
|
287
287
|
launched inside a repository worktree (they run the checkout policy), and share this structured
|
|
288
288
|
input: `title` (single line, at most 256 characters), `summary`, `impact`, `relatedIssues`
|
|
289
289
|
(`[{ number, relation: "closes" | "refs", reason }]`, may be empty), optional `noSourceIssue`
|
|
290
|
-
(`{ reason }`, see below), `details` (string array), `base` (default `main`), `agent`, optional
|
|
290
|
+
(`{ reason }`, see below), `details` (string array), `base` (default `main`), optional `agent`, optional
|
|
291
291
|
`model`, optional `mode` (`interactive` | `autonomous`) and `workspaceSetup`. `pr_update` also
|
|
292
292
|
requires `pr`; `pr_validate` accepts an optional `pr`.
|
|
293
293
|
|
|
@@ -305,6 +305,18 @@ argument can only narrow `interactive` to `autonomous` (it never widens), so an
|
|
|
305
305
|
cannot unlock an interactive-only policy exception. The policy child receives no env markers, so it
|
|
306
306
|
relies on this value.
|
|
307
307
|
|
|
308
|
+
### Agent provenance
|
|
309
|
+
|
|
310
|
+
The `Agent:` line is derived by the server, never taken from the caller. The agent is the harness
|
|
311
|
+
that launched the server: `CODEX_THREAD_ID` (codex), `CLAUDECODE=1` or `CLAUDE_CODE_SESSION_ID`
|
|
312
|
+
(claude), `CURSOR_AGENT` or `CURSOR_SESSION_ID` (cursor), `GROK_AGENT`, `GROK_HOOK_EVENT` or
|
|
313
|
+
`GROK_SESSION_ID` (grok), in that order; failing those, the MCP client's `initialize`
|
|
314
|
+
`clientInfo.name` when it contains one of those names. The server has no source for the model.
|
|
315
|
+
`agent` is optional: a value naming the derived agent is ignored, any other value is rendered as
|
|
316
|
+
`(caller-claimed agent: <value>)`, and `model` as `(caller-claimed model: <value>)`. When no agent
|
|
317
|
+
is derivable the line says `unknown`. Making `agent` optional is compatible with existing callers,
|
|
318
|
+
which may keep sending it.
|
|
319
|
+
|
|
308
320
|
### Pull requests with no source issue
|
|
309
321
|
|
|
310
322
|
Pass `noSourceIssue: { reason }` (a single line) with an empty `relatedIssues`; a non-empty
|
|
@@ -335,7 +347,7 @@ rule) and `pullRequestDefaults`.
|
|
|
335
347
|
<details joined by blank lines>
|
|
336
348
|
|
|
337
349
|
Workspace setup: <workspaceSetup>
|
|
338
|
-
Agent: <agent>[ (
|
|
350
|
+
Agent: <derived agent | unknown>[ (caller-claimed ...)] session <sessionId>
|
|
339
351
|
Device: <os user>@<lowercased hostname>
|
|
340
352
|
Worktree: <path after "/worktrees/", "main" for the main worktree, else the directory name>
|
|
341
353
|
```
|
|
@@ -357,8 +369,10 @@ with the repository's stack tooling instead.
|
|
|
357
369
|
and `project`. It checks the head is pushed and current, writes the body to a mode 0600 temp file
|
|
358
370
|
(removed afterwards) and runs `gh pr create --draft` with the labels, `--milestone` and
|
|
359
371
|
`--project`. Returns `{ number, url, warnings }`.
|
|
360
|
-
- `pr_update` (mutating): reads `gh pr view <pr> --json body,headRefName,baseRefName,state`,
|
|
361
|
-
rejects a pull request that is not `OPEN` or whose head is
|
|
372
|
+
- `pr_update` (mutating): reads `gh pr view <pr> --json body,headRefName,headRefOid,baseRefName,state`,
|
|
373
|
+
rejects a pull request that is not `OPEN` or whose head is neither the worktree branch nor the
|
|
374
|
+
worktree `HEAD` commit (an alias branch at the live head SHA is accepted and the live head name is
|
|
375
|
+
used), and validates
|
|
362
376
|
against the live base (an explicit `base` must equal it). It renders, appends the live Shepherd
|
|
363
377
|
Journal (a `<details><summary>Shepherd Journal</summary>` block, or a legacy `## Shepherd Journal`
|
|
364
378
|
section to the next H2 or the end; examples in fenced code blocks are ignored), validates with
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vouchington-tooling",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.0",
|
|
4
4
|
"description": "Vouchington CLI and extractable tooling libraries.",
|
|
5
5
|
"homepage": "https://github.com/vouchington/vouchington-tooling/tree/main/packages/vouchington-tooling#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -71,11 +71,6 @@
|
|
|
71
71
|
"default": "./dist/agent-blackboard/index.mjs"
|
|
72
72
|
},
|
|
73
73
|
"./mcp-server/bin": "./bin/vouchington-mcp.mjs",
|
|
74
|
-
"./session-friction": {
|
|
75
|
-
"types": "./dist/session-friction/index.d.mts",
|
|
76
|
-
"import": "./dist/session-friction/index.mjs",
|
|
77
|
-
"default": "./dist/session-friction/index.mjs"
|
|
78
|
-
},
|
|
79
74
|
"./sql-ast": {
|
|
80
75
|
"types": "./dist/sql-ast/index.d.mts",
|
|
81
76
|
"import": "./dist/sql-ast/index.mjs",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { FrictionLogReadResult, JournalEntry } from './types.mts';
|
|
2
|
-
import { type AuditRedactor } from './text.mts';
|
|
3
|
-
export declare function isConformingCiFailureBlock(markdown: string): boolean;
|
|
4
|
-
export declare function getConformingGroups(entries: Iterable<JournalEntry>, redact?: AuditRedactor, maxBytes?: number): string[];
|
|
5
|
-
export declare function incompleteCiSection(markdownBlocks: string[]): string;
|
|
6
|
-
export declare function buildCiFailuresSection(sessionId: string, journal: {
|
|
7
|
-
status: 'ok';
|
|
8
|
-
markdownBlocks: string[];
|
|
9
|
-
truncated: boolean;
|
|
10
|
-
} | {
|
|
11
|
-
status: 'unreachable';
|
|
12
|
-
diagnostic: string;
|
|
13
|
-
}, frictionStatus: FrictionLogReadResult['status'] | 'journal-only'): string;
|