vouchington-tooling 0.24.1 → 0.26.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 +43 -0
- package/dist/agent-blackboard/client.d.mts +5 -0
- package/dist/agent-blackboard/client.mjs +1 -1
- package/dist/agent-blackboard/feedback-audit-source.d.mts +13 -0
- package/dist/agent-blackboard/feedback-audit-source.mjs +30 -0
- package/dist/agent-blackboard/feedback-compose.d.mts +5 -1
- package/dist/agent-blackboard/feedback-compose.mjs +8 -18
- package/dist/agent-blackboard/feedback-journal-audit.d.mts +20 -0
- package/dist/agent-blackboard/feedback-journal-audit.mjs +29 -0
- package/dist/agent-blackboard/feedback-journal-sandbox.d.mts +5 -0
- package/dist/agent-blackboard/feedback-journal-sandbox.mjs +40 -0
- package/dist/agent-blackboard/index.d.mts +9 -8
- package/dist/agent-blackboard/index.mjs +7 -34
- package/dist/agent-blackboard/journal.d.mts +21 -0
- package/dist/agent-blackboard/journal.mjs +45 -0
- package/dist/agent-blackboard/session-tools.d.mts +36 -0
- package/dist/agent-blackboard/session-tools.mjs +41 -0
- package/dist/cli/commands/mcp.d.mts +5 -0
- package/dist/cli/commands/mcp.mjs +18 -0
- package/dist/cli/index.mjs +5 -5
- package/dist/cli/installed-version.d.mts +1 -0
- package/dist/cli/installed-version.mjs +5 -0
- package/dist/cli/parse-forwarded-commands.d.mts +3 -0
- package/dist/cli/parse-forwarded-commands.mjs +2 -0
- package/dist/cli/parse.d.mts +3 -0
- package/dist/cli/usage.d.mts +1 -1
- package/dist/cli/usage.mjs +6 -0
- package/dist/mcp-server/args.d.mts +9 -0
- package/dist/mcp-server/args.mjs +48 -0
- package/dist/mcp-server/context.d.mts +19 -0
- package/dist/mcp-server/context.mjs +23 -0
- package/dist/mcp-server/dispatch.d.mts +18 -0
- package/dist/mcp-server/dispatch.mjs +62 -0
- package/dist/mcp-server/fake-blackboard.test-helpers.d.mts +39 -0
- package/dist/mcp-server/fake-blackboard.test-helpers.mjs +75 -0
- package/dist/mcp-server/git-fixture.test-helpers.d.mts +16 -0
- package/dist/mcp-server/git-fixture.test-helpers.mjs +35 -0
- package/dist/mcp-server/handlers-journal.d.mts +6 -0
- package/dist/mcp-server/handlers-journal.mjs +98 -0
- package/dist/mcp-server/handlers-session.d.mts +4 -0
- package/dist/mcp-server/handlers-session.mjs +47 -0
- package/dist/mcp-server/harness.test-helpers.d.mts +33 -0
- package/dist/mcp-server/harness.test-helpers.mjs +48 -0
- package/dist/mcp-server/run.d.mts +20 -0
- package/dist/mcp-server/run.mjs +21 -0
- package/dist/mcp-server/sdk.d.mts +17 -0
- package/dist/mcp-server/sdk.mjs +33 -0
- package/dist/mcp-server/server.d.mts +9 -0
- package/dist/mcp-server/server.mjs +17 -0
- package/dist/mcp-server/tools.d.mts +19 -0
- package/dist/mcp-server/tools.mjs +120 -0
- package/dist/mcp-server/worktree.d.mts +18 -0
- package/dist/mcp-server/worktree.mjs +58 -0
- package/dist/session-friction/audit-block.d.mts +4 -0
- package/dist/session-friction/audit-block.mjs +45 -0
- package/dist/session-friction/ci-failures.d.mts +2 -1
- package/dist/session-friction/ci-failures.mjs +10 -46
- package/dist/session-friction/journal.d.mts +14 -0
- package/dist/session-friction/journal.mjs +66 -0
- package/dist/session-friction/report.mjs +10 -74
- package/docs/mcp-server.md +134 -0
- package/package.json +7 -2
- package/skills/blackboard/SKILL.md +59 -22
- package/skills/manifest.json +19 -19
- package/skills/retrospective-distill/SKILL.md +37 -13
package/README.md
CHANGED
|
@@ -19,8 +19,13 @@ npm install @typescript/typescript6
|
|
|
19
19
|
npm install vitest
|
|
20
20
|
# optional, only for vouchington-tooling/agent-blackboard and agent-blackboard CLI commands
|
|
21
21
|
npm install agent-blackboard@^0.6.0
|
|
22
|
+
# optional, only for `vouchington mcp` (zod is a peer of the SDK)
|
|
23
|
+
npm install @modelcontextprotocol/sdk zod
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
[`vouchington mcp`](docs/mcp-server.md) serves the agent-blackboard journal tools to an agent over
|
|
27
|
+
stdio, with Claude, Codex, and Cursor registration examples.
|
|
28
|
+
|
|
24
29
|
## CLI
|
|
25
30
|
|
|
26
31
|
```bash
|
|
@@ -70,6 +75,7 @@ vouchington agent-blackboard journal append --session-id <uuid> --agent codex --
|
|
|
70
75
|
vouchington agent-blackboard journal entries --session-id <uuid>
|
|
71
76
|
vouchington agent-blackboard snapshot partition --snapshot <snapshot.jsonl> --checksum <sha256> --counts <counts.json>
|
|
72
77
|
vouchington agent-blackboard snapshot cleanup --snapshot <snapshot.jsonl> --partition-directory <partitions-dir> --receipt <receipt-json>
|
|
78
|
+
vouchington mcp
|
|
73
79
|
vouchington install-playwright-chromium-arm64
|
|
74
80
|
vouchington ghcr-package-retention example%2Fapi
|
|
75
81
|
vouchington harness-admission-lane 4
|
|
@@ -578,3 +584,40 @@ aggregate dropped counts below observed friction drops and retains larger caller
|
|
|
578
584
|
double counting. Generated frontmatter carries validated `work_outcome` and `feedback_coverage`
|
|
579
585
|
for consumers to preserve or reject conflicting explicit overrides; trusted mode stays external.
|
|
580
586
|
Human top-five summaries do not authorize dropping additional durable findings.
|
|
587
|
+
|
|
588
|
+
The `## CI Failures` and `## Sandbox & Permission Audit` sections come from one optional audit
|
|
589
|
+
source; the two inputs are mutually exclusive and supplying both throws before any collector runs.
|
|
590
|
+
`friction: {directory, journalLoader, ...}` keeps reading the session-friction log together with the
|
|
591
|
+
journal and is unchanged. `journal: {journalLoader}` needs no friction directory or log: both
|
|
592
|
+
sections are assessed from the session's journal entries alone, and the report carries
|
|
593
|
+
`coverage.frictionStatus: 'journal-only'` (in place of `empty` or `events`) so the text states that
|
|
594
|
+
no log was observed. `feedbackCoverage.status: 'complete'` accepts either source. It is rejected
|
|
595
|
+
when neither is supplied (the error names the missing source), and a journal-only audit does not
|
|
596
|
+
count as assessed when the loader reports `not-found` (there is no log to establish that the session
|
|
597
|
+
was observed), throws, or is truncated by the scan bounds.
|
|
598
|
+
|
|
599
|
+
```ts
|
|
600
|
+
await composeRetrospective({ ...input, journal: { journalLoader } })
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
`journalLoader` is the session-friction `JournalLoader`; `JournalLoader`, `JournalLoadResult`,
|
|
604
|
+
`JournalEntry`, and `JournalAuditOptions` are exported as types from
|
|
605
|
+
`vouchington-tooling/agent-blackboard`. The `## CI Failures` block grammar and its three status
|
|
606
|
+
lines (`failures observed`, `none observed`, `unavailable (<reason>)`) are the same for both sources.
|
|
607
|
+
Journal-only sandbox and permission entries are journal Markdown entries that hold exactly one
|
|
608
|
+
block, escaped and length-bounded like CI failures, and other entries are ignored:
|
|
609
|
+
|
|
610
|
+
```markdown
|
|
611
|
+
- `sandbox-escalation` — git push — network write blocked
|
|
612
|
+
- Outcome: requested | approved | denied | unknown
|
|
613
|
+
- Evidence: permission prompt shown
|
|
614
|
+
- Disposition: reran with approval
|
|
615
|
+
- `sandbox-failure` — node test — EPERM writing outside the worktree
|
|
616
|
+
- Evidence: stderr showed EPERM
|
|
617
|
+
- Disposition: moved output under TMPDIR
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
`ambiguous-failure` takes the same shape as `sandbox-failure`. The section reports
|
|
621
|
+
`Status: none observed` or `Status: events observed`, each followed by
|
|
622
|
+
`(journal entries only; no friction log observed)`; a truncated scan reports
|
|
623
|
+
`unavailable (journal scan incomplete)` with the entries read so far.
|
|
@@ -15,6 +15,7 @@ export type BlackboardClientModule = {
|
|
|
15
15
|
patch(input: unknown): Promise<unknown>;
|
|
16
16
|
list(input: unknown): Promise<unknown>;
|
|
17
17
|
get(id: string): Promise<unknown>;
|
|
18
|
+
archive?(sessionId: string): Promise<unknown>;
|
|
18
19
|
};
|
|
19
20
|
Entries: new (connection: BlackboardConnection) => {
|
|
20
21
|
append(input: unknown): Promise<{
|
|
@@ -23,6 +24,9 @@ export type BlackboardClientModule = {
|
|
|
23
24
|
}>;
|
|
24
25
|
get(input: unknown): AsyncIterable<unknown>;
|
|
25
26
|
};
|
|
27
|
+
Snapshots?: new (connection: BlackboardConnection) => {
|
|
28
|
+
export(options?: unknown): Promise<unknown>;
|
|
29
|
+
};
|
|
26
30
|
};
|
|
27
31
|
type BlackboardClientLoader = () => Promise<BlackboardClientModule>;
|
|
28
32
|
export type BlackboardClientDependencies = {
|
|
@@ -31,4 +35,5 @@ export type BlackboardClientDependencies = {
|
|
|
31
35
|
};
|
|
32
36
|
export declare function resolveBlackboardConnection(env?: NodeJS.ProcessEnv): BlackboardConnection;
|
|
33
37
|
export declare function loadClient(dependencies?: BlackboardClientDependencies): Promise<BlackboardClientModule>;
|
|
38
|
+
export declare function isMissingModuleError(error: unknown): boolean;
|
|
34
39
|
export {};
|
|
@@ -34,7 +34,7 @@ async function defaultClientLoader(resolveFrom) {
|
|
|
34
34
|
const specifier = pathToFileURL(consumerRequire.resolve('agent-blackboard')).href;
|
|
35
35
|
return (await import(__rewriteRelativeImportExtension(specifier)));
|
|
36
36
|
}
|
|
37
|
-
function isMissingModuleError(error) {
|
|
37
|
+
export function isMissingModuleError(error) {
|
|
38
38
|
return (error instanceof Error &&
|
|
39
39
|
'code' in error &&
|
|
40
40
|
(error.code === 'ERR_MODULE_NOT_FOUND' || error.code === 'MODULE_NOT_FOUND'));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type SessionFrictionReport, type SessionFrictionReportOptions } from '../session-friction/index.mts';
|
|
2
|
+
import { type JournalAuditOptions, type JournalAuditReport } from './feedback-journal-audit.mts';
|
|
3
|
+
export type AuditSourceInput = {
|
|
4
|
+
friction?: SessionFrictionReportOptions;
|
|
5
|
+
journal?: JournalAuditOptions;
|
|
6
|
+
};
|
|
7
|
+
export type AuditReport = SessionFrictionReport | JournalAuditReport;
|
|
8
|
+
export declare function assertSingleAuditSource(input: AuditSourceInput): void;
|
|
9
|
+
/** Builds the CI-failure and sandbox sections from the friction log or from journal entries alone. */
|
|
10
|
+
export declare function buildAuditReport(sessionId: string, input: AuditSourceInput): Promise<AuditReport>;
|
|
11
|
+
/** Only a real log status or an explicit journal-only scan counts as assessed. */
|
|
12
|
+
export declare function auditAssessed({ coverage }: AuditReport): boolean;
|
|
13
|
+
export declare function completeCoverageError(input: AuditSourceInput): Error;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { buildSessionFrictionReport, } from '../session-friction/index.mjs';
|
|
2
|
+
import { buildJournalAuditReport, } from './feedback-journal-audit.mjs';
|
|
3
|
+
const ASSESSED_SOURCE_ERROR = 'complete feedback coverage requires assessed available factual and finding sources';
|
|
4
|
+
const NOT_ASSESSED_MARKDOWN = '## CI Failures\nStatus: unavailable (not assessed)\n\n## Sandbox & Permission Audit\nStatus: unavailable (not assessed)';
|
|
5
|
+
export function assertSingleAuditSource(input) {
|
|
6
|
+
if (input.friction && input.journal)
|
|
7
|
+
throw new Error('composition accepts either a friction or a journal audit source, not both');
|
|
8
|
+
}
|
|
9
|
+
/** Builds the CI-failure and sandbox sections from the friction log or from journal entries alone. */
|
|
10
|
+
export async function buildAuditReport(sessionId, input) {
|
|
11
|
+
if (input.friction)
|
|
12
|
+
return buildSessionFrictionReport(sessionId, input.friction);
|
|
13
|
+
if (input.journal)
|
|
14
|
+
return buildJournalAuditReport(sessionId, input.journal);
|
|
15
|
+
return {
|
|
16
|
+
coverage: { journalStatus: 'unavailable', frictionStatus: 'absent', truncated: false },
|
|
17
|
+
markdown: NOT_ASSESSED_MARKDOWN,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Only a real log status or an explicit journal-only scan counts as assessed. */
|
|
21
|
+
export function auditAssessed({ coverage }) {
|
|
22
|
+
return (coverage.journalStatus === 'complete' &&
|
|
23
|
+
['empty', 'events', 'journal-only'].includes(coverage.frictionStatus) &&
|
|
24
|
+
!coverage.truncated);
|
|
25
|
+
}
|
|
26
|
+
export function completeCoverageError(input) {
|
|
27
|
+
return new Error(input.friction || input.journal
|
|
28
|
+
? ASSESSED_SOURCE_ERROR
|
|
29
|
+
: `${ASSESSED_SOURCE_ERROR} (no friction or journal source supplied for CI failures and sandbox audit)`);
|
|
30
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type RetrospectiveFactsOptions } from '../retrospective-facts/index.mts';
|
|
2
2
|
import { type ResolveOptions } from '../retrospective-transcript/index.mts';
|
|
3
|
-
import {
|
|
3
|
+
import type { SessionFrictionReportOptions } from '../session-friction/index.mts';
|
|
4
|
+
import type { JournalAuditOptions } from './feedback-journal-audit.mts';
|
|
4
5
|
import type { FeedbackCoverage, FeedbackReference, WorkOutcome } from './feedback-types.mts';
|
|
5
6
|
export type FeedbackAssessment = {
|
|
6
7
|
status: 'findings' | 'none-observed' | 'not-assessed' | 'unavailable';
|
|
@@ -28,7 +29,10 @@ export type RetrospectiveCompositionInput = {
|
|
|
28
29
|
narrative: string;
|
|
29
30
|
facts: Omit<RetrospectiveFactsOptions, 'raw'> | Unassessed;
|
|
30
31
|
transcript: ResolveOptions | Unassessed;
|
|
32
|
+
/** CI failures and sandbox audit from a friction log plus journal. Exclusive with `journal`. */
|
|
31
33
|
friction?: SessionFrictionReportOptions;
|
|
34
|
+
/** CI failures and sandbox audit from journal entries alone (`frictionStatus: 'journal-only'`). */
|
|
35
|
+
journal?: JournalAuditOptions;
|
|
32
36
|
tools: FeedbackAssessment;
|
|
33
37
|
architecture: FeedbackAssessment;
|
|
34
38
|
knownSensitiveValues?: string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { runRetrospectiveFactsReport, } from '../retrospective-facts/index.mjs';
|
|
2
2
|
import { runRetrospectiveTranscriptReport, } from '../retrospective-transcript/index.mjs';
|
|
3
|
-
import {
|
|
3
|
+
import { assertSingleAuditSource, auditAssessed, buildAuditReport, completeCoverageError, } from './feedback-audit-source.mjs';
|
|
4
4
|
import { createFeedbackEnvelope, redactFeedbackText } from './feedback-codec.mjs';
|
|
5
5
|
import { validateFeedbackText } from './feedback-fields.mjs';
|
|
6
6
|
function assessment(title, value) {
|
|
@@ -32,6 +32,7 @@ function unavailable(marker, input) {
|
|
|
32
32
|
return `${marker}\nStatus: ${input.status.replaceAll('-', ' ')} (${input.reason})`;
|
|
33
33
|
}
|
|
34
34
|
export async function composeRetrospective(input) {
|
|
35
|
+
assertSingleAuditSource(input);
|
|
35
36
|
const unavailableFacts = 'status' in input.facts
|
|
36
37
|
? {
|
|
37
38
|
markdown: unavailable('=== Retrospective Facts ===', input.facts),
|
|
@@ -44,34 +45,23 @@ export async function composeRetrospective(input) {
|
|
|
44
45
|
coverage: input.transcript.status,
|
|
45
46
|
}
|
|
46
47
|
: undefined;
|
|
47
|
-
const [facts, transcript,
|
|
48
|
+
const [facts, transcript, audit] = await Promise.all([
|
|
48
49
|
'status' in input.facts
|
|
49
50
|
? Promise.resolve(unavailableFacts)
|
|
50
51
|
: runRetrospectiveFactsReport({ ...input.facts, raw: false }),
|
|
51
52
|
'status' in input.transcript
|
|
52
53
|
? Promise.resolve(unavailableTranscript)
|
|
53
54
|
: runRetrospectiveTranscriptReport(input.transcript),
|
|
54
|
-
input.
|
|
55
|
-
? buildSessionFrictionReport(input.sessionId, input.friction)
|
|
56
|
-
: Promise.resolve({
|
|
57
|
-
coverage: {
|
|
58
|
-
journalStatus: 'unavailable',
|
|
59
|
-
frictionStatus: 'absent',
|
|
60
|
-
truncated: false,
|
|
61
|
-
},
|
|
62
|
-
markdown: '## CI Failures\nStatus: unavailable (not assessed)\n\n## Sandbox & Permission Audit\nStatus: unavailable (not assessed)',
|
|
63
|
-
}),
|
|
55
|
+
buildAuditReport(input.sessionId, input),
|
|
64
56
|
]);
|
|
65
57
|
if (input.feedbackCoverage.status === 'complete' &&
|
|
66
58
|
(facts.coverage !== 'complete' ||
|
|
67
59
|
transcript.coverage !== 'complete' ||
|
|
68
60
|
['not-assessed', 'unavailable'].includes(input.tools.status) ||
|
|
69
61
|
['not-assessed', 'unavailable'].includes(input.architecture.status) ||
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
throw new Error('complete feedback coverage requires assessed available factual and finding sources');
|
|
74
|
-
if ((friction.coverage.droppedCount ?? 0) > input.feedbackCoverage.droppedCount)
|
|
62
|
+
!auditAssessed(audit)))
|
|
63
|
+
throw completeCoverageError(input);
|
|
64
|
+
if ((audit.coverage.droppedCount ?? 0) > input.feedbackCoverage.droppedCount)
|
|
75
65
|
throw new Error('feedback coverage dropped count must include observed friction drops');
|
|
76
66
|
const markdown = [
|
|
77
67
|
'---',
|
|
@@ -88,7 +78,7 @@ export async function composeRetrospective(input) {
|
|
|
88
78
|
`## Outcome\nWork outcome: ${input.workOutcome}\nFeedback coverage: ${input.feedbackCoverage.status}\nDropped records: ${input.feedbackCoverage.droppedCount}`,
|
|
89
79
|
`## Verifiable Facts\n${facts.markdown.trim()}`,
|
|
90
80
|
`## Transcript Facts\n${transcript.markdown.trim()}`,
|
|
91
|
-
|
|
81
|
+
audit.markdown,
|
|
92
82
|
assessment('Tool Findings', input.tools),
|
|
93
83
|
assessment('Architecture Findings', input.architecture),
|
|
94
84
|
].join('\n\n');
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { JournalLoader, SessionFrictionCoverage } from '../session-friction/types.mts';
|
|
2
|
+
export type JournalAuditOptions = {
|
|
3
|
+
journalLoader: JournalLoader;
|
|
4
|
+
};
|
|
5
|
+
/** `journal-only` says both sections were assessed from journal entries, with no log observed. */
|
|
6
|
+
export type JournalAuditReport = {
|
|
7
|
+
coverage: {
|
|
8
|
+
journalStatus: SessionFrictionCoverage['journalStatus'];
|
|
9
|
+
frictionStatus: 'journal-only';
|
|
10
|
+
truncated: false;
|
|
11
|
+
droppedCount?: never;
|
|
12
|
+
};
|
|
13
|
+
markdown: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Builds `## CI Failures` and `## Sandbox & Permission Audit` from the session's journal entries
|
|
17
|
+
* alone. Unlike `buildSessionFrictionReport`, a session with no journal is unavailable rather than
|
|
18
|
+
* empty: without a log, nothing else establishes that the session was observed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildJournalAuditReport(sessionId: string, options: JournalAuditOptions): Promise<JournalAuditReport>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { buildCiFailuresSection, getConformingGroups, incompleteCiSection, } from '../session-friction/ci-failures.mjs';
|
|
2
|
+
import { scanJournal } from '../session-friction/journal.mjs';
|
|
3
|
+
import { validateSessionId } from '../session-friction/session-id.mjs';
|
|
4
|
+
import { getConformingSandboxBlocks, journalSandboxSection, unavailableSandboxSection, } from './feedback-journal-sandbox.mjs';
|
|
5
|
+
function report(journalStatus, markdown) {
|
|
6
|
+
return { coverage: { journalStatus, frictionStatus: 'journal-only', truncated: false }, markdown };
|
|
7
|
+
}
|
|
8
|
+
function unavailable(reason) {
|
|
9
|
+
return report('unavailable', `## CI Failures\nStatus: unavailable (${reason})\n\n${unavailableSandboxSection(reason)}`);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Builds `## CI Failures` and `## Sandbox & Permission Audit` from the session's journal entries
|
|
13
|
+
* alone. Unlike `buildSessionFrictionReport`, a session with no journal is unavailable rather than
|
|
14
|
+
* empty: without a log, nothing else establishes that the session was observed.
|
|
15
|
+
*/
|
|
16
|
+
export async function buildJournalAuditReport(sessionId, options) {
|
|
17
|
+
validateSessionId(sessionId);
|
|
18
|
+
const scanned = await scanJournal(sessionId, options.journalLoader);
|
|
19
|
+
if (scanned.status === 'unreachable')
|
|
20
|
+
return unavailable('blackboard unreachable');
|
|
21
|
+
if (scanned.status === 'not-found')
|
|
22
|
+
return unavailable('no journal for session');
|
|
23
|
+
const ci = getConformingGroups(scanned.entries);
|
|
24
|
+
const sandbox = getConformingSandboxBlocks(scanned.entries);
|
|
25
|
+
if (scanned.truncated)
|
|
26
|
+
return report('partial', `${incompleteCiSection(ci)}\n\n${unavailableSandboxSection('journal scan incomplete', sandbox)}`);
|
|
27
|
+
const journal = { status: 'ok', markdownBlocks: ci, truncated: false };
|
|
28
|
+
return report('complete', `${buildCiFailuresSection(sessionId, journal, 'journal-only')}\n\n${journalSandboxSection(sandbox)}`);
|
|
29
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { JournalEntry } from '../session-friction/types.mts';
|
|
2
|
+
/** Journal entries that hold exactly one sandbox or permission block, made paste-safe. */
|
|
3
|
+
export declare function getConformingSandboxBlocks(entries: Iterable<JournalEntry>): string[];
|
|
4
|
+
export declare function unavailableSandboxSection(reason: string, blocks?: string[]): string;
|
|
5
|
+
export declare function journalSandboxSection(blocks: string[]): string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { conformingBlocks, matchAuditBlock } from '../session-friction/audit-block.mjs';
|
|
2
|
+
const SANDBOX_SECTION_HEADER = '## Sandbox & Permission Audit';
|
|
3
|
+
const SOURCE = 'journal entries only; no friction log observed';
|
|
4
|
+
const EVIDENCE = /^ {2}- Evidence: .*[^\s]$/;
|
|
5
|
+
const DISPOSITION = /^ {2}- Disposition: .*[^\s]$/;
|
|
6
|
+
const ESCALATION = [
|
|
7
|
+
/^- `sandbox-escalation` — .+ — .*[^\s]$/,
|
|
8
|
+
/^ {2}- Outcome: (?:requested|approved|denied|unknown)$/,
|
|
9
|
+
EVIDENCE,
|
|
10
|
+
DISPOSITION,
|
|
11
|
+
];
|
|
12
|
+
const FAILURE = [
|
|
13
|
+
/^- `(?:sandbox-failure|ambiguous-failure)` — .+ — .*[^\s]$/,
|
|
14
|
+
EVIDENCE,
|
|
15
|
+
DISPOSITION,
|
|
16
|
+
];
|
|
17
|
+
const FIELD_PREFIXES = [
|
|
18
|
+
'- `sandbox-escalation` — ',
|
|
19
|
+
'- `sandbox-failure` — ',
|
|
20
|
+
'- `ambiguous-failure` — ',
|
|
21
|
+
' - Outcome: ',
|
|
22
|
+
' - Evidence: ',
|
|
23
|
+
' - Disposition: ',
|
|
24
|
+
];
|
|
25
|
+
function matchBlock(markdown) {
|
|
26
|
+
return (matchAuditBlock(markdown, ESCALATION, FIELD_PREFIXES) ??
|
|
27
|
+
matchAuditBlock(markdown, FAILURE, FIELD_PREFIXES));
|
|
28
|
+
}
|
|
29
|
+
/** Journal entries that hold exactly one sandbox or permission block, made paste-safe. */
|
|
30
|
+
export function getConformingSandboxBlocks(entries) {
|
|
31
|
+
return conformingBlocks(entries, matchBlock);
|
|
32
|
+
}
|
|
33
|
+
export function unavailableSandboxSection(reason, blocks = []) {
|
|
34
|
+
return [`${SANDBOX_SECTION_HEADER}\nStatus: unavailable (${reason})`, ...blocks].join('\n\n');
|
|
35
|
+
}
|
|
36
|
+
export function journalSandboxSection(blocks) {
|
|
37
|
+
if (blocks.length === 0)
|
|
38
|
+
return `${SANDBOX_SECTION_HEADER}\nStatus: none observed (${SOURCE})`;
|
|
39
|
+
return `${SANDBOX_SECTION_HEADER}\nStatus: events observed (${SOURCE})\n\n${blocks.join('\n\n')}`;
|
|
40
|
+
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FeedbackDeliveryResult } from './feedback-types.mts';
|
|
2
|
+
import { type JournalInput } from './journal.mts';
|
|
2
3
|
import { type BlackboardClientDependencies } from './client.mts';
|
|
3
4
|
export { cleanupSnapshotPartitions, partitionSnapshot } from './snapshot.mts';
|
|
4
5
|
export { assertSessionId } from './session-id.mts';
|
|
6
|
+
export { appendJournalMarkdown } from './journal.mts';
|
|
7
|
+
export type { JournalInput } from './journal.mts';
|
|
8
|
+
export { archiveBlackboardSession, ensureBlackboardSession, exportSnapshot, } from './session-tools.mts';
|
|
9
|
+
export type { EnsureSessionOutcome, SnapshotExportOutcome } from './session-tools.mts';
|
|
5
10
|
export type * from './snapshot-types.mts';
|
|
6
11
|
export declare function probeBlackboard(env?: NodeJS.ProcessEnv, dependencies?: BlackboardClientDependencies): Promise<void>;
|
|
7
|
-
export declare function appendJournal(input:
|
|
8
|
-
repositories: string[];
|
|
12
|
+
export declare function appendJournal(input: JournalInput & {
|
|
9
13
|
markdownFile: string;
|
|
10
|
-
sourceEventId: string;
|
|
11
|
-
workOutcome: WorkOutcome;
|
|
12
|
-
feedbackCoverage: FeedbackCoverage;
|
|
13
|
-
timestamp?: string;
|
|
14
|
-
category?: string;
|
|
15
14
|
}): Promise<FeedbackDeliveryResult>;
|
|
16
15
|
export declare function readJournal(sessionId: string, env?: NodeJS.ProcessEnv, dependencies?: BlackboardClientDependencies): Promise<unknown[]>;
|
|
17
16
|
export declare function formatJournalEntries(sessionId: string, entries: unknown[]): string;
|
|
@@ -23,3 +22,5 @@ export { writeFeedback, verifyFreshFeedback, flushFeedbackOutbox, FeedbackDelive
|
|
|
23
22
|
export { feedbackOutboxStatus } from './feedback-outbox.mts';
|
|
24
23
|
export { composeRetrospective } from './feedback-compose.mts';
|
|
25
24
|
export type { RetrospectiveCompositionInput, FeedbackAssessment } from './feedback-compose.mts';
|
|
25
|
+
export type { JournalAuditOptions } from './feedback-journal-audit.mts';
|
|
26
|
+
export type { JournalEntry, JournalLoader, JournalLoadResult } from '../session-friction/types.mts';
|
|
@@ -1,55 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { writeFeedback } from './feedback-delivery.mjs';
|
|
1
|
+
import { appendJournalMarkdown, checkJournalInput } from './journal.mjs';
|
|
3
2
|
import { loadClient, resolveBlackboardConnection, } from './client.mjs';
|
|
4
3
|
import { readFile } from 'node:fs/promises';
|
|
5
4
|
import { assertSessionId } from './session-id.mjs';
|
|
6
5
|
export { cleanupSnapshotPartitions, partitionSnapshot } from './snapshot.mjs';
|
|
7
6
|
export { assertSessionId } from './session-id.mjs';
|
|
7
|
+
export { appendJournalMarkdown } from './journal.mjs';
|
|
8
|
+
export { archiveBlackboardSession, ensureBlackboardSession, exportSnapshot, } from './session-tools.mjs';
|
|
8
9
|
export async function probeBlackboard(env, dependencies) {
|
|
9
10
|
const { Sessions } = await loadClient(dependencies);
|
|
10
11
|
await new Sessions(resolveBlackboardConnection(env)).list({ limit: 1 });
|
|
11
12
|
}
|
|
12
13
|
export async function appendJournal(input) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
assertSessionId(input.parentSessionId, 'parent session id');
|
|
16
|
-
const repositories = normalizeRepositories(input.repositories);
|
|
17
|
-
const timestamp = input.timestamp === undefined ? new Date() : new Date(input.timestamp);
|
|
18
|
-
if (Number.isNaN(timestamp.valueOf()))
|
|
19
|
-
throw new Error('journal timestamp is not a valid date-time');
|
|
14
|
+
const { markdownFile, ...journal } = input;
|
|
15
|
+
checkJournalInput(journal);
|
|
20
16
|
let markdown;
|
|
21
17
|
try {
|
|
22
|
-
markdown = new TextDecoder('utf-8', { fatal: true }).decode(await readFile(
|
|
18
|
+
markdown = new TextDecoder('utf-8', { fatal: true }).decode(await readFile(markdownFile));
|
|
23
19
|
}
|
|
24
20
|
catch {
|
|
25
21
|
throw new Error('note file is not valid UTF-8 or cannot be read');
|
|
26
22
|
}
|
|
27
23
|
if (!markdown)
|
|
28
24
|
throw new Error('note file is empty');
|
|
29
|
-
return
|
|
30
|
-
identity: {
|
|
31
|
-
sessionId: input.sessionId,
|
|
32
|
-
parentSessionId: input.parentSessionId,
|
|
33
|
-
agent: input.agent,
|
|
34
|
-
version: input.version,
|
|
35
|
-
},
|
|
36
|
-
envelope: createFeedbackEnvelope({
|
|
37
|
-
schemaVersion: 1,
|
|
38
|
-
type: 'journal',
|
|
39
|
-
sourceEventId: input.sourceEventId,
|
|
40
|
-
timestamp: timestamp.toISOString(),
|
|
41
|
-
repositories,
|
|
42
|
-
markdown,
|
|
43
|
-
workOutcome: input.workOutcome,
|
|
44
|
-
feedbackCoverage: input.feedbackCoverage,
|
|
45
|
-
...(input.category === undefined ? {} : { category: input.category }),
|
|
46
|
-
}),
|
|
47
|
-
mode: input.mode,
|
|
48
|
-
...(input.outboxDirectory === undefined ? {} : { outboxDirectory: input.outboxDirectory }),
|
|
49
|
-
...(input.env === undefined ? {} : { env: input.env }),
|
|
50
|
-
...(input.dependencies === undefined ? {} : { dependencies: input.dependencies }),
|
|
51
|
-
...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
|
|
52
|
-
});
|
|
25
|
+
return appendJournalMarkdown({ ...journal, markdown });
|
|
53
26
|
}
|
|
54
27
|
export async function readJournal(sessionId, env, dependencies) {
|
|
55
28
|
assertSessionId(sessionId);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FeedbackCoverage, FeedbackDeliveryOptions, FeedbackDeliveryResult, FeedbackIdentity, WorkOutcome } from './feedback-types.mts';
|
|
2
|
+
export type JournalInput = Omit<FeedbackDeliveryOptions, 'identity' | 'envelope'> & FeedbackIdentity & {
|
|
3
|
+
repositories: string[];
|
|
4
|
+
sourceEventId: string;
|
|
5
|
+
workOutcome: WorkOutcome;
|
|
6
|
+
feedbackCoverage: FeedbackCoverage;
|
|
7
|
+
timestamp?: string;
|
|
8
|
+
category?: string;
|
|
9
|
+
};
|
|
10
|
+
/** Validates the identity, repositories, and timestamp before any note text is read. */
|
|
11
|
+
export declare function checkJournalInput(input: JournalInput): {
|
|
12
|
+
repositories: string[];
|
|
13
|
+
timestamp: Date;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Appends a journal entry whose markdown is already in memory. `appendJournal` reads a note file
|
|
17
|
+
* and delegates here; callers that hold the text (for example the MCP server) skip the file.
|
|
18
|
+
*/
|
|
19
|
+
export declare function appendJournalMarkdown(input: JournalInput & {
|
|
20
|
+
markdown: string;
|
|
21
|
+
}): Promise<FeedbackDeliveryResult>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createFeedbackEnvelope, normalizeRepositories } from './feedback-codec.mjs';
|
|
2
|
+
import { writeFeedback } from './feedback-delivery.mjs';
|
|
3
|
+
import { assertSessionId } from './session-id.mjs';
|
|
4
|
+
/** Validates the identity, repositories, and timestamp before any note text is read. */
|
|
5
|
+
export function checkJournalInput(input) {
|
|
6
|
+
assertSessionId(input.sessionId);
|
|
7
|
+
if (input.parentSessionId != null)
|
|
8
|
+
assertSessionId(input.parentSessionId, 'parent session id');
|
|
9
|
+
const repositories = normalizeRepositories(input.repositories);
|
|
10
|
+
const timestamp = input.timestamp === undefined ? new Date() : new Date(input.timestamp);
|
|
11
|
+
if (Number.isNaN(timestamp.valueOf()))
|
|
12
|
+
throw new Error('journal timestamp is not a valid date-time');
|
|
13
|
+
return { repositories, timestamp };
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Appends a journal entry whose markdown is already in memory. `appendJournal` reads a note file
|
|
17
|
+
* and delegates here; callers that hold the text (for example the MCP server) skip the file.
|
|
18
|
+
*/
|
|
19
|
+
export async function appendJournalMarkdown(input) {
|
|
20
|
+
const { repositories, timestamp } = checkJournalInput(input);
|
|
21
|
+
return writeFeedback({
|
|
22
|
+
identity: {
|
|
23
|
+
sessionId: input.sessionId,
|
|
24
|
+
parentSessionId: input.parentSessionId,
|
|
25
|
+
agent: input.agent,
|
|
26
|
+
version: input.version,
|
|
27
|
+
},
|
|
28
|
+
envelope: createFeedbackEnvelope({
|
|
29
|
+
schemaVersion: 1,
|
|
30
|
+
type: 'journal',
|
|
31
|
+
sourceEventId: input.sourceEventId,
|
|
32
|
+
timestamp: timestamp.toISOString(),
|
|
33
|
+
repositories,
|
|
34
|
+
markdown: input.markdown,
|
|
35
|
+
workOutcome: input.workOutcome,
|
|
36
|
+
feedbackCoverage: input.feedbackCoverage,
|
|
37
|
+
...(input.category === undefined ? {} : { category: input.category }),
|
|
38
|
+
}),
|
|
39
|
+
mode: input.mode,
|
|
40
|
+
...(input.outboxDirectory === undefined ? {} : { outboxDirectory: input.outboxDirectory }),
|
|
41
|
+
...(input.env === undefined ? {} : { env: input.env }),
|
|
42
|
+
...(input.dependencies === undefined ? {} : { dependencies: input.dependencies }),
|
|
43
|
+
...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type BlackboardClientDependencies } from './client.mts';
|
|
2
|
+
import type { FeedbackIdentity } from './feedback-types.mts';
|
|
3
|
+
import type { SnapshotChecksum, SnapshotCounts, SnapshotManifest, SnapshotSelection } from './snapshot-types.mts';
|
|
4
|
+
type ClientOptions = {
|
|
5
|
+
env?: NodeJS.ProcessEnv;
|
|
6
|
+
dependencies?: BlackboardClientDependencies;
|
|
7
|
+
};
|
|
8
|
+
export type EnsureSessionOutcome = {
|
|
9
|
+
sessionId: string;
|
|
10
|
+
status: 'created' | 'exists';
|
|
11
|
+
archived: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type SnapshotExportOutcome = {
|
|
14
|
+
path: string;
|
|
15
|
+
counts: SnapshotCounts;
|
|
16
|
+
checksum: SnapshotChecksum;
|
|
17
|
+
manifest: SnapshotManifest;
|
|
18
|
+
cleanupToken?: string;
|
|
19
|
+
};
|
|
20
|
+
/** Idempotently creates the session; an existing session must match the supplied identity. */
|
|
21
|
+
export declare function ensureBlackboardSession(input: FeedbackIdentity & ClientOptions): Promise<EnsureSessionOutcome>;
|
|
22
|
+
/** Marks a session distilled. Metadata becomes immutable; entries stay appendable. */
|
|
23
|
+
export declare function archiveBlackboardSession(input: {
|
|
24
|
+
sessionId: string;
|
|
25
|
+
} & ClientOptions): Promise<{
|
|
26
|
+
sessionId: string;
|
|
27
|
+
archived: true;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Exports a snapshot into a private file the client generates. Callers cannot choose the
|
|
31
|
+
* destination, so a long-lived process with credentials never writes to an agent-chosen path.
|
|
32
|
+
*/
|
|
33
|
+
export declare function exportSnapshot(input: {
|
|
34
|
+
selection?: SnapshotSelection;
|
|
35
|
+
} & ClientOptions): Promise<SnapshotExportOutcome>;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { loadClient, resolveBlackboardConnection, } from './client.mjs';
|
|
2
|
+
import { validateFeedbackIdentity } from './feedback-identity.mjs';
|
|
3
|
+
import { assertSessionId } from './session-id.mjs';
|
|
4
|
+
import { isObject } from './snapshot-partition-guards.mjs';
|
|
5
|
+
const UPGRADE_HINT = 'upgrade agent-blackboard in the consumer package';
|
|
6
|
+
/** Idempotently creates the session; an existing session must match the supplied identity. */
|
|
7
|
+
export async function ensureBlackboardSession(input) {
|
|
8
|
+
const { sessionId, parentSessionId, agent, version } = input;
|
|
9
|
+
validateFeedbackIdentity({ sessionId, parentSessionId, agent, version });
|
|
10
|
+
const { Sessions } = await loadClient(input.dependencies);
|
|
11
|
+
const { status, session } = await new Sessions(resolveBlackboardConnection(input.env)).ensure({
|
|
12
|
+
id: sessionId,
|
|
13
|
+
parentSessionId,
|
|
14
|
+
agent,
|
|
15
|
+
version,
|
|
16
|
+
});
|
|
17
|
+
return { sessionId, status, archived: session.archivedAt != null };
|
|
18
|
+
}
|
|
19
|
+
/** Marks a session distilled. Metadata becomes immutable; entries stay appendable. */
|
|
20
|
+
export async function archiveBlackboardSession(input) {
|
|
21
|
+
assertSessionId(input.sessionId);
|
|
22
|
+
const { Sessions } = await loadClient(input.dependencies);
|
|
23
|
+
const sessions = new Sessions(resolveBlackboardConnection(input.env));
|
|
24
|
+
if (typeof sessions.archive !== 'function')
|
|
25
|
+
throw new Error(`the installed agent-blackboard client cannot archive sessions; ${UPGRADE_HINT}`);
|
|
26
|
+
await sessions.archive(input.sessionId);
|
|
27
|
+
return { sessionId: input.sessionId, archived: true };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Exports a snapshot into a private file the client generates. Callers cannot choose the
|
|
31
|
+
* destination, so a long-lived process with credentials never writes to an agent-chosen path.
|
|
32
|
+
*/
|
|
33
|
+
export async function exportSnapshot(input) {
|
|
34
|
+
const { Snapshots } = await loadClient(input.dependencies);
|
|
35
|
+
if (!Snapshots)
|
|
36
|
+
throw new Error(`the installed agent-blackboard client cannot export snapshots; ${UPGRADE_HINT}`);
|
|
37
|
+
const result = await new Snapshots(resolveBlackboardConnection(input.env)).export(input.selection === undefined ? {} : { selection: input.selection });
|
|
38
|
+
if (!isObject(result) || typeof result.path !== 'string')
|
|
39
|
+
throw new Error('agent-blackboard returned an unexpected snapshot export result');
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `vouchington mcp`: serves the agent-blackboard journal tools over stdio. It resolves once the
|
|
3
|
+
* server is connected; the open stdin keeps the process alive until the client disconnects.
|
|
4
|
+
*/
|
|
5
|
+
export declare function runMcpCommand(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { runMcpServer } from '../../mcp-server/run.mjs';
|
|
2
|
+
import { readInstalledVersion } from '../installed-version.mjs';
|
|
3
|
+
/**
|
|
4
|
+
* `vouchington mcp`: serves the agent-blackboard journal tools over stdio. It resolves once the
|
|
5
|
+
* server is connected; the open stdin keeps the process alive until the client disconnects.
|
|
6
|
+
*/
|
|
7
|
+
export async function runMcpCommand(args) {
|
|
8
|
+
try {
|
|
9
|
+
if (args.length > 0)
|
|
10
|
+
throw new Error('usage: vouchington mcp (takes no arguments; it serves stdio)');
|
|
11
|
+
await runMcpServer({ cwd: process.cwd(), env: process.env, version: readInstalledVersion() });
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
5
|
import { runAgentHarnessConfigCli } from '../agent-harness-config/cli.mjs';
|
|
6
6
|
import { runPostReviewCli } from '../gha-post-review/cli.mjs';
|
|
7
7
|
import { runStageReviewPayloadCli } from '../gha-review-payload/cli.mjs';
|
|
8
|
-
import { readPackageVersion } from '../package-version.mjs';
|
|
9
8
|
import { runSwiftSemanticEqualCli } from '../swift-semantic-equal/cli.mjs';
|
|
10
9
|
import { runGhaArtifactsCleanup } from './commands/gha-artifacts-cleanup.mjs';
|
|
11
10
|
import { runGhaRuntimeAudit } from './commands/gha-runtime-audit.mjs';
|
|
@@ -21,11 +20,13 @@ import { runRetrospectiveTranscriptCommand } from './commands/retrospective-tran
|
|
|
21
20
|
import { runLinkSkill } from './commands/link-skill.mjs';
|
|
22
21
|
import { runRetrospectiveFactsCommand } from './commands/retrospective-facts.mjs';
|
|
23
22
|
import { runAgentBlackboardCommand } from './commands/agent-blackboard.mjs';
|
|
23
|
+
import { runMcpCommand } from './commands/mcp.mjs';
|
|
24
24
|
import { runWithHostLock } from './commands/with-host-lock.mjs';
|
|
25
25
|
import { runRequireUpToDate } from './commands/require-up-to-date.mjs';
|
|
26
26
|
import { runAstGrepExamplesCommand } from './commands/ast-grep-examples.mjs';
|
|
27
27
|
import { runAstGrepPackCommand } from './commands/ast-grep-pack.mjs';
|
|
28
28
|
import { runGhaWorkspacePolicy } from './commands/gha-workspace-policy.mjs';
|
|
29
|
+
import { readInstalledVersion } from './installed-version.mjs';
|
|
29
30
|
import { parseCli } from './parse.mjs';
|
|
30
31
|
import { packageScriptPath } from './script-path.mjs';
|
|
31
32
|
import { commandUsage, printUsage } from './usage.mjs';
|
|
@@ -129,6 +130,8 @@ export function runCli(argv = process.argv) {
|
|
|
129
130
|
return runRetrospectiveFactsCommand(parsed.args);
|
|
130
131
|
case 'agent-blackboard':
|
|
131
132
|
return runAgentBlackboardCommand(parsed.args);
|
|
133
|
+
case 'mcp':
|
|
134
|
+
return runMcpCommand(parsed.args);
|
|
132
135
|
case 'require-up-to-date':
|
|
133
136
|
return runRequireUpToDate(parsed);
|
|
134
137
|
case 'gitleaks-directory-scan':
|
|
@@ -145,9 +148,6 @@ export function runCli(argv = process.argv) {
|
|
|
145
148
|
return runGhaWorkspacePolicy(parsed);
|
|
146
149
|
}
|
|
147
150
|
}
|
|
148
|
-
function readInstalledVersion() {
|
|
149
|
-
return readPackageVersion(JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8')));
|
|
150
|
-
}
|
|
151
151
|
export function isMainModule(metaUrl, argv1) {
|
|
152
152
|
if (argv1 === undefined)
|
|
153
153
|
return false;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function readInstalledVersion(): string;
|