runbrief 0.1.2 → 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 +1324 -625
- 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("/");
|
|
@@ -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;
|
|
@@ -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) {
|
|
@@ -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"}`
|
|
@@ -28167,16 +28367,20 @@ var init_agentBeforeYouCode = __esm({
|
|
|
28167
28367
|
// ../core/dist/agentWorkPacket.js
|
|
28168
28368
|
function buildAgentWorkPacket(input) {
|
|
28169
28369
|
const before = input.beforeYouCode;
|
|
28170
|
-
const rules = [
|
|
28370
|
+
const rules = uniqueRules2([
|
|
28171
28371
|
...(before.teamGuidance?.applied ?? []).map((item) => ({
|
|
28172
28372
|
rule: item.label,
|
|
28173
28373
|
source: `team:${item.kind}`
|
|
28174
28374
|
})),
|
|
28375
|
+
...(before.rules ?? []).map((item) => ({
|
|
28376
|
+
rule: compact(item.body || item.title, 180),
|
|
28377
|
+
source: item.sourcePaths[0] ?? "repo guidance"
|
|
28378
|
+
})),
|
|
28175
28379
|
...before.productOperatingContext.productRules.map((item) => ({
|
|
28176
28380
|
rule: item.rule,
|
|
28177
28381
|
source: item.source
|
|
28178
28382
|
}))
|
|
28179
|
-
].slice(0, 3);
|
|
28383
|
+
]).slice(0, 3);
|
|
28180
28384
|
const tests = before.exactTests.length > 0 ? before.exactTests.slice(0, 3).map((test) => ({
|
|
28181
28385
|
command: compact(test.command, 180),
|
|
28182
28386
|
reason: compact(test.reason, 180),
|
|
@@ -28192,7 +28396,8 @@ function buildAgentWorkPacket(input) {
|
|
|
28192
28396
|
]).slice(0, 3);
|
|
28193
28397
|
const stopConditions = unique2([
|
|
28194
28398
|
...before.stopSignals,
|
|
28195
|
-
...before.productOperatingContext.stopSignals
|
|
28399
|
+
...before.productOperatingContext.stopSignals,
|
|
28400
|
+
...before.mapCoverage.status === "partial" ? [before.mapCoverage.summary] : []
|
|
28196
28401
|
]).slice(0, 3);
|
|
28197
28402
|
const nextAction = input.nextAction ?? before.next ?? "Inspect the listed files and make the reuse decision before editing.";
|
|
28198
28403
|
const packet = {
|
|
@@ -28220,6 +28425,7 @@ function buildAgentWorkPacket(input) {
|
|
|
28220
28425
|
why: compact(item.why, 140)
|
|
28221
28426
|
}))
|
|
28222
28427
|
},
|
|
28428
|
+
mapCoverage: before.mapCoverage,
|
|
28223
28429
|
rules,
|
|
28224
28430
|
tests,
|
|
28225
28431
|
acceptance,
|
|
@@ -28236,6 +28442,7 @@ function formatAgentWorkPacket(packet) {
|
|
|
28236
28442
|
`Interpretation: ${packet.interpretation}`,
|
|
28237
28443
|
`Inspect first: ${inlineList(packet.inspectFirst.map((item) => `${item.path} - ${item.why}`))}`,
|
|
28238
28444
|
`Reuse (${packet.reuse.status}): ${packet.reuse.decision}; ${inlineList(packet.reuse.candidates.map((item) => `${item.path} - ${item.action}`))}`,
|
|
28445
|
+
`Map: ${packet.mapCoverage.summary}`,
|
|
28239
28446
|
`Rules: ${inlineList(packet.rules.map((item) => `${item.rule} [${item.source}]`))}`,
|
|
28240
28447
|
`Focused tests: ${inlineList(packet.tests.map((item) => `${item.command} - ${item.reason}`))}`,
|
|
28241
28448
|
`Acceptance: ${inlineList(packet.acceptance)}`,
|
|
@@ -28254,6 +28461,16 @@ function compact(value, maxLength) {
|
|
|
28254
28461
|
function unique2(values) {
|
|
28255
28462
|
return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
|
|
28256
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
|
+
}
|
|
28257
28474
|
var init_agentWorkPacket = __esm({
|
|
28258
28475
|
"../core/dist/agentWorkPacket.js"() {
|
|
28259
28476
|
"use strict";
|
|
@@ -31192,6 +31409,7 @@ var init_diffReview = __esm({
|
|
|
31192
31409
|
"handler",
|
|
31193
31410
|
"helpers",
|
|
31194
31411
|
"delete",
|
|
31412
|
+
"dynamic",
|
|
31195
31413
|
"get",
|
|
31196
31414
|
"head",
|
|
31197
31415
|
"input",
|
|
@@ -33102,7 +33320,7 @@ function cloudSyncStatus(env = process.env) {
|
|
|
33102
33320
|
return {
|
|
33103
33321
|
configured: false,
|
|
33104
33322
|
privacyMode,
|
|
33105
|
-
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."
|
|
33106
33324
|
};
|
|
33107
33325
|
}
|
|
33108
33326
|
const status = {
|
|
@@ -33259,6 +33477,64 @@ async function fetchTeamContext(repoRoot, env = process.env, fetcher = fetch) {
|
|
|
33259
33477
|
});
|
|
33260
33478
|
return getTeamContextCloud(config, payload, fetcher);
|
|
33261
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
|
+
}
|
|
33262
33538
|
function toRepoScanSummary(scan, privacyMode) {
|
|
33263
33539
|
return {
|
|
33264
33540
|
repoName: scan.repoName,
|
|
@@ -33304,7 +33580,7 @@ function skippedResult(env) {
|
|
|
33304
33580
|
return {
|
|
33305
33581
|
status: "skipped",
|
|
33306
33582
|
privacyMode,
|
|
33307
|
-
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."
|
|
33308
33584
|
};
|
|
33309
33585
|
}
|
|
33310
33586
|
function skippedTeamContextResult(env) {
|
|
@@ -33312,7 +33588,7 @@ function skippedTeamContextResult(env) {
|
|
|
33312
33588
|
return {
|
|
33313
33589
|
status: "skipped",
|
|
33314
33590
|
privacyMode,
|
|
33315
|
-
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."
|
|
33316
33592
|
};
|
|
33317
33593
|
}
|
|
33318
33594
|
function normalizeApiUrl(apiUrl) {
|
|
@@ -33736,9 +34012,9 @@ function issuesValue(value) {
|
|
|
33736
34012
|
if (typeof item === "string") return item;
|
|
33737
34013
|
if (!item || typeof item !== "object") return "";
|
|
33738
34014
|
const record = item;
|
|
33739
|
-
const
|
|
34015
|
+
const path21 = Array.isArray(record.path) ? record.path.join(".") : "";
|
|
33740
34016
|
const message = stringValue(record.message);
|
|
33741
|
-
return [
|
|
34017
|
+
return [path21, message].filter(Boolean).join(": ");
|
|
33742
34018
|
}).filter(Boolean).slice(0, 5).join("; ");
|
|
33743
34019
|
}
|
|
33744
34020
|
var syncTimeoutMs, canonicalBriefApiUrl, legacyBriefApiUrls;
|
|
@@ -34129,14 +34405,178 @@ var init_missionInputOptions = __esm({
|
|
|
34129
34405
|
}
|
|
34130
34406
|
});
|
|
34131
34407
|
|
|
34132
|
-
// ../mcp/src/
|
|
34133
|
-
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";
|
|
34134
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";
|
|
34135
34575
|
function resolveRepoRoot(repoPath, options2 = {}) {
|
|
34136
34576
|
return resolveRepoRootDetails(repoPath, options2).repoRoot;
|
|
34137
34577
|
}
|
|
34138
34578
|
function resolveRepoRootDetails(repoPath, options2 = {}) {
|
|
34139
|
-
const cwd =
|
|
34579
|
+
const cwd = path15.resolve(options2.cwd ?? process.cwd());
|
|
34140
34580
|
const env = options2.env ?? process.env;
|
|
34141
34581
|
const cwdResolution = resolveExistingRoot(cwd, "cwd");
|
|
34142
34582
|
const cwdIsCustomerWorktree = isGitWorktree(cwdResolution.repoRoot) && !looksLikeBriefSourceCheckout(cwdResolution.repoRoot);
|
|
@@ -34150,7 +34590,7 @@ function resolveRepoRootDetails(repoPath, options2 = {}) {
|
|
|
34150
34590
|
]);
|
|
34151
34591
|
const explicitRepoPath = repoPath?.trim();
|
|
34152
34592
|
if (explicitRepoPath) {
|
|
34153
|
-
const explicitPathKind =
|
|
34593
|
+
const explicitPathKind = path15.isAbsolute(explicitRepoPath) ? "absolute" : "relative";
|
|
34154
34594
|
if (explicitPathKind === "relative" && envCandidates.length > 1) {
|
|
34155
34595
|
return {
|
|
34156
34596
|
...cwdResolution,
|
|
@@ -34162,7 +34602,7 @@ function resolveRepoRootDetails(repoPath, options2 = {}) {
|
|
|
34162
34602
|
const relativeBase = cwdIsCustomerWorktree ? cwdResolution.repoRoot : envCandidates[0]?.repoRoot ?? cwd;
|
|
34163
34603
|
return {
|
|
34164
34604
|
...resolveExistingRoot(
|
|
34165
|
-
|
|
34605
|
+
path15.resolve(
|
|
34166
34606
|
explicitPathKind === "absolute" ? cwd : relativeBase,
|
|
34167
34607
|
explicitRepoPath
|
|
34168
34608
|
),
|
|
@@ -34200,7 +34640,7 @@ function resolveFromEnvVars(cwd, env, envVars, options2 = {}) {
|
|
|
34200
34640
|
for (const envVar of envVars) {
|
|
34201
34641
|
const value = cleanWorkspacePath(env[envVar]);
|
|
34202
34642
|
if (!value) continue;
|
|
34203
|
-
const start =
|
|
34643
|
+
const start = path15.resolve(cwd, value);
|
|
34204
34644
|
if (existsSync5(start)) {
|
|
34205
34645
|
const resolution = resolveExistingRoot(start, "environment", envVar);
|
|
34206
34646
|
if (options2.skipBriefSource && looksLikeBriefSourceCheckout(resolution.repoRoot)) {
|
|
@@ -34213,7 +34653,7 @@ function resolveFromEnvVars(cwd, env, envVars, options2 = {}) {
|
|
|
34213
34653
|
}
|
|
34214
34654
|
function repoTargetHealth(resolution, options2 = {}) {
|
|
34215
34655
|
const env = options2.env ?? process.env;
|
|
34216
|
-
const cwd =
|
|
34656
|
+
const cwd = path15.resolve(options2.cwd ?? process.cwd());
|
|
34217
34657
|
const gitRoot = runGit(resolution.repoRoot, ["rev-parse", "--show-toplevel"]);
|
|
34218
34658
|
const evidence = [
|
|
34219
34659
|
...rootEvidence(resolution, cwd, env),
|
|
@@ -34274,7 +34714,7 @@ function repoTargetHealth(resolution, options2 = {}) {
|
|
|
34274
34714
|
};
|
|
34275
34715
|
}
|
|
34276
34716
|
function resolveExistingRoot(start, source, envVar) {
|
|
34277
|
-
const gitStart = existsSync5(start) && !statSync4(start).isDirectory() ?
|
|
34717
|
+
const gitStart = existsSync5(start) && !statSync4(start).isDirectory() ? path15.dirname(start) : start;
|
|
34278
34718
|
const gitRoot = runGit(gitStart, ["rev-parse", "--show-toplevel"]);
|
|
34279
34719
|
return {
|
|
34280
34720
|
repoRoot: gitRoot && existsSync5(gitRoot) ? gitRoot : start,
|
|
@@ -34325,12 +34765,12 @@ function preferPinnedRepoRoot(env) {
|
|
|
34325
34765
|
return env.BRIEF_REPO_ROOT_MODE === "pinned" || env.BRIEF_REPO_ROOT_PINNED === "true";
|
|
34326
34766
|
}
|
|
34327
34767
|
function looksLikeBriefSourceCheckout(repoRoot) {
|
|
34328
|
-
if (!existsSync5(
|
|
34768
|
+
if (!existsSync5(path15.join(repoRoot, "packages", "mcp", "src", "server.ts"))) {
|
|
34329
34769
|
return false;
|
|
34330
34770
|
}
|
|
34331
34771
|
try {
|
|
34332
34772
|
const pkg = JSON.parse(
|
|
34333
|
-
|
|
34773
|
+
readFileSync4(path15.join(repoRoot, "package.json"), "utf8")
|
|
34334
34774
|
);
|
|
34335
34775
|
return pkg.name === "brief";
|
|
34336
34776
|
} catch {
|
|
@@ -34359,7 +34799,7 @@ var init_workspace = __esm({
|
|
|
34359
34799
|
});
|
|
34360
34800
|
|
|
34361
34801
|
// ../mcp/src/connectorReadiness.ts
|
|
34362
|
-
import
|
|
34802
|
+
import path16 from "node:path";
|
|
34363
34803
|
function connectorReadiness(input) {
|
|
34364
34804
|
const runtimeLabel = input.mode === "cli" ? "Brief CLI process" : "Brief MCP connector";
|
|
34365
34805
|
const installStatusTool = input.mode === "cli" ? "install-status or brief.install_status" : "brief.install_status";
|
|
@@ -34453,8 +34893,8 @@ function connectorReadiness(input) {
|
|
|
34453
34893
|
};
|
|
34454
34894
|
}
|
|
34455
34895
|
function briefSourceCheckoutMismatch(input) {
|
|
34456
|
-
const repoRoot = input.repoRoot ?
|
|
34457
|
-
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;
|
|
34458
34898
|
if (!repoRoot || !sourceRoot) return void 0;
|
|
34459
34899
|
if (samePath(repoRoot, sourceRoot)) return void 0;
|
|
34460
34900
|
if (!looksLikeBriefSourceCheckout(repoRoot)) return void 0;
|
|
@@ -34469,7 +34909,7 @@ function briefSourceCheckoutMismatch(input) {
|
|
|
34469
34909
|
};
|
|
34470
34910
|
}
|
|
34471
34911
|
function samePath(left, right) {
|
|
34472
|
-
return
|
|
34912
|
+
return path16.normalize(left) === path16.normalize(right);
|
|
34473
34913
|
}
|
|
34474
34914
|
var init_connectorReadiness = __esm({
|
|
34475
34915
|
"../mcp/src/connectorReadiness.ts"() {
|
|
@@ -34603,8 +35043,8 @@ var init_connectorRecovery = __esm({
|
|
|
34603
35043
|
});
|
|
34604
35044
|
|
|
34605
35045
|
// ../mcp/src/serverFreshness.ts
|
|
34606
|
-
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as
|
|
34607
|
-
import
|
|
35046
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync5 } from "node:fs";
|
|
35047
|
+
import path17 from "node:path";
|
|
34608
35048
|
function mcpServerFreshness(options2) {
|
|
34609
35049
|
const cwd = options2.cwd ?? process.cwd();
|
|
34610
35050
|
const now = options2.now ?? /* @__PURE__ */ new Date();
|
|
@@ -34615,10 +35055,12 @@ function mcpServerFreshness(options2) {
|
|
|
34615
35055
|
cwd,
|
|
34616
35056
|
sourceRoot: options2.sourceRoot
|
|
34617
35057
|
});
|
|
35058
|
+
const sourceKind = options2.distribution ?? connectorDistributionFor(options2.entrypoint);
|
|
34618
35059
|
const watchedGlobs = watchedSourceGlobs();
|
|
34619
35060
|
const base = {
|
|
34620
35061
|
serverStartedAt: options2.serverStartedAt.toISOString(),
|
|
34621
35062
|
checkedAt: now.toISOString(),
|
|
35063
|
+
sourceKind,
|
|
34622
35064
|
process: {
|
|
34623
35065
|
pid: process.pid,
|
|
34624
35066
|
cwd,
|
|
@@ -34633,6 +35075,15 @@ function mcpServerFreshness(options2) {
|
|
|
34633
35075
|
changedSinceStartCount: 0
|
|
34634
35076
|
};
|
|
34635
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
|
+
}
|
|
34636
35087
|
return {
|
|
34637
35088
|
status: "unknown",
|
|
34638
35089
|
...base,
|
|
@@ -34673,6 +35124,21 @@ function mcpServerFreshness(options2) {
|
|
|
34673
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."
|
|
34674
35125
|
};
|
|
34675
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
|
+
}
|
|
34676
35142
|
function freshnessAction(status) {
|
|
34677
35143
|
if (status === "current") {
|
|
34678
35144
|
return {
|
|
@@ -34707,30 +35173,30 @@ function findBriefSourceRoot(options2) {
|
|
|
34707
35173
|
const candidates = [
|
|
34708
35174
|
options2.sourceRoot,
|
|
34709
35175
|
process.env.BRIEF_SOURCE_ROOT,
|
|
34710
|
-
options2.entrypoint ?
|
|
35176
|
+
options2.entrypoint ? path17.dirname(options2.entrypoint) : void 0,
|
|
34711
35177
|
options2.cwd
|
|
34712
35178
|
].filter((candidate) => Boolean(candidate));
|
|
34713
35179
|
for (const candidate of candidates) {
|
|
34714
|
-
const root = walkUpForBriefRoot(
|
|
35180
|
+
const root = walkUpForBriefRoot(path17.resolve(candidate));
|
|
34715
35181
|
if (root) return root;
|
|
34716
35182
|
}
|
|
34717
35183
|
return void 0;
|
|
34718
35184
|
}
|
|
34719
35185
|
function walkUpForBriefRoot(start) {
|
|
34720
|
-
let current = existsSync6(start) && statSafe(start)?.isFile() ?
|
|
35186
|
+
let current = existsSync6(start) && statSafe(start)?.isFile() ? path17.dirname(start) : start;
|
|
34721
35187
|
while (true) {
|
|
34722
35188
|
if (isBriefSourceRoot(current)) return current;
|
|
34723
|
-
const parent =
|
|
35189
|
+
const parent = path17.dirname(current);
|
|
34724
35190
|
if (parent === current) return void 0;
|
|
34725
35191
|
current = parent;
|
|
34726
35192
|
}
|
|
34727
35193
|
}
|
|
34728
35194
|
function isBriefSourceRoot(candidate) {
|
|
34729
|
-
const packageJsonPath =
|
|
35195
|
+
const packageJsonPath = path17.join(candidate, "package.json");
|
|
34730
35196
|
if (!existsSync6(packageJsonPath)) return false;
|
|
34731
35197
|
const packageJson = readJson(packageJsonPath);
|
|
34732
35198
|
if (packageJson?.name !== "brief") return false;
|
|
34733
|
-
return existsSync6(
|
|
35199
|
+
return existsSync6(path17.join(candidate, "packages", "mcp")) && existsSync6(path17.join(candidate, "packages", "core")) && existsSync6(path17.join(candidate, "packages", "contracts"));
|
|
34734
35200
|
}
|
|
34735
35201
|
function watchedSourceGlobs() {
|
|
34736
35202
|
return [
|
|
@@ -34768,7 +35234,7 @@ function collectWatchedFiles(sourceRoot, maxWatchedFiles) {
|
|
|
34768
35234
|
truncated = true;
|
|
34769
35235
|
break;
|
|
34770
35236
|
}
|
|
34771
|
-
const absolutePath =
|
|
35237
|
+
const absolutePath = path17.join(sourceRoot, relativePath);
|
|
34772
35238
|
const stats = statSafe(absolutePath);
|
|
34773
35239
|
if (!stats) continue;
|
|
34774
35240
|
if (stats.isDirectory()) {
|
|
@@ -34785,7 +35251,7 @@ function collectWatchedFiles(sourceRoot, maxWatchedFiles) {
|
|
|
34785
35251
|
break;
|
|
34786
35252
|
}
|
|
34787
35253
|
files.push({
|
|
34788
|
-
path: normalizePath(
|
|
35254
|
+
path: normalizePath(path17.relative(sourceRoot, absolutePath)),
|
|
34789
35255
|
modifiedAtMs: stats.mtimeMs
|
|
34790
35256
|
});
|
|
34791
35257
|
}
|
|
@@ -34796,7 +35262,7 @@ function walkFiles2(sourceRoot, directory, files, maxWatchedFiles) {
|
|
|
34796
35262
|
const entries = readdirSafe(directory);
|
|
34797
35263
|
for (const entry of entries) {
|
|
34798
35264
|
if (files.length >= maxWatchedFiles) return { truncated: true };
|
|
34799
|
-
const absolutePath =
|
|
35265
|
+
const absolutePath = path17.join(directory, entry.name);
|
|
34800
35266
|
if (entry.isDirectory()) {
|
|
34801
35267
|
if (shouldSkipDirectory(entry.name)) continue;
|
|
34802
35268
|
const result = walkFiles2(
|
|
@@ -34812,7 +35278,7 @@ function walkFiles2(sourceRoot, directory, files, maxWatchedFiles) {
|
|
|
34812
35278
|
const stats = statSafe(absolutePath);
|
|
34813
35279
|
if (!stats) continue;
|
|
34814
35280
|
files.push({
|
|
34815
|
-
path: normalizePath(
|
|
35281
|
+
path: normalizePath(path17.relative(sourceRoot, absolutePath)),
|
|
34816
35282
|
modifiedAtMs: stats.mtimeMs
|
|
34817
35283
|
});
|
|
34818
35284
|
}
|
|
@@ -34831,13 +35297,13 @@ function shouldSkipDirectory(name) {
|
|
|
34831
35297
|
);
|
|
34832
35298
|
}
|
|
34833
35299
|
function shouldWatchFile(filePath) {
|
|
34834
|
-
const base =
|
|
35300
|
+
const base = path17.basename(filePath);
|
|
34835
35301
|
if (base.endsWith(".tsbuildinfo")) return false;
|
|
34836
35302
|
if (base === ".DS_Store") return false;
|
|
34837
35303
|
return true;
|
|
34838
35304
|
}
|
|
34839
35305
|
function normalizePath(value) {
|
|
34840
|
-
return value.split(
|
|
35306
|
+
return value.split(path17.sep).join("/");
|
|
34841
35307
|
}
|
|
34842
35308
|
function statSafe(filePath) {
|
|
34843
35309
|
try {
|
|
@@ -34855,7 +35321,7 @@ function readdirSafe(directory) {
|
|
|
34855
35321
|
}
|
|
34856
35322
|
function readJson(filePath) {
|
|
34857
35323
|
try {
|
|
34858
|
-
return JSON.parse(
|
|
35324
|
+
return JSON.parse(readFileSync5(filePath, "utf8"));
|
|
34859
35325
|
} catch {
|
|
34860
35326
|
return void 0;
|
|
34861
35327
|
}
|
|
@@ -34920,7 +35386,8 @@ var init_serverInstructions = __esm({
|
|
|
34920
35386
|
briefMcpInstructions = [
|
|
34921
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'.",
|
|
34922
35388
|
"At the first Brief-relevant task in a session, call brief.install_status once and confirm the repo target and connector freshness.",
|
|
34923
|
-
"
|
|
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.",
|
|
34924
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.",
|
|
34925
35392
|
"Refresh Brief context when the task, files, risk, or validation plan changes.",
|
|
34926
35393
|
"Before a meaningful handoff, call brief.review_diff. Save and verify a handoff only for multi-step, high-risk, or durable work.",
|
|
@@ -34968,6 +35435,8 @@ function compactInstallStatus(input) {
|
|
|
34968
35435
|
const degraded = !blocked && (Boolean(cloudIssue) || input.readiness.verdict !== "agent_ready" || input.workflowWiring.status === "missing" || input.workflowWiring.status === "manual_workflow_only");
|
|
34969
35436
|
const stats = input.scan.stats;
|
|
34970
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";
|
|
34971
35440
|
const totalMapCandidates = stats.mapTotalCandidateCount ?? stats.mapNodeCount + (stats.mapOmittedCount ?? 0);
|
|
34972
35441
|
const mapCoveragePercent = totalMapCandidates ? Math.round(stats.mapNodeCount / totalMapCandidates * 100) : 100;
|
|
34973
35442
|
const repoGuidanceSignals = unique4(
|
|
@@ -34996,9 +35465,16 @@ function compactInstallStatus(input) {
|
|
|
34996
35465
|
status: input.connectorReadiness.status,
|
|
34997
35466
|
safeToUse: input.connectorReadiness.safeToUseBrief,
|
|
34998
35467
|
fresh: input.serverFreshness.status === "current",
|
|
35468
|
+
distribution: input.serverFreshness.sourceKind,
|
|
34999
35469
|
sourceRoot: input.serverFreshness.sourceRoot,
|
|
35000
35470
|
summary: input.connectorReadiness.summary
|
|
35001
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
|
+
},
|
|
35002
35478
|
cloud: {
|
|
35003
35479
|
configured: input.cloudSync.configured,
|
|
35004
35480
|
privacyMode: input.cloudSync.privacyMode,
|
|
@@ -35055,7 +35531,7 @@ var init_installStatus = __esm({
|
|
|
35055
35531
|
"../mcp/src/installStatus.ts"() {
|
|
35056
35532
|
"use strict";
|
|
35057
35533
|
init_serverInstructions();
|
|
35058
|
-
briefConnectorVersion = "0.1.
|
|
35534
|
+
briefConnectorVersion = "0.1.3";
|
|
35059
35535
|
}
|
|
35060
35536
|
});
|
|
35061
35537
|
|
|
@@ -35075,8 +35551,7 @@ function buildCompactStartEnvelope(input) {
|
|
|
35075
35551
|
route: {
|
|
35076
35552
|
tool: start.intent.tool,
|
|
35077
35553
|
...start.intent.recipe ? { recipe: start.intent.recipe } : {},
|
|
35078
|
-
...start.intent.autonomy ? { autonomy: start.intent.autonomy } : {}
|
|
35079
|
-
...start.intent.reviewBar ? { reviewBar: start.intent.reviewBar } : {}
|
|
35554
|
+
...start.intent.autonomy ? { autonomy: start.intent.autonomy } : {}
|
|
35080
35555
|
},
|
|
35081
35556
|
workPacket: (() => {
|
|
35082
35557
|
const packet = buildAgentWorkPacket({
|
|
@@ -35086,7 +35561,6 @@ function buildCompactStartEnvelope(input) {
|
|
|
35086
35561
|
nextAction: input.next
|
|
35087
35562
|
});
|
|
35088
35563
|
return {
|
|
35089
|
-
schemaVersion: packet.schemaVersion,
|
|
35090
35564
|
compactText: packet.compactText
|
|
35091
35565
|
};
|
|
35092
35566
|
})(),
|
|
@@ -35241,15 +35715,15 @@ var init_startSummary = __esm({
|
|
|
35241
35715
|
});
|
|
35242
35716
|
|
|
35243
35717
|
// ../mcp/src/wikiInit.ts
|
|
35244
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
35245
|
-
import
|
|
35718
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
35719
|
+
import path18 from "node:path";
|
|
35246
35720
|
function writeWikiInitArtifacts(repoRoot, wiki, options2) {
|
|
35247
|
-
const wikiDir =
|
|
35248
|
-
const pagesDir =
|
|
35249
|
-
|
|
35721
|
+
const wikiDir = path18.join(repoRoot, ".brief", "wiki");
|
|
35722
|
+
const pagesDir = path18.join(wikiDir, "pages");
|
|
35723
|
+
mkdirSync3(pagesDir, { recursive: true });
|
|
35250
35724
|
const pageArtifacts = wiki.pages.map((page2) => {
|
|
35251
|
-
const pagePath =
|
|
35252
|
-
|
|
35725
|
+
const pagePath = path18.join(pagesDir, `${wikiPageSlug(page2)}.md`);
|
|
35726
|
+
writeFileSync6(pagePath, renderWikiPageMarkdown(wiki, page2));
|
|
35253
35727
|
return {
|
|
35254
35728
|
id: page2.id,
|
|
35255
35729
|
title: page2.title,
|
|
@@ -35258,32 +35732,32 @@ function writeWikiInitArtifacts(repoRoot, wiki, options2) {
|
|
|
35258
35732
|
quality: page2.quality.status
|
|
35259
35733
|
};
|
|
35260
35734
|
});
|
|
35261
|
-
const readmePath =
|
|
35262
|
-
|
|
35263
|
-
const manifestPath =
|
|
35264
|
-
|
|
35735
|
+
const readmePath = path18.join(wikiDir, "README.md");
|
|
35736
|
+
writeFileSync6(readmePath, renderWikiReadme(wiki, pageArtifacts));
|
|
35737
|
+
const manifestPath = path18.join(wikiDir, "manifest.json");
|
|
35738
|
+
writeFileSync6(
|
|
35265
35739
|
manifestPath,
|
|
35266
35740
|
`${JSON.stringify(wikiInitManifest(wiki, pageArtifacts), null, 2)}
|
|
35267
35741
|
`
|
|
35268
35742
|
);
|
|
35269
|
-
const workflowTemplatePath =
|
|
35743
|
+
const workflowTemplatePath = path18.join(
|
|
35270
35744
|
wikiDir,
|
|
35271
35745
|
"brief-wiki-refresh.github-actions.yml"
|
|
35272
35746
|
);
|
|
35273
|
-
|
|
35747
|
+
writeFileSync6(workflowTemplatePath, renderWikiRefreshWorkflow());
|
|
35274
35748
|
const agentFiles = options2.writeAgentFiles ? ["AGENTS.md", "CLAUDE.md"].map(
|
|
35275
35749
|
(fileName) => upsertWikiAgentInstructions(repoRoot, fileName)
|
|
35276
35750
|
) : [];
|
|
35277
35751
|
let githubWorkflow2;
|
|
35278
35752
|
if (options2.writeGithubWorkflow) {
|
|
35279
|
-
const workflowPath =
|
|
35753
|
+
const workflowPath = path18.join(
|
|
35280
35754
|
repoRoot,
|
|
35281
35755
|
".github",
|
|
35282
35756
|
"workflows",
|
|
35283
35757
|
"brief-wiki-refresh.yml"
|
|
35284
35758
|
);
|
|
35285
|
-
|
|
35286
|
-
|
|
35759
|
+
mkdirSync3(path18.dirname(workflowPath), { recursive: true });
|
|
35760
|
+
writeFileSync6(workflowPath, renderWikiRefreshWorkflow({ active: true }));
|
|
35287
35761
|
githubWorkflow2 = {
|
|
35288
35762
|
path: repoRelativePath(repoRoot, workflowPath),
|
|
35289
35763
|
status: "written",
|
|
@@ -35473,12 +35947,12 @@ function wikiInitManifest(wiki, pageArtifacts) {
|
|
|
35473
35947
|
};
|
|
35474
35948
|
}
|
|
35475
35949
|
function upsertWikiAgentInstructions(repoRoot, fileName) {
|
|
35476
|
-
const filePath =
|
|
35950
|
+
const filePath = path18.join(repoRoot, fileName);
|
|
35477
35951
|
const status = existsSync7(filePath) ? "updated" : "created";
|
|
35478
|
-
const existing = status === "updated" ?
|
|
35952
|
+
const existing = status === "updated" ? readFileSync6(filePath, "utf8") : "";
|
|
35479
35953
|
const initial = existing || `# ${fileName}
|
|
35480
35954
|
`;
|
|
35481
|
-
|
|
35955
|
+
writeFileSync6(filePath, upsertMarkedBlock(initial, wikiAgentBlock()));
|
|
35482
35956
|
return {
|
|
35483
35957
|
path: repoRelativePath(repoRoot, filePath),
|
|
35484
35958
|
status,
|
|
@@ -35550,7 +36024,7 @@ function renderWikiRefreshWorkflow(options2 = {}) {
|
|
|
35550
36024
|
" with:",
|
|
35551
36025
|
" node-version: 22",
|
|
35552
36026
|
" - name: Refresh wiki",
|
|
35553
|
-
' run: npx -y runbrief@0.1.
|
|
36027
|
+
' run: npx -y runbrief@0.1.3 wiki init --repo "$GITHUB_WORKSPACE" --update --no-agent-files',
|
|
35554
36028
|
" - name: Open refresh PR",
|
|
35555
36029
|
" uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11",
|
|
35556
36030
|
" with:",
|
|
@@ -35571,7 +36045,7 @@ function markdownList(items) {
|
|
|
35571
36045
|
return items.map((item) => `- ${item}`).join("\n");
|
|
35572
36046
|
}
|
|
35573
36047
|
function repoRelativePath(repoRoot, filePath) {
|
|
35574
|
-
return
|
|
36048
|
+
return path18.relative(repoRoot, filePath).split(path18.sep).join("/");
|
|
35575
36049
|
}
|
|
35576
36050
|
function wikiReadmeRelativePath(repoRelativeFilePath) {
|
|
35577
36051
|
return repoRelativeFilePath.replace(/^\.brief\/wiki\//, "");
|
|
@@ -35875,8 +36349,8 @@ var init_workflowWiringResponse = __esm({
|
|
|
35875
36349
|
|
|
35876
36350
|
// ../mcp/src/server.ts
|
|
35877
36351
|
var server_exports = {};
|
|
35878
|
-
import { chmodSync, mkdirSync as
|
|
35879
|
-
import
|
|
36352
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
36353
|
+
import path19 from "node:path";
|
|
35880
36354
|
import { fileURLToPath } from "node:url";
|
|
35881
36355
|
import {
|
|
35882
36356
|
McpServer
|
|
@@ -36137,7 +36611,8 @@ function serverFreshness() {
|
|
|
36137
36611
|
return mcpServerFreshness({
|
|
36138
36612
|
serverStartedAt,
|
|
36139
36613
|
entrypoint: serverModulePath,
|
|
36140
|
-
mode: "server"
|
|
36614
|
+
mode: "server",
|
|
36615
|
+
distribution: connectorDistributionFor(serverModulePath)
|
|
36141
36616
|
});
|
|
36142
36617
|
}
|
|
36143
36618
|
function summarizePacket(packet) {
|
|
@@ -36155,7 +36630,8 @@ function summarizePacket(packet) {
|
|
|
36155
36630
|
sources: packet.sources,
|
|
36156
36631
|
omitted: packet.omitted,
|
|
36157
36632
|
...packet.valueSignals ? { valueSignals: packet.valueSignals } : {},
|
|
36158
|
-
...packet.teamGuidance ? { teamGuidance: packet.teamGuidance } : {}
|
|
36633
|
+
...packet.teamGuidance ? { teamGuidance: packet.teamGuidance } : {},
|
|
36634
|
+
...packet.dependencyRemediation ? { dependencyRemediation: packet.dependencyRemediation } : {}
|
|
36159
36635
|
};
|
|
36160
36636
|
}
|
|
36161
36637
|
function summarizeReview(review, detail = "auto") {
|
|
@@ -36593,6 +37069,7 @@ function summarizeBeforeYouCodeForStart(beforeYouCode) {
|
|
|
36593
37069
|
decision: beforeYouCode.reuseFirst.decision,
|
|
36594
37070
|
candidates: beforeYouCode.reuseFirst.candidates.slice(0, 2)
|
|
36595
37071
|
},
|
|
37072
|
+
mapCoverage: beforeYouCode.mapCoverage,
|
|
36596
37073
|
sharedContext: summarizeBeforeYouCodeSharedContext(
|
|
36597
37074
|
beforeYouCode.teamGuidance
|
|
36598
37075
|
),
|
|
@@ -36656,7 +37133,7 @@ function summarizeWorkflowWiringForStart(wiring) {
|
|
|
36656
37133
|
defaultAsk: wiring.defaultAsk,
|
|
36657
37134
|
gaps: wiring.gaps.slice(0, 3),
|
|
36658
37135
|
chatFeedback: wiring.chatFeedback.slice(0, 2),
|
|
36659
|
-
finalRecapPolicy: wiring.finalRecapPolicy,
|
|
37136
|
+
finalRecapPolicy: compactFinalRecapPolicy(wiring.finalRecapPolicy),
|
|
36660
37137
|
nextActions: wiring.nextActions.slice(0, 3)
|
|
36661
37138
|
};
|
|
36662
37139
|
}
|
|
@@ -36665,7 +37142,7 @@ function summarizeAutoEngageForStart(autoEngage) {
|
|
|
36665
37142
|
status: autoEngage.status,
|
|
36666
37143
|
summary: autoEngage.summary,
|
|
36667
37144
|
chatFeedback: autoEngage.chatFeedback.slice(0, 1),
|
|
36668
|
-
finalRecapPolicy: autoEngage.finalRecapPolicy,
|
|
37145
|
+
finalRecapPolicy: compactFinalRecapPolicy(autoEngage.finalRecapPolicy),
|
|
36669
37146
|
triggers: autoEngage.triggerMatrix.slice(0, 3).map((trigger) => ({
|
|
36670
37147
|
id: trigger.id,
|
|
36671
37148
|
label: trigger.label,
|
|
@@ -36674,6 +37151,13 @@ function summarizeAutoEngageForStart(autoEngage) {
|
|
|
36674
37151
|
nextActions: autoEngage.nextActions.slice(0, 2)
|
|
36675
37152
|
};
|
|
36676
37153
|
}
|
|
37154
|
+
function compactFinalRecapPolicy(policy) {
|
|
37155
|
+
return {
|
|
37156
|
+
maxLines: policy.maxLines,
|
|
37157
|
+
template: policy.defaultTemplate,
|
|
37158
|
+
fallbackWhenNotHelpful: policy.fallbackWhenNotHelpful
|
|
37159
|
+
};
|
|
37160
|
+
}
|
|
36677
37161
|
function summarizeWiki(wiki) {
|
|
36678
37162
|
return {
|
|
36679
37163
|
wikiId: wiki.wikiId,
|
|
@@ -36726,21 +37210,22 @@ function summarizeLocalReceipt(receipt) {
|
|
|
36726
37210
|
function writeHookFiles(repoRoot, files) {
|
|
36727
37211
|
const written = [];
|
|
36728
37212
|
for (const file of files) {
|
|
36729
|
-
const targetPath =
|
|
36730
|
-
|
|
36731
|
-
|
|
36732
|
-
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);
|
|
36733
37217
|
written.push(file.path);
|
|
36734
37218
|
}
|
|
36735
37219
|
return written;
|
|
36736
37220
|
}
|
|
36737
|
-
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;
|
|
36738
37222
|
var init_server = __esm({
|
|
36739
|
-
"../mcp/src/server.ts"() {
|
|
37223
|
+
async "../mcp/src/server.ts"() {
|
|
36740
37224
|
"use strict";
|
|
36741
37225
|
init_dist();
|
|
36742
37226
|
init_dist2();
|
|
36743
37227
|
init_cloud();
|
|
37228
|
+
init_cloudCredentials();
|
|
36744
37229
|
init_teamContext();
|
|
36745
37230
|
init_missionInputOptions();
|
|
36746
37231
|
init_connectorReadiness();
|
|
@@ -36756,10 +37241,15 @@ var init_server = __esm({
|
|
|
36756
37241
|
init_workspace();
|
|
36757
37242
|
init_handoffAutofill();
|
|
36758
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
|
+
}
|
|
36759
37249
|
server = new McpServer(
|
|
36760
37250
|
{
|
|
36761
37251
|
name: "brief",
|
|
36762
|
-
version: "0.1.
|
|
37252
|
+
version: "0.1.3"
|
|
36763
37253
|
},
|
|
36764
37254
|
{
|
|
36765
37255
|
instructions: briefMcpInstructions
|
|
@@ -37214,9 +37704,12 @@ var init_server = __esm({
|
|
|
37214
37704
|
{
|
|
37215
37705
|
repoPath: z2.string().optional().describe(
|
|
37216
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."
|
|
37217
37710
|
)
|
|
37218
37711
|
},
|
|
37219
|
-
async ({ repoPath }) => {
|
|
37712
|
+
async ({ repoPath, detail }) => {
|
|
37220
37713
|
const repoTargetInfo = resolveRepoTarget(repoPath);
|
|
37221
37714
|
if (repoTargetInfo.repoTarget.status === "needs_repo_target") {
|
|
37222
37715
|
return repoTargetBlock(repoTargetInfo);
|
|
@@ -37226,14 +37719,19 @@ var init_server = __esm({
|
|
|
37226
37719
|
const skillLearning = buildRepoSkillLearningReport(repoRoot, {
|
|
37227
37720
|
maxFiles: 6e3
|
|
37228
37721
|
});
|
|
37722
|
+
const autoEngage = buildAgentAutoEngagementPlan(scan, skillLearning);
|
|
37723
|
+
const workflowWiring = evaluateAgentWorkflowWiring(scan);
|
|
37724
|
+
const responseDetail = detail ?? "compact";
|
|
37229
37725
|
return jsonText({
|
|
37230
37726
|
repoRoot,
|
|
37231
37727
|
rootResolution,
|
|
37232
37728
|
repoTarget,
|
|
37233
|
-
|
|
37234
|
-
|
|
37729
|
+
detail: responseDetail,
|
|
37730
|
+
autoEngage: responseDetail === "expanded" ? autoEngage : summarizeAutoEngageForStart(autoEngage),
|
|
37731
|
+
workflowWiring: responseDetail === "expanded" ? workflowWiring : summarizeWorkflowWiringForStart(workflowWiring),
|
|
37235
37732
|
skillLearning: summarizeSkillLearningForStart(skillLearning, void 0),
|
|
37236
|
-
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.'
|
|
37237
37735
|
});
|
|
37238
37736
|
}
|
|
37239
37737
|
);
|
|
@@ -37352,7 +37850,7 @@ var init_server = __esm({
|
|
|
37352
37850
|
skills: scan.stats.skillCount
|
|
37353
37851
|
}
|
|
37354
37852
|
},
|
|
37355
|
-
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."
|
|
37356
37854
|
});
|
|
37357
37855
|
}
|
|
37358
37856
|
);
|
|
@@ -38127,7 +38625,7 @@ var init_server = __esm({
|
|
|
38127
38625
|
const sourceRepos = sourceRepoPaths && sourceRepoPaths.length > 0 ? sourceRepoPaths : [repoRoot];
|
|
38128
38626
|
const inventories = sourceRepos.map(
|
|
38129
38627
|
(sourceRepo) => buildAgentPackInventory(
|
|
38130
|
-
|
|
38628
|
+
path19.isAbsolute(sourceRepo) ? sourceRepo : path19.resolve(repoRoot, sourceRepo),
|
|
38131
38629
|
maxFiles === void 0 ? {} : { maxFiles }
|
|
38132
38630
|
)
|
|
38133
38631
|
);
|
|
@@ -39502,6 +40000,7 @@ init_dist2();
|
|
|
39502
40000
|
init_teamContext();
|
|
39503
40001
|
init_missionInputOptions();
|
|
39504
40002
|
init_cloud();
|
|
40003
|
+
init_cloudCredentials();
|
|
39505
40004
|
init_workspace();
|
|
39506
40005
|
init_connectorReadiness();
|
|
39507
40006
|
init_connectorRecovery();
|
|
@@ -39513,15 +40012,139 @@ init_wikiInit();
|
|
|
39513
40012
|
init_handoffAutofill();
|
|
39514
40013
|
init_mapResponse();
|
|
39515
40014
|
init_scanFreshness();
|
|
39516
|
-
import { chmodSync as
|
|
39517
|
-
import
|
|
40015
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync8 } from "node:fs";
|
|
40016
|
+
import path20 from "node:path";
|
|
39518
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
|
|
39519
40134
|
var args = process.argv.slice(2);
|
|
39520
40135
|
var command = args[0];
|
|
39521
40136
|
var cliStartedAt = /* @__PURE__ */ new Date();
|
|
39522
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
|
+
}
|
|
39523
40146
|
if (!command || command === "--stdio" || command === "stdio" || command === "mcp") {
|
|
39524
|
-
await
|
|
40147
|
+
await init_server().then(() => server_exports);
|
|
39525
40148
|
} else {
|
|
39526
40149
|
await runCli(command, args.slice(1));
|
|
39527
40150
|
}
|
|
@@ -39530,11 +40153,41 @@ async function runCli(commandName, commandArgs) {
|
|
|
39530
40153
|
printJson(buildCliHelp(commandName));
|
|
39531
40154
|
return;
|
|
39532
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
|
+
}
|
|
39533
40165
|
const rootResolution = resolveRepoRootDetails(
|
|
39534
40166
|
option2(commandArgs, "repo") ?? option2(commandArgs, "repoPath") ?? option2(commandArgs, "repo-path")
|
|
39535
40167
|
);
|
|
39536
40168
|
const repoRoot = rootResolution.repoRoot;
|
|
39537
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
|
+
}
|
|
39538
40191
|
if (isCommand(commandName, "install-status", "install_status")) {
|
|
39539
40192
|
const freshness = cliServerFreshness();
|
|
39540
40193
|
const connector = connectorReadiness({
|
|
@@ -40200,7 +40853,7 @@ async function runCli(commandName, commandArgs) {
|
|
|
40200
40853
|
const sourceRepos = filesOption2(commandArgs, "source-repos") ?? filesOption2(commandArgs, "sourceRepos") ?? filesOption2(commandArgs, "sources") ?? [repoRoot];
|
|
40201
40854
|
const inventories = sourceRepos.map(
|
|
40202
40855
|
(sourceRepo) => buildAgentPackInventory(
|
|
40203
|
-
|
|
40856
|
+
path20.isAbsolute(sourceRepo) ? sourceRepo : path20.resolve(repoRoot, sourceRepo),
|
|
40204
40857
|
maxFiles === void 0 ? {} : { maxFiles }
|
|
40205
40858
|
)
|
|
40206
40859
|
);
|
|
@@ -41072,7 +41725,7 @@ async function runCli(commandName, commandArgs) {
|
|
|
41072
41725
|
skills: scan.stats.skillCount
|
|
41073
41726
|
}
|
|
41074
41727
|
},
|
|
41075
|
-
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."
|
|
41076
41729
|
});
|
|
41077
41730
|
return;
|
|
41078
41731
|
}
|
|
@@ -41269,6 +41922,11 @@ async function runCli(commandName, commandArgs) {
|
|
|
41269
41922
|
function isCommand(commandName, ...aliases) {
|
|
41270
41923
|
return aliases.includes(commandName);
|
|
41271
41924
|
}
|
|
41925
|
+
function isCloudLogoutCommand(commandName) {
|
|
41926
|
+
return Boolean(
|
|
41927
|
+
commandName && ["cloud-logout", "cloud_logout", "disconnect-cloud"].includes(commandName)
|
|
41928
|
+
);
|
|
41929
|
+
}
|
|
41272
41930
|
function wikiInitMode(argsList) {
|
|
41273
41931
|
if (hasFlag(argsList, "init")) return "init";
|
|
41274
41932
|
if (hasFlag(argsList, "update")) return "update";
|
|
@@ -41352,6 +42010,33 @@ function cliCommandHelp() {
|
|
|
41352
42010
|
"After changing Brief source to confirm the running connector is fresh."
|
|
41353
42011
|
]
|
|
41354
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
|
+
},
|
|
41355
42040
|
{
|
|
41356
42041
|
command: "next",
|
|
41357
42042
|
aliases: ["brief-next", "brief_next"],
|
|
@@ -41697,7 +42382,11 @@ function positionalText(argsList) {
|
|
|
41697
42382
|
"owner",
|
|
41698
42383
|
"receipts",
|
|
41699
42384
|
"added-by",
|
|
41700
|
-
"addedBy"
|
|
42385
|
+
"addedBy",
|
|
42386
|
+
"agent-command",
|
|
42387
|
+
"runner-id",
|
|
42388
|
+
"interval-ms",
|
|
42389
|
+
"timeout-ms"
|
|
41701
42390
|
]);
|
|
41702
42391
|
const parts = [];
|
|
41703
42392
|
for (let index = 0; index < argsList.length; index += 1) {
|
|
@@ -41953,7 +42642,7 @@ function artifactEvidenceFromOptions(argsList) {
|
|
|
41953
42642
|
);
|
|
41954
42643
|
const evidence = [];
|
|
41955
42644
|
for (const raw of rawEvidenceValues) {
|
|
41956
|
-
const json = raw.startsWith("@") ?
|
|
42645
|
+
const json = raw.startsWith("@") ? readFileSync7(path20.resolve(raw.slice(1)), "utf8") : raw;
|
|
41957
42646
|
try {
|
|
41958
42647
|
const parsed = JSON.parse(json);
|
|
41959
42648
|
const items = Array.isArray(parsed) ? parsed : [parsed];
|
|
@@ -42031,7 +42720,7 @@ function missionSummaryFromLocalReceipt2(repoRoot, missionReceiptId) {
|
|
|
42031
42720
|
function runtimeEvidencePacketFromOptions(argsList) {
|
|
42032
42721
|
const raw = option2(argsList, "runtime-packet") ?? option2(argsList, "runtime-evidence-packet") ?? option2(argsList, "runtimeEvidencePacket");
|
|
42033
42722
|
if (!raw) return void 0;
|
|
42034
|
-
const json = raw.startsWith("@") ?
|
|
42723
|
+
const json = raw.startsWith("@") ? readFileSync7(path20.resolve(raw.slice(1)), "utf8") : raw;
|
|
42035
42724
|
try {
|
|
42036
42725
|
return cleanRuntimeEvidencePacket2(
|
|
42037
42726
|
runtimeEvidencePacketSchema.parse(JSON.parse(json))
|
|
@@ -42200,6 +42889,15 @@ function printContextSummary(packet, localReceipt, teamContext) {
|
|
|
42200
42889
|
teamContextLine(teamContext),
|
|
42201
42890
|
teamGuidanceLine(packet),
|
|
42202
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
|
+
] : [],
|
|
42203
42901
|
"",
|
|
42204
42902
|
"Rules:",
|
|
42205
42903
|
...packet.rules.length > 0 ? packet.rules.slice(0, 8).map((rule) => `- [${rule.enforcement}] ${rule.title}`) : ["- none"],
|
|
@@ -42252,10 +42950,10 @@ function valueSignalLine(packet) {
|
|
|
42252
42950
|
function writeHookFiles2(repoRoot, files) {
|
|
42253
42951
|
const written = [];
|
|
42254
42952
|
for (const file of files) {
|
|
42255
|
-
const targetPath =
|
|
42256
|
-
|
|
42257
|
-
|
|
42258
|
-
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);
|
|
42259
42957
|
written.push(file.path);
|
|
42260
42958
|
}
|
|
42261
42959
|
return written;
|
|
@@ -42383,7 +43081,8 @@ function cliServerFreshness() {
|
|
|
42383
43081
|
return mcpServerFreshness({
|
|
42384
43082
|
serverStartedAt: cliStartedAt,
|
|
42385
43083
|
entrypoint: cliModulePath,
|
|
42386
|
-
mode: "cli"
|
|
43084
|
+
mode: "cli",
|
|
43085
|
+
distribution: connectorDistributionFor(cliModulePath)
|
|
42387
43086
|
});
|
|
42388
43087
|
}
|
|
42389
43088
|
function printJson(value) {
|
|
@@ -42407,7 +43106,7 @@ function nextScanStep(cloudSync) {
|
|
|
42407
43106
|
if (cloudSync.status === "failed") {
|
|
42408
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.`;
|
|
42409
43108
|
}
|
|
42410
|
-
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.";
|
|
42411
43110
|
}
|
|
42412
43111
|
function fail(message) {
|
|
42413
43112
|
process.stderr.write(`${message}
|