runbrief 0.1.1 → 0.1.3
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 +25 -3
- package/dist/cli.js +1501 -691
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ var __esm = (fn, res) => function __init() {
|
|
|
6
6
|
|
|
7
7
|
// ../contracts/dist/index.js
|
|
8
8
|
import { z } from "zod";
|
|
9
|
-
var privacyModeSchema, enforcementSchema, skillStatusSchema, learningStatusSchema, findingSeveritySchema, prReadinessVerdictSchema, preCodingContextProofSchema, prReadinessCheckStatusSchema, prReadinessGateIdSchema, prReadinessGateStatusSchema, prReadinessStatusSchema, prReadinessDeliveryModeSchema, githubCheckConclusionSchema, agentSurfaceModeSchema, agentSurfaceCategorySchema, agentSurfaceCredentialStorageSchema, agentSurfaceRepoResolutionSchema, agentSurfaceTrustBoundarySchema, briefProofStateSchema, briefToolNameSchema, agentSurfaceContractSchema, briefRunPhaseSchema, briefRunContractSchema, briefProofContractSchema, repoRefSchema, scanStatsSchema, sourceDocumentSchema, ruleSchema, betaReadinessSchema, skillSchema, mapNodeSchema, reviewMemorySchema, wikiEvidenceItemSchema, wikiPageTypeSchema, wikiPageEvidenceMixSchema, wikiPageEntitySchema, wikiPageFreshnessSchema, wikiPageSourceProofSchema, wikiPageAgentBriefSchema, wikiPageQualitySchema, wikiPageSchema, prReadinessFindingSchema, prReadinessPullRequestSchema, prReadinessContextProofInputSchema, prReadinessCheckSchema, prReadinessGateResultSchema, prReadinessContractSchema, prReadinessReportRequestSchema, severityCountsSchema, prReadinessAnnotationSchema, prReadinessGithubCheckSchema, prReadinessReportSchema, prReadinessReportResponseSchema, repoScanSummarySchema, syncScanRequestSchema, teamGuidanceItemSchema, teamGuidanceDeliverySchema, contextPacketSchema, contextReceiptRequestSchema, missionRecipeIdSchema, missionWorkItemSchema, missionRuntimeEvidenceSchema, runtimeEvidencePullInstructionSchema, runtimeEvidencePacketSchema, missionHandoffValidationSchema, missionHandoffReviewReadinessSchema, missionHandoffReviewSchema, missionHandoffProofStatusSchema, missionHandoffValidationSummarySchema, missionHandoffArtifactEvidenceSchema, missionHandoffArtifactProofSchema, missionHandoffChangedFileAttributionSchema, missionHandoffProofBundleSchema, missionHandoffRequestSchema, evidenceRedactionFindingSchema, evidenceRedactionReportSchema, learningCreateRequestSchema, teamContextRequestSchema, teamContextResponseSchema, apiAcceptedResponseSchema;
|
|
9
|
+
var privacyModeSchema, loopRunStatusSchema, loopRunProofSchema, loopRunSummarySchema, createLoopRunRequestSchema, claimLoopRunRequestSchema, updateLoopRunRequestSchema, enforcementSchema, skillStatusSchema, learningStatusSchema, findingSeveritySchema, prReadinessVerdictSchema, preCodingContextProofSchema, prReadinessCheckStatusSchema, prReadinessGateIdSchema, prReadinessGateStatusSchema, prReadinessStatusSchema, prReadinessDeliveryModeSchema, githubCheckConclusionSchema, agentSurfaceModeSchema, agentSurfaceCategorySchema, agentSurfaceCredentialStorageSchema, agentSurfaceRepoResolutionSchema, agentSurfaceTrustBoundarySchema, briefProofStateSchema, briefToolNameSchema, agentSurfaceContractSchema, briefRunPhaseSchema, briefRunContractSchema, briefProofContractSchema, repoRefSchema, scanStatsSchema, sourceDocumentSchema, ruleSchema, betaReadinessSchema, skillSchema, mapNodeSchema, reviewMemorySchema, wikiEvidenceItemSchema, wikiPageTypeSchema, wikiPageEvidenceMixSchema, wikiPageEntitySchema, wikiPageFreshnessSchema, wikiPageSourceProofSchema, wikiPageAgentBriefSchema, wikiPageQualitySchema, wikiPageSchema, prReadinessFindingSchema, prReadinessPullRequestSchema, prReadinessContextProofInputSchema, prReadinessCheckSchema, prReadinessGateResultSchema, prReadinessContractSchema, prReadinessReportRequestSchema, severityCountsSchema, prReadinessAnnotationSchema, prReadinessGithubCheckSchema, prReadinessReportSchema, prReadinessReportResponseSchema, repoScanSummarySchema, syncScanRequestSchema, teamGuidanceItemSchema, teamGuidanceDeliverySchema, dependencyPackageSignalSchema, dependencyRemediationSchema, contextPacketSchema, contextReceiptRequestSchema, missionRecipeIdSchema, missionWorkItemSchema, missionRuntimeEvidenceSchema, runtimeEvidencePullInstructionSchema, runtimeEvidencePacketSchema, missionHandoffValidationSchema, missionHandoffReviewReadinessSchema, missionHandoffReviewSchema, missionHandoffProofStatusSchema, missionHandoffValidationSummarySchema, missionHandoffArtifactEvidenceSchema, missionHandoffArtifactProofSchema, missionHandoffChangedFileAttributionSchema, missionHandoffProofBundleSchema, missionHandoffRequestSchema, evidenceRedactionFindingSchema, evidenceRedactionReportSchema, learningCreateRequestSchema, teamContextRequestSchema, teamContextResponseSchema, apiAcceptedResponseSchema;
|
|
10
10
|
var init_dist = __esm({
|
|
11
11
|
"../contracts/dist/index.js"() {
|
|
12
12
|
"use strict";
|
|
@@ -15,6 +15,56 @@ var init_dist = __esm({
|
|
|
15
15
|
"cloud-sync-derived",
|
|
16
16
|
"team-cloud"
|
|
17
17
|
]);
|
|
18
|
+
loopRunStatusSchema = z.enum([
|
|
19
|
+
"queued",
|
|
20
|
+
"running",
|
|
21
|
+
"succeeded",
|
|
22
|
+
"failed",
|
|
23
|
+
"cancelled"
|
|
24
|
+
]);
|
|
25
|
+
loopRunProofSchema = z.record(z.string(), z.unknown());
|
|
26
|
+
loopRunSummarySchema = z.object({
|
|
27
|
+
id: z.string().uuid(),
|
|
28
|
+
workspaceId: z.string().uuid(),
|
|
29
|
+
loopId: z.string().uuid(),
|
|
30
|
+
loopName: z.string().min(1),
|
|
31
|
+
loopBody: z.string().min(1),
|
|
32
|
+
guardrails: z.array(z.string().min(1)).max(30),
|
|
33
|
+
loopVersion: z.number().int().positive(),
|
|
34
|
+
task: z.string().min(1).max(12e3),
|
|
35
|
+
repoFullName: z.string().min(1).max(240).optional(),
|
|
36
|
+
autonomy: z.enum(["read_only", "repo_edit", "validate", "handoff"]),
|
|
37
|
+
status: loopRunStatusSchema,
|
|
38
|
+
attemptCount: z.number().int().nonnegative(),
|
|
39
|
+
runnerId: z.string().min(1).max(160).nullable(),
|
|
40
|
+
leaseExpiresAt: z.string().datetime().nullable(),
|
|
41
|
+
lastEvent: z.string().max(2e3).nullable(),
|
|
42
|
+
resultSummary: z.string().max(12e3).nullable(),
|
|
43
|
+
proof: loopRunProofSchema,
|
|
44
|
+
errorMessage: z.string().max(4e3).nullable(),
|
|
45
|
+
createdAt: z.string().datetime(),
|
|
46
|
+
startedAt: z.string().datetime().nullable(),
|
|
47
|
+
completedAt: z.string().datetime().nullable()
|
|
48
|
+
});
|
|
49
|
+
createLoopRunRequestSchema = z.object({
|
|
50
|
+
loopId: z.string().uuid(),
|
|
51
|
+
task: z.string().trim().min(1).max(12e3),
|
|
52
|
+
repoFullName: z.string().trim().min(1).max(240).optional(),
|
|
53
|
+
idempotencyKey: z.string().trim().min(16).max(160)
|
|
54
|
+
});
|
|
55
|
+
claimLoopRunRequestSchema = z.object({
|
|
56
|
+
runnerId: z.string().trim().min(1).max(160),
|
|
57
|
+
leaseSeconds: z.number().int().min(30).max(900).default(180)
|
|
58
|
+
});
|
|
59
|
+
updateLoopRunRequestSchema = z.object({
|
|
60
|
+
runnerId: z.string().trim().min(1).max(160),
|
|
61
|
+
status: loopRunStatusSchema,
|
|
62
|
+
lastEvent: z.string().trim().max(2e3).optional(),
|
|
63
|
+
resultSummary: z.string().trim().max(12e3).optional(),
|
|
64
|
+
proof: loopRunProofSchema.optional(),
|
|
65
|
+
errorMessage: z.string().trim().max(4e3).optional(),
|
|
66
|
+
leaseSeconds: z.number().int().min(30).max(900).optional()
|
|
67
|
+
});
|
|
18
68
|
enforcementSchema = z.enum([
|
|
19
69
|
"advisory",
|
|
20
70
|
"warn",
|
|
@@ -621,6 +671,46 @@ var init_dist = __esm({
|
|
|
621
671
|
applied: z.array(teamGuidanceItemSchema).max(100),
|
|
622
672
|
omittedCount: z.number().int().nonnegative()
|
|
623
673
|
});
|
|
674
|
+
dependencyPackageSignalSchema = z.object({
|
|
675
|
+
name: z.string().min(1).max(160),
|
|
676
|
+
changeKind: z.enum([
|
|
677
|
+
"patch_or_minor",
|
|
678
|
+
"major",
|
|
679
|
+
"added_or_overridden",
|
|
680
|
+
"unknown"
|
|
681
|
+
]),
|
|
682
|
+
manifestPaths: z.array(z.string().min(1).max(500)).max(20),
|
|
683
|
+
lockfilePaths: z.array(z.string().min(1).max(500)).max(20),
|
|
684
|
+
evidence: z.array(z.string().min(1).max(120)).max(10)
|
|
685
|
+
});
|
|
686
|
+
dependencyRemediationSchema = z.object({
|
|
687
|
+
id: z.string().min(1).max(120),
|
|
688
|
+
status: z.enum(["ready", "needs_evidence"]),
|
|
689
|
+
packageManager: z.enum([
|
|
690
|
+
"pnpm",
|
|
691
|
+
"npm",
|
|
692
|
+
"yarn",
|
|
693
|
+
"bun",
|
|
694
|
+
"pip",
|
|
695
|
+
"bundler",
|
|
696
|
+
"go",
|
|
697
|
+
"cargo",
|
|
698
|
+
"unknown"
|
|
699
|
+
]),
|
|
700
|
+
manifestFiles: z.array(z.string().min(1).max(500)).max(30),
|
|
701
|
+
lockfiles: z.array(z.string().min(1).max(500)).max(20),
|
|
702
|
+
workspaceFiles: z.array(z.string().min(1).max(500)).max(20),
|
|
703
|
+
changedDependencyFiles: z.array(z.string().min(1).max(500)).max(30),
|
|
704
|
+
directDependencyFiles: z.array(z.string().min(1).max(500)).max(30),
|
|
705
|
+
packageSignals: z.array(dependencyPackageSignalSchema).max(20),
|
|
706
|
+
graphCommands: z.array(z.string().min(1).max(500)).max(20),
|
|
707
|
+
remediationCommands: z.array(z.string().min(1).max(500)).max(20),
|
|
708
|
+
validationCommands: z.array(z.string().min(1).max(500)).max(20),
|
|
709
|
+
residualRiskChecks: z.array(z.string().min(1).max(800)).max(20),
|
|
710
|
+
handoffRequirements: z.array(z.string().min(1).max(800)).max(20),
|
|
711
|
+
summary: z.string().max(1200),
|
|
712
|
+
confidence: z.number().min(0).max(100)
|
|
713
|
+
});
|
|
624
714
|
contextPacketSchema = z.object({
|
|
625
715
|
packetId: z.string().min(1),
|
|
626
716
|
createdAt: z.string().datetime(),
|
|
@@ -643,7 +733,8 @@ var init_dist = __esm({
|
|
|
643
733
|
appliedTeamGuidanceCount: z.number().int().nonnegative(),
|
|
644
734
|
suggestedTestCount: z.number().int().nonnegative()
|
|
645
735
|
}).optional(),
|
|
646
|
-
teamGuidance: teamGuidanceDeliverySchema.optional()
|
|
736
|
+
teamGuidance: teamGuidanceDeliverySchema.optional(),
|
|
737
|
+
dependencyRemediation: dependencyRemediationSchema.optional()
|
|
647
738
|
});
|
|
648
739
|
contextReceiptRequestSchema = z.object({
|
|
649
740
|
workspaceId: z.string().uuid().optional(),
|
|
@@ -5296,22 +5387,22 @@ function likelyRuleLine(line) {
|
|
|
5296
5387
|
return hasStrongRule || hasOperationalRule;
|
|
5297
5388
|
}
|
|
5298
5389
|
function scopeFromPath(sourcePath, kind) {
|
|
5299
|
-
const
|
|
5300
|
-
const directoryScope = scopedDirectory(
|
|
5301
|
-
if (directoryScope && (
|
|
5390
|
+
const path21 = sourcePath.replaceAll("\\", "/");
|
|
5391
|
+
const directoryScope = scopedDirectory(path21);
|
|
5392
|
+
if (directoryScope && (path21.endsWith("/AGENTS.md") || path21.endsWith("/CLAUDE.md")))
|
|
5302
5393
|
return [directoryScope];
|
|
5303
|
-
if (
|
|
5394
|
+
if (path21.includes("client/") || kind === "frontend")
|
|
5304
5395
|
return ["client/**", "packages/ui/**"];
|
|
5305
|
-
if (
|
|
5396
|
+
if (path21.includes("server/") || kind === "persistence")
|
|
5306
5397
|
return ["server/**"];
|
|
5307
|
-
if (
|
|
5398
|
+
if (path21.includes(".github/") || kind === "workflow")
|
|
5308
5399
|
return ["**/*"];
|
|
5309
|
-
if (
|
|
5400
|
+
if (path21.includes("test") || kind === "testing")
|
|
5310
5401
|
return ["**/*.test.*", "**/*.spec.*", "tests/**"];
|
|
5311
5402
|
return ["**/*"];
|
|
5312
5403
|
}
|
|
5313
|
-
function scopedDirectory(
|
|
5314
|
-
const parts =
|
|
5404
|
+
function scopedDirectory(path21) {
|
|
5405
|
+
const parts = path21.split("/");
|
|
5315
5406
|
if (parts.length <= 1)
|
|
5316
5407
|
return null;
|
|
5317
5408
|
const directory = parts.slice(0, -1).join("/");
|
|
@@ -7491,15 +7582,15 @@ function criticalPathBoost(filePath) {
|
|
|
7491
7582
|
return 0;
|
|
7492
7583
|
}
|
|
7493
7584
|
function compactMetadata(metadata) {
|
|
7494
|
-
const
|
|
7585
|
+
const compact2 = {};
|
|
7495
7586
|
for (const [key, value] of Object.entries(metadata)) {
|
|
7496
7587
|
if (Array.isArray(value) && value.length === 0)
|
|
7497
7588
|
continue;
|
|
7498
7589
|
if (value === "" || value === null)
|
|
7499
7590
|
continue;
|
|
7500
|
-
|
|
7591
|
+
compact2[key] = value;
|
|
7501
7592
|
}
|
|
7502
|
-
return Object.keys(
|
|
7593
|
+
return Object.keys(compact2).length > 0 ? compact2 : void 0;
|
|
7503
7594
|
}
|
|
7504
7595
|
function isCodeFilePath(filePath) {
|
|
7505
7596
|
return /\.(?:[tj]sx?|py|go|rb|sql|graphql|gql)$/.test(filePath.replaceAll("\\", "/"));
|
|
@@ -8605,7 +8696,7 @@ function agentPacketPrompt(input) {
|
|
|
8605
8696
|
].filter(Boolean).join(" ");
|
|
8606
8697
|
}
|
|
8607
8698
|
function inspectReasonForNode(node) {
|
|
8608
|
-
const
|
|
8699
|
+
const path21 = pathKey(node);
|
|
8609
8700
|
const systems = metadataStrings2(node, "systems");
|
|
8610
8701
|
const tables = metadataStrings2(node, "tables");
|
|
8611
8702
|
const access = metadataStrings2(node, "accessControls");
|
|
@@ -8625,7 +8716,7 @@ function inspectReasonForNode(node) {
|
|
|
8625
8716
|
return "Entrypoint that frames runtime flow.";
|
|
8626
8717
|
if (node.type === "component")
|
|
8627
8718
|
return "UI component surface in mapped scope.";
|
|
8628
|
-
return `Mapped ${node.type} node for ${
|
|
8719
|
+
return `Mapped ${node.type} node for ${path21}.`;
|
|
8629
8720
|
}
|
|
8630
8721
|
function strongestEntityEvidenceKind(nodes, kind, name) {
|
|
8631
8722
|
const matchingNodes = nodes.filter((node) => metadataStrings2(node, metadataKeyForEntity(kind)).includes(name));
|
|
@@ -8698,17 +8789,17 @@ function topFacet(nodes, key, limit) {
|
|
|
8698
8789
|
function topAreaFacet(nodes, limit) {
|
|
8699
8790
|
const areas = /* @__PURE__ */ new Map();
|
|
8700
8791
|
for (const node of nodes) {
|
|
8701
|
-
const
|
|
8702
|
-
const prefix = areaPrefix(
|
|
8792
|
+
const path21 = pathKey(node);
|
|
8793
|
+
const prefix = areaPrefix(path21);
|
|
8703
8794
|
const entry = areas.get(prefix) ?? {
|
|
8704
8795
|
paths: /* @__PURE__ */ new Set(),
|
|
8705
8796
|
codeSurfaceCount: 0,
|
|
8706
8797
|
systems: /* @__PURE__ */ new Set()
|
|
8707
8798
|
};
|
|
8708
|
-
if (!entry.paths.has(
|
|
8799
|
+
if (!entry.paths.has(path21) && CODE_SURFACE_TYPES.has(node.type)) {
|
|
8709
8800
|
entry.codeSurfaceCount += 1;
|
|
8710
8801
|
}
|
|
8711
|
-
entry.paths.add(
|
|
8802
|
+
entry.paths.add(path21);
|
|
8712
8803
|
for (const system of metadataStrings2(node, "systems")) {
|
|
8713
8804
|
entry.systems.add(system);
|
|
8714
8805
|
}
|
|
@@ -10564,7 +10655,7 @@ function wikiBuildPipeline(scan, pages, operationalAtlas, loopPlaybooks, refresh
|
|
|
10564
10655
|
},
|
|
10565
10656
|
{
|
|
10566
10657
|
id: "publish",
|
|
10567
|
-
title: "
|
|
10658
|
+
title: "Share with loops",
|
|
10568
10659
|
status: "ready",
|
|
10569
10660
|
summary: "Mission planning and context packets can cite wiki pages as source-grounded operating context.",
|
|
10570
10661
|
evidence: ["brief.wiki_outline", "brief.context_for_task"]
|
|
@@ -10992,7 +11083,7 @@ function loopPlaybookSpec(loopId) {
|
|
|
10992
11083
|
if (loopId === "session_library") {
|
|
10993
11084
|
return {
|
|
10994
11085
|
title: "Session library loop",
|
|
10995
|
-
summary: "Promote proven agent runs into reusable team skills, loops, styles, and run cards without
|
|
11086
|
+
summary: "Promote proven agent runs into reusable team skills, loops, styles, and run cards without sharing raw transcripts by default.",
|
|
10996
11087
|
tools: [
|
|
10997
11088
|
"brief.agent_session_insights",
|
|
10998
11089
|
"brief.value_report",
|
|
@@ -11013,7 +11104,7 @@ function loopPlaybookSpec(loopId) {
|
|
|
11013
11104
|
],
|
|
11014
11105
|
privacyBoundary: [
|
|
11015
11106
|
...common.privacyBoundary,
|
|
11016
|
-
"
|
|
11107
|
+
"Share concise run cards and styles, not raw private sessions, unless explicitly approved."
|
|
11017
11108
|
],
|
|
11018
11109
|
systemHints: ["github", "ci"],
|
|
11019
11110
|
queryHint: "agent session receipts run cards skills loops styles",
|
|
@@ -11204,7 +11295,7 @@ function wikiUsageReceipts(pages, options2) {
|
|
|
11204
11295
|
loopId: "session_library",
|
|
11205
11296
|
tool: "brief.mission_plan",
|
|
11206
11297
|
pageIds: pageIds("Session Library", "Review Memory", "Team Standards", "Maintainers"),
|
|
11207
|
-
reason: "Session library loops need approved examples, privacy decisions, maintainer context, and reusable team standards before
|
|
11298
|
+
reason: "Session library loops need approved examples, privacy decisions, maintainer context, and reusable team standards before sharing run cards or skills."
|
|
11208
11299
|
},
|
|
11209
11300
|
{
|
|
11210
11301
|
id: `wiki_use_${contentHash("docs:overview:structure")}`,
|
|
@@ -11387,9 +11478,9 @@ var init_contextWiki = __esm({
|
|
|
11387
11478
|
});
|
|
11388
11479
|
|
|
11389
11480
|
// ../core/dist/pathIntent.js
|
|
11390
|
-
function namedCodePathIntentScore(
|
|
11481
|
+
function namedCodePathIntentScore(path21, task) {
|
|
11391
11482
|
const normalizedTask = task.toLowerCase().replace(/[_-]+/g, " ");
|
|
11392
|
-
const normalizedPath = (
|
|
11483
|
+
const normalizedPath = (path21.split("#", 1)[0] ?? path21).toLowerCase();
|
|
11393
11484
|
let score = 0;
|
|
11394
11485
|
const namedTargets = [
|
|
11395
11486
|
[/\breview diff\b/, /diffreview|diff[-_]review/],
|
|
@@ -11535,9 +11626,476 @@ var init_pathIntent = __esm({
|
|
|
11535
11626
|
}
|
|
11536
11627
|
});
|
|
11537
11628
|
|
|
11629
|
+
// ../core/dist/dependencyRemediation.js
|
|
11630
|
+
import path6 from "node:path";
|
|
11631
|
+
function buildDependencyRemediationPlan(repoRoot, request) {
|
|
11632
|
+
const files = walkFiles(repoRoot, request.maxFiles ?? 6e3);
|
|
11633
|
+
const manifests = files.filter(isDependencyManifest);
|
|
11634
|
+
const lockfiles = files.filter(isDependencyLockfile);
|
|
11635
|
+
const workspaceFiles = files.filter(isDependencyWorkspaceFile);
|
|
11636
|
+
const changedDependencyFiles = unique((request.changedFiles ?? []).filter(isDependencyFile));
|
|
11637
|
+
const packageManager = inferPackageManager(repoRoot, manifests, lockfiles);
|
|
11638
|
+
const packageSignalInput = {
|
|
11639
|
+
task: request.task,
|
|
11640
|
+
manifests,
|
|
11641
|
+
changedDependencyFiles
|
|
11642
|
+
};
|
|
11643
|
+
if (request.diff)
|
|
11644
|
+
packageSignalInput.diff = request.diff;
|
|
11645
|
+
const packageSignals = packageSignalsFor(repoRoot, packageSignalInput);
|
|
11646
|
+
const directDependencyFiles = unique(packageSignals.flatMap((signal2) => signal2.manifestPaths));
|
|
11647
|
+
const packageNames = packageSignals.map((signal2) => signal2.name);
|
|
11648
|
+
const validationCommands2 = validationCommandsFor2(repoRoot, packageManager);
|
|
11649
|
+
const graphCommands = dependencyGraphCommandsFor(packageManager, packageNames);
|
|
11650
|
+
const remediationCommands = remediationCommandsFor(packageManager, packageNames);
|
|
11651
|
+
const residualRiskChecks = residualRiskChecksFor(packageManager, packageNames, changedDependencyFiles);
|
|
11652
|
+
const confidence = confidenceFor({
|
|
11653
|
+
changedDependencyFiles,
|
|
11654
|
+
packageSignals,
|
|
11655
|
+
lockfiles,
|
|
11656
|
+
validationCommands: validationCommands2
|
|
11657
|
+
});
|
|
11658
|
+
return {
|
|
11659
|
+
id: `dep_${contentHash([
|
|
11660
|
+
request.task,
|
|
11661
|
+
packageManager,
|
|
11662
|
+
changedDependencyFiles.join(","),
|
|
11663
|
+
packageNames.join(",")
|
|
11664
|
+
].join(":"))}`,
|
|
11665
|
+
status: changedDependencyFiles.length > 0 || packageSignals.length > 0 ? "ready" : "needs_evidence",
|
|
11666
|
+
packageManager,
|
|
11667
|
+
manifestFiles: manifests.slice(0, 20),
|
|
11668
|
+
lockfiles,
|
|
11669
|
+
workspaceFiles,
|
|
11670
|
+
changedDependencyFiles,
|
|
11671
|
+
directDependencyFiles,
|
|
11672
|
+
packageSignals,
|
|
11673
|
+
graphCommands,
|
|
11674
|
+
remediationCommands,
|
|
11675
|
+
validationCommands: validationCommands2,
|
|
11676
|
+
residualRiskChecks,
|
|
11677
|
+
handoffRequirements: [
|
|
11678
|
+
"List advisory ids or scanner finding ids that were fixed.",
|
|
11679
|
+
"Name packages still present in the lockfile with vulnerable versions, or state that the scan/audit is clean.",
|
|
11680
|
+
"Explain any major-version upgrades, overrides, peer dependency changes, skipped advisories, or remaining advisory ids.",
|
|
11681
|
+
"Attach validation commands and CI follow-up results before marking the security mission done."
|
|
11682
|
+
],
|
|
11683
|
+
summary: summaryFor3({
|
|
11684
|
+
packageManager,
|
|
11685
|
+
manifests,
|
|
11686
|
+
lockfiles,
|
|
11687
|
+
changedDependencyFiles,
|
|
11688
|
+
packageSignals,
|
|
11689
|
+
validationCommands: validationCommands2
|
|
11690
|
+
}),
|
|
11691
|
+
confidence
|
|
11692
|
+
};
|
|
11693
|
+
}
|
|
11694
|
+
function isDependencyRemediationTask(task, files = []) {
|
|
11695
|
+
const normalized = task.toLowerCase();
|
|
11696
|
+
const hasSecuritySignal = /\b(dependabot|vulnerab\w*|cve-|ghsa-|security advisory|security finding|audit finding|osv|sca|dependency-review)\b/.test(normalized);
|
|
11697
|
+
const hasDependencyChangeSignal = /\b(dependency|dependencies|lockfile|package upgrade|package update|package bump|transitive|override|resolution)\b/.test(normalized);
|
|
11698
|
+
return hasSecuritySignal || hasDependencyChangeSignal && files.some(isDependencyFile);
|
|
11699
|
+
}
|
|
11700
|
+
function isDependencyFile(filePath) {
|
|
11701
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
11702
|
+
return dependencyFilePatterns.some((pattern) => normalized === pattern || normalized.endsWith(`/${pattern}`) || pattern === "package.json" && normalized.endsWith("/package.json"));
|
|
11703
|
+
}
|
|
11704
|
+
function isDependencyLockfile(filePath) {
|
|
11705
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
11706
|
+
return normalized === "pnpm-lock.yaml" || normalized.endsWith("/pnpm-lock.yaml") || normalized === "package-lock.json" || normalized.endsWith("/package-lock.json") || normalized === "yarn.lock" || normalized.endsWith("/yarn.lock") || normalized === "bun.lock" || normalized.endsWith("/bun.lock") || normalized === "npm-shrinkwrap.json" || normalized.endsWith("/npm-shrinkwrap.json") || normalized === "poetry.lock" || normalized.endsWith("/poetry.lock") || normalized === "Pipfile.lock" || normalized.endsWith("/Pipfile.lock") || normalized === "Gemfile.lock" || normalized.endsWith("/Gemfile.lock") || normalized === "go.sum" || normalized.endsWith("/go.sum") || normalized === "Cargo.lock" || normalized.endsWith("/Cargo.lock");
|
|
11707
|
+
}
|
|
11708
|
+
function isDependencyManifest(filePath) {
|
|
11709
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
11710
|
+
return normalized === "package.json" || normalized.endsWith("/package.json") || normalized === "requirements.txt" || normalized.endsWith("/requirements.txt") || normalized === "pyproject.toml" || normalized.endsWith("/pyproject.toml") || normalized === "Gemfile" || normalized.endsWith("/Gemfile") || normalized === "go.mod" || normalized.endsWith("/go.mod") || normalized === "Cargo.toml" || normalized.endsWith("/Cargo.toml");
|
|
11711
|
+
}
|
|
11712
|
+
function isDependencyWorkspaceFile(filePath) {
|
|
11713
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
11714
|
+
return normalized === "pnpm-workspace.yaml" || normalized.endsWith("/pnpm-workspace.yaml") || normalized === "lerna.json" || normalized.endsWith("/lerna.json") || normalized === "turbo.json" || normalized.endsWith("/turbo.json") || normalized === "nx.json" || normalized.endsWith("/nx.json");
|
|
11715
|
+
}
|
|
11716
|
+
function inferPackageManager(repoRoot, manifests, lockfiles) {
|
|
11717
|
+
const rootPackageJson = readPackageJson(repoRoot, "package.json");
|
|
11718
|
+
const packageManager = rootPackageJson?.packageManager;
|
|
11719
|
+
if (typeof packageManager === "string") {
|
|
11720
|
+
if (packageManager.startsWith("pnpm@"))
|
|
11721
|
+
return "pnpm";
|
|
11722
|
+
if (packageManager.startsWith("yarn@"))
|
|
11723
|
+
return "yarn";
|
|
11724
|
+
if (packageManager.startsWith("npm@"))
|
|
11725
|
+
return "npm";
|
|
11726
|
+
if (packageManager.startsWith("bun@"))
|
|
11727
|
+
return "bun";
|
|
11728
|
+
}
|
|
11729
|
+
if (lockfiles.some((file) => file.endsWith("pnpm-lock.yaml")))
|
|
11730
|
+
return "pnpm";
|
|
11731
|
+
if (lockfiles.some((file) => file.endsWith("yarn.lock")))
|
|
11732
|
+
return "yarn";
|
|
11733
|
+
if (lockfiles.some((file) => file.endsWith("package-lock.json"))) {
|
|
11734
|
+
return "npm";
|
|
11735
|
+
}
|
|
11736
|
+
if (lockfiles.some((file) => file.endsWith("bun.lock")))
|
|
11737
|
+
return "bun";
|
|
11738
|
+
if (manifests.some((file) => file.endsWith("requirements.txt") || file.endsWith("pyproject.toml") || file.endsWith("Pipfile"))) {
|
|
11739
|
+
return "pip";
|
|
11740
|
+
}
|
|
11741
|
+
if (manifests.some((file) => file.endsWith("Gemfile")))
|
|
11742
|
+
return "bundler";
|
|
11743
|
+
if (manifests.some((file) => file.endsWith("go.mod")))
|
|
11744
|
+
return "go";
|
|
11745
|
+
if (manifests.some((file) => file.endsWith("Cargo.toml")))
|
|
11746
|
+
return "cargo";
|
|
11747
|
+
return "unknown";
|
|
11748
|
+
}
|
|
11749
|
+
function packageSignalsFor(repoRoot, input) {
|
|
11750
|
+
const manifestDeps = dependencyNamesByManifest(repoRoot, input.manifests);
|
|
11751
|
+
const explicitPackageNames = unique([
|
|
11752
|
+
...packagesMentionedInText(input.task),
|
|
11753
|
+
...packagesMentionedInDiff(input.diff ?? "")
|
|
11754
|
+
]).filter((name) => !looksLikeVersionOrAdvisory(name));
|
|
11755
|
+
const fallbackPackageNames = input.changedDependencyFiles.flatMap((file) => packagesFromChangedDependencyFile(repoRoot, file));
|
|
11756
|
+
const packageNames = unique(explicitPackageNames.length > 0 ? explicitPackageNames : fallbackPackageNames).filter((name) => !looksLikeVersionOrAdvisory(name));
|
|
11757
|
+
return packageNames.slice(0, 16).map((name) => ({
|
|
11758
|
+
name,
|
|
11759
|
+
changeKind: changeKindFor(name, input.diff ?? ""),
|
|
11760
|
+
manifestPaths: manifestsForPackage(name, manifestDeps),
|
|
11761
|
+
lockfilePaths: input.changedDependencyFiles.filter(isDependencyLockfile),
|
|
11762
|
+
evidence: evidenceForPackage(name, input.task, input.diff ?? "")
|
|
11763
|
+
}));
|
|
11764
|
+
}
|
|
11765
|
+
function dependencyNamesByManifest(repoRoot, manifests) {
|
|
11766
|
+
const byPackage = /* @__PURE__ */ new Map();
|
|
11767
|
+
for (const manifest of manifests) {
|
|
11768
|
+
if (!manifest.endsWith("package.json"))
|
|
11769
|
+
continue;
|
|
11770
|
+
const parsed = readPackageJson(repoRoot, manifest);
|
|
11771
|
+
if (!parsed)
|
|
11772
|
+
continue;
|
|
11773
|
+
for (const name of packageJsonDependencyNames(parsed)) {
|
|
11774
|
+
const current = byPackage.get(name) ?? [];
|
|
11775
|
+
current.push(manifest);
|
|
11776
|
+
byPackage.set(name, current);
|
|
11777
|
+
}
|
|
11778
|
+
}
|
|
11779
|
+
return byPackage;
|
|
11780
|
+
}
|
|
11781
|
+
function packageJsonDependencyNames(parsed) {
|
|
11782
|
+
return unique([
|
|
11783
|
+
"dependencies",
|
|
11784
|
+
"devDependencies",
|
|
11785
|
+
"optionalDependencies",
|
|
11786
|
+
"peerDependencies",
|
|
11787
|
+
"overrides",
|
|
11788
|
+
"resolutions",
|
|
11789
|
+
"pnpm"
|
|
11790
|
+
].flatMap((field) => nestedDependencyNames(parsed[field])));
|
|
11791
|
+
}
|
|
11792
|
+
function nestedDependencyNames(value) {
|
|
11793
|
+
if (!value || typeof value !== "object")
|
|
11794
|
+
return [];
|
|
11795
|
+
return Object.entries(value).flatMap(([key, nested]) => [
|
|
11796
|
+
looksLikePackageName(key) ? key : "",
|
|
11797
|
+
...nestedDependencyNames(nested)
|
|
11798
|
+
]);
|
|
11799
|
+
}
|
|
11800
|
+
function packagesMentionedInText(text) {
|
|
11801
|
+
const names = [];
|
|
11802
|
+
const quoted = text.matchAll(/[`'"](@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)[`'"]/gi);
|
|
11803
|
+
for (const match of quoted)
|
|
11804
|
+
names.push(match[1] ?? "");
|
|
11805
|
+
const advisoryContext = text.matchAll(/\b(?:package|dependency|upgrade|update|override|transitive|vulnerable|dependabot|cve|ghsa|audit)\s+(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)/gi);
|
|
11806
|
+
for (const match of advisoryContext)
|
|
11807
|
+
names.push(match[1] ?? "");
|
|
11808
|
+
const atVersion = text.matchAll(/\b(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)@(?:\^|~)?\d/gi);
|
|
11809
|
+
for (const match of atVersion)
|
|
11810
|
+
names.push(match[1] ?? "");
|
|
11811
|
+
if (/\b(dependabot|cve-|ghsa-|audit|vulnerab|advisory)\b/i.test(text)) {
|
|
11812
|
+
const affectedPackageContext = text.matchAll(/\b(?:for|affects?|in)\s+(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)/gi);
|
|
11813
|
+
for (const match of affectedPackageContext)
|
|
11814
|
+
names.push(match[1] ?? "");
|
|
11815
|
+
}
|
|
11816
|
+
return unique(names.map(cleanPackageName).filter(looksLikePackageName).filter((name) => !genericDependencyWords.has(name.toLowerCase())));
|
|
11817
|
+
}
|
|
11818
|
+
function packagesMentionedInDiff(diff) {
|
|
11819
|
+
const names = [];
|
|
11820
|
+
for (const line of diff.split(/\r?\n/)) {
|
|
11821
|
+
if (!/^[+-]/.test(line) || /^[+-]{3}/.test(line))
|
|
11822
|
+
continue;
|
|
11823
|
+
const packageJsonMatch = line.match(/"(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)"\s*:/i);
|
|
11824
|
+
if (packageJsonMatch?.[1])
|
|
11825
|
+
names.push(packageJsonMatch[1]);
|
|
11826
|
+
const pnpmMatch = line.match(/^\s*[+-]\s{0,8}(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)@(?:\^|~)?\d/i);
|
|
11827
|
+
if (pnpmMatch?.[1])
|
|
11828
|
+
names.push(pnpmMatch[1]);
|
|
11829
|
+
const lockPathMatch = line.match(/\/(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)@(?:\^|~)?\d/i);
|
|
11830
|
+
if (lockPathMatch?.[1])
|
|
11831
|
+
names.push(lockPathMatch[1]);
|
|
11832
|
+
}
|
|
11833
|
+
return unique(names.map(cleanPackageName).filter(looksLikePackageName).filter((name) => !genericDependencyWords.has(name.toLowerCase())));
|
|
11834
|
+
}
|
|
11835
|
+
function packagesFromChangedDependencyFile(repoRoot, filePath) {
|
|
11836
|
+
if (!filePath.endsWith("package.json"))
|
|
11837
|
+
return [];
|
|
11838
|
+
const parsed = readPackageJson(repoRoot, filePath);
|
|
11839
|
+
return parsed ? packageJsonDependencyNames(parsed).slice(0, 20) : [];
|
|
11840
|
+
}
|
|
11841
|
+
function readPackageJson(repoRoot, filePath) {
|
|
11842
|
+
const content = safeRead(path6.join(repoRoot, filePath), 4e5);
|
|
11843
|
+
if (!content)
|
|
11844
|
+
return null;
|
|
11845
|
+
try {
|
|
11846
|
+
const parsed = JSON.parse(content);
|
|
11847
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
11848
|
+
} catch {
|
|
11849
|
+
return null;
|
|
11850
|
+
}
|
|
11851
|
+
}
|
|
11852
|
+
function changeKindFor(packageName, diff) {
|
|
11853
|
+
const escaped = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11854
|
+
const removedVersions = [
|
|
11855
|
+
...diff.matchAll(new RegExp(`^-.*${escaped}.*?(\\d+\\.\\d+\\.\\d+)`, "gim"))
|
|
11856
|
+
].map((match) => match[1] ?? "");
|
|
11857
|
+
const addedVersions = [
|
|
11858
|
+
...diff.matchAll(new RegExp(`^\\+.*${escaped}.*?(\\d+\\.\\d+\\.\\d+)`, "gim"))
|
|
11859
|
+
].map((match) => match[1] ?? "");
|
|
11860
|
+
const removed = removedVersions[0];
|
|
11861
|
+
const added = addedVersions[0];
|
|
11862
|
+
if (removed && added) {
|
|
11863
|
+
const [removedMajor] = removed.split(".");
|
|
11864
|
+
const [addedMajor] = added.split(".");
|
|
11865
|
+
return removedMajor && addedMajor && removedMajor !== addedMajor ? "major" : "patch_or_minor";
|
|
11866
|
+
}
|
|
11867
|
+
if (added && !removed)
|
|
11868
|
+
return "added_or_overridden";
|
|
11869
|
+
return "unknown";
|
|
11870
|
+
}
|
|
11871
|
+
function manifestsForPackage(packageName, manifestDeps) {
|
|
11872
|
+
return unique([
|
|
11873
|
+
...manifestDeps.get(packageName) ?? [],
|
|
11874
|
+
...[...manifestDeps.entries()].filter(([name]) => name.endsWith(`/${packageName}`)).flatMap(([, manifests]) => manifests)
|
|
11875
|
+
]).slice(0, 8);
|
|
11876
|
+
}
|
|
11877
|
+
function evidenceForPackage(packageName, task, diff) {
|
|
11878
|
+
const evidence = [];
|
|
11879
|
+
if (task.toLowerCase().includes(packageName.toLowerCase())) {
|
|
11880
|
+
evidence.push("mentioned_in_task");
|
|
11881
|
+
}
|
|
11882
|
+
if (diff.toLowerCase().includes(packageName.toLowerCase())) {
|
|
11883
|
+
evidence.push("mentioned_in_diff");
|
|
11884
|
+
}
|
|
11885
|
+
if (evidence.length === 0)
|
|
11886
|
+
evidence.push("manifest_candidate");
|
|
11887
|
+
return evidence;
|
|
11888
|
+
}
|
|
11889
|
+
function validationCommandsFor2(repoRoot, packageManager) {
|
|
11890
|
+
const scripts = packageScripts(repoRoot);
|
|
11891
|
+
const run = packageRunCommand(packageManager);
|
|
11892
|
+
return unique([
|
|
11893
|
+
...auditCommandsFor(packageManager),
|
|
11894
|
+
...scriptCommand(scripts, "check", run),
|
|
11895
|
+
...scriptCommand(scripts, "test", run),
|
|
11896
|
+
...scriptCommand(scripts, "test:client", run),
|
|
11897
|
+
...scriptCommand(scripts, "test:e2e:smoke", run),
|
|
11898
|
+
...scriptCommand(scripts, "build", run)
|
|
11899
|
+
]).slice(0, 10);
|
|
11900
|
+
}
|
|
11901
|
+
function packageScripts(repoRoot) {
|
|
11902
|
+
const parsed = readPackageJson(repoRoot, "package.json");
|
|
11903
|
+
const scripts = parsed?.scripts;
|
|
11904
|
+
return scripts && typeof scripts === "object" ? Object.fromEntries(Object.entries(scripts).filter((entry) => typeof entry[1] === "string")) : {};
|
|
11905
|
+
}
|
|
11906
|
+
function scriptCommand(scripts, scriptName, runCommand) {
|
|
11907
|
+
return scripts[scriptName] ? [`${runCommand} ${scriptName}`] : [];
|
|
11908
|
+
}
|
|
11909
|
+
function packageRunCommand(packageManager) {
|
|
11910
|
+
switch (packageManager) {
|
|
11911
|
+
case "npm":
|
|
11912
|
+
return "npm run";
|
|
11913
|
+
case "yarn":
|
|
11914
|
+
return "yarn";
|
|
11915
|
+
case "bun":
|
|
11916
|
+
return "bun run";
|
|
11917
|
+
default:
|
|
11918
|
+
return "pnpm";
|
|
11919
|
+
}
|
|
11920
|
+
}
|
|
11921
|
+
function auditCommandsFor(packageManager) {
|
|
11922
|
+
switch (packageManager) {
|
|
11923
|
+
case "pnpm":
|
|
11924
|
+
return ["pnpm audit --prod"];
|
|
11925
|
+
case "npm":
|
|
11926
|
+
return ["npm audit --omit=dev"];
|
|
11927
|
+
case "yarn":
|
|
11928
|
+
return ["yarn npm audit --environment production"];
|
|
11929
|
+
case "bun":
|
|
11930
|
+
return ["bun audit"];
|
|
11931
|
+
case "pip":
|
|
11932
|
+
return ["pip-audit"];
|
|
11933
|
+
case "bundler":
|
|
11934
|
+
return ["bundle audit check"];
|
|
11935
|
+
case "go":
|
|
11936
|
+
return ["govulncheck ./..."];
|
|
11937
|
+
case "cargo":
|
|
11938
|
+
return ["cargo audit"];
|
|
11939
|
+
default:
|
|
11940
|
+
return [];
|
|
11941
|
+
}
|
|
11942
|
+
}
|
|
11943
|
+
function dependencyGraphCommandsFor(packageManager, packageNames) {
|
|
11944
|
+
const selected = packageNames.slice(0, 5);
|
|
11945
|
+
if (selected.length === 0)
|
|
11946
|
+
return [];
|
|
11947
|
+
switch (packageManager) {
|
|
11948
|
+
case "pnpm":
|
|
11949
|
+
return selected.map((name) => `pnpm why ${name}`);
|
|
11950
|
+
case "npm":
|
|
11951
|
+
return selected.map((name) => `npm explain ${name}`);
|
|
11952
|
+
case "yarn":
|
|
11953
|
+
return selected.map((name) => `yarn why ${name}`);
|
|
11954
|
+
case "bun":
|
|
11955
|
+
return selected.map((name) => `bun pm why ${name}`);
|
|
11956
|
+
case "go":
|
|
11957
|
+
return selected.map((name) => `go mod why -m ${name}`);
|
|
11958
|
+
case "cargo":
|
|
11959
|
+
return selected.map((name) => `cargo tree -i ${name}`);
|
|
11960
|
+
default:
|
|
11961
|
+
return [];
|
|
11962
|
+
}
|
|
11963
|
+
}
|
|
11964
|
+
function remediationCommandsFor(packageManager, packageNames) {
|
|
11965
|
+
const selected = packageNames.slice(0, 5);
|
|
11966
|
+
if (selected.length === 0)
|
|
11967
|
+
return [];
|
|
11968
|
+
switch (packageManager) {
|
|
11969
|
+
case "pnpm":
|
|
11970
|
+
return selected.map((name) => `pnpm up ${name} --latest --interactive=false`);
|
|
11971
|
+
case "npm":
|
|
11972
|
+
return selected.map((name) => `npm update ${name}`);
|
|
11973
|
+
case "yarn":
|
|
11974
|
+
return selected.map((name) => `yarn up ${name}`);
|
|
11975
|
+
case "bun":
|
|
11976
|
+
return selected.map((name) => `bun update ${name}`);
|
|
11977
|
+
case "go":
|
|
11978
|
+
return selected.map((name) => `go get ${name}@latest`);
|
|
11979
|
+
case "cargo":
|
|
11980
|
+
return selected.map((name) => `cargo update -p ${name}`);
|
|
11981
|
+
default:
|
|
11982
|
+
return [];
|
|
11983
|
+
}
|
|
11984
|
+
}
|
|
11985
|
+
function residualRiskChecksFor(packageManager, packageNames, changedDependencyFiles) {
|
|
11986
|
+
return unique([
|
|
11987
|
+
packageNames.length > 0 ? `Confirm vulnerable versions are gone for: ${packageNames.slice(0, 8).join(", ")}.` : "Name each advisory/package from the scanner before editing.",
|
|
11988
|
+
changedDependencyFiles.some(isDependencyLockfile) ? "Inspect the lockfile diff for unexpected package churn outside the advisory path." : "Regenerate and inspect the lockfile if the fix changes dependency resolution.",
|
|
11989
|
+
"Split major-version upgrades or broad framework upgrades into a separate mission unless the advisory requires them.",
|
|
11990
|
+
"Record any remaining advisory ids, ignored dev-only findings, or transitive paths that still need owner judgment.",
|
|
11991
|
+
...auditCommandsFor(packageManager).map((command2) => `Rerun ${command2} after the lockfile update.`)
|
|
11992
|
+
]);
|
|
11993
|
+
}
|
|
11994
|
+
function confidenceFor(input) {
|
|
11995
|
+
let score = 35;
|
|
11996
|
+
if (input.changedDependencyFiles.length > 0)
|
|
11997
|
+
score += 20;
|
|
11998
|
+
if (input.packageSignals.length > 0)
|
|
11999
|
+
score += 20;
|
|
12000
|
+
if (input.lockfiles.length > 0)
|
|
12001
|
+
score += 10;
|
|
12002
|
+
if (input.validationCommands.length > 0)
|
|
12003
|
+
score += 10;
|
|
12004
|
+
return Math.min(95, score);
|
|
12005
|
+
}
|
|
12006
|
+
function summaryFor3(input) {
|
|
12007
|
+
const packages = input.packageSignals.map((signal2) => signal2.name);
|
|
12008
|
+
return [
|
|
12009
|
+
`Detected ${input.packageManager} dependency remediation context.`,
|
|
12010
|
+
`${input.manifests.length} manifest${input.manifests.length === 1 ? "" : "s"}, ${input.lockfiles.length} lockfile${input.lockfiles.length === 1 ? "" : "s"}.`,
|
|
12011
|
+
input.changedDependencyFiles.length > 0 ? `Changed dependency files: ${input.changedDependencyFiles.slice(0, 6).join(", ")}.` : "No dependency files are changed yet.",
|
|
12012
|
+
packages.length > 0 ? `Likely packages: ${packages.slice(0, 8).join(", ")}.` : "Package names still need advisory/scanner evidence.",
|
|
12013
|
+
input.validationCommands.length > 0 ? `Validation starts with ${input.validationCommands[0]}.` : "Validation commands need repo-specific confirmation."
|
|
12014
|
+
].join(" ");
|
|
12015
|
+
}
|
|
12016
|
+
function cleanPackageName(input) {
|
|
12017
|
+
return input.replace(/[),.;\]]+$/g, "").trim();
|
|
12018
|
+
}
|
|
12019
|
+
function looksLikePackageName(input) {
|
|
12020
|
+
return /^@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?$/i.test(input);
|
|
12021
|
+
}
|
|
12022
|
+
function looksLikeVersionOrAdvisory(input) {
|
|
12023
|
+
const normalized = input.toLowerCase();
|
|
12024
|
+
return /^\d/.test(input) || /^cve-\d/i.test(input) || /^ghsa-/i.test(input) || [
|
|
12025
|
+
"advisory",
|
|
12026
|
+
"advisories",
|
|
12027
|
+
"change",
|
|
12028
|
+
"changes",
|
|
12029
|
+
"dependency",
|
|
12030
|
+
"dependencies",
|
|
12031
|
+
"dependabot",
|
|
12032
|
+
"finding",
|
|
12033
|
+
"findings",
|
|
12034
|
+
"package",
|
|
12035
|
+
"packages",
|
|
12036
|
+
"security",
|
|
12037
|
+
"transitive",
|
|
12038
|
+
"upgrade",
|
|
12039
|
+
"upgrades",
|
|
12040
|
+
"vulnerabilities",
|
|
12041
|
+
"vulnerability",
|
|
12042
|
+
"vulnerable"
|
|
12043
|
+
].includes(normalized);
|
|
12044
|
+
}
|
|
12045
|
+
var dependencyFilePatterns, genericDependencyWords;
|
|
12046
|
+
var init_dependencyRemediation = __esm({
|
|
12047
|
+
"../core/dist/dependencyRemediation.js"() {
|
|
12048
|
+
"use strict";
|
|
12049
|
+
init_utils();
|
|
12050
|
+
dependencyFilePatterns = [
|
|
12051
|
+
"package.json",
|
|
12052
|
+
"pnpm-lock.yaml",
|
|
12053
|
+
"pnpm-workspace.yaml",
|
|
12054
|
+
"package-lock.json",
|
|
12055
|
+
"yarn.lock",
|
|
12056
|
+
"bun.lock",
|
|
12057
|
+
"npm-shrinkwrap.json",
|
|
12058
|
+
"requirements.txt",
|
|
12059
|
+
"poetry.lock",
|
|
12060
|
+
"pyproject.toml",
|
|
12061
|
+
"Pipfile.lock",
|
|
12062
|
+
"Gemfile",
|
|
12063
|
+
"Gemfile.lock",
|
|
12064
|
+
"go.mod",
|
|
12065
|
+
"go.sum",
|
|
12066
|
+
"Cargo.toml",
|
|
12067
|
+
"Cargo.lock"
|
|
12068
|
+
];
|
|
12069
|
+
genericDependencyWords = /* @__PURE__ */ new Set([
|
|
12070
|
+
"advisory",
|
|
12071
|
+
"audit",
|
|
12072
|
+
"build",
|
|
12073
|
+
"change",
|
|
12074
|
+
"dependency",
|
|
12075
|
+
"dev",
|
|
12076
|
+
"exact",
|
|
12077
|
+
"existing",
|
|
12078
|
+
"focused",
|
|
12079
|
+
"for",
|
|
12080
|
+
"finding",
|
|
12081
|
+
"lockfile",
|
|
12082
|
+
"package",
|
|
12083
|
+
"path",
|
|
12084
|
+
"security",
|
|
12085
|
+
"test",
|
|
12086
|
+
"the",
|
|
12087
|
+
"toolchain",
|
|
12088
|
+
"transitive",
|
|
12089
|
+
"vulnerability",
|
|
12090
|
+
"workflow",
|
|
12091
|
+
"without"
|
|
12092
|
+
]);
|
|
12093
|
+
}
|
|
12094
|
+
});
|
|
12095
|
+
|
|
11538
12096
|
// ../core/dist/testRecommendations.js
|
|
11539
12097
|
import { existsSync as existsSync3 } from "node:fs";
|
|
11540
|
-
import
|
|
12098
|
+
import path7 from "node:path";
|
|
11541
12099
|
function recommendExactTestsForFiles(input) {
|
|
11542
12100
|
const packageManager = detectPackageManager(input.repoRoot);
|
|
11543
12101
|
if (isDocsOnlyChange(input.changedFiles)) {
|
|
@@ -11691,7 +12249,7 @@ function taskRelevantTests(repoRoot, scanMap, scanSources, task, excluded) {
|
|
|
11691
12249
|
}));
|
|
11692
12250
|
return [...mapTests, ...sourceTests].filter((test) => !excludedSet.has(test.path)).map((test) => {
|
|
11693
12251
|
const pathScore = tokens.reduce((total, token) => total + (test.seed.includes(token) ? 2 : 0), 0);
|
|
11694
|
-
const content = pathScore > 0 ? (safeRead(
|
|
12252
|
+
const content = pathScore > 0 ? (safeRead(path7.join(repoRoot, test.path), 6e4) ?? "").toLowerCase() : "";
|
|
11695
12253
|
return {
|
|
11696
12254
|
path: test.path,
|
|
11697
12255
|
score: pathScore + tokens.reduce((total, token) => total + (test.context.includes(token) ? 1 : 0), 0) + tokens.reduce((total, token) => total + (content.includes(token) ? 1 : 0), 0)
|
|
@@ -11755,8 +12313,8 @@ function testCommandForFile(repoRoot, file, packageManager) {
|
|
|
11755
12313
|
if (packageManager === "pnpm") {
|
|
11756
12314
|
const packageInfo = nearestPackageInfo(repoRoot, file);
|
|
11757
12315
|
if (packageInfo?.name && packageInfo.root !== repoRoot) {
|
|
11758
|
-
const packageRelativeFile =
|
|
11759
|
-
const testScript =
|
|
12316
|
+
const packageRelativeFile = path7.relative(packageInfo.root, path7.join(repoRoot, file)).replaceAll("\\", "/");
|
|
12317
|
+
const testScript = readPackageJson2(packageInfo.root)?.scripts?.test;
|
|
11760
12318
|
if (typeof testScript === "string") {
|
|
11761
12319
|
if (/\bvitest\b/.test(testScript)) {
|
|
11762
12320
|
return `pnpm --filter ${packageInfo.name} exec vitest run ${packageRelativeFile}`;
|
|
@@ -11774,11 +12332,11 @@ function testCommandForFile(repoRoot, file, packageManager) {
|
|
|
11774
12332
|
return `${packageManager} test -- ${file}`;
|
|
11775
12333
|
}
|
|
11776
12334
|
function nearestPackageInfo(repoRoot, file) {
|
|
11777
|
-
let current =
|
|
12335
|
+
let current = path7.dirname(path7.join(repoRoot, file));
|
|
11778
12336
|
while (current.startsWith(repoRoot)) {
|
|
11779
|
-
const packageJsonPath =
|
|
12337
|
+
const packageJsonPath = path7.join(current, "package.json");
|
|
11780
12338
|
if (existsSync3(packageJsonPath)) {
|
|
11781
|
-
const pkg =
|
|
12339
|
+
const pkg = readPackageJson2(current);
|
|
11782
12340
|
return {
|
|
11783
12341
|
root: current,
|
|
11784
12342
|
...typeof pkg?.name === "string" ? { name: pkg.name } : {}
|
|
@@ -11786,18 +12344,18 @@ function nearestPackageInfo(repoRoot, file) {
|
|
|
11786
12344
|
}
|
|
11787
12345
|
if (current === repoRoot)
|
|
11788
12346
|
break;
|
|
11789
|
-
current =
|
|
12347
|
+
current = path7.dirname(current);
|
|
11790
12348
|
}
|
|
11791
12349
|
return null;
|
|
11792
12350
|
}
|
|
11793
12351
|
function coLocatedTestCandidates(repoRoot, file) {
|
|
11794
|
-
const parsed =
|
|
12352
|
+
const parsed = path7.parse(file);
|
|
11795
12353
|
const extensions = parsed.ext === ".tsx" ? [".test.tsx", ".spec.tsx", ".test.ts", ".spec.ts"] : parsed.ext === ".jsx" ? [".test.jsx", ".spec.jsx", ".test.js", ".spec.js"] : [`.test${parsed.ext}`, `.spec${parsed.ext}`];
|
|
11796
12354
|
const candidates = [
|
|
11797
|
-
...extensions.map((extension) =>
|
|
11798
|
-
...extensions.map((extension) =>
|
|
12355
|
+
...extensions.map((extension) => path7.join(parsed.dir, `${parsed.name}${extension}`)),
|
|
12356
|
+
...extensions.map((extension) => path7.join(parsed.dir, "__tests__", `${parsed.name}${extension}`))
|
|
11799
12357
|
].map((candidate) => candidate.replaceAll("\\", "/"));
|
|
11800
|
-
return candidates.filter((candidate) => existsSync3(
|
|
12358
|
+
return candidates.filter((candidate) => existsSync3(path7.join(repoRoot, candidate)));
|
|
11801
12359
|
}
|
|
11802
12360
|
function importedByTests(scanMap, sourceFiles) {
|
|
11803
12361
|
const fromSourceMetadata = scanMap.filter((node) => sourceFiles.includes(sourcePathForNode(node))).flatMap((node) => metadataStrings3(node, "importedBy")).filter(isTestPath);
|
|
@@ -11819,11 +12377,11 @@ function isDocsOnlyChange(files) {
|
|
|
11819
12377
|
}
|
|
11820
12378
|
function isDocsOrProductDocPath(file) {
|
|
11821
12379
|
const normalized = file.replaceAll("\\", "/");
|
|
11822
|
-
const basename =
|
|
12380
|
+
const basename = path7.basename(normalized).toLowerCase();
|
|
11823
12381
|
return normalized.startsWith("docs/") || normalized.includes("/docs/") || normalized.startsWith(".github/") || basename === "readme.md" || basename === "agents.md" || basename === "claude.md" || basename.endsWith(".md") || basename.endsWith(".mdx") || basename.endsWith(".rst") || basename.endsWith(".adoc");
|
|
11824
12382
|
}
|
|
11825
12383
|
function docsOnlyRecommendations(repoRoot, packageManager, changedFiles) {
|
|
11826
|
-
const pkg =
|
|
12384
|
+
const pkg = readPackageJson2(repoRoot);
|
|
11827
12385
|
const scripts = pkg?.scripts ?? {};
|
|
11828
12386
|
const recommendations = [
|
|
11829
12387
|
{
|
|
@@ -11847,7 +12405,7 @@ function docsOnlyRecommendations(repoRoot, packageManager, changedFiles) {
|
|
|
11847
12405
|
if (typeof scripts[script] === "string") {
|
|
11848
12406
|
recommendations.push({
|
|
11849
12407
|
command: `${packageManager} ${script}`,
|
|
11850
|
-
reason: `Repo package.json defines ${script}; run it when docs or agent guidance can affect generated output or
|
|
12408
|
+
reason: `Repo package.json defines ${script}; run it when docs or agent guidance can affect generated output or shared docs.`,
|
|
11851
12409
|
files: [],
|
|
11852
12410
|
source: "script",
|
|
11853
12411
|
confidence: script === "check" ? "low" : "medium"
|
|
@@ -11857,7 +12415,7 @@ function docsOnlyRecommendations(repoRoot, packageManager, changedFiles) {
|
|
|
11857
12415
|
return recommendations.slice(0, 4);
|
|
11858
12416
|
}
|
|
11859
12417
|
function packageScriptRecommendations(repoRoot, packageManager) {
|
|
11860
|
-
const pkg =
|
|
12418
|
+
const pkg = readPackageJson2(repoRoot);
|
|
11861
12419
|
const scripts = pkg?.scripts ?? {};
|
|
11862
12420
|
const commands = [];
|
|
11863
12421
|
for (const script of [
|
|
@@ -11890,7 +12448,7 @@ function taskRelevantPackageScriptRecommendations(repoRoot, packageManager, task
|
|
|
11890
12448
|
const packageRoots = unique(sourceFiles.map((file) => nearestPackageInfo(repoRoot, file)?.root).filter((root) => Boolean(root)));
|
|
11891
12449
|
const recommendations = [];
|
|
11892
12450
|
for (const packageRoot of packageRoots) {
|
|
11893
|
-
const pkg =
|
|
12451
|
+
const pkg = readPackageJson2(packageRoot);
|
|
11894
12452
|
const scripts = pkg?.scripts ?? {};
|
|
11895
12453
|
const packageName = typeof pkg?.name === "string" ? pkg.name : void 0;
|
|
11896
12454
|
if (wantsPackageRelease) {
|
|
@@ -11923,8 +12481,8 @@ function packageScriptCommand(packageManager, packageRoot, repoRoot, packageName
|
|
|
11923
12481
|
}
|
|
11924
12482
|
return packageManager === "npm" ? `npm run ${script}` : `${packageManager} ${script}`;
|
|
11925
12483
|
}
|
|
11926
|
-
function
|
|
11927
|
-
const content = safeRead(
|
|
12484
|
+
function readPackageJson2(packageRoot) {
|
|
12485
|
+
const content = safeRead(path7.join(packageRoot, "package.json"), 2e5);
|
|
11928
12486
|
if (!content)
|
|
11929
12487
|
return null;
|
|
11930
12488
|
try {
|
|
@@ -11940,17 +12498,17 @@ function shellQuote(value) {
|
|
|
11940
12498
|
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
11941
12499
|
}
|
|
11942
12500
|
function detectPackageManager(repoRoot) {
|
|
11943
|
-
const pkg =
|
|
12501
|
+
const pkg = readPackageJson2(repoRoot);
|
|
11944
12502
|
if (typeof pkg?.packageManager === "string") {
|
|
11945
12503
|
const name = pkg.packageManager.split("@")[0];
|
|
11946
12504
|
if (name)
|
|
11947
12505
|
return name;
|
|
11948
12506
|
}
|
|
11949
|
-
if (existsSync3(
|
|
12507
|
+
if (existsSync3(path7.join(repoRoot, "pnpm-lock.yaml")))
|
|
11950
12508
|
return "pnpm";
|
|
11951
|
-
if (existsSync3(
|
|
12509
|
+
if (existsSync3(path7.join(repoRoot, "yarn.lock")))
|
|
11952
12510
|
return "yarn";
|
|
11953
|
-
if (existsSync3(
|
|
12511
|
+
if (existsSync3(path7.join(repoRoot, "bun.lockb")))
|
|
11954
12512
|
return "bun";
|
|
11955
12513
|
return "npm";
|
|
11956
12514
|
}
|
|
@@ -11967,6 +12525,10 @@ function contextForTask(scan, request) {
|
|
|
11967
12525
|
const files = request.files ?? [];
|
|
11968
12526
|
const maxTokens = request.maxTokens ?? 6e3;
|
|
11969
12527
|
const scoped = files.length > 0;
|
|
12528
|
+
const dependencyRemediation = isDependencyRemediationTask(task, files) ? buildDependencyRemediationPlan(request.repoRoot ?? scan.repoRoot, {
|
|
12529
|
+
task,
|
|
12530
|
+
changedFiles: files
|
|
12531
|
+
}) : void 0;
|
|
11970
12532
|
const rankedRules = rankRules(scan.rules, task, files);
|
|
11971
12533
|
const initialRules = rankedRules.slice(0, scoped ? 8 : 12);
|
|
11972
12534
|
const initialSkills = selectSkills(scan.skills, task, files, scoped).map(compactSkillForContext);
|
|
@@ -11974,13 +12536,18 @@ function contextForTask(scan, request) {
|
|
|
11974
12536
|
const rankedMap = rankMap(mapCandidates, task, files);
|
|
11975
12537
|
const selectedMap = takeGuidanceGroundedMapNodes(mapCandidates, scan.sources, rulesStronglyRelevantForGrounding(initialRules, task), initialSkills, rankedMap, files, scoped ? 14 : 18).map(compactMapNodeForContext);
|
|
11976
12538
|
const suggestedTests = selectValidationForContext(scan.map, scan.sources, task, files, selectedMap, request.repoRoot);
|
|
12539
|
+
const dependencyTests = dependencyValidationForContext(dependencyRemediation, task);
|
|
12540
|
+
const focusedSuggestedTests = dependencyRemediation ? dependencyTests : suggestedTests;
|
|
11977
12541
|
const initialSelection = {
|
|
11978
12542
|
rules: initialRules,
|
|
11979
12543
|
skills: initialSkills,
|
|
11980
12544
|
map: selectedMap,
|
|
11981
|
-
wikiPages: selectWikiPages(buildContextWiki(scan).pages, task, files, scoped,
|
|
12545
|
+
wikiPages: selectWikiPages(buildContextWiki(scan).pages, task, files, scoped, focusedSuggestedTests).map(compactWikiPageForContext),
|
|
11982
12546
|
memories: rankMemories(scan.memories, task, files).slice(0, scoped ? 4 : 8).map(compactMemoryForContext),
|
|
11983
|
-
suggestedTests
|
|
12547
|
+
suggestedTests: unique([...dependencyTests, ...focusedSuggestedTests]),
|
|
12548
|
+
...dependencyRemediation ? {
|
|
12549
|
+
dependencyRemediation: compactDependencyRemediationForContext(dependencyRemediation)
|
|
12550
|
+
} : {}
|
|
11984
12551
|
};
|
|
11985
12552
|
const { selection, tokenEstimate, omitted } = fitSelectionToBudget(initialSelection, {
|
|
11986
12553
|
maxTokens,
|
|
@@ -11991,32 +12558,39 @@ function contextForTask(scan, request) {
|
|
|
11991
12558
|
const { rules: selectedRules, skills: selectedSkills, map: budgetedMap, wikiPages: selectedWikiPages, memories: selectedMemories } = selection;
|
|
11992
12559
|
const finalMap = takeGuidanceGroundedMapNodes(mapCandidates, scan.sources, rulesStronglyRelevantForGrounding(selectedRules, task), selectedSkills, budgetedMap, files, Math.max(budgetedMap.length, scoped ? 2 : 4)).map(compactMapNodeForContext);
|
|
11993
12560
|
const finalSuggestedTests = selectValidationForContext(scan.map, scan.sources, task, files, finalMap, request.repoRoot);
|
|
12561
|
+
const packetSuggestedTests = unique([
|
|
12562
|
+
...dependencyRemediation ? dependencyValidationForContext(dependencyRemediation, task) : finalSuggestedTests
|
|
12563
|
+
]);
|
|
11994
12564
|
const owners = selectOwners(scan.map, files);
|
|
11995
12565
|
const sources = unique([
|
|
11996
12566
|
...selectedRules.flatMap((rule) => rule.sourcePaths),
|
|
11997
12567
|
...selectedSkills.map((skill) => skill.sourcePath),
|
|
11998
12568
|
...finalMap.map(mapNodeSourcePath),
|
|
11999
12569
|
...selectedWikiPages.flatMap((page2) => page2.sourcePaths),
|
|
12000
|
-
...selectedMemories.flatMap((memory) => memory.sourcePaths)
|
|
12570
|
+
...selectedMemories.flatMap((memory) => memory.sourcePaths),
|
|
12571
|
+
...dependencySourcePaths(dependencyRemediation)
|
|
12001
12572
|
]);
|
|
12002
12573
|
const teamGuidance = scan.teamGuidanceCatalog ? teamGuidanceDeliveryFor(scan, selectedRules, selectedSkills, selectedMemories) : void 0;
|
|
12003
12574
|
const packet = {
|
|
12004
12575
|
packetId: packetId(),
|
|
12005
12576
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12006
12577
|
task,
|
|
12007
|
-
summary: summarizeContext(task, selectedRules,
|
|
12578
|
+
summary: summarizeContext(task, selectedRules, packetSuggestedTests, finalMap),
|
|
12008
12579
|
rules: selectedRules,
|
|
12009
12580
|
skills: selectedSkills,
|
|
12010
12581
|
map: finalMap,
|
|
12011
12582
|
wikiPages: selectedWikiPages,
|
|
12012
12583
|
memories: selectedMemories,
|
|
12013
|
-
suggestedTests:
|
|
12584
|
+
suggestedTests: packetSuggestedTests,
|
|
12014
12585
|
owners,
|
|
12015
12586
|
sources,
|
|
12016
12587
|
tokenEstimate,
|
|
12017
12588
|
omitted,
|
|
12018
|
-
valueSignals: contextValueSignals(finalMap,
|
|
12019
|
-
...teamGuidance ? { teamGuidance } : {}
|
|
12589
|
+
valueSignals: contextValueSignals(finalMap, packetSuggestedTests, sources.length, teamGuidance?.applied.length ?? 0),
|
|
12590
|
+
...teamGuidance ? { teamGuidance } : {},
|
|
12591
|
+
...dependencyRemediation ? {
|
|
12592
|
+
dependencyRemediation: compactDependencyRemediationForContext(dependencyRemediation)
|
|
12593
|
+
} : {}
|
|
12020
12594
|
};
|
|
12021
12595
|
return enforceContextPacketBudget(packet, maxTokens, files);
|
|
12022
12596
|
}
|
|
@@ -12050,6 +12624,47 @@ function contextValueSignals(map, suggestedTests, relevantSourceCount, appliedTe
|
|
|
12050
12624
|
suggestedTestCount: suggestedTests.length
|
|
12051
12625
|
};
|
|
12052
12626
|
}
|
|
12627
|
+
function dependencyValidationForContext(plan, task) {
|
|
12628
|
+
if (!plan)
|
|
12629
|
+
return [];
|
|
12630
|
+
const allowsRuntimeProof = /\b(runtime|smoke|e2e|browser|production|integration)\b/i.test(task);
|
|
12631
|
+
return plan.validationCommands.filter((command2) => allowsRuntimeProof ? true : !/\b(e2e|smoke|ux)\b/i.test(command2)).slice(0, allowsRuntimeProof ? 5 : 4);
|
|
12632
|
+
}
|
|
12633
|
+
function dependencySourcePaths(plan) {
|
|
12634
|
+
if (!plan)
|
|
12635
|
+
return [];
|
|
12636
|
+
return unique([
|
|
12637
|
+
...plan.manifestFiles,
|
|
12638
|
+
...plan.lockfiles,
|
|
12639
|
+
...plan.workspaceFiles,
|
|
12640
|
+
...plan.changedDependencyFiles,
|
|
12641
|
+
...plan.directDependencyFiles
|
|
12642
|
+
]);
|
|
12643
|
+
}
|
|
12644
|
+
function compactDependencyRemediationForContext(plan) {
|
|
12645
|
+
if (!plan)
|
|
12646
|
+
return void 0;
|
|
12647
|
+
return {
|
|
12648
|
+
...plan,
|
|
12649
|
+
manifestFiles: plan.manifestFiles.slice(0, 8),
|
|
12650
|
+
lockfiles: plan.lockfiles.slice(0, 6),
|
|
12651
|
+
workspaceFiles: plan.workspaceFiles.slice(0, 4),
|
|
12652
|
+
changedDependencyFiles: plan.changedDependencyFiles.slice(0, 8),
|
|
12653
|
+
directDependencyFiles: plan.directDependencyFiles.slice(0, 8),
|
|
12654
|
+
packageSignals: plan.packageSignals.slice(0, 8).map((signal2) => ({
|
|
12655
|
+
...signal2,
|
|
12656
|
+
manifestPaths: signal2.manifestPaths.slice(0, 4),
|
|
12657
|
+
lockfilePaths: signal2.lockfilePaths.slice(0, 4),
|
|
12658
|
+
evidence: signal2.evidence.slice(0, 3)
|
|
12659
|
+
})),
|
|
12660
|
+
graphCommands: plan.graphCommands.slice(0, 6),
|
|
12661
|
+
remediationCommands: plan.remediationCommands.slice(0, 6),
|
|
12662
|
+
validationCommands: plan.validationCommands.slice(0, 8),
|
|
12663
|
+
residualRiskChecks: plan.residualRiskChecks.slice(0, 6),
|
|
12664
|
+
handoffRequirements: plan.handoffRequirements.slice(0, 4),
|
|
12665
|
+
summary: truncateText(plan.summary, 520)
|
|
12666
|
+
};
|
|
12667
|
+
}
|
|
12053
12668
|
function codebaseMapForTask(scan, request, limit = 80) {
|
|
12054
12669
|
const files = request.files ?? [];
|
|
12055
12670
|
const hasSpecificScope = files.length > 0 || wordsFor3(request.task).length > 1;
|
|
@@ -12927,7 +13542,8 @@ function cloneSelection(selection) {
|
|
|
12927
13542
|
map: [...selection.map],
|
|
12928
13543
|
wikiPages: [...selection.wikiPages],
|
|
12929
13544
|
memories: [...selection.memories],
|
|
12930
|
-
suggestedTests: [...selection.suggestedTests]
|
|
13545
|
+
suggestedTests: [...selection.suggestedTests],
|
|
13546
|
+
...selection.dependencyRemediation ? { dependencyRemediation: selection.dependencyRemediation } : {}
|
|
12931
13547
|
};
|
|
12932
13548
|
}
|
|
12933
13549
|
function estimateSelectionTokens(selection, task) {
|
|
@@ -12942,6 +13558,7 @@ function estimateSelectionTokens(selection, task) {
|
|
|
12942
13558
|
wikiPages: selection.wikiPages,
|
|
12943
13559
|
memories: selection.memories,
|
|
12944
13560
|
suggestedTests: selection.suggestedTests,
|
|
13561
|
+
...selection.dependencyRemediation ? { dependencyRemediation: selection.dependencyRemediation } : {},
|
|
12945
13562
|
owners: [],
|
|
12946
13563
|
sources: selectionSources(selection),
|
|
12947
13564
|
tokenEstimate: 0,
|
|
@@ -13038,10 +13655,6 @@ function trimContextPacket(packet, protectedMapPaths) {
|
|
|
13038
13655
|
packet.suggestedTests.pop();
|
|
13039
13656
|
return true;
|
|
13040
13657
|
}
|
|
13041
|
-
if (packet.rules.length > 0) {
|
|
13042
|
-
packet.rules.pop();
|
|
13043
|
-
return true;
|
|
13044
|
-
}
|
|
13045
13658
|
if (packet.map.length > protectedMapPaths.size) {
|
|
13046
13659
|
packet.map.pop();
|
|
13047
13660
|
return true;
|
|
@@ -13084,7 +13697,7 @@ function compactProtectedMapNodes(map, protectedMapPaths) {
|
|
|
13084
13697
|
function compactProtectedMapMetadata(metadata) {
|
|
13085
13698
|
if (!metadata)
|
|
13086
13699
|
return void 0;
|
|
13087
|
-
const
|
|
13700
|
+
const compact2 = {};
|
|
13088
13701
|
for (const key of [
|
|
13089
13702
|
"sourcePath",
|
|
13090
13703
|
"symbolKind",
|
|
@@ -13095,7 +13708,7 @@ function compactProtectedMapMetadata(metadata) {
|
|
|
13095
13708
|
]) {
|
|
13096
13709
|
const value = metadata[key];
|
|
13097
13710
|
if (value !== void 0)
|
|
13098
|
-
|
|
13711
|
+
compact2[key] = value;
|
|
13099
13712
|
}
|
|
13100
13713
|
for (const key of [
|
|
13101
13714
|
"evidenceKinds",
|
|
@@ -13124,9 +13737,9 @@ function compactProtectedMapMetadata(metadata) {
|
|
|
13124
13737
|
]) {
|
|
13125
13738
|
const value = metadata[key];
|
|
13126
13739
|
if (Array.isArray(value))
|
|
13127
|
-
|
|
13740
|
+
compact2[key] = value.slice(0, 2);
|
|
13128
13741
|
}
|
|
13129
|
-
return
|
|
13742
|
+
return compact2;
|
|
13130
13743
|
}
|
|
13131
13744
|
function refreshContextPacketDerivedFields(packet) {
|
|
13132
13745
|
packet.summary = summarizeContext(packet.task, packet.rules, packet.suggestedTests, packet.map);
|
|
@@ -13136,7 +13749,8 @@ function refreshContextPacketDerivedFields(packet) {
|
|
|
13136
13749
|
map: packet.map,
|
|
13137
13750
|
wikiPages: packet.wikiPages,
|
|
13138
13751
|
memories: packet.memories,
|
|
13139
|
-
suggestedTests: packet.suggestedTests
|
|
13752
|
+
suggestedTests: packet.suggestedTests,
|
|
13753
|
+
...packet.dependencyRemediation ? { dependencyRemediation: packet.dependencyRemediation } : {}
|
|
13140
13754
|
});
|
|
13141
13755
|
refreshTeamGuidanceDelivery(packet);
|
|
13142
13756
|
packet.valueSignals = contextValueSignals(packet.map, packet.suggestedTests, packet.sources.length, packet.teamGuidance?.applied.length ?? 0);
|
|
@@ -13188,7 +13802,8 @@ function selectionSources(selection) {
|
|
|
13188
13802
|
...selection.skills.map((skill) => skill.sourcePath),
|
|
13189
13803
|
...selection.map.map((node) => node.path),
|
|
13190
13804
|
...selection.wikiPages.flatMap((page2) => page2.sourcePaths),
|
|
13191
|
-
...selection.memories.flatMap((memory) => memory.sourcePaths)
|
|
13805
|
+
...selection.memories.flatMap((memory) => memory.sourcePaths),
|
|
13806
|
+
...dependencySourcePaths(selection.dependencyRemediation)
|
|
13192
13807
|
]);
|
|
13193
13808
|
}
|
|
13194
13809
|
function trimSelection(selection, minimums, protectedMapPaths) {
|
|
@@ -13302,17 +13917,17 @@ function compactWikiPageForContext(page2) {
|
|
|
13302
13917
|
function compactMetadata2(metadata) {
|
|
13303
13918
|
if (!metadata)
|
|
13304
13919
|
return void 0;
|
|
13305
|
-
const
|
|
13920
|
+
const compact2 = {};
|
|
13306
13921
|
for (const [key, value] of Object.entries(metadata)) {
|
|
13307
13922
|
if (!contextMetadataKeys.has(key))
|
|
13308
13923
|
continue;
|
|
13309
13924
|
if (Array.isArray(value)) {
|
|
13310
|
-
|
|
13925
|
+
compact2[key] = value.slice(0, metadataArrayLimit(key));
|
|
13311
13926
|
} else {
|
|
13312
|
-
|
|
13927
|
+
compact2[key] = value;
|
|
13313
13928
|
}
|
|
13314
13929
|
}
|
|
13315
|
-
return
|
|
13930
|
+
return compact2;
|
|
13316
13931
|
}
|
|
13317
13932
|
function metadataArrayLimit(key) {
|
|
13318
13933
|
if (["imports", "importedBy"].includes(key))
|
|
@@ -13333,6 +13948,7 @@ var init_context = __esm({
|
|
|
13333
13948
|
init_scanner();
|
|
13334
13949
|
init_contextWiki();
|
|
13335
13950
|
init_pathIntent();
|
|
13951
|
+
init_dependencyRemediation();
|
|
13336
13952
|
init_testRecommendations();
|
|
13337
13953
|
init_utils();
|
|
13338
13954
|
contextStopWords = /* @__PURE__ */ new Set([
|
|
@@ -13405,443 +14021,6 @@ var init_context = __esm({
|
|
|
13405
14021
|
}
|
|
13406
14022
|
});
|
|
13407
14023
|
|
|
13408
|
-
// ../core/dist/dependencyRemediation.js
|
|
13409
|
-
import path7 from "node:path";
|
|
13410
|
-
function buildDependencyRemediationPlan(repoRoot, request) {
|
|
13411
|
-
const files = walkFiles(repoRoot, request.maxFiles ?? 6e3);
|
|
13412
|
-
const manifests = files.filter(isDependencyManifest);
|
|
13413
|
-
const lockfiles = files.filter(isDependencyLockfile);
|
|
13414
|
-
const workspaceFiles = files.filter(isDependencyWorkspaceFile);
|
|
13415
|
-
const changedDependencyFiles = unique((request.changedFiles ?? []).filter(isDependencyFile));
|
|
13416
|
-
const packageManager = inferPackageManager(repoRoot, manifests, lockfiles);
|
|
13417
|
-
const packageSignalInput = {
|
|
13418
|
-
task: request.task,
|
|
13419
|
-
manifests,
|
|
13420
|
-
changedDependencyFiles
|
|
13421
|
-
};
|
|
13422
|
-
if (request.diff)
|
|
13423
|
-
packageSignalInput.diff = request.diff;
|
|
13424
|
-
const packageSignals = packageSignalsFor(repoRoot, packageSignalInput);
|
|
13425
|
-
const directDependencyFiles = unique(packageSignals.flatMap((signal2) => signal2.manifestPaths));
|
|
13426
|
-
const packageNames = packageSignals.map((signal2) => signal2.name);
|
|
13427
|
-
const validationCommands2 = validationCommandsFor2(repoRoot, packageManager);
|
|
13428
|
-
const graphCommands = dependencyGraphCommandsFor(packageManager, packageNames);
|
|
13429
|
-
const remediationCommands = remediationCommandsFor(packageManager, packageNames);
|
|
13430
|
-
const residualRiskChecks = residualRiskChecksFor(packageManager, packageNames, changedDependencyFiles);
|
|
13431
|
-
const confidence = confidenceFor({
|
|
13432
|
-
changedDependencyFiles,
|
|
13433
|
-
packageSignals,
|
|
13434
|
-
lockfiles,
|
|
13435
|
-
validationCommands: validationCommands2
|
|
13436
|
-
});
|
|
13437
|
-
return {
|
|
13438
|
-
id: `dep_${contentHash([
|
|
13439
|
-
request.task,
|
|
13440
|
-
packageManager,
|
|
13441
|
-
changedDependencyFiles.join(","),
|
|
13442
|
-
packageNames.join(",")
|
|
13443
|
-
].join(":"))}`,
|
|
13444
|
-
status: changedDependencyFiles.length > 0 || packageSignals.length > 0 ? "ready" : "needs_evidence",
|
|
13445
|
-
packageManager,
|
|
13446
|
-
manifestFiles: manifests.slice(0, 20),
|
|
13447
|
-
lockfiles,
|
|
13448
|
-
workspaceFiles,
|
|
13449
|
-
changedDependencyFiles,
|
|
13450
|
-
directDependencyFiles,
|
|
13451
|
-
packageSignals,
|
|
13452
|
-
graphCommands,
|
|
13453
|
-
remediationCommands,
|
|
13454
|
-
validationCommands: validationCommands2,
|
|
13455
|
-
residualRiskChecks,
|
|
13456
|
-
handoffRequirements: [
|
|
13457
|
-
"List advisory ids or scanner finding ids that were fixed.",
|
|
13458
|
-
"Name packages still present in the lockfile with vulnerable versions, or state that the scan/audit is clean.",
|
|
13459
|
-
"Explain any major-version upgrades, overrides, peer dependency changes, skipped advisories, or remaining advisory ids.",
|
|
13460
|
-
"Attach validation commands and CI follow-up results before marking the security mission done."
|
|
13461
|
-
],
|
|
13462
|
-
summary: summaryFor3({
|
|
13463
|
-
packageManager,
|
|
13464
|
-
manifests,
|
|
13465
|
-
lockfiles,
|
|
13466
|
-
changedDependencyFiles,
|
|
13467
|
-
packageSignals,
|
|
13468
|
-
validationCommands: validationCommands2
|
|
13469
|
-
}),
|
|
13470
|
-
confidence
|
|
13471
|
-
};
|
|
13472
|
-
}
|
|
13473
|
-
function isDependencyFile(filePath) {
|
|
13474
|
-
const normalized = filePath.replaceAll("\\", "/");
|
|
13475
|
-
return dependencyFilePatterns.some((pattern) => normalized === pattern || normalized.endsWith(`/${pattern}`) || pattern === "package.json" && normalized.endsWith("/package.json"));
|
|
13476
|
-
}
|
|
13477
|
-
function isDependencyLockfile(filePath) {
|
|
13478
|
-
const normalized = filePath.replaceAll("\\", "/");
|
|
13479
|
-
return normalized === "pnpm-lock.yaml" || normalized.endsWith("/pnpm-lock.yaml") || normalized === "package-lock.json" || normalized.endsWith("/package-lock.json") || normalized === "yarn.lock" || normalized.endsWith("/yarn.lock") || normalized === "bun.lock" || normalized.endsWith("/bun.lock") || normalized === "npm-shrinkwrap.json" || normalized.endsWith("/npm-shrinkwrap.json") || normalized === "poetry.lock" || normalized.endsWith("/poetry.lock") || normalized === "Pipfile.lock" || normalized.endsWith("/Pipfile.lock") || normalized === "Gemfile.lock" || normalized.endsWith("/Gemfile.lock") || normalized === "go.sum" || normalized.endsWith("/go.sum") || normalized === "Cargo.lock" || normalized.endsWith("/Cargo.lock");
|
|
13480
|
-
}
|
|
13481
|
-
function isDependencyManifest(filePath) {
|
|
13482
|
-
const normalized = filePath.replaceAll("\\", "/");
|
|
13483
|
-
return normalized === "package.json" || normalized.endsWith("/package.json") || normalized === "requirements.txt" || normalized.endsWith("/requirements.txt") || normalized === "pyproject.toml" || normalized.endsWith("/pyproject.toml") || normalized === "Gemfile" || normalized.endsWith("/Gemfile") || normalized === "go.mod" || normalized.endsWith("/go.mod") || normalized === "Cargo.toml" || normalized.endsWith("/Cargo.toml");
|
|
13484
|
-
}
|
|
13485
|
-
function isDependencyWorkspaceFile(filePath) {
|
|
13486
|
-
const normalized = filePath.replaceAll("\\", "/");
|
|
13487
|
-
return normalized === "pnpm-workspace.yaml" || normalized.endsWith("/pnpm-workspace.yaml") || normalized === "lerna.json" || normalized.endsWith("/lerna.json") || normalized === "turbo.json" || normalized.endsWith("/turbo.json") || normalized === "nx.json" || normalized.endsWith("/nx.json");
|
|
13488
|
-
}
|
|
13489
|
-
function inferPackageManager(repoRoot, manifests, lockfiles) {
|
|
13490
|
-
const rootPackageJson = readPackageJson2(repoRoot, "package.json");
|
|
13491
|
-
const packageManager = rootPackageJson?.packageManager;
|
|
13492
|
-
if (typeof packageManager === "string") {
|
|
13493
|
-
if (packageManager.startsWith("pnpm@"))
|
|
13494
|
-
return "pnpm";
|
|
13495
|
-
if (packageManager.startsWith("yarn@"))
|
|
13496
|
-
return "yarn";
|
|
13497
|
-
if (packageManager.startsWith("npm@"))
|
|
13498
|
-
return "npm";
|
|
13499
|
-
if (packageManager.startsWith("bun@"))
|
|
13500
|
-
return "bun";
|
|
13501
|
-
}
|
|
13502
|
-
if (lockfiles.some((file) => file.endsWith("pnpm-lock.yaml")))
|
|
13503
|
-
return "pnpm";
|
|
13504
|
-
if (lockfiles.some((file) => file.endsWith("yarn.lock")))
|
|
13505
|
-
return "yarn";
|
|
13506
|
-
if (lockfiles.some((file) => file.endsWith("package-lock.json"))) {
|
|
13507
|
-
return "npm";
|
|
13508
|
-
}
|
|
13509
|
-
if (lockfiles.some((file) => file.endsWith("bun.lock")))
|
|
13510
|
-
return "bun";
|
|
13511
|
-
if (manifests.some((file) => file.endsWith("requirements.txt") || file.endsWith("pyproject.toml") || file.endsWith("Pipfile"))) {
|
|
13512
|
-
return "pip";
|
|
13513
|
-
}
|
|
13514
|
-
if (manifests.some((file) => file.endsWith("Gemfile")))
|
|
13515
|
-
return "bundler";
|
|
13516
|
-
if (manifests.some((file) => file.endsWith("go.mod")))
|
|
13517
|
-
return "go";
|
|
13518
|
-
if (manifests.some((file) => file.endsWith("Cargo.toml")))
|
|
13519
|
-
return "cargo";
|
|
13520
|
-
return "unknown";
|
|
13521
|
-
}
|
|
13522
|
-
function packageSignalsFor(repoRoot, input) {
|
|
13523
|
-
const manifestDeps = dependencyNamesByManifest(repoRoot, input.manifests);
|
|
13524
|
-
const explicitPackageNames = unique([
|
|
13525
|
-
...packagesMentionedInText(input.task),
|
|
13526
|
-
...packagesMentionedInDiff(input.diff ?? "")
|
|
13527
|
-
]).filter((name) => !looksLikeVersionOrAdvisory(name));
|
|
13528
|
-
const fallbackPackageNames = input.changedDependencyFiles.flatMap((file) => packagesFromChangedDependencyFile(repoRoot, file));
|
|
13529
|
-
const packageNames = unique(explicitPackageNames.length > 0 ? explicitPackageNames : fallbackPackageNames).filter((name) => !looksLikeVersionOrAdvisory(name));
|
|
13530
|
-
return packageNames.slice(0, 16).map((name) => ({
|
|
13531
|
-
name,
|
|
13532
|
-
changeKind: changeKindFor(name, input.diff ?? ""),
|
|
13533
|
-
manifestPaths: manifestsForPackage(name, manifestDeps),
|
|
13534
|
-
lockfilePaths: input.changedDependencyFiles.filter(isDependencyLockfile),
|
|
13535
|
-
evidence: evidenceForPackage(name, input.task, input.diff ?? "")
|
|
13536
|
-
}));
|
|
13537
|
-
}
|
|
13538
|
-
function dependencyNamesByManifest(repoRoot, manifests) {
|
|
13539
|
-
const byPackage = /* @__PURE__ */ new Map();
|
|
13540
|
-
for (const manifest of manifests) {
|
|
13541
|
-
if (!manifest.endsWith("package.json"))
|
|
13542
|
-
continue;
|
|
13543
|
-
const parsed = readPackageJson2(repoRoot, manifest);
|
|
13544
|
-
if (!parsed)
|
|
13545
|
-
continue;
|
|
13546
|
-
for (const name of packageJsonDependencyNames(parsed)) {
|
|
13547
|
-
const current = byPackage.get(name) ?? [];
|
|
13548
|
-
current.push(manifest);
|
|
13549
|
-
byPackage.set(name, current);
|
|
13550
|
-
}
|
|
13551
|
-
}
|
|
13552
|
-
return byPackage;
|
|
13553
|
-
}
|
|
13554
|
-
function packageJsonDependencyNames(parsed) {
|
|
13555
|
-
return unique([
|
|
13556
|
-
"dependencies",
|
|
13557
|
-
"devDependencies",
|
|
13558
|
-
"optionalDependencies",
|
|
13559
|
-
"peerDependencies",
|
|
13560
|
-
"overrides",
|
|
13561
|
-
"resolutions",
|
|
13562
|
-
"pnpm"
|
|
13563
|
-
].flatMap((field) => nestedDependencyNames(parsed[field])));
|
|
13564
|
-
}
|
|
13565
|
-
function nestedDependencyNames(value) {
|
|
13566
|
-
if (!value || typeof value !== "object")
|
|
13567
|
-
return [];
|
|
13568
|
-
return Object.entries(value).flatMap(([key, nested]) => [
|
|
13569
|
-
looksLikePackageName(key) ? key : "",
|
|
13570
|
-
...nestedDependencyNames(nested)
|
|
13571
|
-
]);
|
|
13572
|
-
}
|
|
13573
|
-
function packagesMentionedInText(text) {
|
|
13574
|
-
const names = [];
|
|
13575
|
-
const quoted = text.matchAll(/[`'"](@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)[`'"]/gi);
|
|
13576
|
-
for (const match of quoted)
|
|
13577
|
-
names.push(match[1] ?? "");
|
|
13578
|
-
const advisoryContext = text.matchAll(/\b(?:package|dependency|upgrade|update|override|transitive|vulnerable|dependabot|cve|ghsa|audit)\s+(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)/gi);
|
|
13579
|
-
for (const match of advisoryContext)
|
|
13580
|
-
names.push(match[1] ?? "");
|
|
13581
|
-
const atVersion = text.matchAll(/\b(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)@(?:\^|~)?\d/gi);
|
|
13582
|
-
for (const match of atVersion)
|
|
13583
|
-
names.push(match[1] ?? "");
|
|
13584
|
-
if (/\b(dependabot|cve-|ghsa-|audit|vulnerab|advisory)\b/i.test(text)) {
|
|
13585
|
-
const affectedPackageContext = text.matchAll(/\b(?:for|affects?|in)\s+(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)/gi);
|
|
13586
|
-
for (const match of affectedPackageContext)
|
|
13587
|
-
names.push(match[1] ?? "");
|
|
13588
|
-
}
|
|
13589
|
-
return unique(names.map(cleanPackageName).filter(looksLikePackageName));
|
|
13590
|
-
}
|
|
13591
|
-
function packagesMentionedInDiff(diff) {
|
|
13592
|
-
const names = [];
|
|
13593
|
-
for (const line of diff.split(/\r?\n/)) {
|
|
13594
|
-
if (!/^[+-]/.test(line) || /^[+-]{3}/.test(line))
|
|
13595
|
-
continue;
|
|
13596
|
-
const packageJsonMatch = line.match(/"(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)"\s*:/i);
|
|
13597
|
-
if (packageJsonMatch?.[1])
|
|
13598
|
-
names.push(packageJsonMatch[1]);
|
|
13599
|
-
const pnpmMatch = line.match(/^\s*[+-]\s{0,8}(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)@(?:\^|~)?\d/i);
|
|
13600
|
-
if (pnpmMatch?.[1])
|
|
13601
|
-
names.push(pnpmMatch[1]);
|
|
13602
|
-
const lockPathMatch = line.match(/\/(@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?)@(?:\^|~)?\d/i);
|
|
13603
|
-
if (lockPathMatch?.[1])
|
|
13604
|
-
names.push(lockPathMatch[1]);
|
|
13605
|
-
}
|
|
13606
|
-
return unique(names.map(cleanPackageName).filter(looksLikePackageName));
|
|
13607
|
-
}
|
|
13608
|
-
function packagesFromChangedDependencyFile(repoRoot, filePath) {
|
|
13609
|
-
if (!filePath.endsWith("package.json"))
|
|
13610
|
-
return [];
|
|
13611
|
-
const parsed = readPackageJson2(repoRoot, filePath);
|
|
13612
|
-
return parsed ? packageJsonDependencyNames(parsed).slice(0, 20) : [];
|
|
13613
|
-
}
|
|
13614
|
-
function readPackageJson2(repoRoot, filePath) {
|
|
13615
|
-
const content = safeRead(path7.join(repoRoot, filePath), 4e5);
|
|
13616
|
-
if (!content)
|
|
13617
|
-
return null;
|
|
13618
|
-
try {
|
|
13619
|
-
const parsed = JSON.parse(content);
|
|
13620
|
-
return parsed && typeof parsed === "object" ? parsed : null;
|
|
13621
|
-
} catch {
|
|
13622
|
-
return null;
|
|
13623
|
-
}
|
|
13624
|
-
}
|
|
13625
|
-
function changeKindFor(packageName, diff) {
|
|
13626
|
-
const escaped = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13627
|
-
const removedVersions = [
|
|
13628
|
-
...diff.matchAll(new RegExp(`^-.*${escaped}.*?(\\d+\\.\\d+\\.\\d+)`, "gim"))
|
|
13629
|
-
].map((match) => match[1] ?? "");
|
|
13630
|
-
const addedVersions = [
|
|
13631
|
-
...diff.matchAll(new RegExp(`^\\+.*${escaped}.*?(\\d+\\.\\d+\\.\\d+)`, "gim"))
|
|
13632
|
-
].map((match) => match[1] ?? "");
|
|
13633
|
-
const removed = removedVersions[0];
|
|
13634
|
-
const added = addedVersions[0];
|
|
13635
|
-
if (removed && added) {
|
|
13636
|
-
const [removedMajor] = removed.split(".");
|
|
13637
|
-
const [addedMajor] = added.split(".");
|
|
13638
|
-
return removedMajor && addedMajor && removedMajor !== addedMajor ? "major" : "patch_or_minor";
|
|
13639
|
-
}
|
|
13640
|
-
if (added && !removed)
|
|
13641
|
-
return "added_or_overridden";
|
|
13642
|
-
return "unknown";
|
|
13643
|
-
}
|
|
13644
|
-
function manifestsForPackage(packageName, manifestDeps) {
|
|
13645
|
-
return unique([
|
|
13646
|
-
...manifestDeps.get(packageName) ?? [],
|
|
13647
|
-
...[...manifestDeps.entries()].filter(([name]) => name.endsWith(`/${packageName}`)).flatMap(([, manifests]) => manifests)
|
|
13648
|
-
]).slice(0, 8);
|
|
13649
|
-
}
|
|
13650
|
-
function evidenceForPackage(packageName, task, diff) {
|
|
13651
|
-
const evidence = [];
|
|
13652
|
-
if (task.toLowerCase().includes(packageName.toLowerCase())) {
|
|
13653
|
-
evidence.push("mentioned_in_task");
|
|
13654
|
-
}
|
|
13655
|
-
if (diff.toLowerCase().includes(packageName.toLowerCase())) {
|
|
13656
|
-
evidence.push("mentioned_in_diff");
|
|
13657
|
-
}
|
|
13658
|
-
if (evidence.length === 0)
|
|
13659
|
-
evidence.push("manifest_candidate");
|
|
13660
|
-
return evidence;
|
|
13661
|
-
}
|
|
13662
|
-
function validationCommandsFor2(repoRoot, packageManager) {
|
|
13663
|
-
const scripts = packageScripts(repoRoot);
|
|
13664
|
-
const run = packageRunCommand(packageManager);
|
|
13665
|
-
return unique([
|
|
13666
|
-
...auditCommandsFor(packageManager),
|
|
13667
|
-
...scriptCommand(scripts, "check", run),
|
|
13668
|
-
...scriptCommand(scripts, "test", run),
|
|
13669
|
-
...scriptCommand(scripts, "test:client", run),
|
|
13670
|
-
...scriptCommand(scripts, "test:e2e:smoke", run),
|
|
13671
|
-
...scriptCommand(scripts, "build", run)
|
|
13672
|
-
]).slice(0, 10);
|
|
13673
|
-
}
|
|
13674
|
-
function packageScripts(repoRoot) {
|
|
13675
|
-
const parsed = readPackageJson2(repoRoot, "package.json");
|
|
13676
|
-
const scripts = parsed?.scripts;
|
|
13677
|
-
return scripts && typeof scripts === "object" ? Object.fromEntries(Object.entries(scripts).filter((entry) => typeof entry[1] === "string")) : {};
|
|
13678
|
-
}
|
|
13679
|
-
function scriptCommand(scripts, scriptName, runCommand) {
|
|
13680
|
-
return scripts[scriptName] ? [`${runCommand} ${scriptName}`] : [];
|
|
13681
|
-
}
|
|
13682
|
-
function packageRunCommand(packageManager) {
|
|
13683
|
-
switch (packageManager) {
|
|
13684
|
-
case "npm":
|
|
13685
|
-
return "npm run";
|
|
13686
|
-
case "yarn":
|
|
13687
|
-
return "yarn";
|
|
13688
|
-
case "bun":
|
|
13689
|
-
return "bun run";
|
|
13690
|
-
default:
|
|
13691
|
-
return "pnpm";
|
|
13692
|
-
}
|
|
13693
|
-
}
|
|
13694
|
-
function auditCommandsFor(packageManager) {
|
|
13695
|
-
switch (packageManager) {
|
|
13696
|
-
case "pnpm":
|
|
13697
|
-
return ["pnpm audit --prod"];
|
|
13698
|
-
case "npm":
|
|
13699
|
-
return ["npm audit --omit=dev"];
|
|
13700
|
-
case "yarn":
|
|
13701
|
-
return ["yarn npm audit --environment production"];
|
|
13702
|
-
case "bun":
|
|
13703
|
-
return ["bun audit"];
|
|
13704
|
-
case "pip":
|
|
13705
|
-
return ["pip-audit"];
|
|
13706
|
-
case "bundler":
|
|
13707
|
-
return ["bundle audit check"];
|
|
13708
|
-
case "go":
|
|
13709
|
-
return ["govulncheck ./..."];
|
|
13710
|
-
case "cargo":
|
|
13711
|
-
return ["cargo audit"];
|
|
13712
|
-
default:
|
|
13713
|
-
return [];
|
|
13714
|
-
}
|
|
13715
|
-
}
|
|
13716
|
-
function dependencyGraphCommandsFor(packageManager, packageNames) {
|
|
13717
|
-
const selected = packageNames.slice(0, 5);
|
|
13718
|
-
if (selected.length === 0)
|
|
13719
|
-
return [];
|
|
13720
|
-
switch (packageManager) {
|
|
13721
|
-
case "pnpm":
|
|
13722
|
-
return selected.map((name) => `pnpm why ${name}`);
|
|
13723
|
-
case "npm":
|
|
13724
|
-
return selected.map((name) => `npm explain ${name}`);
|
|
13725
|
-
case "yarn":
|
|
13726
|
-
return selected.map((name) => `yarn why ${name}`);
|
|
13727
|
-
case "bun":
|
|
13728
|
-
return selected.map((name) => `bun pm why ${name}`);
|
|
13729
|
-
case "go":
|
|
13730
|
-
return selected.map((name) => `go mod why -m ${name}`);
|
|
13731
|
-
case "cargo":
|
|
13732
|
-
return selected.map((name) => `cargo tree -i ${name}`);
|
|
13733
|
-
default:
|
|
13734
|
-
return [];
|
|
13735
|
-
}
|
|
13736
|
-
}
|
|
13737
|
-
function remediationCommandsFor(packageManager, packageNames) {
|
|
13738
|
-
const selected = packageNames.slice(0, 5);
|
|
13739
|
-
if (selected.length === 0)
|
|
13740
|
-
return [];
|
|
13741
|
-
switch (packageManager) {
|
|
13742
|
-
case "pnpm":
|
|
13743
|
-
return selected.map((name) => `pnpm up ${name} --latest --interactive=false`);
|
|
13744
|
-
case "npm":
|
|
13745
|
-
return selected.map((name) => `npm update ${name}`);
|
|
13746
|
-
case "yarn":
|
|
13747
|
-
return selected.map((name) => `yarn up ${name}`);
|
|
13748
|
-
case "bun":
|
|
13749
|
-
return selected.map((name) => `bun update ${name}`);
|
|
13750
|
-
case "go":
|
|
13751
|
-
return selected.map((name) => `go get ${name}@latest`);
|
|
13752
|
-
case "cargo":
|
|
13753
|
-
return selected.map((name) => `cargo update -p ${name}`);
|
|
13754
|
-
default:
|
|
13755
|
-
return [];
|
|
13756
|
-
}
|
|
13757
|
-
}
|
|
13758
|
-
function residualRiskChecksFor(packageManager, packageNames, changedDependencyFiles) {
|
|
13759
|
-
return unique([
|
|
13760
|
-
packageNames.length > 0 ? `Confirm vulnerable versions are gone for: ${packageNames.slice(0, 8).join(", ")}.` : "Name each advisory/package from the scanner before editing.",
|
|
13761
|
-
changedDependencyFiles.some(isDependencyLockfile) ? "Inspect the lockfile diff for unexpected package churn outside the advisory path." : "Regenerate and inspect the lockfile if the fix changes dependency resolution.",
|
|
13762
|
-
"Split major-version upgrades or broad framework upgrades into a separate mission unless the advisory requires them.",
|
|
13763
|
-
"Record any remaining advisory ids, ignored dev-only findings, or transitive paths that still need owner judgment.",
|
|
13764
|
-
...auditCommandsFor(packageManager).map((command2) => `Rerun ${command2} after the lockfile update.`)
|
|
13765
|
-
]);
|
|
13766
|
-
}
|
|
13767
|
-
function confidenceFor(input) {
|
|
13768
|
-
let score = 35;
|
|
13769
|
-
if (input.changedDependencyFiles.length > 0)
|
|
13770
|
-
score += 20;
|
|
13771
|
-
if (input.packageSignals.length > 0)
|
|
13772
|
-
score += 20;
|
|
13773
|
-
if (input.lockfiles.length > 0)
|
|
13774
|
-
score += 10;
|
|
13775
|
-
if (input.validationCommands.length > 0)
|
|
13776
|
-
score += 10;
|
|
13777
|
-
return Math.min(95, score);
|
|
13778
|
-
}
|
|
13779
|
-
function summaryFor3(input) {
|
|
13780
|
-
const packages = input.packageSignals.map((signal2) => signal2.name);
|
|
13781
|
-
return [
|
|
13782
|
-
`Detected ${input.packageManager} dependency remediation context.`,
|
|
13783
|
-
`${input.manifests.length} manifest${input.manifests.length === 1 ? "" : "s"}, ${input.lockfiles.length} lockfile${input.lockfiles.length === 1 ? "" : "s"}.`,
|
|
13784
|
-
input.changedDependencyFiles.length > 0 ? `Changed dependency files: ${input.changedDependencyFiles.slice(0, 6).join(", ")}.` : "No dependency files are changed yet.",
|
|
13785
|
-
packages.length > 0 ? `Likely packages: ${packages.slice(0, 8).join(", ")}.` : "Package names still need advisory/scanner evidence.",
|
|
13786
|
-
input.validationCommands.length > 0 ? `Validation starts with ${input.validationCommands[0]}.` : "Validation commands need repo-specific confirmation."
|
|
13787
|
-
].join(" ");
|
|
13788
|
-
}
|
|
13789
|
-
function cleanPackageName(input) {
|
|
13790
|
-
return input.replace(/[),.;\]]+$/g, "").trim();
|
|
13791
|
-
}
|
|
13792
|
-
function looksLikePackageName(input) {
|
|
13793
|
-
return /^@?[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9._-]+)?$/i.test(input);
|
|
13794
|
-
}
|
|
13795
|
-
function looksLikeVersionOrAdvisory(input) {
|
|
13796
|
-
const normalized = input.toLowerCase();
|
|
13797
|
-
return /^\d/.test(input) || /^cve-\d/i.test(input) || /^ghsa-/i.test(input) || [
|
|
13798
|
-
"advisory",
|
|
13799
|
-
"advisories",
|
|
13800
|
-
"change",
|
|
13801
|
-
"changes",
|
|
13802
|
-
"dependency",
|
|
13803
|
-
"dependencies",
|
|
13804
|
-
"dependabot",
|
|
13805
|
-
"finding",
|
|
13806
|
-
"findings",
|
|
13807
|
-
"package",
|
|
13808
|
-
"packages",
|
|
13809
|
-
"security",
|
|
13810
|
-
"transitive",
|
|
13811
|
-
"upgrade",
|
|
13812
|
-
"upgrades",
|
|
13813
|
-
"vulnerabilities",
|
|
13814
|
-
"vulnerability",
|
|
13815
|
-
"vulnerable"
|
|
13816
|
-
].includes(normalized);
|
|
13817
|
-
}
|
|
13818
|
-
var dependencyFilePatterns;
|
|
13819
|
-
var init_dependencyRemediation = __esm({
|
|
13820
|
-
"../core/dist/dependencyRemediation.js"() {
|
|
13821
|
-
"use strict";
|
|
13822
|
-
init_utils();
|
|
13823
|
-
dependencyFilePatterns = [
|
|
13824
|
-
"package.json",
|
|
13825
|
-
"pnpm-lock.yaml",
|
|
13826
|
-
"pnpm-workspace.yaml",
|
|
13827
|
-
"package-lock.json",
|
|
13828
|
-
"yarn.lock",
|
|
13829
|
-
"bun.lock",
|
|
13830
|
-
"npm-shrinkwrap.json",
|
|
13831
|
-
"requirements.txt",
|
|
13832
|
-
"poetry.lock",
|
|
13833
|
-
"pyproject.toml",
|
|
13834
|
-
"Pipfile.lock",
|
|
13835
|
-
"Gemfile",
|
|
13836
|
-
"Gemfile.lock",
|
|
13837
|
-
"go.mod",
|
|
13838
|
-
"go.sum",
|
|
13839
|
-
"Cargo.toml",
|
|
13840
|
-
"Cargo.lock"
|
|
13841
|
-
];
|
|
13842
|
-
}
|
|
13843
|
-
});
|
|
13844
|
-
|
|
13845
14024
|
// ../core/dist/productOperatingContext.js
|
|
13846
14025
|
function buildProductOperatingContext(scan, request) {
|
|
13847
14026
|
const files = unique(request.files ?? []);
|
|
@@ -17164,7 +17343,7 @@ function missionGates(autonomy, recipe, options2) {
|
|
|
17164
17343
|
label: "Library privacy gate",
|
|
17165
17344
|
requiredTool: "brief.agent_session_insights",
|
|
17166
17345
|
passCriteria: "Every candidate example is classified as derived-only, redacted transcript, or explicitly approved raw import before sharing.",
|
|
17167
|
-
failureMode: "Do not
|
|
17346
|
+
failureMode: "Do not share raw prompts, secrets, customer data, private logs, or sensitive repo context without explicit approval."
|
|
17168
17347
|
}, {
|
|
17169
17348
|
id: "reuse_quality",
|
|
17170
17349
|
label: "Reuse quality gate",
|
|
@@ -17548,7 +17727,7 @@ function missionSteps(task, autonomy, recipe, options2) {
|
|
|
17548
17727
|
id: "verify_receipts",
|
|
17549
17728
|
title: "Verify ticket receipt ledger",
|
|
17550
17729
|
objective: "Prove the ticket-writing receipt chain before another agent runs the ticket.",
|
|
17551
|
-
agentAction: "Run Brief receipt verification and fix missing, mismatched, or broken-chain ticket proof before
|
|
17730
|
+
agentAction: "Run Brief receipt verification and fix missing, mismatched, or broken-chain ticket proof before sending the ticket.",
|
|
17552
17731
|
briefTool: "brief.verify_receipts",
|
|
17553
17732
|
expectedOutput: "Receipt ledger verification with digest and chain-link status.",
|
|
17554
17733
|
gateId: "ticket"
|
|
@@ -17777,7 +17956,7 @@ function automationLoopContract(autonomy, recipe, validation, options2, delivery
|
|
|
17777
17956
|
"executionContract.evidenceContract.mapProof",
|
|
17778
17957
|
"context.likelyFiles"
|
|
17779
17958
|
],
|
|
17780
|
-
stopIfMissing: isTicketWriter ? "Do not
|
|
17959
|
+
stopIfMissing: isTicketWriter ? "Do not send the ticket until product intent, owner judgment, acceptance criteria, and stop conditions are explicit." : "Do not edit until likely files, rules, tests, owners, and affected systems are grounded in Brief context."
|
|
17781
17960
|
},
|
|
17782
17961
|
...isRuntimeFix ? [
|
|
17783
17962
|
{
|
|
@@ -18173,7 +18352,7 @@ function missionRunContract(autonomy, recipe, validation, options2, deliveryMode
|
|
|
18173
18352
|
successCriteria: [
|
|
18174
18353
|
"The context receipt cites the rules, source paths, tests, owners, and memories used by the agent.",
|
|
18175
18354
|
recipe.id === "ticket_write" ? "The ticket separates human judgment from execution instructions and names unresolved decisions before automation starts." : recipe.id === "security_dependency" ? "The dependency vulnerability packet names advisory id, package, affected range, fixed range, manifest, lockfile, direct/transitive path, reachability, remediation choice, and rollback." : recipe.id === "security_finding" ? "The security finding packet names alert source, rule id, classification, source-to-sink or trust boundary, affected users/data, owner, exploitability, and validation path." : recipe.id === "security_testing" ? "The security test plan names the protected property, bad case, safe case, command, severity threshold, false-positive policy, owner, privacy boundary, and rollout mode." : recipe.id === "internal_app" ? "The app contract names the internal route, data source, auth context, allowed roles, row filters, audit events, and redaction rules before implementation." : recipe.id === "stale_pr" ? "The PR intent packet names original scope, unresolved review feedback, stale assumptions, validation, and handoff expectation." : recipe.id === "merge_conflict" ? "The conflict packet names conflicted files, both sides' intent, semantic conflicts, and validation before resolution." : recipe.id === "flaky_test" ? "The CI evidence packet names failing job or test, sample failure, platform, seed or timing signal, hypothesis, and validation path." : recipe.id === "small_refactor" ? "The mechanical scope packet names exact pattern, allowed files, exclusions, and expected behavior preservation." : recipe.id === "bug_investigation" ? "The hypothesis ledger names observed facts, prior attempts, plausible causes, disproven causes, next probes, and confidence." : recipe.id === "qa_edge_cases" ? "The edge-case inventory names current coverage, missing boundary cases, risky inputs, and validation commands." : recipe.id === "performance" ? "The benchmark packet names workload, command, metric, baseline, variance, success threshold, and rollback signal before edits." : recipe.id === "porting" ? "The source behavior packet names source paths, target paths, incompatible assumptions, owner decision, validation, and attribution notes." : recipe.id === "experiment" ? "The experiment contract names the hypothesis, success signal, throwaway boundary, rollback or discard path, and decision owner." : recipe.id === "session_review" ? "The session review uses receipt-derived activity and marks any need for raw prompts, logs, or transcripts explicitly." : recipe.id === "session_library" ? "The session library classifies every reusable example by proof quality, privacy posture, owner approval, and reuse trigger." : options2.needsRuntimeEvidence ? "The runtime evidence packet names the observed failure source, identifier, environment, time window, symptom, and open gaps." : options2.needsWorkItem ? "The work item packet names source, id, acceptance criteria, non-goals, and the update expected after execution." : recipe.id === "research" ? "The answer names sources, risks, and next steps without editing the repo." : "Required validation evidence is attached or the missing environment is explicitly explained.",
|
|
18176
|
-
recipe.id === "ticket_write" ? "Acceptance criteria, constraints, validation plan, review bar, stop conditions, and update template are parseable from the ticket body." : recipe.id === "security_dependency" ? "Install integrity, build/typecheck, targeted tests, and scanner/audit evidence show the vulnerability is remediated without breaking the dependency path." : recipe.id === "security_finding" ? "The root cause is fixed with negative regression, safe abuse-case proof, or scanner rerun evidence; suppression-only fixes are explicitly rejected or owner-approved." : recipe.id === "security_testing" ? "The added test or scanner catches the intended bad case or has a clear preventive rationale, and rollout mode is calibrated for developer workflow." : recipe.id === "internal_app" ? "The built app follows repo-native UI/data patterns and validation proves the access-control contract." : recipe.id === "stale_pr" ? "The handoff names review feedback addressed, validation, remaining risk, and next reviewer action." : recipe.id === "merge_conflict" ? "The resolution preserves intended behavior from both sides or clearly escalates unresolved semantic conflicts." : recipe.id === "flaky_test" ? "The result stabilizes the test or explains the product root cause with evidence rather than hiding the signal." : recipe.id === "small_refactor" ? "The diff stays mechanical and validation proves no intended behavior changed." : recipe.id === "bug_investigation" ? "The root cause, fix, no-fix decision, or escalation is tied to evidence and includes a follow-up watch signal." : recipe.id === "qa_edge_cases" ? "The added or improved tests cover meaningful behavior risk and do not mute, skip, or obscure the signal." : recipe.id === "performance" ? "Before/after measurements, tradeoffs, and rollback signals are recorded before the optimization is accepted." : recipe.id === "porting" ? "The target behavior preserves source intent, attribution is handled, and intentional differences are explicit." : recipe.id === "experiment" ? "The keep, discard, or formalize decision is recorded with validation and remaining production-readiness gaps." : recipe.id === "session_review" ? "Run cards or skill drafts are tied to actual receipts, validation quality, review outcomes, and privacy posture." : recipe.id === "session_library" ? "The
|
|
18355
|
+
recipe.id === "ticket_write" ? "Acceptance criteria, constraints, validation plan, review bar, stop conditions, and update template are parseable from the ticket body." : recipe.id === "security_dependency" ? "Install integrity, build/typecheck, targeted tests, and scanner/audit evidence show the vulnerability is remediated without breaking the dependency path." : recipe.id === "security_finding" ? "The root cause is fixed with negative regression, safe abuse-case proof, or scanner rerun evidence; suppression-only fixes are explicitly rejected or owner-approved." : recipe.id === "security_testing" ? "The added test or scanner catches the intended bad case or has a clear preventive rationale, and rollout mode is calibrated for developer workflow." : recipe.id === "internal_app" ? "The built app follows repo-native UI/data patterns and validation proves the access-control contract." : recipe.id === "stale_pr" ? "The handoff names review feedback addressed, validation, remaining risk, and next reviewer action." : recipe.id === "merge_conflict" ? "The resolution preserves intended behavior from both sides or clearly escalates unresolved semantic conflicts." : recipe.id === "flaky_test" ? "The result stabilizes the test or explains the product root cause with evidence rather than hiding the signal." : recipe.id === "small_refactor" ? "The diff stays mechanical and validation proves no intended behavior changed." : recipe.id === "bug_investigation" ? "The root cause, fix, no-fix decision, or escalation is tied to evidence and includes a follow-up watch signal." : recipe.id === "qa_edge_cases" ? "The added or improved tests cover meaningful behavior risk and do not mute, skip, or obscure the signal." : recipe.id === "performance" ? "Before/after measurements, tradeoffs, and rollback signals are recorded before the optimization is accepted." : recipe.id === "porting" ? "The target behavior preserves source intent, attribution is handled, and intentional differences are explicit." : recipe.id === "experiment" ? "The keep, discard, or formalize decision is recorded with validation and remaining production-readiness gaps." : recipe.id === "session_review" ? "Run cards or skill drafts are tied to actual receipts, validation quality, review outcomes, and privacy posture." : recipe.id === "session_library" ? "The shared examples are derived from approved receipts or explicitly approved imports and include first-run commands, stop conditions, and validation expectations." : options2.needsRuntimeEvidence ? "The root cause, fix, validation, and incident or ticket update are tied back to the runtime evidence." : "The mission output is tied back to the selected recipe and context receipt.",
|
|
18177
18356
|
autonomy === "read_only" ? "No repo files are changed." : "The local diff has no blocker or high Brief findings before human review.",
|
|
18178
18357
|
"Useful repeated feedback is saved or intentionally skipped with a reason."
|
|
18179
18358
|
],
|
|
@@ -19012,10 +19191,10 @@ function missionHookEvents(recipe, autonomy, options2) {
|
|
|
19012
19191
|
if (recipe.id === "session_library") {
|
|
19013
19192
|
events.push({
|
|
19014
19193
|
id: "before_session_library_publish",
|
|
19015
|
-
label: "Before
|
|
19194
|
+
label: "Before team sharing",
|
|
19016
19195
|
timing: "before",
|
|
19017
19196
|
trigger: "An agent turns previous sessions, transcripts, prompts, or run cards into shared examples.",
|
|
19018
|
-
action: "Require receipt proof, privacy classification, owner approval, and explicit raw-import approval before
|
|
19197
|
+
action: "Require receipt proof, privacy classification, owner approval, and explicit raw-import approval before sharing examples with the team.",
|
|
19019
19198
|
mode: "blocking"
|
|
19020
19199
|
});
|
|
19021
19200
|
}
|
|
@@ -20251,7 +20430,7 @@ var init_missionPlan = __esm({
|
|
|
20251
20430
|
guidance: [
|
|
20252
20431
|
"Keep one curator responsible for privacy classification and final library shape.",
|
|
20253
20432
|
"Use parallel agents only to summarize candidate receipts or draft examples from approved sources.",
|
|
20254
|
-
"Do not
|
|
20433
|
+
"Do not share raw transcripts, secrets, logs, or customer data without explicit approval."
|
|
20255
20434
|
]
|
|
20256
20435
|
}
|
|
20257
20436
|
}),
|
|
@@ -20758,7 +20937,7 @@ function privacyBoundaryForRecipe(recipeId) {
|
|
|
20758
20937
|
if (recipeId === "security_finding") {
|
|
20759
20938
|
return [
|
|
20760
20939
|
"redact raw secrets, tokens, cookies, customer payloads, and private logs before agent use",
|
|
20761
|
-
"do not
|
|
20940
|
+
"do not share exploit strings or abuse-case details outside the approved repo/security channel",
|
|
20762
20941
|
"provider rotation or invalidation status is tracked without exposing the replacement credential",
|
|
20763
20942
|
"false-positive and accepted-risk decisions need named owner approval and audit trail"
|
|
20764
20943
|
];
|
|
@@ -20789,7 +20968,7 @@ function privacyBoundaryForRecipe(recipeId) {
|
|
|
20789
20968
|
return [
|
|
20790
20969
|
"derive examples from receipts before raw transcripts",
|
|
20791
20970
|
"require approval for prompts, logs, secrets, or customer data",
|
|
20792
|
-
"
|
|
20971
|
+
"share concise run cards, not private session dumps"
|
|
20793
20972
|
];
|
|
20794
20973
|
}
|
|
20795
20974
|
return [
|
|
@@ -26220,7 +26399,7 @@ var init_agentSetup = __esm({
|
|
|
26220
26399
|
"ide",
|
|
26221
26400
|
"generic"
|
|
26222
26401
|
];
|
|
26223
|
-
briefPublishedPackageSpec = "runbrief@0.1.
|
|
26402
|
+
briefPublishedPackageSpec = "runbrief@0.1.3";
|
|
26224
26403
|
TARGET_LABELS = {
|
|
26225
26404
|
terminal: "Terminal agent",
|
|
26226
26405
|
vscode: "VS Code",
|
|
@@ -27281,7 +27460,7 @@ function summarizeBeforeYouCodeSharedContext(delivery) {
|
|
|
27281
27460
|
next: "Shared guidance is not available in this session; keep new learning personal until the workspace connection is ready."
|
|
27282
27461
|
};
|
|
27283
27462
|
}
|
|
27284
|
-
const next = delivery.status === "applied" ? "Use the applied shared guidance, then save a focused learning or reference when the pass proves a reusable pattern." : delivery.status === "available_not_applied" ? "Shared guidance exists but did not match this task; inspect the relevant team item before creating a new pattern." : "No approved shared guidance exists yet; keep this pass personal and
|
|
27463
|
+
const next = delivery.status === "applied" ? "Use the applied shared guidance, then save a focused learning or reference when the pass proves a reusable pattern." : delivery.status === "available_not_applied" ? "Shared guidance exists but did not match this task; inspect the relevant team item before creating a new pattern." : "No approved shared guidance exists yet; keep this pass personal and make it available to the team only after the pattern is proven.";
|
|
27285
27464
|
return {
|
|
27286
27465
|
status: delivery.status,
|
|
27287
27466
|
workspaceId: delivery.workspaceId,
|
|
@@ -27424,11 +27603,13 @@ function buildBeforeYouCodeMap(scan, input) {
|
|
|
27424
27603
|
files,
|
|
27425
27604
|
maxLines: 18
|
|
27426
27605
|
});
|
|
27606
|
+
const mapCoverage = mapCoverageFor2(scan);
|
|
27427
27607
|
const stopSignals2 = unique([
|
|
27428
27608
|
"Wrong repo, branch, or worktree.",
|
|
27429
27609
|
...target.branch?.startsWith("detached@") ? ["Detached HEAD; select the intended feature branch before editing."] : [],
|
|
27430
27610
|
...insights.agentPacket.stopSignals,
|
|
27431
27611
|
...productOperatingContext.stopSignals.slice(0, 3),
|
|
27612
|
+
...mapCoverage.status === "partial" ? [mapCoverage.summary] : [],
|
|
27432
27613
|
...target.dirty && files.length === 0 ? ["Dirty worktree is broad; classify baseline before editing."] : []
|
|
27433
27614
|
]).slice(0, 5);
|
|
27434
27615
|
const status = inspectFirst.length === 0 && reuseCandidates.length === 0 ? "needs_narrower_scope" : "ready";
|
|
@@ -27448,6 +27629,7 @@ function buildBeforeYouCodeMap(scan, input) {
|
|
|
27448
27629
|
reuseCandidates,
|
|
27449
27630
|
likelyTests,
|
|
27450
27631
|
productOperatingContext,
|
|
27632
|
+
mapCoverage,
|
|
27451
27633
|
...context.teamGuidance ? { teamGuidance: context.teamGuidance } : {},
|
|
27452
27634
|
referenceFirst,
|
|
27453
27635
|
validationChecklist,
|
|
@@ -27460,6 +27642,7 @@ function buildBeforeYouCodeMap(scan, input) {
|
|
|
27460
27642
|
reuseCandidates,
|
|
27461
27643
|
likelyTests,
|
|
27462
27644
|
productOperatingContext,
|
|
27645
|
+
mapCoverage,
|
|
27463
27646
|
validationChecklist,
|
|
27464
27647
|
stopSignals: stopSignals2,
|
|
27465
27648
|
...context.teamGuidance ? { teamGuidance: context.teamGuidance } : {},
|
|
@@ -27479,7 +27662,9 @@ function buildBeforeYouCodeMap(scan, input) {
|
|
|
27479
27662
|
candidates: reuseCandidates,
|
|
27480
27663
|
decision: reuseCandidates.length > 0 ? "For each candidate, choose reuse, adapt, or rule out and record the decision before creating a new primitive." : "No reuse candidate is grounded yet; run one focused search before creating a new primitive."
|
|
27481
27664
|
},
|
|
27665
|
+
mapCoverage,
|
|
27482
27666
|
...context.teamGuidance ? { teamGuidance: context.teamGuidance } : {},
|
|
27667
|
+
rules: context.rules.slice(0, 8),
|
|
27483
27668
|
referenceFirst,
|
|
27484
27669
|
likelyTests,
|
|
27485
27670
|
exactTests,
|
|
@@ -27491,6 +27676,19 @@ function buildBeforeYouCodeMap(scan, input) {
|
|
|
27491
27676
|
next: status === "ready" ? "Inspect these files and reuse candidates before editing; cite the reuse decision in the final handoff." : "Run brief.codebase_map or brief.context_for_task with a narrower task, folder, or file list before editing."
|
|
27492
27677
|
};
|
|
27493
27678
|
}
|
|
27679
|
+
function mapCoverageFor2(scan) {
|
|
27680
|
+
const mappedNodes = scan.stats.mapNodeCount;
|
|
27681
|
+
const omittedNodes = Math.max(0, scan.stats.mapOmittedCount ?? 0);
|
|
27682
|
+
const candidateNodes = Math.max(mappedNodes, scan.stats.mapTotalCandidateCount ?? mappedNodes + omittedNodes);
|
|
27683
|
+
const partial = Boolean(scan.stats.mapPartial) || omittedNodes > 0;
|
|
27684
|
+
return {
|
|
27685
|
+
status: partial ? "partial" : "complete",
|
|
27686
|
+
mappedNodes,
|
|
27687
|
+
candidateNodes,
|
|
27688
|
+
omittedNodes,
|
|
27689
|
+
summary: partial ? `Code map is partial: ${mappedNodes} of ${candidateNodes} candidate nodes are available; narrow by feature, folder, or symbol before treating a missing reuse candidate as proof none exists.` : `Code map covers all ${mappedNodes} indexed candidate nodes for this repo.`
|
|
27690
|
+
};
|
|
27691
|
+
}
|
|
27494
27692
|
function reuseStatusFor(candidates) {
|
|
27495
27693
|
if (candidates.length === 0)
|
|
27496
27694
|
return "missing";
|
|
@@ -27611,6 +27809,7 @@ function cockpitFor(input) {
|
|
|
27611
27809
|
"Broad e2e or full-suite tests unless routing, auth, persistence, or cross-page state changed."
|
|
27612
27810
|
];
|
|
27613
27811
|
const stopSignals2 = unique([
|
|
27812
|
+
...input.mapCoverage.status === "partial" ? [input.mapCoverage.summary] : [],
|
|
27614
27813
|
...input.stopSignals.slice(0, 3),
|
|
27615
27814
|
...mode === "lightweight" ? [
|
|
27616
27815
|
"The tiny pass starts touching behavior, state, data, auth, or multiple surfaces."
|
|
@@ -27798,55 +27997,55 @@ function diversifyJourneyStages(ranked, task) {
|
|
|
27798
27997
|
];
|
|
27799
27998
|
}
|
|
27800
27999
|
function journeyStagePathPreference(stage, filePath) {
|
|
27801
|
-
const
|
|
28000
|
+
const path21 = filePath.toLowerCase();
|
|
27802
28001
|
if (stage === "acquisition") {
|
|
27803
|
-
if (/landinginteractive\.[cm]?[tj]sx?$/.test(
|
|
28002
|
+
if (/landinginteractive\.[cm]?[tj]sx?$/.test(path21))
|
|
27804
28003
|
return 40;
|
|
27805
|
-
if (/apps\/web\/src\/app\/page\.[cm]?[tj]sx?$/.test(
|
|
28004
|
+
if (/apps\/web\/src\/app\/page\.[cm]?[tj]sx?$/.test(path21))
|
|
27806
28005
|
return 35;
|
|
27807
28006
|
}
|
|
27808
28007
|
if (stage === "access") {
|
|
27809
|
-
if (/apps\/web\/src\/app\/login\/page\.[cm]?[tj]sx?$/.test(
|
|
28008
|
+
if (/apps\/web\/src\/app\/login\/page\.[cm]?[tj]sx?$/.test(path21))
|
|
27810
28009
|
return 40;
|
|
27811
|
-
if (/api\/auth\/magic-link\/route\.[cm]?[tj]s$/.test(
|
|
28010
|
+
if (/api\/auth\/magic-link\/route\.[cm]?[tj]s$/.test(path21))
|
|
27812
28011
|
return 35;
|
|
27813
28012
|
}
|
|
27814
28013
|
if (stage === "workspace") {
|
|
27815
|
-
if (/api\/v1\/workspaces\/bootstrap\/route\.[cm]?[tj]s$/.test(
|
|
28014
|
+
if (/api\/v1\/workspaces\/bootstrap\/route\.[cm]?[tj]s$/.test(path21)) {
|
|
27816
28015
|
return 40;
|
|
27817
28016
|
}
|
|
27818
28017
|
}
|
|
27819
28018
|
if (stage === "activation") {
|
|
27820
|
-
if (/api\/v1\/workspaces\/[^/]+\/api-keys\/route\.[cm]?[tj]s$/.test(
|
|
28019
|
+
if (/api\/v1\/workspaces\/[^/]+\/api-keys\/route\.[cm]?[tj]s$/.test(path21)) {
|
|
27821
28020
|
return 40;
|
|
27822
28021
|
}
|
|
27823
|
-
if (/workspace-agent-actions\.[cm]?[tj]s$/.test(
|
|
28022
|
+
if (/workspace-agent-actions\.[cm]?[tj]s$/.test(path21))
|
|
27824
28023
|
return 35;
|
|
27825
|
-
if (/agent-handoff-composer\.[cm]?[tj]s$/.test(
|
|
28024
|
+
if (/agent-handoff-composer\.[cm]?[tj]s$/.test(path21))
|
|
27826
28025
|
return 30;
|
|
27827
28026
|
}
|
|
27828
28027
|
if (stage === "collaboration") {
|
|
27829
|
-
if (/api\/v1\/workspaces\/[^/]+\/invitations\/route\.[cm]?[tj]s$/.test(
|
|
28028
|
+
if (/api\/v1\/workspaces\/[^/]+\/invitations\/route\.[cm]?[tj]s$/.test(path21)) {
|
|
27830
28029
|
return 40;
|
|
27831
28030
|
}
|
|
27832
|
-
if (/api\/v1\/workspaces\/[^/]+\/members\/[^/]+\/route/.test(
|
|
28031
|
+
if (/api\/v1\/workspaces\/[^/]+\/members\/[^/]+\/route/.test(path21)) {
|
|
27833
28032
|
return 30;
|
|
27834
28033
|
}
|
|
27835
28034
|
}
|
|
27836
28035
|
if (stage === "monetization") {
|
|
27837
|
-
if (/billing\/checkout\/route\.[cm]?[tj]s$/.test(
|
|
28036
|
+
if (/billing\/checkout\/route\.[cm]?[tj]s$/.test(path21))
|
|
27838
28037
|
return 40;
|
|
27839
|
-
if (/pricing\/page\.[cm]?[tj]sx?$/.test(
|
|
28038
|
+
if (/pricing\/page\.[cm]?[tj]sx?$/.test(path21))
|
|
27840
28039
|
return 35;
|
|
27841
28040
|
}
|
|
27842
28041
|
return 0;
|
|
27843
28042
|
}
|
|
27844
|
-
function beforeYouCodePathIntentScore(
|
|
27845
|
-
const lowerPath = (
|
|
28043
|
+
function beforeYouCodePathIntentScore(path21, task) {
|
|
28044
|
+
const lowerPath = (path21.split("#", 1)[0] ?? path21).toLowerCase();
|
|
27846
28045
|
const lowerTask = task.toLowerCase();
|
|
27847
|
-
let score = namedCodePathIntentScore(
|
|
28046
|
+
let score = namedCodePathIntentScore(path21, task);
|
|
27848
28047
|
const wantsInterface = /\b(app|design|header|interface|landing|layout|mobile|navigation|page|responsive|spacing|ui|ux|visual|workspace)\b/.test(lowerTask);
|
|
27849
|
-
score += lexicalPathTaskScore(
|
|
28048
|
+
score += lexicalPathTaskScore(path21, task);
|
|
27850
28049
|
const wantsLanding = /\b(hero|homepage|landing)\b/.test(lowerTask);
|
|
27851
28050
|
const wantsAppShell = /\b(app|header|internal|mobile|navigation|responsive|sidebar|workspace)\b/.test(lowerTask);
|
|
27852
28051
|
const wantsAuth = /\b(auth|authentication|callback|login|magic link|otp|session|sign[ -]?in|sign[ -]?out)\b/.test(lowerTask);
|
|
@@ -27996,8 +28195,8 @@ function beforeYouCodePathIntentScore(path20, task) {
|
|
|
27996
28195
|
}
|
|
27997
28196
|
return score;
|
|
27998
28197
|
}
|
|
27999
|
-
function beforeYouCodeIntentSummary(
|
|
28000
|
-
const normalizedPath = (
|
|
28198
|
+
function beforeYouCodeIntentSummary(path21, task) {
|
|
28199
|
+
const normalizedPath = (path21.split("#", 1)[0] ?? path21).toLowerCase();
|
|
28001
28200
|
if (!isInternalAppTask(task))
|
|
28002
28201
|
return void 0;
|
|
28003
28202
|
if (/apps\/web\/src\/app\/app\/page\.[cm]?[tj]sx?$/.test(normalizedPath)) {
|
|
@@ -28023,7 +28222,7 @@ function prefersPrimaryWorkspaceTask(task) {
|
|
|
28023
28222
|
return true;
|
|
28024
28223
|
return /\b(design|designer|figma|screenshot|visual|ui|ux|layout|spacing|typography|responsive|mobile)\b/i.test(task);
|
|
28025
28224
|
}
|
|
28026
|
-
function lexicalPathTaskScore(
|
|
28225
|
+
function lexicalPathTaskScore(path21, task) {
|
|
28027
28226
|
const ignored = /* @__PURE__ */ new Set([
|
|
28028
28227
|
"agent",
|
|
28029
28228
|
"brief",
|
|
@@ -28043,7 +28242,7 @@ function lexicalPathTaskScore(path20, task) {
|
|
|
28043
28242
|
taskWords.add("workspace");
|
|
28044
28243
|
taskWords.add("pane");
|
|
28045
28244
|
}
|
|
28046
|
-
const pathWords =
|
|
28245
|
+
const pathWords = path21.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter((word) => word.length >= 4 && !ignored.has(word));
|
|
28047
28246
|
const matches = unique(pathWords.filter((word) => taskWords.has(word)));
|
|
28048
28247
|
const structuralBonus = matches.reduce((score, word) => {
|
|
28049
28248
|
if (!["header", "pane", "shell", "sidebar", "workspace"].includes(word)) {
|
|
@@ -28117,6 +28316,7 @@ function compactTextFor2(input) {
|
|
|
28117
28316
|
`Before coding: ${input.headline}`,
|
|
28118
28317
|
`Target: ${input.target.repoName} | ${input.target.branch ?? "branch unknown"} | ${input.target.repoRoot}`,
|
|
28119
28318
|
`Worktree: ${input.target.dirty ? "dirty" : "clean"}${input.target.changedFiles.length ? `; changed ${input.target.changedFiles.slice(0, 4).join(", ")}` : ""}${input.target.untrackedFiles.length ? `; untracked ${input.target.untrackedFiles.slice(0, 3).join(", ")}` : ""}`,
|
|
28319
|
+
`Map coverage: ${input.mapCoverage.summary}`,
|
|
28120
28320
|
...input.target.requestedFiles.length ? [`Scope files: ${input.target.requestedFiles.slice(0, 5).join(", ")}`] : [],
|
|
28121
28321
|
...input.teamGuidance ? [
|
|
28122
28322
|
`Shared guidance: ${input.teamGuidance.applied.length > 0 ? input.teamGuidance.applied.slice(0, 2).map((item) => item.label).join(", ") : input.teamGuidance.status === "available_not_applied" ? "available, but none matched this task" : "none approved yet"}`
|
|
@@ -28164,6 +28364,119 @@ var init_agentBeforeYouCode = __esm({
|
|
|
28164
28364
|
}
|
|
28165
28365
|
});
|
|
28166
28366
|
|
|
28367
|
+
// ../core/dist/agentWorkPacket.js
|
|
28368
|
+
function buildAgentWorkPacket(input) {
|
|
28369
|
+
const before = input.beforeYouCode;
|
|
28370
|
+
const rules = uniqueRules2([
|
|
28371
|
+
...(before.teamGuidance?.applied ?? []).map((item) => ({
|
|
28372
|
+
rule: item.label,
|
|
28373
|
+
source: `team:${item.kind}`
|
|
28374
|
+
})),
|
|
28375
|
+
...(before.rules ?? []).map((item) => ({
|
|
28376
|
+
rule: compact(item.body || item.title, 180),
|
|
28377
|
+
source: item.sourcePaths[0] ?? "repo guidance"
|
|
28378
|
+
})),
|
|
28379
|
+
...before.productOperatingContext.productRules.map((item) => ({
|
|
28380
|
+
rule: item.rule,
|
|
28381
|
+
source: item.source
|
|
28382
|
+
}))
|
|
28383
|
+
]).slice(0, 3);
|
|
28384
|
+
const tests = before.exactTests.length > 0 ? before.exactTests.slice(0, 3).map((test) => ({
|
|
28385
|
+
command: compact(test.command, 180),
|
|
28386
|
+
reason: compact(test.reason, 180),
|
|
28387
|
+
confidence: test.confidence
|
|
28388
|
+
})) : before.likelyTests.slice(0, 3).map((command2) => ({
|
|
28389
|
+
command: compact(command2, 180),
|
|
28390
|
+
reason: "Nearest validation signal Brief found for this task.",
|
|
28391
|
+
confidence: "medium"
|
|
28392
|
+
}));
|
|
28393
|
+
const acceptance = unique2([
|
|
28394
|
+
...before.productOperatingContext.acceptanceCriteria,
|
|
28395
|
+
...before.validationChecklist
|
|
28396
|
+
]).slice(0, 3);
|
|
28397
|
+
const stopConditions = unique2([
|
|
28398
|
+
...before.stopSignals,
|
|
28399
|
+
...before.productOperatingContext.stopSignals,
|
|
28400
|
+
...before.mapCoverage.status === "partial" ? [before.mapCoverage.summary] : []
|
|
28401
|
+
]).slice(0, 3);
|
|
28402
|
+
const nextAction = input.nextAction ?? before.next ?? "Inspect the listed files and make the reuse decision before editing.";
|
|
28403
|
+
const packet = {
|
|
28404
|
+
schemaVersion: 1,
|
|
28405
|
+
objective: compact(input.task, 240),
|
|
28406
|
+
interpretation: compact(input.interpretation ?? before.productOperatingContext.summary ?? before.headline, 160),
|
|
28407
|
+
target: {
|
|
28408
|
+
repoRoot: before.target.repoRoot,
|
|
28409
|
+
repoName: before.target.repoName,
|
|
28410
|
+
...before.target.branch ? { branch: before.target.branch } : {},
|
|
28411
|
+
...before.target.baseRef ? { baseRef: before.target.baseRef } : {},
|
|
28412
|
+
dirty: before.target.dirty,
|
|
28413
|
+
changedFiles: before.target.changedFiles.slice(0, 4)
|
|
28414
|
+
},
|
|
28415
|
+
inspectFirst: before.inspectFirst.slice(0, 3).map((item) => ({
|
|
28416
|
+
path: item.path,
|
|
28417
|
+
why: compact(item.why, 160)
|
|
28418
|
+
})),
|
|
28419
|
+
reuse: {
|
|
28420
|
+
status: before.reuseFirst.status,
|
|
28421
|
+
decision: compact(before.reuseFirst.decision, 220),
|
|
28422
|
+
candidates: before.reuseFirst.candidates.slice(0, 2).map((item) => ({
|
|
28423
|
+
path: item.path,
|
|
28424
|
+
action: compact(item.action, 140),
|
|
28425
|
+
why: compact(item.why, 140)
|
|
28426
|
+
}))
|
|
28427
|
+
},
|
|
28428
|
+
mapCoverage: before.mapCoverage,
|
|
28429
|
+
rules,
|
|
28430
|
+
tests,
|
|
28431
|
+
acceptance,
|
|
28432
|
+
stopConditions,
|
|
28433
|
+
nextAction: compact(nextAction, 200)
|
|
28434
|
+
};
|
|
28435
|
+
const compactText = formatAgentWorkPacket(packet);
|
|
28436
|
+
return { ...packet, compactText, lineCount: compactText.split("\n").length };
|
|
28437
|
+
}
|
|
28438
|
+
function formatAgentWorkPacket(packet) {
|
|
28439
|
+
const lines = [
|
|
28440
|
+
`Objective: ${packet.objective}`,
|
|
28441
|
+
`Target: ${packet.target.repoName}${packet.target.branch ? ` @ ${packet.target.branch}` : ""} (${packet.target.dirty ? "dirty" : "clean"})`,
|
|
28442
|
+
`Interpretation: ${packet.interpretation}`,
|
|
28443
|
+
`Inspect first: ${inlineList(packet.inspectFirst.map((item) => `${item.path} - ${item.why}`))}`,
|
|
28444
|
+
`Reuse (${packet.reuse.status}): ${packet.reuse.decision}; ${inlineList(packet.reuse.candidates.map((item) => `${item.path} - ${item.action}`))}`,
|
|
28445
|
+
`Map: ${packet.mapCoverage.summary}`,
|
|
28446
|
+
`Rules: ${inlineList(packet.rules.map((item) => `${item.rule} [${item.source}]`))}`,
|
|
28447
|
+
`Focused tests: ${inlineList(packet.tests.map((item) => `${item.command} - ${item.reason}`))}`,
|
|
28448
|
+
`Acceptance: ${inlineList(packet.acceptance)}`,
|
|
28449
|
+
`Stop if: ${inlineList(packet.stopConditions)}`,
|
|
28450
|
+
`Next: ${packet.nextAction}`
|
|
28451
|
+
];
|
|
28452
|
+
return lines.join("\n");
|
|
28453
|
+
}
|
|
28454
|
+
function inlineList(items) {
|
|
28455
|
+
return items.length > 0 ? items.join("; ") : "none found";
|
|
28456
|
+
}
|
|
28457
|
+
function compact(value, maxLength) {
|
|
28458
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
28459
|
+
return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 3).trimEnd()}...`;
|
|
28460
|
+
}
|
|
28461
|
+
function unique2(values) {
|
|
28462
|
+
return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
|
|
28463
|
+
}
|
|
28464
|
+
function uniqueRules2(rules) {
|
|
28465
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28466
|
+
return rules.filter((item) => {
|
|
28467
|
+
const key = item.rule.toLowerCase();
|
|
28468
|
+
if (!item.rule || seen.has(key))
|
|
28469
|
+
return false;
|
|
28470
|
+
seen.add(key);
|
|
28471
|
+
return true;
|
|
28472
|
+
});
|
|
28473
|
+
}
|
|
28474
|
+
var init_agentWorkPacket = __esm({
|
|
28475
|
+
"../core/dist/agentWorkPacket.js"() {
|
|
28476
|
+
"use strict";
|
|
28477
|
+
}
|
|
28478
|
+
});
|
|
28479
|
+
|
|
28167
28480
|
// ../core/dist/ticketMissionRuntime.js
|
|
28168
28481
|
var init_ticketMissionRuntime = __esm({
|
|
28169
28482
|
"../core/dist/ticketMissionRuntime.js"() {
|
|
@@ -28803,7 +29116,7 @@ function codeMapBetaReadiness(input) {
|
|
|
28803
29116
|
score: Math.min(100, Math.round((betaScore + input.qualityScore) / 2)),
|
|
28804
29117
|
summary: status === "beta_plus" ? "Beta+ ready: agents have source-grounded code surfaces, parser facts, ownership, validation, operational context, and focused map proof." : status === "beta" ? "Beta: source-grounded enough to use, with remaining proof gaps that should be explicit in missions." : status === "alpha" ? "Alpha: useful orientation, but agents need narrower source, proof, or operational context before autonomous edits." : "Blocked: this map is not safe to use as architecture proof yet.",
|
|
28805
29118
|
checks,
|
|
28806
|
-
blockingGaps:
|
|
29119
|
+
blockingGaps: unique3(blockingGaps),
|
|
28807
29120
|
nextActions: status === "beta_plus" ? [
|
|
28808
29121
|
"Use this map as the pre-edit context gate for agent missions.",
|
|
28809
29122
|
"Preserve mapQuality.betaReadiness in review_diff and save_handoff proof."
|
|
@@ -28876,7 +29189,7 @@ function metadataList(node, key) {
|
|
|
28876
29189
|
return [];
|
|
28877
29190
|
return value.filter((item) => typeof item === "string");
|
|
28878
29191
|
}
|
|
28879
|
-
function
|
|
29192
|
+
function unique3(items) {
|
|
28880
29193
|
return [...new Set(items)];
|
|
28881
29194
|
}
|
|
28882
29195
|
var CODE_SURFACE_TYPES2, SOURCE_AWARE_TYPES, OBSERVABILITY_SYSTEMS, TICKET_SYSTEMS, DATA_SYSTEMS;
|
|
@@ -29907,12 +30220,12 @@ function humanQuestionsFor(advisory, omittedFindingCount) {
|
|
|
29907
30220
|
return unique(questions.map((question) => compactReviewQuestion(question))).slice(0, 8);
|
|
29908
30221
|
}
|
|
29909
30222
|
function compactReviewQuestion(value, maxLength = 800) {
|
|
29910
|
-
const
|
|
29911
|
-
if (
|
|
29912
|
-
return
|
|
30223
|
+
const compact2 = value.replace(/\s+/g, " ").trim();
|
|
30224
|
+
if (compact2.length <= maxLength)
|
|
30225
|
+
return compact2;
|
|
29913
30226
|
if (maxLength <= 3)
|
|
29914
|
-
return
|
|
29915
|
-
return `${
|
|
30227
|
+
return compact2.slice(0, maxLength);
|
|
30228
|
+
return `${compact2.slice(0, maxLength - 3).trimEnd()}...`;
|
|
29916
30229
|
}
|
|
29917
30230
|
function reviewReadinessScore(counts, proofStatus, review) {
|
|
29918
30231
|
const penalty = counts.blocker * 35 + counts.high * 28 + counts.medium * 12 + counts.low * 5 + counts.info * 1 + review.omittedFindingCount * 2;
|
|
@@ -31096,6 +31409,7 @@ var init_diffReview = __esm({
|
|
|
31096
31409
|
"handler",
|
|
31097
31410
|
"helpers",
|
|
31098
31411
|
"delete",
|
|
31412
|
+
"dynamic",
|
|
31099
31413
|
"get",
|
|
31100
31414
|
"head",
|
|
31101
31415
|
"input",
|
|
@@ -32978,6 +33292,7 @@ var init_dist2 = __esm({
|
|
|
32978
33292
|
init_missionPlan();
|
|
32979
33293
|
init_agentStart();
|
|
32980
33294
|
init_agentBeforeYouCode();
|
|
33295
|
+
init_agentWorkPacket();
|
|
32981
33296
|
init_productOperatingContext();
|
|
32982
33297
|
init_ticketMissionRuntime();
|
|
32983
33298
|
init_governance();
|
|
@@ -33005,7 +33320,7 @@ function cloudSyncStatus(env = process.env) {
|
|
|
33005
33320
|
return {
|
|
33006
33321
|
configured: false,
|
|
33007
33322
|
privacyMode,
|
|
33008
|
-
reason: privacyMode === "local-only" ? "Cloud sync is disabled by privacy mode." : "
|
|
33323
|
+
reason: privacyMode === "local-only" ? "Cloud sync is disabled by privacy mode." : "Connect Brief from the app to authorize this device, or provide BRIEF_API_URL and BRIEF_API_KEY for an approved legacy setup."
|
|
33009
33324
|
};
|
|
33010
33325
|
}
|
|
33011
33326
|
const status = {
|
|
@@ -33162,6 +33477,64 @@ async function fetchTeamContext(repoRoot, env = process.env, fetcher = fetch) {
|
|
|
33162
33477
|
});
|
|
33163
33478
|
return getTeamContextCloud(config, payload, fetcher);
|
|
33164
33479
|
}
|
|
33480
|
+
async function claimRemoteLoopRun(runnerId, leaseSeconds = 180, env = process.env, fetcher = fetch) {
|
|
33481
|
+
const config = cloudConfigFromEnv(env);
|
|
33482
|
+
if (!config) throw new Error("Brief cloud connection is not configured for the runner.");
|
|
33483
|
+
const payload = claimLoopRunRequestSchema.parse({ runnerId, leaseSeconds });
|
|
33484
|
+
const body = await loopRunRequest(
|
|
33485
|
+
config,
|
|
33486
|
+
"/api/v1/mcp/loop-runs/claim",
|
|
33487
|
+
"POST",
|
|
33488
|
+
payload,
|
|
33489
|
+
fetcher
|
|
33490
|
+
);
|
|
33491
|
+
if (!body.ok) throw new Error(body.message ?? "Brief could not claim a loop run.");
|
|
33492
|
+
if (!body.run) return null;
|
|
33493
|
+
const parsed = loopRunSummarySchema.safeParse(body.run);
|
|
33494
|
+
if (!parsed.success) throw new Error("Brief returned an invalid loop run.");
|
|
33495
|
+
return parsed.data;
|
|
33496
|
+
}
|
|
33497
|
+
async function updateRemoteLoopRun(runId, input, env = process.env, fetcher = fetch) {
|
|
33498
|
+
const config = cloudConfigFromEnv(env);
|
|
33499
|
+
if (!config) throw new Error("Brief cloud connection is not configured for the runner.");
|
|
33500
|
+
const payload = updateLoopRunRequestSchema.parse(input);
|
|
33501
|
+
const body = await loopRunRequest(
|
|
33502
|
+
config,
|
|
33503
|
+
`/api/v1/mcp/loop-runs/${encodeURIComponent(runId)}`,
|
|
33504
|
+
"PATCH",
|
|
33505
|
+
payload,
|
|
33506
|
+
fetcher
|
|
33507
|
+
);
|
|
33508
|
+
if (!body.ok) throw new Error(body.message ?? "Brief could not update the loop run.");
|
|
33509
|
+
const parsed = loopRunSummarySchema.safeParse(body.run);
|
|
33510
|
+
if (!parsed.success) throw new Error("Brief returned an invalid updated loop run.");
|
|
33511
|
+
return parsed.data;
|
|
33512
|
+
}
|
|
33513
|
+
async function loopRunRequest(config, route, method, payload, fetcher) {
|
|
33514
|
+
const controller = new AbortController();
|
|
33515
|
+
const timeout = setTimeout(() => controller.abort(), syncTimeoutMs);
|
|
33516
|
+
try {
|
|
33517
|
+
const response = await fetcher(`${config.apiUrl}${route}`, {
|
|
33518
|
+
method,
|
|
33519
|
+
headers: {
|
|
33520
|
+
authorization: `Bearer ${config.apiKey}`,
|
|
33521
|
+
"content-type": "application/json"
|
|
33522
|
+
},
|
|
33523
|
+
body: JSON.stringify(payload),
|
|
33524
|
+
signal: controller.signal
|
|
33525
|
+
});
|
|
33526
|
+
const body = await safeJson(response);
|
|
33527
|
+
const record = body && typeof body === "object" && !Array.isArray(body) ? body : {};
|
|
33528
|
+
const result = {
|
|
33529
|
+
ok: response.ok && record.ok === true
|
|
33530
|
+
};
|
|
33531
|
+
if (typeof record.message === "string") result.message = record.message;
|
|
33532
|
+
if (record.run !== void 0) result.run = record.run;
|
|
33533
|
+
return result;
|
|
33534
|
+
} finally {
|
|
33535
|
+
clearTimeout(timeout);
|
|
33536
|
+
}
|
|
33537
|
+
}
|
|
33165
33538
|
function toRepoScanSummary(scan, privacyMode) {
|
|
33166
33539
|
return {
|
|
33167
33540
|
repoName: scan.repoName,
|
|
@@ -33207,7 +33580,7 @@ function skippedResult(env) {
|
|
|
33207
33580
|
return {
|
|
33208
33581
|
status: "skipped",
|
|
33209
33582
|
privacyMode,
|
|
33210
|
-
reason: privacyMode === "local-only" ? "Cloud sync skipped because privacy mode is local-only." : "Cloud sync skipped because
|
|
33583
|
+
reason: privacyMode === "local-only" ? "Cloud sync skipped because privacy mode is local-only." : "Cloud sync skipped because this device is not connected. Create a browser-authorized connection from the Brief app, then restart the agent."
|
|
33211
33584
|
};
|
|
33212
33585
|
}
|
|
33213
33586
|
function skippedTeamContextResult(env) {
|
|
@@ -33215,7 +33588,7 @@ function skippedTeamContextResult(env) {
|
|
|
33215
33588
|
return {
|
|
33216
33589
|
status: "skipped",
|
|
33217
33590
|
privacyMode,
|
|
33218
|
-
reason: privacyMode === "local-only" ? "Cloud sync skipped because privacy mode is local-only." : "Cloud sync skipped because
|
|
33591
|
+
reason: privacyMode === "local-only" ? "Cloud sync skipped because privacy mode is local-only." : "Cloud sync skipped because this device is not connected. Create a browser-authorized connection from the Brief app, then restart the agent."
|
|
33219
33592
|
};
|
|
33220
33593
|
}
|
|
33221
33594
|
function normalizeApiUrl(apiUrl) {
|
|
@@ -33639,9 +34012,9 @@ function issuesValue(value) {
|
|
|
33639
34012
|
if (typeof item === "string") return item;
|
|
33640
34013
|
if (!item || typeof item !== "object") return "";
|
|
33641
34014
|
const record = item;
|
|
33642
|
-
const
|
|
34015
|
+
const path21 = Array.isArray(record.path) ? record.path.join(".") : "";
|
|
33643
34016
|
const message = stringValue(record.message);
|
|
33644
|
-
return [
|
|
34017
|
+
return [path21, message].filter(Boolean).join(": ");
|
|
33645
34018
|
}).filter(Boolean).slice(0, 5).join("; ");
|
|
33646
34019
|
}
|
|
33647
34020
|
var syncTimeoutMs, canonicalBriefApiUrl, legacyBriefApiUrls;
|
|
@@ -34032,14 +34405,178 @@ var init_missionInputOptions = __esm({
|
|
|
34032
34405
|
}
|
|
34033
34406
|
});
|
|
34034
34407
|
|
|
34035
|
-
// ../mcp/src/
|
|
34036
|
-
import {
|
|
34408
|
+
// ../mcp/src/cloudCredentials.ts
|
|
34409
|
+
import { chmodSync, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
34410
|
+
import os from "node:os";
|
|
34037
34411
|
import path14 from "node:path";
|
|
34412
|
+
async function bootstrapCloudCredentials(env = process.env) {
|
|
34413
|
+
if (env.BRIEF_PRIVACY_MODE === "local-only") {
|
|
34414
|
+
return { status: "skipped", reason: "local_only" };
|
|
34415
|
+
}
|
|
34416
|
+
if (env.BRIEF_API_URL && env.BRIEF_API_KEY) {
|
|
34417
|
+
return { status: "configured", source: "env" };
|
|
34418
|
+
}
|
|
34419
|
+
const credentialPath = credentialsPath(env);
|
|
34420
|
+
const requestedOrigin = originFrom(
|
|
34421
|
+
env.BRIEF_API_URL ?? env.BRIEF_CONNECT_URL
|
|
34422
|
+
);
|
|
34423
|
+
const requestedWorkspace = env.BRIEF_WORKSPACE_ID?.trim();
|
|
34424
|
+
const stored = readCredentialFile(credentialPath);
|
|
34425
|
+
const existing = stored.credentials.find((credential2) => {
|
|
34426
|
+
if (requestedOrigin && originFrom(credential2.apiUrl) !== requestedOrigin) {
|
|
34427
|
+
return false;
|
|
34428
|
+
}
|
|
34429
|
+
return !requestedWorkspace || credential2.workspaceId === requestedWorkspace;
|
|
34430
|
+
});
|
|
34431
|
+
if (existing) {
|
|
34432
|
+
applyCredential(env, existing);
|
|
34433
|
+
return { status: "configured", source: "local_store" };
|
|
34434
|
+
}
|
|
34435
|
+
const connectUrl = env.BRIEF_CONNECT_URL?.trim();
|
|
34436
|
+
const connectCode = env.BRIEF_CONNECT_CODE?.trim();
|
|
34437
|
+
if (!connectUrl || !connectCode) {
|
|
34438
|
+
return {
|
|
34439
|
+
status: "skipped",
|
|
34440
|
+
reason: "no_cloud_credential_or_pairing_setup"
|
|
34441
|
+
};
|
|
34442
|
+
}
|
|
34443
|
+
let response;
|
|
34444
|
+
try {
|
|
34445
|
+
response = await fetch(connectUrl, {
|
|
34446
|
+
method: "POST",
|
|
34447
|
+
headers: {
|
|
34448
|
+
accept: "application/json",
|
|
34449
|
+
"content-type": "application/json"
|
|
34450
|
+
},
|
|
34451
|
+
body: JSON.stringify({ code: connectCode }),
|
|
34452
|
+
signal: AbortSignal.timeout(1e4)
|
|
34453
|
+
});
|
|
34454
|
+
} catch {
|
|
34455
|
+
return {
|
|
34456
|
+
status: "failed",
|
|
34457
|
+
reason: "Could not reach the Brief connection service. Check your network and try a fresh setup from the Brief app."
|
|
34458
|
+
};
|
|
34459
|
+
}
|
|
34460
|
+
const body = await response.json().catch(() => null);
|
|
34461
|
+
if (!response.ok || !body?.ok || !body.apiUrl || !body.apiKey || !apiKeyPattern.test(body.apiKey) || !body.workspaceId || !body.privacyMode) {
|
|
34462
|
+
return {
|
|
34463
|
+
status: "failed",
|
|
34464
|
+
reason: body?.message ?? "This Brief setup link is expired or already used. Create a fresh connection from the Brief app."
|
|
34465
|
+
};
|
|
34466
|
+
}
|
|
34467
|
+
const credential = {
|
|
34468
|
+
apiUrl: body.apiUrl,
|
|
34469
|
+
apiKey: body.apiKey,
|
|
34470
|
+
workspaceId: body.workspaceId,
|
|
34471
|
+
privacyMode: body.privacyMode,
|
|
34472
|
+
...body.connectorId ? { connectorId: body.connectorId } : {},
|
|
34473
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
34474
|
+
};
|
|
34475
|
+
try {
|
|
34476
|
+
writeCredentialFile(credentialPath, [
|
|
34477
|
+
...stored.credentials.filter(
|
|
34478
|
+
(item) => item.workspaceId !== credential.workspaceId || originFrom(item.apiUrl) !== originFrom(credential.apiUrl)
|
|
34479
|
+
),
|
|
34480
|
+
credential
|
|
34481
|
+
]);
|
|
34482
|
+
} catch {
|
|
34483
|
+
return {
|
|
34484
|
+
status: "failed",
|
|
34485
|
+
reason: "Brief connected, but could not save the local credential. Check permissions for the local Brief config directory and try again."
|
|
34486
|
+
};
|
|
34487
|
+
}
|
|
34488
|
+
applyCredential(env, credential);
|
|
34489
|
+
return { status: "configured", source: "pairing" };
|
|
34490
|
+
}
|
|
34491
|
+
function forgetCloudCredentials(env = process.env) {
|
|
34492
|
+
const credentialPath = credentialsPath(env);
|
|
34493
|
+
const stored = readCredentialFile(credentialPath);
|
|
34494
|
+
const requestedOrigin = originFrom(
|
|
34495
|
+
env.BRIEF_API_URL ?? env.BRIEF_CONNECT_URL
|
|
34496
|
+
);
|
|
34497
|
+
const requestedWorkspace = env.BRIEF_WORKSPACE_ID?.trim();
|
|
34498
|
+
const remaining = stored.credentials.filter((credential) => {
|
|
34499
|
+
if (requestedOrigin && originFrom(credential.apiUrl) !== requestedOrigin) {
|
|
34500
|
+
return true;
|
|
34501
|
+
}
|
|
34502
|
+
return Boolean(
|
|
34503
|
+
requestedWorkspace && credential.workspaceId !== requestedWorkspace
|
|
34504
|
+
);
|
|
34505
|
+
});
|
|
34506
|
+
writeCredentialFile(credentialPath, remaining);
|
|
34507
|
+
}
|
|
34508
|
+
function defaultCredentialsPath(env = process.env) {
|
|
34509
|
+
return credentialsPath(env);
|
|
34510
|
+
}
|
|
34511
|
+
function credentialsPath(env) {
|
|
34512
|
+
return env.BRIEF_CREDENTIALS_FILE?.trim() || path14.join(
|
|
34513
|
+
env.XDG_CONFIG_HOME?.trim() || path14.join(os.homedir(), ".config"),
|
|
34514
|
+
"runbrief",
|
|
34515
|
+
"credentials.json"
|
|
34516
|
+
);
|
|
34517
|
+
}
|
|
34518
|
+
function readCredentialFile(filePath) {
|
|
34519
|
+
try {
|
|
34520
|
+
const parsed = JSON.parse(readFileSync3(filePath, "utf8"));
|
|
34521
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.credentials)) {
|
|
34522
|
+
return { version: 1, credentials: [] };
|
|
34523
|
+
}
|
|
34524
|
+
return {
|
|
34525
|
+
version: 1,
|
|
34526
|
+
credentials: parsed.credentials.filter(isStoredCredential)
|
|
34527
|
+
};
|
|
34528
|
+
} catch {
|
|
34529
|
+
return { version: 1, credentials: [] };
|
|
34530
|
+
}
|
|
34531
|
+
}
|
|
34532
|
+
function writeCredentialFile(filePath, credentials) {
|
|
34533
|
+
mkdirSync2(path14.dirname(filePath), { recursive: true, mode: 448 });
|
|
34534
|
+
chmodSync(path14.dirname(filePath), 448);
|
|
34535
|
+
writeFileSync5(
|
|
34536
|
+
filePath,
|
|
34537
|
+
`${JSON.stringify({ version: 1, credentials }, null, 2)}
|
|
34538
|
+
`,
|
|
34539
|
+
{ encoding: "utf8", mode: 384 }
|
|
34540
|
+
);
|
|
34541
|
+
chmodSync(filePath, 384);
|
|
34542
|
+
}
|
|
34543
|
+
function applyCredential(env, credential) {
|
|
34544
|
+
env.BRIEF_API_URL = credential.apiUrl;
|
|
34545
|
+
env.BRIEF_API_KEY = credential.apiKey;
|
|
34546
|
+
env.BRIEF_WORKSPACE_ID = credential.workspaceId;
|
|
34547
|
+
env.BRIEF_PRIVACY_MODE = credential.privacyMode;
|
|
34548
|
+
}
|
|
34549
|
+
function originFrom(value) {
|
|
34550
|
+
if (!value) return void 0;
|
|
34551
|
+
try {
|
|
34552
|
+
return new URL(value).origin;
|
|
34553
|
+
} catch {
|
|
34554
|
+
return void 0;
|
|
34555
|
+
}
|
|
34556
|
+
}
|
|
34557
|
+
function isStoredCredential(value) {
|
|
34558
|
+
if (!value || typeof value !== "object") return false;
|
|
34559
|
+
const candidate = value;
|
|
34560
|
+
return Boolean(
|
|
34561
|
+
typeof candidate.apiUrl === "string" && typeof candidate.apiKey === "string" && apiKeyPattern.test(candidate.apiKey) && typeof candidate.workspaceId === "string" && typeof candidate.privacyMode === "string" && typeof candidate.updatedAt === "string"
|
|
34562
|
+
);
|
|
34563
|
+
}
|
|
34564
|
+
var apiKeyPattern;
|
|
34565
|
+
var init_cloudCredentials = __esm({
|
|
34566
|
+
"../mcp/src/cloudCredentials.ts"() {
|
|
34567
|
+
"use strict";
|
|
34568
|
+
apiKeyPattern = /^brf_(live|test)_[a-zA-Z0-9]{8,}_[a-zA-Z0-9]{24,}$/;
|
|
34569
|
+
}
|
|
34570
|
+
});
|
|
34571
|
+
|
|
34572
|
+
// ../mcp/src/workspace.ts
|
|
34573
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync4 } from "node:fs";
|
|
34574
|
+
import path15 from "node:path";
|
|
34038
34575
|
function resolveRepoRoot(repoPath, options2 = {}) {
|
|
34039
34576
|
return resolveRepoRootDetails(repoPath, options2).repoRoot;
|
|
34040
34577
|
}
|
|
34041
34578
|
function resolveRepoRootDetails(repoPath, options2 = {}) {
|
|
34042
|
-
const cwd =
|
|
34579
|
+
const cwd = path15.resolve(options2.cwd ?? process.cwd());
|
|
34043
34580
|
const env = options2.env ?? process.env;
|
|
34044
34581
|
const cwdResolution = resolveExistingRoot(cwd, "cwd");
|
|
34045
34582
|
const cwdIsCustomerWorktree = isGitWorktree(cwdResolution.repoRoot) && !looksLikeBriefSourceCheckout(cwdResolution.repoRoot);
|
|
@@ -34053,7 +34590,7 @@ function resolveRepoRootDetails(repoPath, options2 = {}) {
|
|
|
34053
34590
|
]);
|
|
34054
34591
|
const explicitRepoPath = repoPath?.trim();
|
|
34055
34592
|
if (explicitRepoPath) {
|
|
34056
|
-
const explicitPathKind =
|
|
34593
|
+
const explicitPathKind = path15.isAbsolute(explicitRepoPath) ? "absolute" : "relative";
|
|
34057
34594
|
if (explicitPathKind === "relative" && envCandidates.length > 1) {
|
|
34058
34595
|
return {
|
|
34059
34596
|
...cwdResolution,
|
|
@@ -34065,7 +34602,7 @@ function resolveRepoRootDetails(repoPath, options2 = {}) {
|
|
|
34065
34602
|
const relativeBase = cwdIsCustomerWorktree ? cwdResolution.repoRoot : envCandidates[0]?.repoRoot ?? cwd;
|
|
34066
34603
|
return {
|
|
34067
34604
|
...resolveExistingRoot(
|
|
34068
|
-
|
|
34605
|
+
path15.resolve(
|
|
34069
34606
|
explicitPathKind === "absolute" ? cwd : relativeBase,
|
|
34070
34607
|
explicitRepoPath
|
|
34071
34608
|
),
|
|
@@ -34103,7 +34640,7 @@ function resolveFromEnvVars(cwd, env, envVars, options2 = {}) {
|
|
|
34103
34640
|
for (const envVar of envVars) {
|
|
34104
34641
|
const value = cleanWorkspacePath(env[envVar]);
|
|
34105
34642
|
if (!value) continue;
|
|
34106
|
-
const start =
|
|
34643
|
+
const start = path15.resolve(cwd, value);
|
|
34107
34644
|
if (existsSync5(start)) {
|
|
34108
34645
|
const resolution = resolveExistingRoot(start, "environment", envVar);
|
|
34109
34646
|
if (options2.skipBriefSource && looksLikeBriefSourceCheckout(resolution.repoRoot)) {
|
|
@@ -34116,7 +34653,7 @@ function resolveFromEnvVars(cwd, env, envVars, options2 = {}) {
|
|
|
34116
34653
|
}
|
|
34117
34654
|
function repoTargetHealth(resolution, options2 = {}) {
|
|
34118
34655
|
const env = options2.env ?? process.env;
|
|
34119
|
-
const cwd =
|
|
34656
|
+
const cwd = path15.resolve(options2.cwd ?? process.cwd());
|
|
34120
34657
|
const gitRoot = runGit(resolution.repoRoot, ["rev-parse", "--show-toplevel"]);
|
|
34121
34658
|
const evidence = [
|
|
34122
34659
|
...rootEvidence(resolution, cwd, env),
|
|
@@ -34177,7 +34714,7 @@ function repoTargetHealth(resolution, options2 = {}) {
|
|
|
34177
34714
|
};
|
|
34178
34715
|
}
|
|
34179
34716
|
function resolveExistingRoot(start, source, envVar) {
|
|
34180
|
-
const gitStart = existsSync5(start) && !statSync4(start).isDirectory() ?
|
|
34717
|
+
const gitStart = existsSync5(start) && !statSync4(start).isDirectory() ? path15.dirname(start) : start;
|
|
34181
34718
|
const gitRoot = runGit(gitStart, ["rev-parse", "--show-toplevel"]);
|
|
34182
34719
|
return {
|
|
34183
34720
|
repoRoot: gitRoot && existsSync5(gitRoot) ? gitRoot : start,
|
|
@@ -34228,12 +34765,12 @@ function preferPinnedRepoRoot(env) {
|
|
|
34228
34765
|
return env.BRIEF_REPO_ROOT_MODE === "pinned" || env.BRIEF_REPO_ROOT_PINNED === "true";
|
|
34229
34766
|
}
|
|
34230
34767
|
function looksLikeBriefSourceCheckout(repoRoot) {
|
|
34231
|
-
if (!existsSync5(
|
|
34768
|
+
if (!existsSync5(path15.join(repoRoot, "packages", "mcp", "src", "server.ts"))) {
|
|
34232
34769
|
return false;
|
|
34233
34770
|
}
|
|
34234
34771
|
try {
|
|
34235
34772
|
const pkg = JSON.parse(
|
|
34236
|
-
|
|
34773
|
+
readFileSync4(path15.join(repoRoot, "package.json"), "utf8")
|
|
34237
34774
|
);
|
|
34238
34775
|
return pkg.name === "brief";
|
|
34239
34776
|
} catch {
|
|
@@ -34262,7 +34799,7 @@ var init_workspace = __esm({
|
|
|
34262
34799
|
});
|
|
34263
34800
|
|
|
34264
34801
|
// ../mcp/src/connectorReadiness.ts
|
|
34265
|
-
import
|
|
34802
|
+
import path16 from "node:path";
|
|
34266
34803
|
function connectorReadiness(input) {
|
|
34267
34804
|
const runtimeLabel = input.mode === "cli" ? "Brief CLI process" : "Brief MCP connector";
|
|
34268
34805
|
const installStatusTool = input.mode === "cli" ? "install-status or brief.install_status" : "brief.install_status";
|
|
@@ -34356,8 +34893,8 @@ function connectorReadiness(input) {
|
|
|
34356
34893
|
};
|
|
34357
34894
|
}
|
|
34358
34895
|
function briefSourceCheckoutMismatch(input) {
|
|
34359
|
-
const repoRoot = input.repoRoot ?
|
|
34360
|
-
const sourceRoot = input.freshness.sourceRoot ?
|
|
34896
|
+
const repoRoot = input.repoRoot ? path16.resolve(input.repoRoot) : void 0;
|
|
34897
|
+
const sourceRoot = input.freshness.sourceRoot ? path16.resolve(input.freshness.sourceRoot) : void 0;
|
|
34361
34898
|
if (!repoRoot || !sourceRoot) return void 0;
|
|
34362
34899
|
if (samePath(repoRoot, sourceRoot)) return void 0;
|
|
34363
34900
|
if (!looksLikeBriefSourceCheckout(repoRoot)) return void 0;
|
|
@@ -34372,7 +34909,7 @@ function briefSourceCheckoutMismatch(input) {
|
|
|
34372
34909
|
};
|
|
34373
34910
|
}
|
|
34374
34911
|
function samePath(left, right) {
|
|
34375
|
-
return
|
|
34912
|
+
return path16.normalize(left) === path16.normalize(right);
|
|
34376
34913
|
}
|
|
34377
34914
|
var init_connectorReadiness = __esm({
|
|
34378
34915
|
"../mcp/src/connectorReadiness.ts"() {
|
|
@@ -34506,8 +35043,8 @@ var init_connectorRecovery = __esm({
|
|
|
34506
35043
|
});
|
|
34507
35044
|
|
|
34508
35045
|
// ../mcp/src/serverFreshness.ts
|
|
34509
|
-
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as
|
|
34510
|
-
import
|
|
35046
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync5 } from "node:fs";
|
|
35047
|
+
import path17 from "node:path";
|
|
34511
35048
|
function mcpServerFreshness(options2) {
|
|
34512
35049
|
const cwd = options2.cwd ?? process.cwd();
|
|
34513
35050
|
const now = options2.now ?? /* @__PURE__ */ new Date();
|
|
@@ -34518,10 +35055,12 @@ function mcpServerFreshness(options2) {
|
|
|
34518
35055
|
cwd,
|
|
34519
35056
|
sourceRoot: options2.sourceRoot
|
|
34520
35057
|
});
|
|
35058
|
+
const sourceKind = options2.distribution ?? connectorDistributionFor(options2.entrypoint);
|
|
34521
35059
|
const watchedGlobs = watchedSourceGlobs();
|
|
34522
35060
|
const base = {
|
|
34523
35061
|
serverStartedAt: options2.serverStartedAt.toISOString(),
|
|
34524
35062
|
checkedAt: now.toISOString(),
|
|
35063
|
+
sourceKind,
|
|
34525
35064
|
process: {
|
|
34526
35065
|
pid: process.pid,
|
|
34527
35066
|
cwd,
|
|
@@ -34536,6 +35075,15 @@ function mcpServerFreshness(options2) {
|
|
|
34536
35075
|
changedSinceStartCount: 0
|
|
34537
35076
|
};
|
|
34538
35077
|
if (!sourceRoot) {
|
|
35078
|
+
if (sourceKind === "package") {
|
|
35079
|
+
return {
|
|
35080
|
+
status: "current",
|
|
35081
|
+
...base,
|
|
35082
|
+
action: freshnessAction("current"),
|
|
35083
|
+
summary: "The published Brief connector is running from an immutable package; source-checkout freshness checks are not applicable.",
|
|
35084
|
+
next: "Continue using Brief normally. Update the package when you want a newer connector release."
|
|
35085
|
+
};
|
|
35086
|
+
}
|
|
34539
35087
|
return {
|
|
34540
35088
|
status: "unknown",
|
|
34541
35089
|
...base,
|
|
@@ -34576,6 +35124,21 @@ function mcpServerFreshness(options2) {
|
|
|
34576
35124
|
next: status === "restart_recommended" ? "Call brief.restart_connector from the coding agent, then call brief.install_status again and confirm serverFreshness.status is current." : "Continue using Brief normally."
|
|
34577
35125
|
};
|
|
34578
35126
|
}
|
|
35127
|
+
function connectorDistributionFor(entrypoint) {
|
|
35128
|
+
const configured = process.env.BRIEF_CONNECTOR_DISTRIBUTION;
|
|
35129
|
+
if (configured === "package" || configured === "source_checkout") {
|
|
35130
|
+
return configured;
|
|
35131
|
+
}
|
|
35132
|
+
const normalizedEntrypoint = path17.normalize(entrypoint);
|
|
35133
|
+
if (normalizedEntrypoint.includes(
|
|
35134
|
+
`${path17.sep}node_modules${path17.sep}runbrief${path17.sep}`
|
|
35135
|
+
) || normalizedEntrypoint.includes(
|
|
35136
|
+
`${path17.sep}packages${path17.sep}runbrief${path17.sep}`
|
|
35137
|
+
)) {
|
|
35138
|
+
return "package";
|
|
35139
|
+
}
|
|
35140
|
+
return "unknown";
|
|
35141
|
+
}
|
|
34579
35142
|
function freshnessAction(status) {
|
|
34580
35143
|
if (status === "current") {
|
|
34581
35144
|
return {
|
|
@@ -34610,30 +35173,30 @@ function findBriefSourceRoot(options2) {
|
|
|
34610
35173
|
const candidates = [
|
|
34611
35174
|
options2.sourceRoot,
|
|
34612
35175
|
process.env.BRIEF_SOURCE_ROOT,
|
|
34613
|
-
options2.entrypoint ?
|
|
35176
|
+
options2.entrypoint ? path17.dirname(options2.entrypoint) : void 0,
|
|
34614
35177
|
options2.cwd
|
|
34615
35178
|
].filter((candidate) => Boolean(candidate));
|
|
34616
35179
|
for (const candidate of candidates) {
|
|
34617
|
-
const root = walkUpForBriefRoot(
|
|
35180
|
+
const root = walkUpForBriefRoot(path17.resolve(candidate));
|
|
34618
35181
|
if (root) return root;
|
|
34619
35182
|
}
|
|
34620
35183
|
return void 0;
|
|
34621
35184
|
}
|
|
34622
35185
|
function walkUpForBriefRoot(start) {
|
|
34623
|
-
let current = existsSync6(start) && statSafe(start)?.isFile() ?
|
|
35186
|
+
let current = existsSync6(start) && statSafe(start)?.isFile() ? path17.dirname(start) : start;
|
|
34624
35187
|
while (true) {
|
|
34625
35188
|
if (isBriefSourceRoot(current)) return current;
|
|
34626
|
-
const parent =
|
|
35189
|
+
const parent = path17.dirname(current);
|
|
34627
35190
|
if (parent === current) return void 0;
|
|
34628
35191
|
current = parent;
|
|
34629
35192
|
}
|
|
34630
35193
|
}
|
|
34631
35194
|
function isBriefSourceRoot(candidate) {
|
|
34632
|
-
const packageJsonPath =
|
|
35195
|
+
const packageJsonPath = path17.join(candidate, "package.json");
|
|
34633
35196
|
if (!existsSync6(packageJsonPath)) return false;
|
|
34634
35197
|
const packageJson = readJson(packageJsonPath);
|
|
34635
35198
|
if (packageJson?.name !== "brief") return false;
|
|
34636
|
-
return existsSync6(
|
|
35199
|
+
return existsSync6(path17.join(candidate, "packages", "mcp")) && existsSync6(path17.join(candidate, "packages", "core")) && existsSync6(path17.join(candidate, "packages", "contracts"));
|
|
34637
35200
|
}
|
|
34638
35201
|
function watchedSourceGlobs() {
|
|
34639
35202
|
return [
|
|
@@ -34671,7 +35234,7 @@ function collectWatchedFiles(sourceRoot, maxWatchedFiles) {
|
|
|
34671
35234
|
truncated = true;
|
|
34672
35235
|
break;
|
|
34673
35236
|
}
|
|
34674
|
-
const absolutePath =
|
|
35237
|
+
const absolutePath = path17.join(sourceRoot, relativePath);
|
|
34675
35238
|
const stats = statSafe(absolutePath);
|
|
34676
35239
|
if (!stats) continue;
|
|
34677
35240
|
if (stats.isDirectory()) {
|
|
@@ -34688,7 +35251,7 @@ function collectWatchedFiles(sourceRoot, maxWatchedFiles) {
|
|
|
34688
35251
|
break;
|
|
34689
35252
|
}
|
|
34690
35253
|
files.push({
|
|
34691
|
-
path: normalizePath(
|
|
35254
|
+
path: normalizePath(path17.relative(sourceRoot, absolutePath)),
|
|
34692
35255
|
modifiedAtMs: stats.mtimeMs
|
|
34693
35256
|
});
|
|
34694
35257
|
}
|
|
@@ -34699,7 +35262,7 @@ function walkFiles2(sourceRoot, directory, files, maxWatchedFiles) {
|
|
|
34699
35262
|
const entries = readdirSafe(directory);
|
|
34700
35263
|
for (const entry of entries) {
|
|
34701
35264
|
if (files.length >= maxWatchedFiles) return { truncated: true };
|
|
34702
|
-
const absolutePath =
|
|
35265
|
+
const absolutePath = path17.join(directory, entry.name);
|
|
34703
35266
|
if (entry.isDirectory()) {
|
|
34704
35267
|
if (shouldSkipDirectory(entry.name)) continue;
|
|
34705
35268
|
const result = walkFiles2(
|
|
@@ -34715,7 +35278,7 @@ function walkFiles2(sourceRoot, directory, files, maxWatchedFiles) {
|
|
|
34715
35278
|
const stats = statSafe(absolutePath);
|
|
34716
35279
|
if (!stats) continue;
|
|
34717
35280
|
files.push({
|
|
34718
|
-
path: normalizePath(
|
|
35281
|
+
path: normalizePath(path17.relative(sourceRoot, absolutePath)),
|
|
34719
35282
|
modifiedAtMs: stats.mtimeMs
|
|
34720
35283
|
});
|
|
34721
35284
|
}
|
|
@@ -34734,13 +35297,13 @@ function shouldSkipDirectory(name) {
|
|
|
34734
35297
|
);
|
|
34735
35298
|
}
|
|
34736
35299
|
function shouldWatchFile(filePath) {
|
|
34737
|
-
const base =
|
|
35300
|
+
const base = path17.basename(filePath);
|
|
34738
35301
|
if (base.endsWith(".tsbuildinfo")) return false;
|
|
34739
35302
|
if (base === ".DS_Store") return false;
|
|
34740
35303
|
return true;
|
|
34741
35304
|
}
|
|
34742
35305
|
function normalizePath(value) {
|
|
34743
|
-
return value.split(
|
|
35306
|
+
return value.split(path17.sep).join("/");
|
|
34744
35307
|
}
|
|
34745
35308
|
function statSafe(filePath) {
|
|
34746
35309
|
try {
|
|
@@ -34758,7 +35321,7 @@ function readdirSafe(directory) {
|
|
|
34758
35321
|
}
|
|
34759
35322
|
function readJson(filePath) {
|
|
34760
35323
|
try {
|
|
34761
|
-
return JSON.parse(
|
|
35324
|
+
return JSON.parse(readFileSync5(filePath, "utf8"));
|
|
34762
35325
|
} catch {
|
|
34763
35326
|
return void 0;
|
|
34764
35327
|
}
|
|
@@ -34821,9 +35384,10 @@ var init_serverInstructions = __esm({
|
|
|
34821
35384
|
"../mcp/src/serverInstructions.ts"() {
|
|
34822
35385
|
"use strict";
|
|
34823
35386
|
briefMcpInstructions = [
|
|
34824
|
-
"Brief is the default repo-context, reuse, review, and handoff companion for non-trivial coding work. Do not wait for the user to repeat 'use Brief'.",
|
|
35387
|
+
"Brief is the default repo-context, reuse, review, and handoff companion for non-trivial coding work. This is the normal path, not an optional reminder. Do not wait for the user to repeat 'use Brief'.",
|
|
34825
35388
|
"At the first Brief-relevant task in a session, call brief.install_status once and confirm the repo target and connector freshness.",
|
|
34826
|
-
"
|
|
35389
|
+
"Local mode is the default and does not require an account. Team mode is optional: it adds approved shared guidance through browser-authorized sync. If team sync is unavailable, continue local repo work and mention the team-sync limitation only when it affects the task.",
|
|
35390
|
+
"When the user asks for non-trivial work, call brief.next with the user's actual request before inspecting or editing files, read the returned compact workPacket, and follow its recommendation before editing. Keep micro changes lightweight.",
|
|
34827
35391
|
"Before creating a helper, component, route, workflow, command, or skill, use the returned reuse candidates or call brief.reference_implementations and brief.codebase_map.",
|
|
34828
35392
|
"Refresh Brief context when the task, files, risk, or validation plan changes.",
|
|
34829
35393
|
"Before a meaningful handoff, call brief.review_diff. Save and verify a handoff only for multi-step, high-risk, or durable work.",
|
|
@@ -34861,7 +35425,7 @@ function compactBlockedInstallStatus(input) {
|
|
|
34861
35425
|
fresh: input.serverFreshness.status === "current",
|
|
34862
35426
|
summary: input.connectorReadiness.summary
|
|
34863
35427
|
},
|
|
34864
|
-
next:
|
|
35428
|
+
next: unique4(input.repoTarget.next).slice(0, 2),
|
|
34865
35429
|
detailHint: "Open a Git repository or pass its path, then run install-status again."
|
|
34866
35430
|
};
|
|
34867
35431
|
}
|
|
@@ -34871,12 +35435,14 @@ function compactInstallStatus(input) {
|
|
|
34871
35435
|
const degraded = !blocked && (Boolean(cloudIssue) || input.readiness.verdict !== "agent_ready" || input.workflowWiring.status === "missing" || input.workflowWiring.status === "manual_workflow_only");
|
|
34872
35436
|
const stats = input.scan.stats;
|
|
34873
35437
|
const mcpContractActive = input.serverInstructionsActive && input.connectorReadiness.safeToUseBrief;
|
|
35438
|
+
const teamSyncStatus = input.cloudSync.configured ? input.teamContext.status === "failed" ? "unavailable" : input.teamContext.status === "fetched" ? "connected" : "checking" : "not_connected";
|
|
35439
|
+
const connectionMode = teamSyncStatus === "unavailable" ? "team_degraded" : teamSyncStatus === "connected" ? "team" : "local";
|
|
34874
35440
|
const totalMapCandidates = stats.mapTotalCandidateCount ?? stats.mapNodeCount + (stats.mapOmittedCount ?? 0);
|
|
34875
35441
|
const mapCoveragePercent = totalMapCandidates ? Math.round(stats.mapNodeCount / totalMapCandidates * 100) : 100;
|
|
34876
|
-
const repoGuidanceSignals =
|
|
35442
|
+
const repoGuidanceSignals = unique4(
|
|
34877
35443
|
input.workflowWiring.surfaces.filter((surface) => surface.kind === "always_on_guidance").flatMap((surface) => surface.signals)
|
|
34878
35444
|
);
|
|
34879
|
-
const next =
|
|
35445
|
+
const next = unique4([
|
|
34880
35446
|
...blocked ? [input.connectorReadiness.firstAction] : [],
|
|
34881
35447
|
...cloudIssue ? [cloudIssue] : [],
|
|
34882
35448
|
...input.readiness.nextBestActions,
|
|
@@ -34899,9 +35465,16 @@ function compactInstallStatus(input) {
|
|
|
34899
35465
|
status: input.connectorReadiness.status,
|
|
34900
35466
|
safeToUse: input.connectorReadiness.safeToUseBrief,
|
|
34901
35467
|
fresh: input.serverFreshness.status === "current",
|
|
35468
|
+
distribution: input.serverFreshness.sourceKind,
|
|
34902
35469
|
sourceRoot: input.serverFreshness.sourceRoot,
|
|
34903
35470
|
summary: input.connectorReadiness.summary
|
|
34904
35471
|
},
|
|
35472
|
+
connection: {
|
|
35473
|
+
mode: connectionMode,
|
|
35474
|
+
localAvailable: input.connectorReadiness.safeToUseBrief,
|
|
35475
|
+
teamSync: teamSyncStatus,
|
|
35476
|
+
summary: connectionMode === "team_degraded" ? "Local repo work is available. Team sync needs attention and will not block local analysis." : connectionMode === "team" ? "Local repo work and approved team context are available." : "Local repo work is available without an account. Team sync is optional."
|
|
35477
|
+
},
|
|
34905
35478
|
cloud: {
|
|
34906
35479
|
configured: input.cloudSync.configured,
|
|
34907
35480
|
privacyMode: input.cloudSync.privacyMode,
|
|
@@ -34923,7 +35496,7 @@ function compactInstallStatus(input) {
|
|
|
34923
35496
|
score: input.readiness.score,
|
|
34924
35497
|
verdict: input.readiness.verdict,
|
|
34925
35498
|
summary: input.readiness.summary,
|
|
34926
|
-
gaps:
|
|
35499
|
+
gaps: unique4([
|
|
34927
35500
|
...input.readiness.quickWins,
|
|
34928
35501
|
...input.readiness.nextBestActions
|
|
34929
35502
|
]).slice(0, 3)
|
|
@@ -34950,7 +35523,7 @@ function compactInstallStatus(input) {
|
|
|
34950
35523
|
detailHint: 'Use detail: "expanded" in MCP or --full in the CLI only when diagnosing setup, workflow wiring, or receipt history.'
|
|
34951
35524
|
};
|
|
34952
35525
|
}
|
|
34953
|
-
function
|
|
35526
|
+
function unique4(values) {
|
|
34954
35527
|
return [...new Set(values.filter((value) => value.trim()))];
|
|
34955
35528
|
}
|
|
34956
35529
|
var briefConnectorVersion;
|
|
@@ -34958,7 +35531,7 @@ var init_installStatus = __esm({
|
|
|
34958
35531
|
"../mcp/src/installStatus.ts"() {
|
|
34959
35532
|
"use strict";
|
|
34960
35533
|
init_serverInstructions();
|
|
34961
|
-
briefConnectorVersion = "0.1.
|
|
35534
|
+
briefConnectorVersion = "0.1.3";
|
|
34962
35535
|
}
|
|
34963
35536
|
});
|
|
34964
35537
|
|
|
@@ -34978,27 +35551,27 @@ function buildCompactStartEnvelope(input) {
|
|
|
34978
35551
|
route: {
|
|
34979
35552
|
tool: start.intent.tool,
|
|
34980
35553
|
...start.intent.recipe ? { recipe: start.intent.recipe } : {},
|
|
34981
|
-
...start.intent.autonomy ? { autonomy: start.intent.autonomy } : {}
|
|
34982
|
-
...start.intent.reviewBar ? { reviewBar: start.intent.reviewBar } : {}
|
|
35554
|
+
...start.intent.autonomy ? { autonomy: start.intent.autonomy } : {}
|
|
34983
35555
|
},
|
|
35556
|
+
workPacket: (() => {
|
|
35557
|
+
const packet = buildAgentWorkPacket({
|
|
35558
|
+
task: start.normalizedInput.task,
|
|
35559
|
+
beforeYouCode,
|
|
35560
|
+
interpretation: start.summary,
|
|
35561
|
+
nextAction: input.next
|
|
35562
|
+
});
|
|
35563
|
+
return {
|
|
35564
|
+
compactText: packet.compactText
|
|
35565
|
+
};
|
|
35566
|
+
})(),
|
|
34984
35567
|
inspectFirst: beforeYouCode.inspectFirst.slice(0, 3).map((item) => ({
|
|
34985
35568
|
path: item.path,
|
|
34986
35569
|
why: compactLine(item.why, 160)
|
|
34987
35570
|
})),
|
|
34988
|
-
reuse: beforeYouCode.reuseFirst.candidates.slice(0, 2).map((item) => ({
|
|
34989
|
-
path: item.path,
|
|
34990
|
-
action: compactLine(item.action, 160)
|
|
34991
|
-
})),
|
|
34992
|
-
reuseDecision: compactLine(beforeYouCode.reuseFirst.decision, 240),
|
|
34993
|
-
sharedContext: summarizeBeforeYouCodeSharedContext(
|
|
34994
|
-
beforeYouCode.teamGuidance
|
|
34995
|
-
),
|
|
34996
|
-
referenceFirst: summarizeBeforeYouCodeReferences(beforeYouCode),
|
|
34997
35571
|
validation: beforeYouCode.likelyTests.slice(0, 3),
|
|
34998
35572
|
result: input.result,
|
|
34999
|
-
|
|
35000
|
-
|
|
35001
|
-
detailHint: 'Request expanded detail only when needed: CLI --json/--full or MCP detail: "expanded".'
|
|
35573
|
+
next: compactLine(input.next, 240),
|
|
35574
|
+
detailHint: 'Expand with MCP detail: "expanded" or CLI --full.'
|
|
35002
35575
|
};
|
|
35003
35576
|
}
|
|
35004
35577
|
function formatCompactStartText(envelope) {
|
|
@@ -35013,26 +35586,13 @@ function formatCompactStartText(envelope) {
|
|
|
35013
35586
|
`Target: ${target} | ${envelope.target.dirty ? "dirty" : "clean"}`,
|
|
35014
35587
|
`Job: ${envelope.job}`,
|
|
35015
35588
|
`Route: ${route}`,
|
|
35016
|
-
|
|
35017
|
-
...listLines(
|
|
35018
|
-
envelope.inspectFirst.map((item) => `${item.path} - ${item.why}`)
|
|
35019
|
-
),
|
|
35020
|
-
"Reuse:",
|
|
35021
|
-
...listLines(envelope.reuse.map((item) => `${item.path} - ${item.action}`)),
|
|
35022
|
-
`Reuse decision: ${envelope.reuseDecision}`,
|
|
35023
|
-
`Shared context: ${envelope.sharedContext.status === "applied" ? envelope.sharedContext.applied.map((item) => item.label).join(", ") : envelope.sharedContext.status}`,
|
|
35024
|
-
`Saved reference: ${envelope.referenceFirst.status === "matched" ? envelope.referenceFirst.references.map((reference) => reference.title).join(", ") : envelope.referenceFirst.status}`,
|
|
35025
|
-
"Validate:",
|
|
35026
|
-
...listLines(envelope.validation),
|
|
35589
|
+
envelope.workPacket.compactText,
|
|
35027
35590
|
`Result: ${envelope.result.summary}`,
|
|
35028
35591
|
`Next: ${envelope.next}`,
|
|
35029
35592
|
`Details: ${envelope.detailHint}`
|
|
35030
35593
|
];
|
|
35031
35594
|
return lines.join("\n");
|
|
35032
35595
|
}
|
|
35033
|
-
function listLines(items) {
|
|
35034
|
-
return items.length > 0 ? items.map((item) => `- ${item}`) : ["- none"];
|
|
35035
|
-
}
|
|
35036
35596
|
function compactLine(value, maxLength) {
|
|
35037
35597
|
const normalized = value.replace(/\s+/g, " ").trim();
|
|
35038
35598
|
if (normalized.length <= maxLength) return normalized;
|
|
@@ -35155,15 +35715,15 @@ var init_startSummary = __esm({
|
|
|
35155
35715
|
});
|
|
35156
35716
|
|
|
35157
35717
|
// ../mcp/src/wikiInit.ts
|
|
35158
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
35159
|
-
import
|
|
35718
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
35719
|
+
import path18 from "node:path";
|
|
35160
35720
|
function writeWikiInitArtifacts(repoRoot, wiki, options2) {
|
|
35161
|
-
const wikiDir =
|
|
35162
|
-
const pagesDir =
|
|
35163
|
-
|
|
35721
|
+
const wikiDir = path18.join(repoRoot, ".brief", "wiki");
|
|
35722
|
+
const pagesDir = path18.join(wikiDir, "pages");
|
|
35723
|
+
mkdirSync3(pagesDir, { recursive: true });
|
|
35164
35724
|
const pageArtifacts = wiki.pages.map((page2) => {
|
|
35165
|
-
const pagePath =
|
|
35166
|
-
|
|
35725
|
+
const pagePath = path18.join(pagesDir, `${wikiPageSlug(page2)}.md`);
|
|
35726
|
+
writeFileSync6(pagePath, renderWikiPageMarkdown(wiki, page2));
|
|
35167
35727
|
return {
|
|
35168
35728
|
id: page2.id,
|
|
35169
35729
|
title: page2.title,
|
|
@@ -35172,32 +35732,32 @@ function writeWikiInitArtifacts(repoRoot, wiki, options2) {
|
|
|
35172
35732
|
quality: page2.quality.status
|
|
35173
35733
|
};
|
|
35174
35734
|
});
|
|
35175
|
-
const readmePath =
|
|
35176
|
-
|
|
35177
|
-
const manifestPath =
|
|
35178
|
-
|
|
35735
|
+
const readmePath = path18.join(wikiDir, "README.md");
|
|
35736
|
+
writeFileSync6(readmePath, renderWikiReadme(wiki, pageArtifacts));
|
|
35737
|
+
const manifestPath = path18.join(wikiDir, "manifest.json");
|
|
35738
|
+
writeFileSync6(
|
|
35179
35739
|
manifestPath,
|
|
35180
35740
|
`${JSON.stringify(wikiInitManifest(wiki, pageArtifacts), null, 2)}
|
|
35181
35741
|
`
|
|
35182
35742
|
);
|
|
35183
|
-
const workflowTemplatePath =
|
|
35743
|
+
const workflowTemplatePath = path18.join(
|
|
35184
35744
|
wikiDir,
|
|
35185
35745
|
"brief-wiki-refresh.github-actions.yml"
|
|
35186
35746
|
);
|
|
35187
|
-
|
|
35747
|
+
writeFileSync6(workflowTemplatePath, renderWikiRefreshWorkflow());
|
|
35188
35748
|
const agentFiles = options2.writeAgentFiles ? ["AGENTS.md", "CLAUDE.md"].map(
|
|
35189
35749
|
(fileName) => upsertWikiAgentInstructions(repoRoot, fileName)
|
|
35190
35750
|
) : [];
|
|
35191
35751
|
let githubWorkflow2;
|
|
35192
35752
|
if (options2.writeGithubWorkflow) {
|
|
35193
|
-
const workflowPath =
|
|
35753
|
+
const workflowPath = path18.join(
|
|
35194
35754
|
repoRoot,
|
|
35195
35755
|
".github",
|
|
35196
35756
|
"workflows",
|
|
35197
35757
|
"brief-wiki-refresh.yml"
|
|
35198
35758
|
);
|
|
35199
|
-
|
|
35200
|
-
|
|
35759
|
+
mkdirSync3(path18.dirname(workflowPath), { recursive: true });
|
|
35760
|
+
writeFileSync6(workflowPath, renderWikiRefreshWorkflow({ active: true }));
|
|
35201
35761
|
githubWorkflow2 = {
|
|
35202
35762
|
path: repoRelativePath(repoRoot, workflowPath),
|
|
35203
35763
|
status: "written",
|
|
@@ -35387,12 +35947,12 @@ function wikiInitManifest(wiki, pageArtifacts) {
|
|
|
35387
35947
|
};
|
|
35388
35948
|
}
|
|
35389
35949
|
function upsertWikiAgentInstructions(repoRoot, fileName) {
|
|
35390
|
-
const filePath =
|
|
35950
|
+
const filePath = path18.join(repoRoot, fileName);
|
|
35391
35951
|
const status = existsSync7(filePath) ? "updated" : "created";
|
|
35392
|
-
const existing = status === "updated" ?
|
|
35952
|
+
const existing = status === "updated" ? readFileSync6(filePath, "utf8") : "";
|
|
35393
35953
|
const initial = existing || `# ${fileName}
|
|
35394
35954
|
`;
|
|
35395
|
-
|
|
35955
|
+
writeFileSync6(filePath, upsertMarkedBlock(initial, wikiAgentBlock()));
|
|
35396
35956
|
return {
|
|
35397
35957
|
path: repoRelativePath(repoRoot, filePath),
|
|
35398
35958
|
status,
|
|
@@ -35464,7 +36024,7 @@ function renderWikiRefreshWorkflow(options2 = {}) {
|
|
|
35464
36024
|
" with:",
|
|
35465
36025
|
" node-version: 22",
|
|
35466
36026
|
" - name: Refresh wiki",
|
|
35467
|
-
' run: npx -y runbrief@0.1.
|
|
36027
|
+
' run: npx -y runbrief@0.1.3 wiki init --repo "$GITHUB_WORKSPACE" --update --no-agent-files',
|
|
35468
36028
|
" - name: Open refresh PR",
|
|
35469
36029
|
" uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11",
|
|
35470
36030
|
" with:",
|
|
@@ -35485,7 +36045,7 @@ function markdownList(items) {
|
|
|
35485
36045
|
return items.map((item) => `- ${item}`).join("\n");
|
|
35486
36046
|
}
|
|
35487
36047
|
function repoRelativePath(repoRoot, filePath) {
|
|
35488
|
-
return
|
|
36048
|
+
return path18.relative(repoRoot, filePath).split(path18.sep).join("/");
|
|
35489
36049
|
}
|
|
35490
36050
|
function wikiReadmeRelativePath(repoRelativeFilePath) {
|
|
35491
36051
|
return repoRelativeFilePath.replace(/^\.brief\/wiki\//, "");
|
|
@@ -35564,7 +36124,7 @@ function resolveHandoffAutofill(repoRoot, input) {
|
|
|
35564
36124
|
sources,
|
|
35565
36125
|
missionReceiptId,
|
|
35566
36126
|
reviewReceiptId,
|
|
35567
|
-
autoFilled:
|
|
36127
|
+
autoFilled: unique5(autoFilled)
|
|
35568
36128
|
});
|
|
35569
36129
|
}
|
|
35570
36130
|
function bestMatchingReceipt(receipts, kind, input) {
|
|
@@ -35644,10 +36204,10 @@ function compactResult(result) {
|
|
|
35644
36204
|
}
|
|
35645
36205
|
function cleanValues(values, limit = 300) {
|
|
35646
36206
|
if (!values) return void 0;
|
|
35647
|
-
const cleaned =
|
|
36207
|
+
const cleaned = unique5(values.map((value) => value.trim()).filter(Boolean)).sort().slice(0, limit);
|
|
35648
36208
|
return cleaned.length > 0 ? cleaned : void 0;
|
|
35649
36209
|
}
|
|
35650
|
-
function
|
|
36210
|
+
function unique5(values) {
|
|
35651
36211
|
return [...new Set(values)];
|
|
35652
36212
|
}
|
|
35653
36213
|
function normalizeText(value) {
|
|
@@ -35704,35 +36264,35 @@ function compactCodebaseMapResponse(input) {
|
|
|
35704
36264
|
};
|
|
35705
36265
|
}
|
|
35706
36266
|
function formatCompactCodebaseMap(input) {
|
|
35707
|
-
const
|
|
36267
|
+
const compact2 = compactCodebaseMapResponse(input);
|
|
35708
36268
|
const lines = [
|
|
35709
|
-
`Codebase map: ${
|
|
35710
|
-
`Target: ${
|
|
36269
|
+
`Codebase map: ${compact2.summary}`,
|
|
36270
|
+
`Target: ${compact2.target.repoName} | ${compact2.target.repoRoot}${compact2.target.mapPartial ? " | partial map" : ""}`,
|
|
35711
36271
|
"Inspect first:",
|
|
35712
|
-
...
|
|
35713
|
-
|
|
36272
|
+
...listLines(
|
|
36273
|
+
compact2.inspectFirst,
|
|
35714
36274
|
(item) => `${item.path} - ${item.reason}`,
|
|
35715
36275
|
"No focused source matched; narrow the query before editing."
|
|
35716
36276
|
),
|
|
35717
36277
|
"Reuse before creating:",
|
|
35718
|
-
...
|
|
35719
|
-
|
|
36278
|
+
...listLines(
|
|
36279
|
+
compact2.reuse.candidates,
|
|
35720
36280
|
(item) => `${item.path}${item.symbols.length > 0 ? ` - ${item.symbols.join(", ")}` : ""}`,
|
|
35721
36281
|
"No reusable primitive is proven yet; run a narrower map query."
|
|
35722
36282
|
),
|
|
35723
36283
|
"Validate:",
|
|
35724
|
-
...
|
|
35725
|
-
|
|
36284
|
+
...listLines(
|
|
36285
|
+
compact2.validate,
|
|
35726
36286
|
(item) => item,
|
|
35727
36287
|
"No focused validation command was found."
|
|
35728
36288
|
),
|
|
35729
|
-
...
|
|
36289
|
+
...compact2.warnings.length > 0 ? ["Warnings:", ...listLines(compact2.warnings, (item) => item, "")] : [],
|
|
35730
36290
|
"Next:",
|
|
35731
|
-
...
|
|
36291
|
+
...listLines(compact2.next, (item) => item, "Inspect the first source.")
|
|
35732
36292
|
];
|
|
35733
36293
|
return lines.slice(0, 30).join("\n");
|
|
35734
36294
|
}
|
|
35735
|
-
function
|
|
36295
|
+
function listLines(items, render, empty) {
|
|
35736
36296
|
if (items.length === 0) return empty ? [`- ${empty}`] : [];
|
|
35737
36297
|
return items.map((item) => `- ${render(item)}`);
|
|
35738
36298
|
}
|
|
@@ -35789,8 +36349,8 @@ var init_workflowWiringResponse = __esm({
|
|
|
35789
36349
|
|
|
35790
36350
|
// ../mcp/src/server.ts
|
|
35791
36351
|
var server_exports = {};
|
|
35792
|
-
import { chmodSync, mkdirSync as
|
|
35793
|
-
import
|
|
36352
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
36353
|
+
import path19 from "node:path";
|
|
35794
36354
|
import { fileURLToPath } from "node:url";
|
|
35795
36355
|
import {
|
|
35796
36356
|
McpServer
|
|
@@ -36051,7 +36611,8 @@ function serverFreshness() {
|
|
|
36051
36611
|
return mcpServerFreshness({
|
|
36052
36612
|
serverStartedAt,
|
|
36053
36613
|
entrypoint: serverModulePath,
|
|
36054
|
-
mode: "server"
|
|
36614
|
+
mode: "server",
|
|
36615
|
+
distribution: connectorDistributionFor(serverModulePath)
|
|
36055
36616
|
});
|
|
36056
36617
|
}
|
|
36057
36618
|
function summarizePacket(packet) {
|
|
@@ -36069,7 +36630,8 @@ function summarizePacket(packet) {
|
|
|
36069
36630
|
sources: packet.sources,
|
|
36070
36631
|
omitted: packet.omitted,
|
|
36071
36632
|
...packet.valueSignals ? { valueSignals: packet.valueSignals } : {},
|
|
36072
|
-
...packet.teamGuidance ? { teamGuidance: packet.teamGuidance } : {}
|
|
36633
|
+
...packet.teamGuidance ? { teamGuidance: packet.teamGuidance } : {},
|
|
36634
|
+
...packet.dependencyRemediation ? { dependencyRemediation: packet.dependencyRemediation } : {}
|
|
36073
36635
|
};
|
|
36074
36636
|
}
|
|
36075
36637
|
function summarizeReview(review, detail = "auto") {
|
|
@@ -36507,6 +37069,7 @@ function summarizeBeforeYouCodeForStart(beforeYouCode) {
|
|
|
36507
37069
|
decision: beforeYouCode.reuseFirst.decision,
|
|
36508
37070
|
candidates: beforeYouCode.reuseFirst.candidates.slice(0, 2)
|
|
36509
37071
|
},
|
|
37072
|
+
mapCoverage: beforeYouCode.mapCoverage,
|
|
36510
37073
|
sharedContext: summarizeBeforeYouCodeSharedContext(
|
|
36511
37074
|
beforeYouCode.teamGuidance
|
|
36512
37075
|
),
|
|
@@ -36570,7 +37133,7 @@ function summarizeWorkflowWiringForStart(wiring) {
|
|
|
36570
37133
|
defaultAsk: wiring.defaultAsk,
|
|
36571
37134
|
gaps: wiring.gaps.slice(0, 3),
|
|
36572
37135
|
chatFeedback: wiring.chatFeedback.slice(0, 2),
|
|
36573
|
-
finalRecapPolicy: wiring.finalRecapPolicy,
|
|
37136
|
+
finalRecapPolicy: compactFinalRecapPolicy(wiring.finalRecapPolicy),
|
|
36574
37137
|
nextActions: wiring.nextActions.slice(0, 3)
|
|
36575
37138
|
};
|
|
36576
37139
|
}
|
|
@@ -36579,7 +37142,7 @@ function summarizeAutoEngageForStart(autoEngage) {
|
|
|
36579
37142
|
status: autoEngage.status,
|
|
36580
37143
|
summary: autoEngage.summary,
|
|
36581
37144
|
chatFeedback: autoEngage.chatFeedback.slice(0, 1),
|
|
36582
|
-
finalRecapPolicy: autoEngage.finalRecapPolicy,
|
|
37145
|
+
finalRecapPolicy: compactFinalRecapPolicy(autoEngage.finalRecapPolicy),
|
|
36583
37146
|
triggers: autoEngage.triggerMatrix.slice(0, 3).map((trigger) => ({
|
|
36584
37147
|
id: trigger.id,
|
|
36585
37148
|
label: trigger.label,
|
|
@@ -36588,6 +37151,13 @@ function summarizeAutoEngageForStart(autoEngage) {
|
|
|
36588
37151
|
nextActions: autoEngage.nextActions.slice(0, 2)
|
|
36589
37152
|
};
|
|
36590
37153
|
}
|
|
37154
|
+
function compactFinalRecapPolicy(policy) {
|
|
37155
|
+
return {
|
|
37156
|
+
maxLines: policy.maxLines,
|
|
37157
|
+
template: policy.defaultTemplate,
|
|
37158
|
+
fallbackWhenNotHelpful: policy.fallbackWhenNotHelpful
|
|
37159
|
+
};
|
|
37160
|
+
}
|
|
36591
37161
|
function summarizeWiki(wiki) {
|
|
36592
37162
|
return {
|
|
36593
37163
|
wikiId: wiki.wikiId,
|
|
@@ -36640,21 +37210,22 @@ function summarizeLocalReceipt(receipt) {
|
|
|
36640
37210
|
function writeHookFiles(repoRoot, files) {
|
|
36641
37211
|
const written = [];
|
|
36642
37212
|
for (const file of files) {
|
|
36643
|
-
const targetPath =
|
|
36644
|
-
|
|
36645
|
-
|
|
36646
|
-
if (file.path.endsWith(".sh"))
|
|
37213
|
+
const targetPath = path19.join(repoRoot, file.path);
|
|
37214
|
+
mkdirSync4(path19.dirname(targetPath), { recursive: true });
|
|
37215
|
+
writeFileSync7(targetPath, file.body);
|
|
37216
|
+
if (file.path.endsWith(".sh")) chmodSync2(targetPath, 493);
|
|
36647
37217
|
written.push(file.path);
|
|
36648
37218
|
}
|
|
36649
37219
|
return written;
|
|
36650
37220
|
}
|
|
36651
|
-
var server, personalizationKindSchema, referenceImplementationKindSchema, referenceImplementationStatusSchema, savePersonalizationToolSchema, workItemSchema, runtimeEvidenceSchema, handoffValidationSchema, artifactEvidenceSchema, loopCatalogFocusSchema, missionRecipeIdSchema2, startIntentSchema, nextStageSchema, responseDetailSchema, serverStartedAt, serverModulePath, repoTargetGuardExemptTools;
|
|
37221
|
+
var cloudBootstrap, server, personalizationKindSchema, referenceImplementationKindSchema, referenceImplementationStatusSchema, savePersonalizationToolSchema, workItemSchema, runtimeEvidenceSchema, handoffValidationSchema, artifactEvidenceSchema, loopCatalogFocusSchema, missionRecipeIdSchema2, startIntentSchema, nextStageSchema, responseDetailSchema, serverStartedAt, serverModulePath, repoTargetGuardExemptTools;
|
|
36652
37222
|
var init_server = __esm({
|
|
36653
|
-
"../mcp/src/server.ts"() {
|
|
37223
|
+
async "../mcp/src/server.ts"() {
|
|
36654
37224
|
"use strict";
|
|
36655
37225
|
init_dist();
|
|
36656
37226
|
init_dist2();
|
|
36657
37227
|
init_cloud();
|
|
37228
|
+
init_cloudCredentials();
|
|
36658
37229
|
init_teamContext();
|
|
36659
37230
|
init_missionInputOptions();
|
|
36660
37231
|
init_connectorReadiness();
|
|
@@ -36670,10 +37241,15 @@ var init_server = __esm({
|
|
|
36670
37241
|
init_workspace();
|
|
36671
37242
|
init_handoffAutofill();
|
|
36672
37243
|
init_scanFreshness();
|
|
37244
|
+
cloudBootstrap = await bootstrapCloudCredentials();
|
|
37245
|
+
if (cloudBootstrap.status === "failed") {
|
|
37246
|
+
console.error(`Brief cloud setup: ${cloudBootstrap.reason}`);
|
|
37247
|
+
process.exit(1);
|
|
37248
|
+
}
|
|
36673
37249
|
server = new McpServer(
|
|
36674
37250
|
{
|
|
36675
37251
|
name: "brief",
|
|
36676
|
-
version: "0.1.
|
|
37252
|
+
version: "0.1.3"
|
|
36677
37253
|
},
|
|
36678
37254
|
{
|
|
36679
37255
|
instructions: briefMcpInstructions
|
|
@@ -37128,9 +37704,12 @@ var init_server = __esm({
|
|
|
37128
37704
|
{
|
|
37129
37705
|
repoPath: z2.string().optional().describe(
|
|
37130
37706
|
"Path inside the repo. Defaults to BRIEF_REPO_ROOT captured from the agent workspace, then current working directory."
|
|
37707
|
+
),
|
|
37708
|
+
detail: z2.enum(["compact", "expanded"]).optional().describe(
|
|
37709
|
+
"Use compact by default for the agent loop; request expanded only when diagnosing wiring or setup."
|
|
37131
37710
|
)
|
|
37132
37711
|
},
|
|
37133
|
-
async ({ repoPath }) => {
|
|
37712
|
+
async ({ repoPath, detail }) => {
|
|
37134
37713
|
const repoTargetInfo = resolveRepoTarget(repoPath);
|
|
37135
37714
|
if (repoTargetInfo.repoTarget.status === "needs_repo_target") {
|
|
37136
37715
|
return repoTargetBlock(repoTargetInfo);
|
|
@@ -37140,14 +37719,19 @@ var init_server = __esm({
|
|
|
37140
37719
|
const skillLearning = buildRepoSkillLearningReport(repoRoot, {
|
|
37141
37720
|
maxFiles: 6e3
|
|
37142
37721
|
});
|
|
37722
|
+
const autoEngage = buildAgentAutoEngagementPlan(scan, skillLearning);
|
|
37723
|
+
const workflowWiring = evaluateAgentWorkflowWiring(scan);
|
|
37724
|
+
const responseDetail = detail ?? "compact";
|
|
37143
37725
|
return jsonText({
|
|
37144
37726
|
repoRoot,
|
|
37145
37727
|
rootResolution,
|
|
37146
37728
|
repoTarget,
|
|
37147
|
-
|
|
37148
|
-
|
|
37729
|
+
detail: responseDetail,
|
|
37730
|
+
autoEngage: responseDetail === "expanded" ? autoEngage : summarizeAutoEngageForStart(autoEngage),
|
|
37731
|
+
workflowWiring: responseDetail === "expanded" ? workflowWiring : summarizeWorkflowWiringForStart(workflowWiring),
|
|
37149
37732
|
skillLearning: summarizeSkillLearningForStart(skillLearning, void 0),
|
|
37150
|
-
next: "Install the default instruction into always-on agent guidance, then run the smoke test from the connected coding agent to prove Brief stays engaged from natural task asks."
|
|
37733
|
+
next: responseDetail === "expanded" ? "Install the default instruction into always-on agent guidance, then run the smoke test from the connected coding agent to prove Brief stays engaged from natural task asks." : "Install the default instruction, then give the connected agent a normal task and confirm it calls brief.next before editing. Request detail: expanded only to diagnose wiring.",
|
|
37734
|
+
detailHint: 'Call brief.auto_engage with detail: "expanded" only when diagnosing setup or workflow wiring.'
|
|
37151
37735
|
});
|
|
37152
37736
|
}
|
|
37153
37737
|
);
|
|
@@ -37266,7 +37850,7 @@ var init_server = __esm({
|
|
|
37266
37850
|
skills: scan.stats.skillCount
|
|
37267
37851
|
}
|
|
37268
37852
|
},
|
|
37269
|
-
next: teamContext.status === "fetched" ? "Use brief.context_for_task to route this team context into the next task." : "
|
|
37853
|
+
next: teamContext.status === "fetched" ? "Use brief.context_for_task to route this team context into the next task." : "Create a browser-authorized connection from the Brief app, then restart the agent. Approved legacy setups can provide BRIEF_API_URL, BRIEF_API_KEY, and BRIEF_WORKSPACE_ID."
|
|
37270
37854
|
});
|
|
37271
37855
|
}
|
|
37272
37856
|
);
|
|
@@ -37439,6 +38023,12 @@ var init_server = __esm({
|
|
|
37439
38023
|
}) : void 0;
|
|
37440
38024
|
const autoEngage = buildAgentAutoEngagementPlan(scan, skillLearning);
|
|
37441
38025
|
const workflowWiring = evaluateAgentWorkflowWiring(scan);
|
|
38026
|
+
const workPacket = buildAgentWorkPacket({
|
|
38027
|
+
task,
|
|
38028
|
+
beforeYouCode,
|
|
38029
|
+
interpretation: recommendation.reason,
|
|
38030
|
+
nextAction: `Call ${recommendation.mcpTool} next. ${recommendation.stopUntil}`
|
|
38031
|
+
});
|
|
37442
38032
|
const fullResponse = {
|
|
37443
38033
|
status: "brief_next",
|
|
37444
38034
|
repoRoot,
|
|
@@ -37447,6 +38037,7 @@ var init_server = __esm({
|
|
|
37447
38037
|
stage: resolvedStage,
|
|
37448
38038
|
recommendation,
|
|
37449
38039
|
cockpit: beforeYouCode.cockpit,
|
|
38040
|
+
workPacket,
|
|
37450
38041
|
beforeYouCode: summarizeBeforeYouCodeForStart(beforeYouCode),
|
|
37451
38042
|
...start && recommendation.mcpTool !== "brief.before_you_code" ? { start: summarizeStartForStart(start) } : {},
|
|
37452
38043
|
...readinessPreview ? { readinessPreview } : {},
|
|
@@ -37470,6 +38061,7 @@ var init_server = __esm({
|
|
|
37470
38061
|
},
|
|
37471
38062
|
stage: resolvedStage,
|
|
37472
38063
|
recommendation,
|
|
38064
|
+
workPacket,
|
|
37473
38065
|
cockpit: {
|
|
37474
38066
|
taskSize: beforeYouCode.cockpit.taskSize,
|
|
37475
38067
|
mode: beforeYouCode.cockpit.mode,
|
|
@@ -37491,7 +38083,8 @@ var init_server = __esm({
|
|
|
37491
38083
|
taskClasses: beforeYouCode.productOperatingContext.taskClasses
|
|
37492
38084
|
},
|
|
37493
38085
|
autoEngage: {
|
|
37494
|
-
status:
|
|
38086
|
+
status: autoEngage.status,
|
|
38087
|
+
workflowWiring: workflowWiring.status,
|
|
37495
38088
|
firstCall: "brief.next",
|
|
37496
38089
|
beforeEditing: "brief.before_you_code or brief.start",
|
|
37497
38090
|
beforeHandoff: "brief.review_diff",
|
|
@@ -38032,7 +38625,7 @@ var init_server = __esm({
|
|
|
38032
38625
|
const sourceRepos = sourceRepoPaths && sourceRepoPaths.length > 0 ? sourceRepoPaths : [repoRoot];
|
|
38033
38626
|
const inventories = sourceRepos.map(
|
|
38034
38627
|
(sourceRepo) => buildAgentPackInventory(
|
|
38035
|
-
|
|
38628
|
+
path19.isAbsolute(sourceRepo) ? sourceRepo : path19.resolve(repoRoot, sourceRepo),
|
|
38036
38629
|
maxFiles === void 0 ? {} : { maxFiles }
|
|
38037
38630
|
)
|
|
38038
38631
|
);
|
|
@@ -39407,6 +40000,7 @@ init_dist2();
|
|
|
39407
40000
|
init_teamContext();
|
|
39408
40001
|
init_missionInputOptions();
|
|
39409
40002
|
init_cloud();
|
|
40003
|
+
init_cloudCredentials();
|
|
39410
40004
|
init_workspace();
|
|
39411
40005
|
init_connectorReadiness();
|
|
39412
40006
|
init_connectorRecovery();
|
|
@@ -39418,15 +40012,139 @@ init_wikiInit();
|
|
|
39418
40012
|
init_handoffAutofill();
|
|
39419
40013
|
init_mapResponse();
|
|
39420
40014
|
init_scanFreshness();
|
|
39421
|
-
import { chmodSync as
|
|
39422
|
-
import
|
|
40015
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync8 } from "node:fs";
|
|
40016
|
+
import path20 from "node:path";
|
|
39423
40017
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
40018
|
+
|
|
40019
|
+
// ../mcp/src/runner.ts
|
|
40020
|
+
init_cloud();
|
|
40021
|
+
import { hostname } from "node:os";
|
|
40022
|
+
import { spawn } from "node:child_process";
|
|
40023
|
+
async function runLoopRunner(options2, log = console.log) {
|
|
40024
|
+
const runnerId = options2.runnerId ?? `${hostname()}-${process.pid}`;
|
|
40025
|
+
const intervalMs = Math.max(options2.intervalMs ?? 4e3, 1e3);
|
|
40026
|
+
const env = options2.env ?? process.env;
|
|
40027
|
+
let didRun = false;
|
|
40028
|
+
do {
|
|
40029
|
+
const run = await claimRemoteLoopRun(runnerId, 180, env);
|
|
40030
|
+
if (!run) {
|
|
40031
|
+
if (options2.once) return;
|
|
40032
|
+
await sleep(intervalMs);
|
|
40033
|
+
continue;
|
|
40034
|
+
}
|
|
40035
|
+
didRun = true;
|
|
40036
|
+
log({ status: "running", runId: run.id, loop: run.loopName });
|
|
40037
|
+
try {
|
|
40038
|
+
const result = await executeAgentCommand(
|
|
40039
|
+
options2.agentCommand,
|
|
40040
|
+
run,
|
|
40041
|
+
options2.repoRoot,
|
|
40042
|
+
options2.commandTimeoutMs ?? 30 * 60 * 1e3
|
|
40043
|
+
);
|
|
40044
|
+
const proof = {
|
|
40045
|
+
runnerId,
|
|
40046
|
+
exitCode: result.exitCode,
|
|
40047
|
+
stdoutBytes: Buffer.byteLength(result.stdout, "utf8"),
|
|
40048
|
+
stderrBytes: Buffer.byteLength(result.stderr, "utf8"),
|
|
40049
|
+
completedLocallyAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
40050
|
+
};
|
|
40051
|
+
const updated = await updateRemoteLoopRun(run.id, {
|
|
40052
|
+
runnerId,
|
|
40053
|
+
status: result.exitCode === 0 ? "succeeded" : "failed",
|
|
40054
|
+
lastEvent: result.exitCode === 0 ? "The local agent completed the loop." : "The local agent exited with a failure.",
|
|
40055
|
+
resultSummary: compactOutput(result.stdout || result.stderr),
|
|
40056
|
+
proof,
|
|
40057
|
+
...result.exitCode === 0 ? {} : { errorMessage: compactOutput(result.stderr || result.stdout) }
|
|
40058
|
+
}, env);
|
|
40059
|
+
log({ status: updated.status, runId: updated.id, proof });
|
|
40060
|
+
} catch (caught) {
|
|
40061
|
+
const message = caught instanceof Error ? caught.message : "Local runner failed.";
|
|
40062
|
+
try {
|
|
40063
|
+
const updated = await updateRemoteLoopRun(run.id, {
|
|
40064
|
+
runnerId,
|
|
40065
|
+
status: "failed",
|
|
40066
|
+
lastEvent: "The local runner could not execute the agent command.",
|
|
40067
|
+
errorMessage: message,
|
|
40068
|
+
proof: { runnerId, completedLocallyAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
40069
|
+
}, env);
|
|
40070
|
+
log({ status: updated.status, runId: updated.id, error: message });
|
|
40071
|
+
} catch (updateError) {
|
|
40072
|
+
log({ status: "failed", runId: run.id, error: message, updateError });
|
|
40073
|
+
throw new Error(
|
|
40074
|
+
`The runner could not persist the failed loop state: ${updateError instanceof Error ? updateError.message : "unknown update error"}`
|
|
40075
|
+
);
|
|
40076
|
+
}
|
|
40077
|
+
}
|
|
40078
|
+
} while (!options2.once || !didRun);
|
|
40079
|
+
}
|
|
40080
|
+
async function executeAgentCommand(command2, run, repoRoot, timeoutMs) {
|
|
40081
|
+
const prompt = [
|
|
40082
|
+
`You are running the approved Brief team loop: ${run.loopName}.`,
|
|
40083
|
+
`Run id: ${run.id}`,
|
|
40084
|
+
`Repository: ${run.repoFullName ?? repoRoot}`,
|
|
40085
|
+
"",
|
|
40086
|
+
"Approved loop guidance:",
|
|
40087
|
+
run.loopBody,
|
|
40088
|
+
"",
|
|
40089
|
+
"Guardrails:",
|
|
40090
|
+
...run.guardrails.length > 0 ? run.guardrails.map((item) => `- ${item}`) : ["- Stop before external side effects without approval."],
|
|
40091
|
+
"",
|
|
40092
|
+
"Task:",
|
|
40093
|
+
run.task,
|
|
40094
|
+
"",
|
|
40095
|
+
"Return a concise summary of what you changed, validation run, proof, and remaining risk."
|
|
40096
|
+
].join("\n");
|
|
40097
|
+
return await new Promise((resolve, reject) => {
|
|
40098
|
+
const child = spawn("/bin/sh", ["-lc", command2], {
|
|
40099
|
+
cwd: repoRoot,
|
|
40100
|
+
env: process.env,
|
|
40101
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
40102
|
+
});
|
|
40103
|
+
let stdout = "";
|
|
40104
|
+
let stderr = "";
|
|
40105
|
+
const timer = setTimeout(() => {
|
|
40106
|
+
child.kill("SIGTERM");
|
|
40107
|
+
reject(new Error(`Agent command timed out after ${Math.round(timeoutMs / 6e4)} minutes.`));
|
|
40108
|
+
}, timeoutMs);
|
|
40109
|
+
child.stdout.on("data", (chunk) => {
|
|
40110
|
+
stdout = `${stdout}${chunk.toString()}`.slice(-6e4);
|
|
40111
|
+
});
|
|
40112
|
+
child.stderr.on("data", (chunk) => {
|
|
40113
|
+
stderr = `${stderr}${chunk.toString()}`.slice(-2e4);
|
|
40114
|
+
});
|
|
40115
|
+
child.on("error", (error) => {
|
|
40116
|
+
clearTimeout(timer);
|
|
40117
|
+
reject(error);
|
|
40118
|
+
});
|
|
40119
|
+
child.on("close", (code) => {
|
|
40120
|
+
clearTimeout(timer);
|
|
40121
|
+
resolve({ exitCode: code ?? 1, stdout, stderr });
|
|
40122
|
+
});
|
|
40123
|
+
child.stdin.end(prompt);
|
|
40124
|
+
});
|
|
40125
|
+
}
|
|
40126
|
+
function compactOutput(value) {
|
|
40127
|
+
return value.trim().slice(-12e3) || "The agent returned no summary.";
|
|
40128
|
+
}
|
|
40129
|
+
function sleep(ms) {
|
|
40130
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
40131
|
+
}
|
|
40132
|
+
|
|
40133
|
+
// ../mcp/src/cli.ts
|
|
39424
40134
|
var args = process.argv.slice(2);
|
|
39425
40135
|
var command = args[0];
|
|
39426
40136
|
var cliStartedAt = /* @__PURE__ */ new Date();
|
|
39427
40137
|
var cliModulePath = fileURLToPath2(import.meta.url);
|
|
40138
|
+
if (!isCloudLogoutCommand(command)) {
|
|
40139
|
+
const cloudBootstrap2 = await bootstrapCloudCredentials();
|
|
40140
|
+
if (cloudBootstrap2.status === "failed") {
|
|
40141
|
+
console.error(
|
|
40142
|
+
`Brief team sync is unavailable: ${cloudBootstrap2.reason} Continuing in local mode.`
|
|
40143
|
+
);
|
|
40144
|
+
}
|
|
40145
|
+
}
|
|
39428
40146
|
if (!command || command === "--stdio" || command === "stdio" || command === "mcp") {
|
|
39429
|
-
await
|
|
40147
|
+
await init_server().then(() => server_exports);
|
|
39430
40148
|
} else {
|
|
39431
40149
|
await runCli(command, args.slice(1));
|
|
39432
40150
|
}
|
|
@@ -39435,11 +40153,41 @@ async function runCli(commandName, commandArgs) {
|
|
|
39435
40153
|
printJson(buildCliHelp(commandName));
|
|
39436
40154
|
return;
|
|
39437
40155
|
}
|
|
40156
|
+
if (isCloudLogoutCommand(commandName)) {
|
|
40157
|
+
forgetCloudCredentials();
|
|
40158
|
+
printJson({
|
|
40159
|
+
status: "cloud_credentials_removed",
|
|
40160
|
+
path: defaultCredentialsPath(),
|
|
40161
|
+
next: "Create a fresh browser-authorized connection from the Brief app before using team sync again."
|
|
40162
|
+
});
|
|
40163
|
+
return;
|
|
40164
|
+
}
|
|
39438
40165
|
const rootResolution = resolveRepoRootDetails(
|
|
39439
40166
|
option2(commandArgs, "repo") ?? option2(commandArgs, "repoPath") ?? option2(commandArgs, "repo-path")
|
|
39440
40167
|
);
|
|
39441
40168
|
const repoRoot = rootResolution.repoRoot;
|
|
39442
40169
|
const repoTarget = repoTargetHealth(rootResolution);
|
|
40170
|
+
if (isCommand(commandName, "runner", "loop-runner", "run-loop")) {
|
|
40171
|
+
const agentCommand = option2(commandArgs, "agent-command") ?? process.env.BRIEF_AGENT_COMMAND;
|
|
40172
|
+
if (!agentCommand) {
|
|
40173
|
+
fail(
|
|
40174
|
+
"Missing --agent-command. Set BRIEF_AGENT_COMMAND to the local Claude, Codex, or compatible agent command."
|
|
40175
|
+
);
|
|
40176
|
+
}
|
|
40177
|
+
const runnerOptions = {
|
|
40178
|
+
repoRoot,
|
|
40179
|
+
agentCommand,
|
|
40180
|
+
once: hasFlag(commandArgs, "once")
|
|
40181
|
+
};
|
|
40182
|
+
const runnerId = option2(commandArgs, "runner-id");
|
|
40183
|
+
const intervalMs = numberOption(commandArgs, "interval-ms");
|
|
40184
|
+
const commandTimeoutMs = numberOption(commandArgs, "timeout-ms");
|
|
40185
|
+
if (runnerId) runnerOptions.runnerId = runnerId;
|
|
40186
|
+
if (intervalMs) runnerOptions.intervalMs = intervalMs;
|
|
40187
|
+
if (commandTimeoutMs) runnerOptions.commandTimeoutMs = commandTimeoutMs;
|
|
40188
|
+
await runLoopRunner(runnerOptions);
|
|
40189
|
+
return;
|
|
40190
|
+
}
|
|
39443
40191
|
if (isCommand(commandName, "install-status", "install_status")) {
|
|
39444
40192
|
const freshness = cliServerFreshness();
|
|
39445
40193
|
const connector = connectorReadiness({
|
|
@@ -39670,6 +40418,12 @@ async function runCli(commandName, commandArgs) {
|
|
|
39670
40418
|
beforeYouCode,
|
|
39671
40419
|
baseRef
|
|
39672
40420
|
});
|
|
40421
|
+
const workPacket = buildAgentWorkPacket({
|
|
40422
|
+
task,
|
|
40423
|
+
beforeYouCode,
|
|
40424
|
+
interpretation: recommendation.reason,
|
|
40425
|
+
nextAction: recommendation.stopUntil
|
|
40426
|
+
});
|
|
39673
40427
|
const fullResponse = {
|
|
39674
40428
|
status: "brief_next",
|
|
39675
40429
|
repoRoot,
|
|
@@ -39678,6 +40432,7 @@ async function runCli(commandName, commandArgs) {
|
|
|
39678
40432
|
stage,
|
|
39679
40433
|
recommendation,
|
|
39680
40434
|
cockpit: beforeYouCode.cockpit,
|
|
40435
|
+
workPacket,
|
|
39681
40436
|
beforeYouCode: summarizeBeforeYouCodeForCli(beforeYouCode),
|
|
39682
40437
|
...start && recommendation.mcpTool !== "brief.before_you_code" ? { start: summarizeStartForCli(start) } : {},
|
|
39683
40438
|
workflowWiring: summarizeWorkflowWiringForCli(workflowWiring),
|
|
@@ -39700,6 +40455,11 @@ async function runCli(commandName, commandArgs) {
|
|
|
39700
40455
|
},
|
|
39701
40456
|
stage,
|
|
39702
40457
|
recommendation,
|
|
40458
|
+
workPacket: {
|
|
40459
|
+
schemaVersion: workPacket.schemaVersion,
|
|
40460
|
+
compactText: workPacket.compactText,
|
|
40461
|
+
lineCount: workPacket.lineCount
|
|
40462
|
+
},
|
|
39703
40463
|
cockpit: {
|
|
39704
40464
|
taskSize: beforeYouCode.cockpit.taskSize,
|
|
39705
40465
|
mode: beforeYouCode.cockpit.mode,
|
|
@@ -39726,7 +40486,11 @@ async function runCli(commandName, commandArgs) {
|
|
|
39726
40486
|
autoEngage: {
|
|
39727
40487
|
status: autoEngage.status,
|
|
39728
40488
|
chatFeedback: autoEngage.chatFeedback.slice(0, 1),
|
|
39729
|
-
finalRecapPolicy:
|
|
40489
|
+
finalRecapPolicy: {
|
|
40490
|
+
maxLines: autoEngage.finalRecapPolicy.maxLines,
|
|
40491
|
+
defaultTemplate: autoEngage.finalRecapPolicy.defaultTemplate,
|
|
40492
|
+
fallbackWhenNotHelpful: autoEngage.finalRecapPolicy.fallbackWhenNotHelpful
|
|
40493
|
+
}
|
|
39730
40494
|
},
|
|
39731
40495
|
referenceFirst: summarizeBeforeYouCodeReferences(beforeYouCode),
|
|
39732
40496
|
...learnedWorkflow ? {
|
|
@@ -40089,7 +40853,7 @@ async function runCli(commandName, commandArgs) {
|
|
|
40089
40853
|
const sourceRepos = filesOption2(commandArgs, "source-repos") ?? filesOption2(commandArgs, "sourceRepos") ?? filesOption2(commandArgs, "sources") ?? [repoRoot];
|
|
40090
40854
|
const inventories = sourceRepos.map(
|
|
40091
40855
|
(sourceRepo) => buildAgentPackInventory(
|
|
40092
|
-
|
|
40856
|
+
path20.isAbsolute(sourceRepo) ? sourceRepo : path20.resolve(repoRoot, sourceRepo),
|
|
40093
40857
|
maxFiles === void 0 ? {} : { maxFiles }
|
|
40094
40858
|
)
|
|
40095
40859
|
);
|
|
@@ -40881,14 +41645,14 @@ async function runCli(commandName, commandArgs) {
|
|
|
40881
41645
|
if (isCommand(commandName, "workflow-wiring", "workflow_wiring")) {
|
|
40882
41646
|
const scan = scanRepo(repoRoot, { maxFiles: 400 });
|
|
40883
41647
|
const workflowWiring = evaluateAgentWorkflowWiring(scan);
|
|
40884
|
-
const
|
|
41648
|
+
const compact2 = hasFlag(commandArgs, "compact") && !hasFlag(commandArgs, "full");
|
|
40885
41649
|
const explicitlyExpanded = hasFlag(commandArgs, "full");
|
|
40886
41650
|
printJson({
|
|
40887
41651
|
status: "workflow_wiring",
|
|
40888
41652
|
repoRoot,
|
|
40889
41653
|
repoName: scan.repoName,
|
|
40890
|
-
workflowWiring:
|
|
40891
|
-
...
|
|
41654
|
+
workflowWiring: compact2 ? summarizeAgentWorkflowWiring(workflowWiring) : workflowWiring,
|
|
41655
|
+
...compact2 ? {
|
|
40892
41656
|
detailHint: "Use --full only when diagnosing wiring evidence, contracts, or copyable prompts."
|
|
40893
41657
|
} : explicitlyExpanded ? { detail: "expanded" } : {
|
|
40894
41658
|
compatibility: "Expanded detail was returned for backward compatibility. Use --compact for the agent-safe response."
|
|
@@ -40961,7 +41725,7 @@ async function runCli(commandName, commandArgs) {
|
|
|
40961
41725
|
skills: scan.stats.skillCount
|
|
40962
41726
|
}
|
|
40963
41727
|
},
|
|
40964
|
-
next: teamContext.status === "fetched" ? "Use context_for_task to route this team context into the next task." : "
|
|
41728
|
+
next: teamContext.status === "fetched" ? "Use context_for_task to route this team context into the next task." : "Create a browser-authorized connection from the Brief app, then restart the agent. Approved legacy setups can provide BRIEF_API_URL, BRIEF_API_KEY, and BRIEF_WORKSPACE_ID."
|
|
40965
41729
|
});
|
|
40966
41730
|
return;
|
|
40967
41731
|
}
|
|
@@ -41158,6 +41922,11 @@ async function runCli(commandName, commandArgs) {
|
|
|
41158
41922
|
function isCommand(commandName, ...aliases) {
|
|
41159
41923
|
return aliases.includes(commandName);
|
|
41160
41924
|
}
|
|
41925
|
+
function isCloudLogoutCommand(commandName) {
|
|
41926
|
+
return Boolean(
|
|
41927
|
+
commandName && ["cloud-logout", "cloud_logout", "disconnect-cloud"].includes(commandName)
|
|
41928
|
+
);
|
|
41929
|
+
}
|
|
41161
41930
|
function wikiInitMode(argsList) {
|
|
41162
41931
|
if (hasFlag(argsList, "init")) return "init";
|
|
41163
41932
|
if (hasFlag(argsList, "update")) return "update";
|
|
@@ -41241,6 +42010,33 @@ function cliCommandHelp() {
|
|
|
41241
42010
|
"After changing Brief source to confirm the running connector is fresh."
|
|
41242
42011
|
]
|
|
41243
42012
|
},
|
|
42013
|
+
{
|
|
42014
|
+
command: "cloud-logout",
|
|
42015
|
+
aliases: ["cloud_logout", "disconnect-cloud"],
|
|
42016
|
+
purpose: "Remove the locally stored cloud credential so the next setup can pair a device again.",
|
|
42017
|
+
repoBound: false,
|
|
42018
|
+
usage: "brief cloud-logout",
|
|
42019
|
+
examples: ["brief cloud-logout"],
|
|
42020
|
+
whenToUse: [
|
|
42021
|
+
"When a device needs to be disconnected from a Brief workspace.",
|
|
42022
|
+
"When a one-time browser pairing has expired before the connector started."
|
|
42023
|
+
]
|
|
42024
|
+
},
|
|
42025
|
+
{
|
|
42026
|
+
command: "runner",
|
|
42027
|
+
aliases: ["loop-runner", "run-loop"],
|
|
42028
|
+
purpose: "Poll for an approved team loop and execute it with the developer's local agent command.",
|
|
42029
|
+
repoBound: true,
|
|
42030
|
+
usage: 'runbrief runner --repo $PWD --agent-command "claude -p"',
|
|
42031
|
+
examples: [
|
|
42032
|
+
'runbrief runner --repo $PWD --agent-command "claude -p"',
|
|
42033
|
+
'runbrief runner --repo $PWD --agent-command "codex exec" --once'
|
|
42034
|
+
],
|
|
42035
|
+
whenToUse: [
|
|
42036
|
+
"After pairing a connector from the Brief app.",
|
|
42037
|
+
"When a team-approved loop is queued in the web app."
|
|
42038
|
+
]
|
|
42039
|
+
},
|
|
41244
42040
|
{
|
|
41245
42041
|
command: "next",
|
|
41246
42042
|
aliases: ["brief-next", "brief_next"],
|
|
@@ -41586,7 +42382,11 @@ function positionalText(argsList) {
|
|
|
41586
42382
|
"owner",
|
|
41587
42383
|
"receipts",
|
|
41588
42384
|
"added-by",
|
|
41589
|
-
"addedBy"
|
|
42385
|
+
"addedBy",
|
|
42386
|
+
"agent-command",
|
|
42387
|
+
"runner-id",
|
|
42388
|
+
"interval-ms",
|
|
42389
|
+
"timeout-ms"
|
|
41590
42390
|
]);
|
|
41591
42391
|
const parts = [];
|
|
41592
42392
|
for (let index = 0; index < argsList.length; index += 1) {
|
|
@@ -41842,7 +42642,7 @@ function artifactEvidenceFromOptions(argsList) {
|
|
|
41842
42642
|
);
|
|
41843
42643
|
const evidence = [];
|
|
41844
42644
|
for (const raw of rawEvidenceValues) {
|
|
41845
|
-
const json = raw.startsWith("@") ?
|
|
42645
|
+
const json = raw.startsWith("@") ? readFileSync7(path20.resolve(raw.slice(1)), "utf8") : raw;
|
|
41846
42646
|
try {
|
|
41847
42647
|
const parsed = JSON.parse(json);
|
|
41848
42648
|
const items = Array.isArray(parsed) ? parsed : [parsed];
|
|
@@ -41920,7 +42720,7 @@ function missionSummaryFromLocalReceipt2(repoRoot, missionReceiptId) {
|
|
|
41920
42720
|
function runtimeEvidencePacketFromOptions(argsList) {
|
|
41921
42721
|
const raw = option2(argsList, "runtime-packet") ?? option2(argsList, "runtime-evidence-packet") ?? option2(argsList, "runtimeEvidencePacket");
|
|
41922
42722
|
if (!raw) return void 0;
|
|
41923
|
-
const json = raw.startsWith("@") ?
|
|
42723
|
+
const json = raw.startsWith("@") ? readFileSync7(path20.resolve(raw.slice(1)), "utf8") : raw;
|
|
41924
42724
|
try {
|
|
41925
42725
|
return cleanRuntimeEvidencePacket2(
|
|
41926
42726
|
runtimeEvidencePacketSchema.parse(JSON.parse(json))
|
|
@@ -42089,6 +42889,15 @@ function printContextSummary(packet, localReceipt, teamContext) {
|
|
|
42089
42889
|
teamContextLine(teamContext),
|
|
42090
42890
|
teamGuidanceLine(packet),
|
|
42091
42891
|
valueSignalLine(packet),
|
|
42892
|
+
...packet.dependencyRemediation ? [
|
|
42893
|
+
"",
|
|
42894
|
+
"Dependency plan:",
|
|
42895
|
+
`- ${packet.dependencyRemediation.packageManager} \xB7 ${packet.dependencyRemediation.status}`,
|
|
42896
|
+
`- manifests: ${packet.dependencyRemediation.manifestFiles.slice(0, 4).join(", ") || "none found"}`,
|
|
42897
|
+
`- lockfiles: ${packet.dependencyRemediation.lockfiles.slice(0, 3).join(", ") || "none found"}`,
|
|
42898
|
+
`- packages: ${packet.dependencyRemediation.packageSignals.map((item) => item.name).join(", ") || "need advisory/scanner evidence"}`,
|
|
42899
|
+
`- graph proof: ${packet.dependencyRemediation.graphCommands.slice(0, 2).join(", ") || "name the direct/transitive path"}`
|
|
42900
|
+
] : [],
|
|
42092
42901
|
"",
|
|
42093
42902
|
"Rules:",
|
|
42094
42903
|
...packet.rules.length > 0 ? packet.rules.slice(0, 8).map((rule) => `- [${rule.enforcement}] ${rule.title}`) : ["- none"],
|
|
@@ -42141,10 +42950,10 @@ function valueSignalLine(packet) {
|
|
|
42141
42950
|
function writeHookFiles2(repoRoot, files) {
|
|
42142
42951
|
const written = [];
|
|
42143
42952
|
for (const file of files) {
|
|
42144
|
-
const targetPath =
|
|
42145
|
-
|
|
42146
|
-
|
|
42147
|
-
if (file.path.endsWith(".sh"))
|
|
42953
|
+
const targetPath = path20.join(repoRoot, file.path);
|
|
42954
|
+
mkdirSync5(path20.dirname(targetPath), { recursive: true });
|
|
42955
|
+
writeFileSync8(targetPath, file.body);
|
|
42956
|
+
if (file.path.endsWith(".sh")) chmodSync3(targetPath, 493);
|
|
42148
42957
|
written.push(file.path);
|
|
42149
42958
|
}
|
|
42150
42959
|
return written;
|
|
@@ -42272,7 +43081,8 @@ function cliServerFreshness() {
|
|
|
42272
43081
|
return mcpServerFreshness({
|
|
42273
43082
|
serverStartedAt: cliStartedAt,
|
|
42274
43083
|
entrypoint: cliModulePath,
|
|
42275
|
-
mode: "cli"
|
|
43084
|
+
mode: "cli",
|
|
43085
|
+
distribution: connectorDistributionFor(cliModulePath)
|
|
42276
43086
|
});
|
|
42277
43087
|
}
|
|
42278
43088
|
function printJson(value) {
|
|
@@ -42296,7 +43106,7 @@ function nextScanStep(cloudSync) {
|
|
|
42296
43106
|
if (cloudSync.status === "failed") {
|
|
42297
43107
|
return `The local scan succeeded, but the web app did not update because cloud sync failed: ${cloudSync.reason}. Fix cloud sync before trusting hosted freshness; refresh local wiki separately with brief.initialize_repo_wiki update: true.`;
|
|
42298
43108
|
}
|
|
42299
|
-
return "The local scan succeeded, but the web app did not update.
|
|
43109
|
+
return "The local scan succeeded, but the web app did not update. Create a browser-authorized connection from the Brief app and restart the agent; approved legacy setups can provide BRIEF_API_URL, BRIEF_API_KEY, and BRIEF_WORKSPACE_ID. To refresh repo-local wiki docs, ask the agent to call brief.initialize_repo_wiki with update: true.";
|
|
42300
43110
|
}
|
|
42301
43111
|
function fail(message) {
|
|
42302
43112
|
process.stderr.write(`${message}
|