@cejel/cejel 0.1.1 → 0.1.2
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 +127 -78
- package/dist/{chunk-H5T65GGS.js → chunk-MBYVOPJR.js} +2680 -1168
- package/dist/index.js +124 -30
- package/dist/mcp/index.js +222 -218
- package/package.json +10 -9
|
@@ -29,7 +29,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
29
|
mod
|
|
30
30
|
));
|
|
31
31
|
|
|
32
|
-
// src/
|
|
32
|
+
// ../witan/src/external-findings.ts
|
|
33
33
|
var EXTERNAL_FINDINGS_DISPLAY_LIMIT = 10;
|
|
34
34
|
var SEVERITY_RANK = {
|
|
35
35
|
critical: 0,
|
|
@@ -82,7 +82,7 @@ function collectExternalFindings(consumedSignals) {
|
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
// src/
|
|
85
|
+
// ../witan/src/html.ts
|
|
86
86
|
function renderWitanHtmlReport(report) {
|
|
87
87
|
const codeCriteria = criteriaByCategory(report, "code_trust");
|
|
88
88
|
const processCriteria = criteriaByCategory(report, "process_trust");
|
|
@@ -403,7 +403,7 @@ a:hover { text-decoration: underline; text-underline-offset: 2px; }
|
|
|
403
403
|
}
|
|
404
404
|
`;
|
|
405
405
|
|
|
406
|
-
// src/
|
|
406
|
+
// ../witan/src/badge.ts
|
|
407
407
|
var VERDICT_COLOR = {
|
|
408
408
|
Verified: "brightgreen",
|
|
409
409
|
Conditional: "yellow",
|
|
@@ -470,7 +470,15 @@ function escapeXml(value) {
|
|
|
470
470
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
-
//
|
|
473
|
+
// ../witan/src/claim-reality.ts
|
|
474
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
475
|
+
import { join } from "path";
|
|
476
|
+
|
|
477
|
+
// ../witan/src/leaderboard.ts
|
|
478
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "fs";
|
|
479
|
+
import { join as join6 } from "path";
|
|
480
|
+
|
|
481
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
474
482
|
var external_exports = {};
|
|
475
483
|
__export(external_exports, {
|
|
476
484
|
BRAND: () => BRAND,
|
|
@@ -582,7 +590,7 @@ __export(external_exports, {
|
|
|
582
590
|
void: () => voidType
|
|
583
591
|
});
|
|
584
592
|
|
|
585
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
593
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
586
594
|
var util;
|
|
587
595
|
(function(util2) {
|
|
588
596
|
util2.assertEqual = (_) => {
|
|
@@ -716,7 +724,7 @@ var getParsedType = (data) => {
|
|
|
716
724
|
}
|
|
717
725
|
};
|
|
718
726
|
|
|
719
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js
|
|
727
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js
|
|
720
728
|
var ZodIssueCode = util.arrayToEnum([
|
|
721
729
|
"invalid_type",
|
|
722
730
|
"invalid_literal",
|
|
@@ -834,7 +842,7 @@ ZodError.create = (issues) => {
|
|
|
834
842
|
return error;
|
|
835
843
|
};
|
|
836
844
|
|
|
837
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
845
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
838
846
|
var errorMap = (issue, _ctx) => {
|
|
839
847
|
let message;
|
|
840
848
|
switch (issue.code) {
|
|
@@ -937,7 +945,7 @@ var errorMap = (issue, _ctx) => {
|
|
|
937
945
|
};
|
|
938
946
|
var en_default = errorMap;
|
|
939
947
|
|
|
940
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js
|
|
948
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js
|
|
941
949
|
var overrideErrorMap = en_default;
|
|
942
950
|
function setErrorMap(map) {
|
|
943
951
|
overrideErrorMap = map;
|
|
@@ -946,7 +954,7 @@ function getErrorMap() {
|
|
|
946
954
|
return overrideErrorMap;
|
|
947
955
|
}
|
|
948
956
|
|
|
949
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
957
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
950
958
|
var makeIssue = (params) => {
|
|
951
959
|
const { data, path, errorMaps, issueData } = params;
|
|
952
960
|
const fullPath = [...path, ...issueData.path || []];
|
|
@@ -1056,14 +1064,14 @@ var isDirty = (x) => x.status === "dirty";
|
|
|
1056
1064
|
var isValid = (x) => x.status === "valid";
|
|
1057
1065
|
var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
|
|
1058
1066
|
|
|
1059
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
1067
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
1060
1068
|
var errorUtil;
|
|
1061
1069
|
(function(errorUtil2) {
|
|
1062
1070
|
errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
|
|
1063
1071
|
errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
|
|
1064
1072
|
})(errorUtil || (errorUtil = {}));
|
|
1065
1073
|
|
|
1066
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
1074
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
1067
1075
|
var ParseInputLazyPath = class {
|
|
1068
1076
|
constructor(parent, value, path, key) {
|
|
1069
1077
|
this._cachedPath = [];
|
|
@@ -4511,10 +4519,853 @@ var coerce = {
|
|
|
4511
4519
|
};
|
|
4512
4520
|
var NEVER = INVALID;
|
|
4513
4521
|
|
|
4514
|
-
// src/
|
|
4522
|
+
// ../shared/src/types/attestation.ts
|
|
4523
|
+
var attestationOutcomeSchema = external_exports.enum([
|
|
4524
|
+
"ATTESTED_READY",
|
|
4525
|
+
"ATTESTED_WITH_GAPS",
|
|
4526
|
+
"NOT_READY",
|
|
4527
|
+
"REVOKED"
|
|
4528
|
+
]);
|
|
4529
|
+
var attestationKindSchema = external_exports.enum(["OPERATOR_READINESS", "EXTERNAL_ASSESSOR_REFERENCE"]);
|
|
4530
|
+
var attestationEvidenceRefKindSchema = external_exports.enum([
|
|
4531
|
+
"runbook_path",
|
|
4532
|
+
"github_run_url",
|
|
4533
|
+
"vercel_deployment_id",
|
|
4534
|
+
"neon_query_evidence",
|
|
4535
|
+
"report_hash",
|
|
4536
|
+
"external_assessor_ref"
|
|
4537
|
+
]);
|
|
4538
|
+
var attestationEvidenceRefSchema = external_exports.object({
|
|
4539
|
+
kind: attestationEvidenceRefKindSchema,
|
|
4540
|
+
/** Redacted reference string (path, URL, ID, or hash). Max 512 chars. */
|
|
4541
|
+
ref: external_exports.string().min(1).max(512),
|
|
4542
|
+
/** Optional one-line redacted description. */
|
|
4543
|
+
note: external_exports.string().max(280).optional()
|
|
4544
|
+
});
|
|
4545
|
+
var createAttestationInputSchema = external_exports.object({
|
|
4546
|
+
studioId: external_exports.string().uuid(),
|
|
4547
|
+
complianceProfileId: external_exports.string().uuid(),
|
|
4548
|
+
productId: external_exports.string().uuid().nullable().optional(),
|
|
4549
|
+
framework: external_exports.string().min(1).max(120),
|
|
4550
|
+
kind: attestationKindSchema,
|
|
4551
|
+
outcome: attestationOutcomeSchema,
|
|
4552
|
+
/** Redacted operator statement; no payloads. */
|
|
4553
|
+
statement: external_exports.string().min(1).max(4e3),
|
|
4554
|
+
evidenceRefs: external_exports.array(attestationEvidenceRefSchema).min(1),
|
|
4555
|
+
supersedesAttestationId: external_exports.string().uuid().nullable().optional(),
|
|
4556
|
+
metadata: external_exports.record(external_exports.unknown()).default({})
|
|
4557
|
+
});
|
|
4558
|
+
|
|
4559
|
+
// ../shared/src/types/standup-provisioning.ts
|
|
4560
|
+
var ScaffoldFileSchema = external_exports.object({
|
|
4561
|
+
path: external_exports.string().min(1),
|
|
4562
|
+
contents: external_exports.string()
|
|
4563
|
+
}).strict();
|
|
4564
|
+
var ScaffoldManifestSchema = external_exports.array(ScaffoldFileSchema).min(1);
|
|
4565
|
+
var RepoRefSchema = external_exports.object({
|
|
4566
|
+
studioId: external_exports.string().uuid(),
|
|
4567
|
+
owner: external_exports.string().min(1),
|
|
4568
|
+
// GitHub org/account that owns the repo
|
|
4569
|
+
name: external_exports.string().min(1),
|
|
4570
|
+
fullName: external_exports.string().min(1),
|
|
4571
|
+
// owner/name
|
|
4572
|
+
htmlUrl: external_exports.string().url(),
|
|
4573
|
+
defaultBranch: external_exports.string().min(1).default("main")
|
|
4574
|
+
}).strict();
|
|
4575
|
+
var ScopedTokenSchema = external_exports.object({
|
|
4576
|
+
token: external_exports.string().min(1),
|
|
4577
|
+
expiresAt: external_exports.string(),
|
|
4578
|
+
// ISO-8601
|
|
4579
|
+
scope: external_exports.string().min(1)
|
|
4580
|
+
// human-readable, e.g. "contents:write on owner/name"
|
|
4581
|
+
}).strict();
|
|
4582
|
+
var BranchProtectionStatusSchema = external_exports.object({
|
|
4583
|
+
protected: external_exports.boolean(),
|
|
4584
|
+
requiresPullRequestReview: external_exports.boolean(),
|
|
4585
|
+
requiredApprovingReviewCount: external_exports.number().int().nonnegative(),
|
|
4586
|
+
allowsForcePushes: external_exports.boolean(),
|
|
4587
|
+
allowsDeletions: external_exports.boolean()
|
|
4588
|
+
}).strict();
|
|
4589
|
+
var RenderParamsSchema = external_exports.object({
|
|
4590
|
+
productName: external_exports.string().min(1),
|
|
4591
|
+
slug: external_exports.string().min(1),
|
|
4592
|
+
vertical: external_exports.string().min(1)
|
|
4593
|
+
}).strict();
|
|
4594
|
+
var TemplateInputFieldSchema = external_exports.object({
|
|
4595
|
+
name: external_exports.string().min(1),
|
|
4596
|
+
label: external_exports.string().min(1),
|
|
4597
|
+
inputType: external_exports.enum(["text", "number", "date", "slug"]),
|
|
4598
|
+
required: external_exports.boolean().default(true),
|
|
4599
|
+
helperText: external_exports.string().min(1),
|
|
4600
|
+
example: external_exports.string().min(1),
|
|
4601
|
+
defaultValue: external_exports.string().optional()
|
|
4602
|
+
}).strict();
|
|
4603
|
+
var TemplateInputSchema = external_exports.object({
|
|
4604
|
+
fields: external_exports.array(TemplateInputFieldSchema).min(1)
|
|
4605
|
+
}).strict();
|
|
4606
|
+
var TemplateDescriptorSchema = external_exports.object({
|
|
4607
|
+
templateRef: external_exports.string().min(1),
|
|
4608
|
+
vertical: external_exports.string().min(1),
|
|
4609
|
+
description: external_exports.string().default(""),
|
|
4610
|
+
inputSchema: TemplateInputSchema.optional()
|
|
4611
|
+
}).strict();
|
|
4612
|
+
var StandupDryRunPlanSchema = external_exports.object({
|
|
4613
|
+
planOnly: external_exports.literal(true),
|
|
4614
|
+
planOnlyMessage: external_exports.string().min(1),
|
|
4615
|
+
product: external_exports.object({
|
|
4616
|
+
studioId: external_exports.string().min(1),
|
|
4617
|
+
productId: external_exports.string().min(1),
|
|
4618
|
+
name: external_exports.string().min(1),
|
|
4619
|
+
slug: external_exports.string().min(1),
|
|
4620
|
+
vertical: external_exports.string().min(1)
|
|
4621
|
+
}).strict(),
|
|
4622
|
+
targetRepo: external_exports.object({
|
|
4623
|
+
owner: external_exports.string().min(1),
|
|
4624
|
+
name: external_exports.string().min(1),
|
|
4625
|
+
fullName: external_exports.string().min(1),
|
|
4626
|
+
defaultBranch: external_exports.string().min(1),
|
|
4627
|
+
plannedState: external_exports.literal("would_create"),
|
|
4628
|
+
exists: external_exports.literal(false)
|
|
4629
|
+
}).strict(),
|
|
4630
|
+
template: TemplateDescriptorSchema,
|
|
4631
|
+
scaffold: external_exports.object({
|
|
4632
|
+
label: external_exports.literal("scaffold (template output)"),
|
|
4633
|
+
files: ScaffoldManifestSchema
|
|
4634
|
+
}).strict(),
|
|
4635
|
+
buildAgentSeed: external_exports.object({
|
|
4636
|
+
label: external_exports.literal("build-agent instructions (not yet run)"),
|
|
4637
|
+
instructions: external_exports.array(external_exports.string().min(1)).min(1),
|
|
4638
|
+
product: external_exports.object({
|
|
4639
|
+
name: external_exports.string().min(1),
|
|
4640
|
+
slug: external_exports.string().min(1),
|
|
4641
|
+
vertical: external_exports.string().min(1)
|
|
4642
|
+
}).strict(),
|
|
4643
|
+
repoFullName: external_exports.string().min(1)
|
|
4644
|
+
}).strict(),
|
|
4645
|
+
safetyEnvelope: external_exports.object({
|
|
4646
|
+
estimatedCostUsd: external_exports.number().finite().nonnegative(),
|
|
4647
|
+
costCapUsd: external_exports.number().finite().nonnegative(),
|
|
4648
|
+
networkPolicy: external_exports.object({
|
|
4649
|
+
mode: external_exports.literal("restricted"),
|
|
4650
|
+
allowedHosts: external_exports.array(external_exports.string().min(1)).min(1)
|
|
4651
|
+
}).strict(),
|
|
4652
|
+
scopedToken: external_exports.object({
|
|
4653
|
+
tokenMinted: external_exports.literal(false),
|
|
4654
|
+
scope: external_exports.string().min(1),
|
|
4655
|
+
ttlSeconds: external_exports.number().int().positive()
|
|
4656
|
+
}).strict()
|
|
4657
|
+
}).strict()
|
|
4658
|
+
}).strict();
|
|
4659
|
+
var ConstructionWorkflowArtifactKindSchema = external_exports.enum([
|
|
4660
|
+
"profile",
|
|
4661
|
+
"milestone_schedule",
|
|
4662
|
+
"risk_register",
|
|
4663
|
+
"submittal_register",
|
|
4664
|
+
"long_lead_log",
|
|
4665
|
+
"rfi_log",
|
|
4666
|
+
"responsibility_matrix"
|
|
4667
|
+
]);
|
|
4668
|
+
var IsoDateSchema = external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
4669
|
+
var ConstructionWorkflowTemplateDescriptorSchema = external_exports.object({
|
|
4670
|
+
templateRef: external_exports.string().min(1),
|
|
4671
|
+
workflowKind: external_exports.literal("construction_project"),
|
|
4672
|
+
templateKind: external_exports.literal("workflow_documents"),
|
|
4673
|
+
name: external_exports.string().min(1),
|
|
4674
|
+
description: external_exports.string().default(""),
|
|
4675
|
+
artifacts: external_exports.array(ConstructionWorkflowArtifactKindSchema).min(1),
|
|
4676
|
+
inputSchema: TemplateInputSchema
|
|
4677
|
+
}).strict();
|
|
4678
|
+
var ConstructionProjectSeedSchema = external_exports.object({
|
|
4679
|
+
projectName: external_exports.string().min(1).max(120),
|
|
4680
|
+
areaSqFt: external_exports.number().int().positive(),
|
|
4681
|
+
projectType: external_exports.string().min(1).max(120),
|
|
4682
|
+
buildingName: external_exports.string().min(1).max(160),
|
|
4683
|
+
ntpDate: IsoDateSchema,
|
|
4684
|
+
scheduleTargetDate: IsoDateSchema
|
|
4685
|
+
}).strict();
|
|
4686
|
+
var ConstructionMilestoneSchema = external_exports.object({
|
|
4687
|
+
id: external_exports.string().min(1),
|
|
4688
|
+
name: external_exports.string().min(1),
|
|
4689
|
+
targetDate: IsoDateSchema,
|
|
4690
|
+
status: external_exports.enum(["planned", "at_risk", "slipped", "complete"])
|
|
4691
|
+
}).strict();
|
|
4692
|
+
var ConstructionSubmittalSchema = external_exports.object({
|
|
4693
|
+
id: external_exports.string().min(1),
|
|
4694
|
+
item: external_exports.string().min(1),
|
|
4695
|
+
division: external_exports.string().min(1),
|
|
4696
|
+
needByDate: IsoDateSchema,
|
|
4697
|
+
status: external_exports.enum(["not_started", "open", "in_review", "approved", "done"])
|
|
4698
|
+
}).strict();
|
|
4699
|
+
var ConstructionRfiSchema = external_exports.object({
|
|
4700
|
+
id: external_exports.string().min(1),
|
|
4701
|
+
subject: external_exports.string().min(1),
|
|
4702
|
+
to: external_exports.string().min(1),
|
|
4703
|
+
status: external_exports.enum(["draft", "open", "answered", "closed"]),
|
|
4704
|
+
openedDate: IsoDateSchema
|
|
4705
|
+
}).strict();
|
|
4706
|
+
var ConstructionRiskSchema = external_exports.object({
|
|
4707
|
+
id: external_exports.string().min(1),
|
|
4708
|
+
risk: external_exports.string().min(1),
|
|
4709
|
+
rating: external_exports.enum(["low", "medium", "high"]),
|
|
4710
|
+
mitigation: external_exports.string().min(1),
|
|
4711
|
+
confidence: external_exports.number().min(0).max(1)
|
|
4712
|
+
}).strict();
|
|
4713
|
+
var ConstructionLongLeadItemSchema = external_exports.object({
|
|
4714
|
+
id: external_exports.string().min(1),
|
|
4715
|
+
item: external_exports.string().min(1),
|
|
4716
|
+
needByDate: IsoDateSchema,
|
|
4717
|
+
status: external_exports.enum(["tracking", "ordered", "received", "done"]),
|
|
4718
|
+
assumption: external_exports.string().min(1)
|
|
4719
|
+
}).strict();
|
|
4720
|
+
var ConstructionResponsibilitySchema = external_exports.object({
|
|
4721
|
+
id: external_exports.string().min(1),
|
|
4722
|
+
role: external_exports.string().min(1),
|
|
4723
|
+
owner: external_exports.string().min(1),
|
|
4724
|
+
responsibility: external_exports.string().min(1)
|
|
4725
|
+
}).strict();
|
|
4726
|
+
var ConstructionMarkdownArtifactSchema = external_exports.object({
|
|
4727
|
+
kind: ConstructionWorkflowArtifactKindSchema,
|
|
4728
|
+
path: external_exports.string().min(1),
|
|
4729
|
+
markdown: external_exports.string().min(1)
|
|
4730
|
+
}).strict();
|
|
4731
|
+
var ConstructionWorkflowArtifactSetSchema = external_exports.object({
|
|
4732
|
+
projectName: external_exports.string().min(1),
|
|
4733
|
+
generatedAt: external_exports.string().datetime(),
|
|
4734
|
+
assumptions: external_exports.array(external_exports.string().min(1)).default([]),
|
|
4735
|
+
needsPmData: external_exports.array(external_exports.string().min(1)).default([]),
|
|
4736
|
+
markdownArtifacts: external_exports.array(ConstructionMarkdownArtifactSchema).min(1),
|
|
4737
|
+
structured: external_exports.object({
|
|
4738
|
+
milestones: external_exports.array(ConstructionMilestoneSchema),
|
|
4739
|
+
submittals: external_exports.array(ConstructionSubmittalSchema),
|
|
4740
|
+
rfis: external_exports.array(ConstructionRfiSchema),
|
|
4741
|
+
risks: external_exports.array(ConstructionRiskSchema),
|
|
4742
|
+
longLeadItems: external_exports.array(ConstructionLongLeadItemSchema),
|
|
4743
|
+
responsibilities: external_exports.array(ConstructionResponsibilitySchema)
|
|
4744
|
+
}).strict()
|
|
4745
|
+
}).strict();
|
|
4746
|
+
var ConstructionWorkflowDryRunPlanSchema = external_exports.object({
|
|
4747
|
+
planOnly: external_exports.literal(true),
|
|
4748
|
+
planOnlyMessage: external_exports.string().min(1),
|
|
4749
|
+
product: external_exports.object({
|
|
4750
|
+
studioId: external_exports.string().min(1),
|
|
4751
|
+
productId: external_exports.string().min(1),
|
|
4752
|
+
name: external_exports.string().min(1),
|
|
4753
|
+
vertical: external_exports.string().min(1)
|
|
4754
|
+
}).strict(),
|
|
4755
|
+
template: ConstructionWorkflowTemplateDescriptorSchema,
|
|
4756
|
+
seed: ConstructionProjectSeedSchema,
|
|
4757
|
+
safetyEnvelope: external_exports.object({
|
|
4758
|
+
executor: external_exports.literal("benign_workflow_populator"),
|
|
4759
|
+
sandboxUsed: external_exports.literal(false),
|
|
4760
|
+
scopedTokenMinted: external_exports.literal(false),
|
|
4761
|
+
externalWritesAllowed: external_exports.literal(false),
|
|
4762
|
+
workspaceWriteMode: external_exports.literal("markdown_only")
|
|
4763
|
+
}).strict()
|
|
4764
|
+
}).strict();
|
|
4765
|
+
|
|
4766
|
+
// ../shared/src/types/construction-log-excel.ts
|
|
4767
|
+
var CONSTRUCTION_LOG_EXCEL_SCHEMA_VERSION = "construction-log-excel-v1";
|
|
4768
|
+
var ConstructionLogExcelSheetKeySchema = external_exports.enum([
|
|
4769
|
+
"submittals",
|
|
4770
|
+
"rfis",
|
|
4771
|
+
"riskRegister",
|
|
4772
|
+
"longLead",
|
|
4773
|
+
"responsibilityMatrix",
|
|
4774
|
+
"milestones"
|
|
4775
|
+
]);
|
|
4776
|
+
var ConstructionLogExcelColumnSchema = external_exports.object({
|
|
4777
|
+
key: external_exports.string().min(1),
|
|
4778
|
+
header: external_exports.string().min(1),
|
|
4779
|
+
required: external_exports.boolean(),
|
|
4780
|
+
description: external_exports.string().min(1)
|
|
4781
|
+
}).strict().describe("Canonical column definition for Alfred construction log Excel round-trips.");
|
|
4782
|
+
var ConstructionLogExcelSheetSchema = external_exports.object({
|
|
4783
|
+
key: ConstructionLogExcelSheetKeySchema,
|
|
4784
|
+
sheetName: external_exports.string().min(1),
|
|
4785
|
+
description: external_exports.string().min(1),
|
|
4786
|
+
columns: external_exports.array(ConstructionLogExcelColumnSchema).min(1)
|
|
4787
|
+
}).strict().describe("Canonical worksheet definition for Alfred construction log Excel round-trips.");
|
|
4788
|
+
var ConstructionLogExcelWorkbookSchema = external_exports.object({
|
|
4789
|
+
schemaVersion: external_exports.literal(CONSTRUCTION_LOG_EXCEL_SCHEMA_VERSION),
|
|
4790
|
+
sheets: external_exports.record(ConstructionLogExcelSheetKeySchema, ConstructionLogExcelSheetSchema)
|
|
4791
|
+
}).strict().describe(
|
|
4792
|
+
"Canonical Alfred construction log Excel workbook schema shared by native output generation and export-upload ingestion."
|
|
4793
|
+
);
|
|
4794
|
+
var CONSTRUCTION_LOG_EXCEL_SHEETS = {
|
|
4795
|
+
submittals: {
|
|
4796
|
+
key: "submittals",
|
|
4797
|
+
sheetName: "Submittals",
|
|
4798
|
+
description: "Submittal register rows generated by Alfred or edited by the PM.",
|
|
4799
|
+
columns: [
|
|
4800
|
+
column("id", "ID", true, "Stable submittal identifier, for example SUB-001."),
|
|
4801
|
+
column("item", "Item", true, "Submittal item or package name."),
|
|
4802
|
+
column("division", "Division", true, "Spec division or trade grouping."),
|
|
4803
|
+
column("needByDate", "Need By Date", true, "Date needed in YYYY-MM-DD format."),
|
|
4804
|
+
column("status", "Status", true, "One of not_started, open, in_review, approved, or done."),
|
|
4805
|
+
commonColumn("assumptionsNotes")
|
|
4806
|
+
]
|
|
4807
|
+
},
|
|
4808
|
+
rfis: {
|
|
4809
|
+
key: "rfis",
|
|
4810
|
+
sheetName: "RFIs",
|
|
4811
|
+
description: "RFI log rows generated by Alfred or edited by the PM.",
|
|
4812
|
+
columns: [
|
|
4813
|
+
column("id", "ID", true, "Stable RFI identifier, for example RFI-001."),
|
|
4814
|
+
column("subject", "Subject", true, "RFI subject."),
|
|
4815
|
+
column("to", "To", true, "Responsible recipient or ball-in-court party."),
|
|
4816
|
+
column("status", "Status", true, "One of draft, open, answered, or closed."),
|
|
4817
|
+
column("openedDate", "Opened Date", true, "Date opened in YYYY-MM-DD format."),
|
|
4818
|
+
commonColumn("assumptionsNotes")
|
|
4819
|
+
]
|
|
4820
|
+
},
|
|
4821
|
+
riskRegister: {
|
|
4822
|
+
key: "riskRegister",
|
|
4823
|
+
sheetName: "Risk Register",
|
|
4824
|
+
description: "Risk register rows generated by Alfred or edited by the PM.",
|
|
4825
|
+
columns: [
|
|
4826
|
+
column("id", "ID", true, "Stable risk identifier, for example RISK-001."),
|
|
4827
|
+
column("risk", "Risk", true, "Risk statement."),
|
|
4828
|
+
column("rating", "Rating", true, "One of low, medium, or high."),
|
|
4829
|
+
column("mitigation", "Mitigation", true, "Mitigation plan."),
|
|
4830
|
+
column("confidence", "Confidence", true, "Confidence score from 0 to 1."),
|
|
4831
|
+
commonColumn("assumptionsNotes")
|
|
4832
|
+
]
|
|
4833
|
+
},
|
|
4834
|
+
longLead: {
|
|
4835
|
+
key: "longLead",
|
|
4836
|
+
sheetName: "Long-Lead",
|
|
4837
|
+
description: "Long-lead procurement rows generated by Alfred or edited by the PM.",
|
|
4838
|
+
columns: [
|
|
4839
|
+
column("id", "ID", true, "Stable long-lead identifier, for example LL-001."),
|
|
4840
|
+
column("item", "Item", true, "Long-lead item name."),
|
|
4841
|
+
column("needByDate", "Need By Date", true, "Date needed in YYYY-MM-DD format."),
|
|
4842
|
+
column("status", "Status", true, "One of tracking, ordered, received, or done."),
|
|
4843
|
+
column("assumption", "Assumption", true, "Procurement assumption behind this row."),
|
|
4844
|
+
commonColumn("assumptionsNotes")
|
|
4845
|
+
]
|
|
4846
|
+
},
|
|
4847
|
+
responsibilityMatrix: {
|
|
4848
|
+
key: "responsibilityMatrix",
|
|
4849
|
+
sheetName: "Responsibility Matrix",
|
|
4850
|
+
description: "Responsibility matrix rows generated by Alfred or edited by the PM.",
|
|
4851
|
+
columns: [
|
|
4852
|
+
column("id", "ID", true, "Stable responsibility identifier, for example RESP-001."),
|
|
4853
|
+
column("role", "Role", true, "Role or party."),
|
|
4854
|
+
column("owner", "Owner", true, "Named owner, or Needs PM input when unknown."),
|
|
4855
|
+
column("responsibility", "Responsibility", true, "Responsibility statement."),
|
|
4856
|
+
commonColumn("assumptionsNotes")
|
|
4857
|
+
]
|
|
4858
|
+
},
|
|
4859
|
+
milestones: {
|
|
4860
|
+
key: "milestones",
|
|
4861
|
+
sheetName: "Milestones",
|
|
4862
|
+
description: "Milestone schedule rows used to generate the MS Project XML schedule.",
|
|
4863
|
+
columns: [
|
|
4864
|
+
column("id", "ID", true, "Stable milestone identifier, for example MS-001."),
|
|
4865
|
+
column("name", "Name", true, "Milestone or task name."),
|
|
4866
|
+
column("targetDate", "Target Date", true, "Target date in YYYY-MM-DD format."),
|
|
4867
|
+
column("status", "Status", true, "One of planned, at_risk, slipped, or complete."),
|
|
4868
|
+
column("predecessorId", "Predecessor ID", false, "Optional predecessor milestone ID."),
|
|
4869
|
+
commonColumn("assumptionsNotes")
|
|
4870
|
+
]
|
|
4871
|
+
}
|
|
4872
|
+
};
|
|
4873
|
+
var CONSTRUCTION_LOG_EXCEL_WORKBOOK_SCHEMA = ConstructionLogExcelWorkbookSchema.parse({
|
|
4874
|
+
schemaVersion: CONSTRUCTION_LOG_EXCEL_SCHEMA_VERSION,
|
|
4875
|
+
sheets: CONSTRUCTION_LOG_EXCEL_SHEETS
|
|
4876
|
+
});
|
|
4877
|
+
function column(key, header, required, description) {
|
|
4878
|
+
return { key, header, required, description };
|
|
4879
|
+
}
|
|
4880
|
+
function commonColumn(key) {
|
|
4881
|
+
return column(
|
|
4882
|
+
key,
|
|
4883
|
+
"Assumptions / Notes",
|
|
4884
|
+
false,
|
|
4885
|
+
"Show-your-work note, including generated assumptions and PM-input gaps."
|
|
4886
|
+
);
|
|
4887
|
+
}
|
|
4888
|
+
|
|
4889
|
+
// ../shared/src/types/dev-task-dispatch.ts
|
|
4890
|
+
var CodingAgentExecutorSchema = external_exports.enum(["claude-code", "codex"]);
|
|
4891
|
+
var DevTaskDispatchRequestSchema = external_exports.object({
|
|
4892
|
+
studioId: external_exports.string().uuid(),
|
|
4893
|
+
productId: external_exports.string().uuid(),
|
|
4894
|
+
repo: RepoRefSchema,
|
|
4895
|
+
task: external_exports.string().min(1).max(2e4),
|
|
4896
|
+
executor: CodingAgentExecutorSchema
|
|
4897
|
+
}).strict();
|
|
4898
|
+
var DevTaskDispatchDryRunPlanSchema = external_exports.object({
|
|
4899
|
+
planOnly: external_exports.literal(true),
|
|
4900
|
+
planOnlyMessage: external_exports.string().min(1),
|
|
4901
|
+
targetRepo: RepoRefSchema,
|
|
4902
|
+
task: external_exports.string().min(1),
|
|
4903
|
+
executor: CodingAgentExecutorSchema,
|
|
4904
|
+
branchName: external_exports.string().min(1),
|
|
4905
|
+
safetyEnvelope: external_exports.object({
|
|
4906
|
+
estimatedCostUsd: external_exports.number().finite().nonnegative(),
|
|
4907
|
+
costCapUsd: external_exports.number().finite().nonnegative(),
|
|
4908
|
+
timeoutMs: external_exports.number().int().positive(),
|
|
4909
|
+
scopedToken: external_exports.object({
|
|
4910
|
+
tokenMinted: external_exports.literal(false),
|
|
4911
|
+
scope: external_exports.string().min(1),
|
|
4912
|
+
ttlSeconds: external_exports.number().int().positive()
|
|
4913
|
+
}).strict(),
|
|
4914
|
+
prOnly: external_exports.object({
|
|
4915
|
+
opensPullRequest: external_exports.literal(true),
|
|
4916
|
+
mergesPullRequest: external_exports.literal(false),
|
|
4917
|
+
pushesMain: external_exports.literal(false),
|
|
4918
|
+
deploys: external_exports.literal(false)
|
|
4919
|
+
}).strict()
|
|
4920
|
+
}).strict()
|
|
4921
|
+
}).strict();
|
|
4922
|
+
var CodingAgentRunInputSchema = external_exports.object({
|
|
4923
|
+
executor: CodingAgentExecutorSchema,
|
|
4924
|
+
repo: RepoRefSchema,
|
|
4925
|
+
task: external_exports.string().min(1),
|
|
4926
|
+
scopedToken: ScopedTokenSchema,
|
|
4927
|
+
branchName: external_exports.string().min(1),
|
|
4928
|
+
costCapUsd: external_exports.number().finite().nonnegative(),
|
|
4929
|
+
timeoutMs: external_exports.number().int().positive()
|
|
4930
|
+
}).strict();
|
|
4931
|
+
var CodingAgentRunResultSchema = external_exports.discriminatedUnion("status", [
|
|
4932
|
+
external_exports.object({
|
|
4933
|
+
status: external_exports.literal("succeeded"),
|
|
4934
|
+
prUrl: external_exports.string().url(),
|
|
4935
|
+
summary: external_exports.string().min(1),
|
|
4936
|
+
costUsd: external_exports.number().finite().nonnegative(),
|
|
4937
|
+
/**
|
|
4938
|
+
* The exact commit sha the PR branch was pushed at when it opened —
|
|
4939
|
+
* captured server-side (see server-dispatch-backend.ts) right after a
|
|
4940
|
+
* successful run, before the workspace is torn down. Lets the Maeve
|
|
4941
|
+
* in-flight-fix detector (maeve-in-flight-pr-fix-lesson.ts) key off the
|
|
4942
|
+
* real PR-open head instead of falling back to timestamp matching.
|
|
4943
|
+
*/
|
|
4944
|
+
openedHeadSha: external_exports.string().min(1).optional()
|
|
4945
|
+
}).strict(),
|
|
4946
|
+
external_exports.object({
|
|
4947
|
+
status: external_exports.literal("failed"),
|
|
4948
|
+
summary: external_exports.string().min(1),
|
|
4949
|
+
reason: external_exports.string().min(1),
|
|
4950
|
+
costUsd: external_exports.number().finite().nonnegative().optional()
|
|
4951
|
+
}).strict()
|
|
4952
|
+
]);
|
|
4953
|
+
var DevTaskOutcomeSchema = external_exports.enum(["ci_passed", "pr_merged", "ci_failed"]);
|
|
4954
|
+
var SecurityFindingClassSchema = external_exports.enum(["authz", "csrf", "injection", "secrets", "ssrf"]);
|
|
4955
|
+
var RecordDevTaskOutcomeInputSchema = external_exports.object({
|
|
4956
|
+
product: external_exports.string().min(1).max(120),
|
|
4957
|
+
repo: external_exports.string().min(1).max(240),
|
|
4958
|
+
prUrl: external_exports.string().url(),
|
|
4959
|
+
outcome: DevTaskOutcomeSchema,
|
|
4960
|
+
task: external_exports.string().min(1).max(2e4).optional(),
|
|
4961
|
+
executor: CodingAgentExecutorSchema.optional(),
|
|
4962
|
+
occurredAt: external_exports.string().datetime().optional(),
|
|
4963
|
+
maeveLessonStatement: external_exports.string().min(1).max(1e3).optional(),
|
|
4964
|
+
maeveLessonTags: external_exports.array(external_exports.string().min(1).max(120)).optional(),
|
|
4965
|
+
/** Security metadata — enriches the Maeve lesson with class/pattern, never raw vulnerable detail. */
|
|
4966
|
+
findingClass: SecurityFindingClassSchema.optional(),
|
|
4967
|
+
ruleId: external_exports.string().min(1).max(120).optional(),
|
|
4968
|
+
signalSource: external_exports.string().min(1).max(240).optional()
|
|
4969
|
+
}).strict();
|
|
4970
|
+
|
|
4971
|
+
// ../shared/src/schemas/standup-plan.ts
|
|
4972
|
+
var StandupRequestSchema = external_exports.object({
|
|
4973
|
+
productName: external_exports.string().min(1).max(80),
|
|
4974
|
+
slug: external_exports.string().min(1).optional(),
|
|
4975
|
+
vertical: external_exports.string().min(1).max(80),
|
|
4976
|
+
repoTarget: external_exports.string().min(1).default("barg-labs"),
|
|
4977
|
+
repoName: external_exports.string().min(1).optional(),
|
|
4978
|
+
templateRef: external_exports.string().min(1).optional(),
|
|
4979
|
+
scopeNotes: external_exports.string().max(2e3).optional()
|
|
4980
|
+
}).strict();
|
|
4981
|
+
var StandupPlanSchema = external_exports.object({
|
|
4982
|
+
productName: external_exports.string().min(1).max(80),
|
|
4983
|
+
slug: external_exports.string().regex(/^[a-z0-9][a-z0-9-]*[a-z0-9]$/),
|
|
4984
|
+
vertical: external_exports.string().min(1).max(80),
|
|
4985
|
+
templateRef: external_exports.string().min(1),
|
|
4986
|
+
repoTarget: external_exports.string().min(1),
|
|
4987
|
+
repoName: external_exports.string().regex(/^[a-z0-9][a-z0-9-]*[a-z0-9]$/),
|
|
4988
|
+
fileManifest: external_exports.array(external_exports.string().min(1)).min(1),
|
|
4989
|
+
credentialScope: external_exports.string().min(1),
|
|
4990
|
+
estimatedCostUsd: external_exports.number().nonnegative(),
|
|
4991
|
+
steps: external_exports.array(external_exports.string().min(1)).min(1),
|
|
4992
|
+
dryRun: external_exports.literal(true)
|
|
4993
|
+
}).strict();
|
|
4994
|
+
|
|
4995
|
+
// ../shared/src/types/coordinator-prompt.ts
|
|
4996
|
+
var CoordinatorPromptContextBlockSchema = external_exports.object({
|
|
4997
|
+
title: external_exports.string().min(1).max(120),
|
|
4998
|
+
body: external_exports.string().min(1).max(6e3),
|
|
4999
|
+
source: external_exports.string().max(500).optional()
|
|
5000
|
+
});
|
|
5001
|
+
var CoordinatorPromptInputPayloadSchema = external_exports.object({
|
|
5002
|
+
objective: external_exports.string().min(1).max(4e3),
|
|
5003
|
+
productId: external_exports.string().min(1),
|
|
5004
|
+
context: external_exports.array(CoordinatorPromptContextBlockSchema).min(1).max(20),
|
|
5005
|
+
escalationHints: external_exports.array(external_exports.string().min(1).max(500)).max(10).optional()
|
|
5006
|
+
});
|
|
5007
|
+
var CoordinatorPromptTokensUsedSchema = external_exports.object({
|
|
5008
|
+
input: external_exports.number().int().nonnegative(),
|
|
5009
|
+
output: external_exports.number().int().nonnegative(),
|
|
5010
|
+
total: external_exports.number().int().nonnegative(),
|
|
5011
|
+
costCents: external_exports.number().nonnegative()
|
|
5012
|
+
});
|
|
5013
|
+
var CoordinatorPromptSchema = external_exports.object({
|
|
5014
|
+
id: external_exports.string().uuid(),
|
|
5015
|
+
studioId: external_exports.string().min(1),
|
|
5016
|
+
productId: external_exports.string().min(1),
|
|
5017
|
+
draftedAt: external_exports.coerce.date(),
|
|
5018
|
+
inputPayload: CoordinatorPromptInputPayloadSchema,
|
|
5019
|
+
markdown: external_exports.string().min(1),
|
|
5020
|
+
metadata: external_exports.object({
|
|
5021
|
+
tokensUsed: CoordinatorPromptTokensUsedSchema.optional(),
|
|
5022
|
+
model: external_exports.string().optional(),
|
|
5023
|
+
templateVersion: external_exports.string().optional()
|
|
5024
|
+
}).catchall(external_exports.unknown()).optional()
|
|
5025
|
+
});
|
|
5026
|
+
var CreateCoordinatorPromptInputSchema = external_exports.object({
|
|
5027
|
+
productId: external_exports.string().min(1),
|
|
5028
|
+
inputPayload: CoordinatorPromptInputPayloadSchema,
|
|
5029
|
+
markdown: external_exports.string().min(1),
|
|
5030
|
+
metadata: external_exports.record(external_exports.unknown()).optional(),
|
|
5031
|
+
draftedAt: external_exports.coerce.date().optional()
|
|
5032
|
+
});
|
|
5033
|
+
var ListCoordinatorPromptsInputSchema = external_exports.object({
|
|
5034
|
+
productId: external_exports.string().min(1).optional(),
|
|
5035
|
+
since: external_exports.coerce.date().optional()
|
|
5036
|
+
});
|
|
5037
|
+
|
|
5038
|
+
// ../shared/src/schemas/inbox-triage.ts
|
|
5039
|
+
var InboxTriageClassificationSchema = external_exports.enum([
|
|
5040
|
+
"needs_reply",
|
|
5041
|
+
"fyi",
|
|
5042
|
+
"waiting",
|
|
5043
|
+
"escalate"
|
|
5044
|
+
]);
|
|
5045
|
+
var InboxTriageLegacyUrgencySchema = external_exports.enum(["needs_reply", "fyi", "noise", "escalation"]);
|
|
5046
|
+
var InboxTriageThreadSchema = external_exports.object({
|
|
5047
|
+
id: external_exports.string().min(1),
|
|
5048
|
+
subject: external_exports.string().min(1),
|
|
5049
|
+
from: external_exports.string(),
|
|
5050
|
+
to: external_exports.string(),
|
|
5051
|
+
snippet: external_exports.string(),
|
|
5052
|
+
labels: external_exports.array(external_exports.string()),
|
|
5053
|
+
unread: external_exports.boolean(),
|
|
5054
|
+
needsReply: external_exports.boolean(),
|
|
5055
|
+
updatedAt: external_exports.string().min(1),
|
|
5056
|
+
url: external_exports.string().min(1),
|
|
5057
|
+
messageCount: external_exports.number().int().nonnegative()
|
|
5058
|
+
});
|
|
5059
|
+
var InboxTriageResultSchema = external_exports.object({
|
|
5060
|
+
threadId: external_exports.string().min(1),
|
|
5061
|
+
classification: InboxTriageClassificationSchema,
|
|
5062
|
+
confidence: external_exports.number().min(0).max(1),
|
|
5063
|
+
reason: external_exports.string(),
|
|
5064
|
+
labelName: external_exports.string(),
|
|
5065
|
+
applied: external_exports.boolean(),
|
|
5066
|
+
error: external_exports.string().optional()
|
|
5067
|
+
});
|
|
5068
|
+
var TriageInboxUsageSchema = external_exports.object({
|
|
5069
|
+
input_tokens: external_exports.number().int().nonnegative(),
|
|
5070
|
+
output_tokens: external_exports.number().int().nonnegative(),
|
|
5071
|
+
cached_tokens: external_exports.number().int().nonnegative().optional(),
|
|
5072
|
+
cost_cents: external_exports.number().nonnegative()
|
|
5073
|
+
});
|
|
5074
|
+
var TriageInboxResultSchema = external_exports.object({
|
|
5075
|
+
productId: external_exports.string().min(1),
|
|
5076
|
+
results: external_exports.array(InboxTriageResultSchema),
|
|
5077
|
+
usage: TriageInboxUsageSchema.optional()
|
|
5078
|
+
});
|
|
5079
|
+
|
|
5080
|
+
// ../shared/src/schemas/inference-usage.ts
|
|
5081
|
+
var InferenceUsageSurfaceSchema = external_exports.string().min(1).max(80).regex(/^[a-z][a-z0-9_-]*$/);
|
|
5082
|
+
var RecordInferenceUsageInputSchema = external_exports.object({
|
|
5083
|
+
product: external_exports.string().min(1).optional(),
|
|
5084
|
+
surface: InferenceUsageSurfaceSchema,
|
|
5085
|
+
model: external_exports.string().min(1).max(120),
|
|
5086
|
+
inputTokens: external_exports.number().int().nonnegative(),
|
|
5087
|
+
outputTokens: external_exports.number().int().nonnegative(),
|
|
5088
|
+
cachedTokens: external_exports.number().int().nonnegative().default(0),
|
|
5089
|
+
costCents: external_exports.number().nonnegative(),
|
|
5090
|
+
timestamp: external_exports.coerce.date().optional()
|
|
5091
|
+
});
|
|
5092
|
+
var InferenceUsageBreakdownQuerySchema = external_exports.object({
|
|
5093
|
+
from: external_exports.coerce.date(),
|
|
5094
|
+
to: external_exports.coerce.date()
|
|
5095
|
+
});
|
|
5096
|
+
var InferenceUsageGroupSchema = external_exports.object({
|
|
5097
|
+
calls: external_exports.number().int().nonnegative(),
|
|
5098
|
+
costCents: external_exports.number().nonnegative(),
|
|
5099
|
+
inputTokens: external_exports.number().int().nonnegative(),
|
|
5100
|
+
outputTokens: external_exports.number().int().nonnegative(),
|
|
5101
|
+
cachedTokens: external_exports.number().int().nonnegative()
|
|
5102
|
+
});
|
|
5103
|
+
var InferenceUsageBreakdownSchema = external_exports.object({
|
|
5104
|
+
from: external_exports.string().datetime(),
|
|
5105
|
+
to: external_exports.string().datetime(),
|
|
5106
|
+
totals: InferenceUsageGroupSchema,
|
|
5107
|
+
bySurface: external_exports.array(InferenceUsageGroupSchema.extend({ surface: InferenceUsageSurfaceSchema })),
|
|
5108
|
+
byModel: external_exports.array(InferenceUsageGroupSchema.extend({ model: external_exports.string().min(1) }))
|
|
5109
|
+
});
|
|
5110
|
+
|
|
5111
|
+
// ../shared/src/schemas/product-health.ts
|
|
5112
|
+
var DEFAULT_PRODUCT_HEALTH_INTERVAL_SECONDS = 24 * 60 * 60;
|
|
5113
|
+
var ISO_DATE_STRING = external_exports.string().datetime({ offset: true }).describe("ISO-8601 timestamp with timezone offset.");
|
|
5114
|
+
var ProductHealthStatusSchema = external_exports.enum(["healthy", "degraded", "halted"]);
|
|
5115
|
+
var ProductHealthDetailsSchema = external_exports.record(external_exports.unknown()).superRefine((details, ctx) => {
|
|
5116
|
+
const credentialPath = findCredentialLikePath(details);
|
|
5117
|
+
if (!credentialPath) return;
|
|
5118
|
+
ctx.addIssue({
|
|
5119
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5120
|
+
message: `Product health details must not contain credentials (${credentialPath}).`
|
|
5121
|
+
});
|
|
5122
|
+
});
|
|
5123
|
+
var ProductHealthReportInputSchema = external_exports.object({
|
|
5124
|
+
productId: external_exports.string().min(1).max(120),
|
|
5125
|
+
status: ProductHealthStatusSchema,
|
|
5126
|
+
lastActivityAt: ISO_DATE_STRING,
|
|
5127
|
+
summary: external_exports.string().min(1).max(1e3),
|
|
5128
|
+
details: ProductHealthDetailsSchema.optional(),
|
|
5129
|
+
reportedAt: ISO_DATE_STRING,
|
|
5130
|
+
expectedIntervalSeconds: external_exports.number().int().positive().optional()
|
|
5131
|
+
});
|
|
5132
|
+
var StoredProductHealthReportSchema = ProductHealthReportInputSchema.extend({
|
|
5133
|
+
expectedIntervalSeconds: external_exports.number().int().positive()
|
|
5134
|
+
});
|
|
5135
|
+
var ProductLivenessStateSchema = external_exports.enum([
|
|
5136
|
+
"healthy",
|
|
5137
|
+
"degraded",
|
|
5138
|
+
"halted",
|
|
5139
|
+
"stale",
|
|
5140
|
+
"unknown"
|
|
5141
|
+
]);
|
|
5142
|
+
var ProductLivenessSnapshotEntrySchema = external_exports.object({
|
|
5143
|
+
productId: external_exports.string().min(1),
|
|
5144
|
+
state: ProductLivenessStateSchema,
|
|
5145
|
+
flagged: external_exports.boolean(),
|
|
5146
|
+
status: ProductHealthStatusSchema.optional(),
|
|
5147
|
+
lastActivityAt: ISO_DATE_STRING.optional(),
|
|
5148
|
+
reportedAt: ISO_DATE_STRING.optional(),
|
|
5149
|
+
expectedIntervalSeconds: external_exports.number().int().positive(),
|
|
5150
|
+
ageSeconds: external_exports.number().int().nonnegative().nullable(),
|
|
5151
|
+
summary: external_exports.string()
|
|
5152
|
+
});
|
|
5153
|
+
function findCredentialLikePath(value, path = []) {
|
|
5154
|
+
if (!value || typeof value !== "object") return null;
|
|
5155
|
+
if (Array.isArray(value)) {
|
|
5156
|
+
for (const [index, item] of value.entries()) {
|
|
5157
|
+
const match = findCredentialLikePath(item, [...path, String(index)]);
|
|
5158
|
+
if (match) return match;
|
|
5159
|
+
}
|
|
5160
|
+
return null;
|
|
5161
|
+
}
|
|
5162
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
5163
|
+
const nextPath = [...path, key];
|
|
5164
|
+
if (/(?:secret|token|password|credential|api[-_]?key|private[-_]?key)/i.test(key)) {
|
|
5165
|
+
return nextPath.join(".");
|
|
5166
|
+
}
|
|
5167
|
+
const match = findCredentialLikePath(nested, nextPath);
|
|
5168
|
+
if (match) return match;
|
|
5169
|
+
}
|
|
5170
|
+
return null;
|
|
5171
|
+
}
|
|
5172
|
+
|
|
5173
|
+
// ../shared/src/schemas/interaction-trace.ts
|
|
5174
|
+
var InteractionTraceVerificationSignalSchema = external_exports.enum([
|
|
5175
|
+
"no_signal",
|
|
5176
|
+
"human_accepted_output",
|
|
5177
|
+
"human_rejected_output",
|
|
5178
|
+
"ci_pr_succeeded",
|
|
5179
|
+
"ci_pr_failed",
|
|
5180
|
+
"brief_accepted",
|
|
5181
|
+
"brief_rejected",
|
|
5182
|
+
"standup_completed",
|
|
5183
|
+
"standup_failed"
|
|
5184
|
+
]);
|
|
5185
|
+
var InteractionTraceVerificationSchema = external_exports.object({
|
|
5186
|
+
success: external_exports.boolean(),
|
|
5187
|
+
signal: InteractionTraceVerificationSignalSchema,
|
|
5188
|
+
confidence: external_exports.number().min(0).max(1),
|
|
5189
|
+
reason: external_exports.string().min(1).max(1e3)
|
|
5190
|
+
});
|
|
5191
|
+
var InteractionTraceActorSchema = external_exports.object({
|
|
5192
|
+
type: external_exports.enum(["human", "agent", "system"]),
|
|
5193
|
+
id: external_exports.string().min(1).max(200),
|
|
5194
|
+
name: external_exports.string().min(1).max(200).optional()
|
|
5195
|
+
});
|
|
5196
|
+
var RecordInteractionTraceInputSchema = external_exports.object({
|
|
5197
|
+
product: external_exports.string().min(1).max(120),
|
|
5198
|
+
intent: external_exports.string().min(1).max(500),
|
|
5199
|
+
actionSummary: external_exports.string().min(1).max(4e3),
|
|
5200
|
+
outcomeSummary: external_exports.string().min(1).max(4e3),
|
|
5201
|
+
model: external_exports.string().min(1).max(200).nullable().optional(),
|
|
5202
|
+
actor: InteractionTraceActorSchema,
|
|
5203
|
+
occurredAt: external_exports.string().datetime().optional(),
|
|
5204
|
+
verification: InteractionTraceVerificationSchema.optional(),
|
|
5205
|
+
metadata: external_exports.record(external_exports.unknown()).optional()
|
|
5206
|
+
});
|
|
5207
|
+
var StoredInteractionTraceSchema = RecordInteractionTraceInputSchema.extend({
|
|
5208
|
+
id: external_exports.string().uuid(),
|
|
5209
|
+
occurredAt: external_exports.string().datetime(),
|
|
5210
|
+
createdAt: external_exports.string().datetime(),
|
|
5211
|
+
verification: InteractionTraceVerificationSchema
|
|
5212
|
+
});
|
|
5213
|
+
var InteractionTraceQualityScoreSchema = external_exports.number().min(0).max(1);
|
|
5214
|
+
var RetrieveRelevantTracesQuerySchema = external_exports.object({
|
|
5215
|
+
product: external_exports.string().min(1).max(120),
|
|
5216
|
+
intent: external_exports.string().min(1).max(500),
|
|
5217
|
+
limit: external_exports.number().int().positive().max(10).optional()
|
|
5218
|
+
});
|
|
5219
|
+
var RetrievedInteractionTraceSchema = StoredInteractionTraceSchema.extend({
|
|
5220
|
+
score: external_exports.number().min(0).max(1),
|
|
5221
|
+
qualityScore: InteractionTraceQualityScoreSchema
|
|
5222
|
+
});
|
|
5223
|
+
|
|
5224
|
+
// ../shared/src/schemas/maeve-lesson.ts
|
|
5225
|
+
var MaeveLessonStatusSchema = external_exports.enum(["candidate", "verified", "retired"]);
|
|
5226
|
+
var MaeveLessonEvidenceSchema = external_exports.object({
|
|
5227
|
+
source: external_exports.enum(["interaction_trace", "artifact"]),
|
|
5228
|
+
traceId: external_exports.string().uuid().optional(),
|
|
5229
|
+
artifact: external_exports.string().min(1).max(1e3).optional(),
|
|
5230
|
+
summary: external_exports.string().min(1).max(1e3),
|
|
5231
|
+
hash: external_exports.string().regex(/^sha256:[a-f0-9]{64}$/)
|
|
5232
|
+
});
|
|
5233
|
+
var MaeveLessonSchema = external_exports.object({
|
|
5234
|
+
id: external_exports.string().uuid(),
|
|
5235
|
+
product: external_exports.string().min(1).max(120),
|
|
5236
|
+
statement: external_exports.string().min(1).max(1e3),
|
|
5237
|
+
scope: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5238
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5239
|
+
evidence: external_exports.array(MaeveLessonEvidenceSchema),
|
|
5240
|
+
status: MaeveLessonStatusSchema,
|
|
5241
|
+
createdAt: external_exports.string().datetime(),
|
|
5242
|
+
lastSeenAt: external_exports.string().datetime()
|
|
5243
|
+
});
|
|
5244
|
+
var CreateMaeveLessonInputSchema = external_exports.object({
|
|
5245
|
+
product: external_exports.string().min(1).max(120),
|
|
5246
|
+
statement: external_exports.string().min(1).max(1e3),
|
|
5247
|
+
scope: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5248
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5249
|
+
evidence: external_exports.array(MaeveLessonEvidenceSchema).default([]),
|
|
5250
|
+
status: MaeveLessonStatusSchema.default("candidate"),
|
|
5251
|
+
lastSeenAt: external_exports.string().datetime().optional()
|
|
5252
|
+
});
|
|
5253
|
+
var PromoteMaeveLessonInputSchema = external_exports.object({
|
|
5254
|
+
id: external_exports.string().uuid(),
|
|
5255
|
+
status: MaeveLessonStatusSchema,
|
|
5256
|
+
appendEvidence: external_exports.array(MaeveLessonEvidenceSchema).optional()
|
|
5257
|
+
});
|
|
5258
|
+
var RecallMaeveLessonsQuerySchema = external_exports.object({
|
|
5259
|
+
product: external_exports.string().min(1).max(120).optional(),
|
|
5260
|
+
taskType: external_exports.string().min(1).max(120).optional(),
|
|
5261
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5262
|
+
limit: external_exports.number().int().positive().max(10).default(5),
|
|
5263
|
+
/**
|
|
5264
|
+
* Free-text query for semantic (pgvector cosine) recall. When set and an
|
|
5265
|
+
* EmbeddingProvider is configured, recallMaeveLessons embeds this text and
|
|
5266
|
+
* retrieves by cosine similarity, with exact-tag matches as a boost.
|
|
5267
|
+
* Falls back to exact-class matching when the provider is NoOp.
|
|
5268
|
+
*/
|
|
5269
|
+
semanticQuery: external_exports.string().min(1).max(500).optional()
|
|
5270
|
+
});
|
|
5271
|
+
var MaeveLessonSeedAnchorSchema = external_exports.object({
|
|
5272
|
+
commit: external_exports.string().regex(/^[0-9a-f]{40}$/i, "commit must be a full 40-character git SHA"),
|
|
5273
|
+
pr: external_exports.number().int().positive().nullable(),
|
|
5274
|
+
summary: external_exports.string().min(1).max(1e3)
|
|
5275
|
+
});
|
|
5276
|
+
var MaeveLessonSeedSchema = external_exports.object({
|
|
5277
|
+
statement: external_exports.string().min(1).max(1e3),
|
|
5278
|
+
scope: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5279
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5280
|
+
anchors: external_exports.array(MaeveLessonSeedAnchorSchema).min(1),
|
|
5281
|
+
lastSeenAt: external_exports.string().datetime()
|
|
5282
|
+
});
|
|
5283
|
+
var ReviewFindingSeveritySchema = external_exports.enum(["critical", "high", "medium", "low"]);
|
|
5284
|
+
var ReviewFindingLessonInputSchema = external_exports.object({
|
|
5285
|
+
studioId: external_exports.string().min(1),
|
|
5286
|
+
findingStudioId: external_exports.string().min(1),
|
|
5287
|
+
product: external_exports.string().min(1).max(120),
|
|
5288
|
+
repository: external_exports.string().min(1).max(240),
|
|
5289
|
+
pullRequestNumber: external_exports.number().int().positive(),
|
|
5290
|
+
findingText: external_exports.string().min(1).max(4e3),
|
|
5291
|
+
severity: ReviewFindingSeveritySchema,
|
|
5292
|
+
reviewer: external_exports.string().min(1).max(120),
|
|
5293
|
+
remediatingCommitSha: external_exports.string().min(4).max(64),
|
|
5294
|
+
/** The durable, reusable rule distilled from the finding — NOT the finding text verbatim. */
|
|
5295
|
+
lessonStatement: external_exports.string().min(1).max(1e3),
|
|
5296
|
+
scope: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5297
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5298
|
+
occurredAt: external_exports.string().datetime()
|
|
5299
|
+
});
|
|
5300
|
+
|
|
5301
|
+
// ../shared/src/schemas/operator-trace.ts
|
|
5302
|
+
var TRACE_ACTORS = [
|
|
5303
|
+
"human",
|
|
5304
|
+
"cowork",
|
|
5305
|
+
"claude-code",
|
|
5306
|
+
"codex",
|
|
5307
|
+
"goal-runner",
|
|
5308
|
+
"ci"
|
|
5309
|
+
];
|
|
5310
|
+
var TraceActorSchema = external_exports.enum(TRACE_ACTORS);
|
|
5311
|
+
var TRACE_SOURCES = [
|
|
5312
|
+
"shell",
|
|
5313
|
+
"cowork",
|
|
5314
|
+
"claude-code",
|
|
5315
|
+
"codex",
|
|
5316
|
+
"goal-runner",
|
|
5317
|
+
"github"
|
|
5318
|
+
];
|
|
5319
|
+
var TraceSourceSchema = external_exports.enum(TRACE_SOURCES);
|
|
5320
|
+
var TraceProvenanceSchema = external_exports.object({
|
|
5321
|
+
source: TraceSourceSchema,
|
|
5322
|
+
/** Absolute path of the source file/dir, or the gh query for CI events. */
|
|
5323
|
+
path: external_exports.string().min(1).max(1e3),
|
|
5324
|
+
/** Line number, session id, or PR number locating the row inside the source. */
|
|
5325
|
+
locator: external_exports.string().min(1).max(200).optional()
|
|
5326
|
+
});
|
|
5327
|
+
var TraceRecordSchema = external_exports.object({
|
|
5328
|
+
t: external_exports.string().datetime(),
|
|
5329
|
+
actor: TraceActorSchema,
|
|
5330
|
+
action: external_exports.string().min(1).max(2e3),
|
|
5331
|
+
target: external_exports.string().max(1e3).default(""),
|
|
5332
|
+
outcome: external_exports.string().max(2e3).default(""),
|
|
5333
|
+
product: external_exports.string().min(1).max(120).optional(),
|
|
5334
|
+
provenance: TraceProvenanceSchema
|
|
5335
|
+
});
|
|
5336
|
+
var ShellRedactionSchema = external_exports.enum(["none", "secret", "unclassified"]);
|
|
5337
|
+
var ShellTraceEntrySchema = external_exports.object({
|
|
5338
|
+
ts: external_exports.string().datetime(),
|
|
5339
|
+
cwd: external_exports.string().min(1).max(1e3),
|
|
5340
|
+
command: external_exports.string().min(1).max(4e3),
|
|
5341
|
+
exitCode: external_exports.number().int(),
|
|
5342
|
+
shellSessionId: external_exports.string().min(1).max(200),
|
|
5343
|
+
redaction: ShellRedactionSchema
|
|
5344
|
+
});
|
|
5345
|
+
var TraceSourceReportSchema = external_exports.discriminatedUnion("status", [
|
|
5346
|
+
external_exports.object({
|
|
5347
|
+
status: external_exports.literal("ok"),
|
|
5348
|
+
source: TraceSourceSchema,
|
|
5349
|
+
recordCount: external_exports.number().int().nonnegative(),
|
|
5350
|
+
/** Files/entries present but skipped (unparseable, filtered) — named, not silent. */
|
|
5351
|
+
skipped: external_exports.array(external_exports.string().min(1).max(500)).default([])
|
|
5352
|
+
}),
|
|
5353
|
+
external_exports.object({
|
|
5354
|
+
status: external_exports.literal("dark"),
|
|
5355
|
+
source: TraceSourceSchema,
|
|
5356
|
+
reason: external_exports.string().min(1).max(500)
|
|
5357
|
+
})
|
|
5358
|
+
]);
|
|
5359
|
+
var OperatorTimelineSchema = external_exports.object({
|
|
5360
|
+
records: external_exports.array(TraceRecordSchema),
|
|
5361
|
+
sources: external_exports.array(TraceSourceReportSchema)
|
|
5362
|
+
});
|
|
5363
|
+
|
|
5364
|
+
// ../shared/src/schemas/witan.ts
|
|
4515
5365
|
var WITAN_RUBRIC_VERSION_V1 = "witan-rubric-v1-2026-06-24";
|
|
4516
5366
|
var WITAN_RUBRIC_VERSION_V2 = "witan-rubric-v2-2026-07-12";
|
|
4517
|
-
var
|
|
5367
|
+
var WITAN_RUBRIC_VERSION_V3 = "witan-rubric-v3-2026-07-13";
|
|
5368
|
+
var WITAN_RUBRIC_VERSION = WITAN_RUBRIC_VERSION_V3;
|
|
4518
5369
|
var WITAN_TRADING_RUBRIC_VERSION_V0 = "witan-trading-rubric-v0-2026-07-01";
|
|
4519
5370
|
var WITAN_CRITERION_IDS = [
|
|
4520
5371
|
"A1",
|
|
@@ -4540,9 +5391,11 @@ var WITAN_TRADING_RUBRIC_V0_CRITERION_IDS = [
|
|
|
4540
5391
|
"audit-completeness",
|
|
4541
5392
|
"claim-reality"
|
|
4542
5393
|
];
|
|
5394
|
+
var WITAN_QUANT_INTEGRITY_RUBRIC_V0_CRITERION_IDS = ["quant-integrity"];
|
|
4543
5395
|
var WitanCriterionIdSchema = external_exports.enum([
|
|
4544
5396
|
...WITAN_CRITERION_IDS,
|
|
4545
|
-
...WITAN_TRADING_RUBRIC_V0_CRITERION_IDS
|
|
5397
|
+
...WITAN_TRADING_RUBRIC_V0_CRITERION_IDS,
|
|
5398
|
+
...WITAN_QUANT_INTEGRITY_RUBRIC_V0_CRITERION_IDS
|
|
4546
5399
|
]);
|
|
4547
5400
|
var WitanTradingCriterionIdSchema = external_exports.enum(WITAN_TRADING_RUBRIC_V0_CRITERION_IDS);
|
|
4548
5401
|
var WitanCriterionCategorySchema = external_exports.enum([
|
|
@@ -4584,6 +5437,7 @@ var WITAN_REPO_ARCHETYPES = [
|
|
|
4584
5437
|
"monorepo",
|
|
4585
5438
|
"docs_only",
|
|
4586
5439
|
"binary_only",
|
|
5440
|
+
"unrecognised_ecosystem",
|
|
4587
5441
|
"empty"
|
|
4588
5442
|
];
|
|
4589
5443
|
var WitanRepoArchetypeSchema = external_exports.enum(WITAN_REPO_ARCHETYPES);
|
|
@@ -4697,72 +5551,1074 @@ var WitanReportSchema = external_exports.object({
|
|
|
4697
5551
|
categoryScores: external_exports.record(external_exports.string(), external_exports.number().min(0).max(4)).optional(),
|
|
4698
5552
|
// Repo-archetype metadata (see WitanRepoArchetypeSchema above). Both fields are omitted for
|
|
4699
5553
|
// callers that don't classify an archetype (e.g. the trading rubric). insufficientSourceReason
|
|
4700
|
-
// is present only for the non-source archetypes ('docs_only' | 'binary_only' |
|
|
4701
|
-
// presence is what presentation layers
|
|
4702
|
-
// insufficient-source verdict instead of
|
|
5554
|
+
// is present only for the non-source archetypes ('docs_only' | 'binary_only' |
|
|
5555
|
+
// 'unrecognised_ecosystem' | 'empty') — its presence is what presentation layers
|
|
5556
|
+
// (badge/terminal/verdict) key off to show an explicit insufficient-source verdict instead of
|
|
5557
|
+
// a confident numeric score.
|
|
4703
5558
|
archetype: WitanRepoArchetypeSchema.optional(),
|
|
4704
5559
|
insufficientSourceReason: external_exports.string().min(1).max(2e3).optional()
|
|
4705
5560
|
}).strict();
|
|
4706
5561
|
|
|
4707
|
-
// src/
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
5562
|
+
// ../shared/src/schemas/work-item.ts
|
|
5563
|
+
var WorkItemTypeSchema = external_exports.enum(["feature", "bug"]);
|
|
5564
|
+
var WorkItemPrioritySchema = external_exports.enum(["low", "normal", "high", "urgent"]);
|
|
5565
|
+
var WorkItemStatusSchema = external_exports.enum([
|
|
5566
|
+
"submitted",
|
|
5567
|
+
"scoped",
|
|
5568
|
+
"dispatched",
|
|
5569
|
+
"pr_open",
|
|
5570
|
+
"done",
|
|
5571
|
+
"declined"
|
|
5572
|
+
]);
|
|
5573
|
+
var CreateWorkItemInputSchema = external_exports.object({
|
|
5574
|
+
productId: external_exports.string().uuid(),
|
|
5575
|
+
type: WorkItemTypeSchema,
|
|
5576
|
+
title: external_exports.string().min(3).max(180),
|
|
5577
|
+
description: external_exports.string().min(8).max(2e4),
|
|
5578
|
+
acceptanceCriteria: external_exports.string().max(2e4).optional(),
|
|
5579
|
+
priority: WorkItemPrioritySchema.default("normal")
|
|
5580
|
+
}).strict();
|
|
5581
|
+
var ScopeWorkItemInputSchema = external_exports.object({
|
|
5582
|
+
scopedTask: external_exports.string().min(8).max(2e4).optional()
|
|
5583
|
+
}).strict();
|
|
5584
|
+
var ListWorkItemsQuerySchema = external_exports.object({
|
|
5585
|
+
productId: external_exports.string().uuid().optional(),
|
|
5586
|
+
status: WorkItemStatusSchema.optional()
|
|
5587
|
+
}).strict();
|
|
5588
|
+
var DispatchWorkItemInputSchema = external_exports.object({
|
|
5589
|
+
executor: external_exports.enum(["claude-code", "codex"]).default("codex"),
|
|
5590
|
+
mode: external_exports.enum(["dry-run", "execute"]).default("dry-run")
|
|
5591
|
+
}).strict();
|
|
4712
5592
|
|
|
4713
|
-
// src/
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
5593
|
+
// ../shared/src/schemas/goal-frontmatter.ts
|
|
5594
|
+
var GoalStreamKindSchema = external_exports.enum(["code", "process"]);
|
|
5595
|
+
var GoalPrioritySchema = external_exports.enum(["p0", "p1", "p2"]);
|
|
5596
|
+
var GoalFrontmatterExtrasSchema = external_exports.object({
|
|
5597
|
+
stream: external_exports.string().min(1).nullable().default(null),
|
|
5598
|
+
order: external_exports.number().int().nullable().default(null),
|
|
5599
|
+
dependsOn: external_exports.array(external_exports.string().min(1)).default([]),
|
|
5600
|
+
priority: GoalPrioritySchema.nullable().default(null),
|
|
5601
|
+
kind: GoalStreamKindSchema.default("code")
|
|
5602
|
+
});
|
|
4717
5603
|
|
|
4718
|
-
// src/
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
5604
|
+
// ../shared/src/schemas/stream.ts
|
|
5605
|
+
var StreamSchema = external_exports.object({
|
|
5606
|
+
id: external_exports.string().uuid(),
|
|
5607
|
+
studioId: external_exports.string().uuid(),
|
|
5608
|
+
name: external_exports.string().min(1).max(120),
|
|
5609
|
+
tag: external_exports.string().max(60).nullable(),
|
|
5610
|
+
kind: GoalStreamKindSchema,
|
|
5611
|
+
orderIndex: external_exports.number().int(),
|
|
5612
|
+
createdAt: external_exports.coerce.date(),
|
|
5613
|
+
updatedAt: external_exports.coerce.date()
|
|
5614
|
+
});
|
|
5615
|
+
var StreamItemSchema = external_exports.object({
|
|
5616
|
+
id: external_exports.string().uuid(),
|
|
5617
|
+
studioId: external_exports.string().uuid(),
|
|
5618
|
+
streamId: external_exports.string().uuid(),
|
|
5619
|
+
orderIndex: external_exports.number().int(),
|
|
5620
|
+
title: external_exports.string().min(1).max(200),
|
|
5621
|
+
/** docs/orchestration/goal_*.md filename (no extension) for code items; null for process items. */
|
|
5622
|
+
goalName: external_exports.string().min(1).nullable(),
|
|
5623
|
+
refLabel: external_exports.string().max(60).nullable(),
|
|
5624
|
+
/** Free-form governed-run prompt text (mirrors the prototype's per-item `run` string). Null = no run control shown. */
|
|
5625
|
+
runPrompt: external_exports.string().min(1).nullable(),
|
|
5626
|
+
createdAt: external_exports.coerce.date(),
|
|
5627
|
+
updatedAt: external_exports.coerce.date()
|
|
5628
|
+
});
|
|
5629
|
+
var StreamItemDisplayStatusSchema = external_exports.enum([
|
|
5630
|
+
"done",
|
|
5631
|
+
"in-review",
|
|
5632
|
+
"running",
|
|
5633
|
+
"queued",
|
|
5634
|
+
"blocked",
|
|
5635
|
+
"local-unknown"
|
|
5636
|
+
]);
|
|
5637
|
+
|
|
5638
|
+
// ../shared/src/schemas/runner-dispatch.ts
|
|
5639
|
+
var RUNNER_DISPATCH_MODES = ["dry-run", "execute"];
|
|
5640
|
+
var RunnerDispatchModeSchema = external_exports.enum(RUNNER_DISPATCH_MODES);
|
|
5641
|
+
var RUNNER_DISPATCH_STATUSES = ["queued", "claimed", "running", "done", "failed"];
|
|
5642
|
+
var RunnerDispatchStatusSchema = external_exports.enum(RUNNER_DISPATCH_STATUSES);
|
|
5643
|
+
var GOAL_CARD_PATTERN = /^docs\/orchestration\/[A-Za-z0-9_./-]+\.md$/;
|
|
5644
|
+
function isAllowedGoalCardPath(goalCard) {
|
|
5645
|
+
if (!GOAL_CARD_PATTERN.test(goalCard)) return false;
|
|
5646
|
+
return goalCard.split("/").every((segment) => segment !== "." && segment !== "..");
|
|
5647
|
+
}
|
|
5648
|
+
var GoalCardPathSchema = external_exports.string().min(1).max(300).refine(isAllowedGoalCardPath, { message: "goal_card_invalid" });
|
|
5649
|
+
var RunnerDispatchRequestSchema = external_exports.object({
|
|
5650
|
+
goalCard: GoalCardPathSchema,
|
|
5651
|
+
stream: external_exports.string().min(1).max(120).optional(),
|
|
5652
|
+
mode: RunnerDispatchModeSchema
|
|
5653
|
+
});
|
|
5654
|
+
|
|
5655
|
+
// ../shared/src/schemas/witan-metrics-manifest.ts
|
|
5656
|
+
var WITAN_METRICS_MANIFEST_SCHEMA_VERSION = "witan-metrics-manifest-v0";
|
|
5657
|
+
var WitanMetricsManifestReturnsFrequencySchema = external_exports.enum([
|
|
5658
|
+
"daily",
|
|
5659
|
+
"weekly",
|
|
5660
|
+
"monthly",
|
|
5661
|
+
"annual"
|
|
5662
|
+
]);
|
|
5663
|
+
var WitanMetricsManifestFoldSchema = external_exports.object({
|
|
5664
|
+
foldId: external_exports.string().min(1).max(80),
|
|
5665
|
+
inSampleSharpe: external_exports.number().optional(),
|
|
5666
|
+
outOfSampleSharpe: external_exports.number().optional()
|
|
5667
|
+
}).strict();
|
|
5668
|
+
var WitanMetricsManifestCscvTrialSchema = external_exports.object({
|
|
5669
|
+
trialId: external_exports.string().min(1).max(80),
|
|
5670
|
+
blockReturns: external_exports.array(external_exports.number()).min(2)
|
|
5671
|
+
}).strict();
|
|
5672
|
+
var WitanMetricsManifestCscvSchema = external_exports.object({
|
|
5673
|
+
// Must be even (split into IS/OOS halves) — enforced by the grader, not the schema.
|
|
5674
|
+
blocks: external_exports.number().int().min(4).max(16),
|
|
5675
|
+
trials: external_exports.array(WitanMetricsManifestCscvTrialSchema).min(2).max(200)
|
|
5676
|
+
}).strict();
|
|
5677
|
+
var WitanMetricsManifestCostModelSchema = external_exports.object({
|
|
5678
|
+
feeBps: external_exports.number().min(0).optional(),
|
|
5679
|
+
slippageBps: external_exports.number().min(0).optional(),
|
|
5680
|
+
borrowBps: external_exports.number().min(0).optional(),
|
|
5681
|
+
notes: external_exports.string().min(1).max(300).optional()
|
|
5682
|
+
}).strict();
|
|
5683
|
+
var WitanMetricsManifestParameterPointSchema = external_exports.object({
|
|
5684
|
+
// Human-readable label for this point (e.g. "72" or "72 bars") — evidence/display only.
|
|
5685
|
+
paramLabel: external_exports.string().min(1).max(80),
|
|
5686
|
+
// The point's position on its swept axis, used to find its nearest neighbors by distance.
|
|
5687
|
+
paramValue: external_exports.number(),
|
|
5688
|
+
outOfSampleSharpe: external_exports.number()
|
|
5689
|
+
}).strict();
|
|
5690
|
+
var WitanMetricsManifestParameterSweepSchema = external_exports.object({
|
|
5691
|
+
// Name of the swept parameter (e.g. "lookback_bars") — evidence/display only.
|
|
5692
|
+
paramName: external_exports.string().min(1).max(80),
|
|
5693
|
+
points: external_exports.array(WitanMetricsManifestParameterPointSchema).min(3).max(500)
|
|
5694
|
+
}).strict();
|
|
5695
|
+
var WitanMetricsManifestLabelSourceSchema = external_exports.enum([
|
|
5696
|
+
"real_forward_returns",
|
|
5697
|
+
"synthetic",
|
|
5698
|
+
"unknown"
|
|
5699
|
+
]);
|
|
5700
|
+
var WitanMetricsManifestSchema = external_exports.object({
|
|
5701
|
+
schemaVersion: external_exports.literal(WITAN_METRICS_MANIFEST_SCHEMA_VERSION),
|
|
5702
|
+
strategyName: external_exports.string().min(1).max(200).optional(),
|
|
5703
|
+
// The headline reported Sharpe ratio the target repo is claiming.
|
|
5704
|
+
reportedSharpe: external_exports.number(),
|
|
5705
|
+
// How many trials/backtests were run in the search that produced reportedSharpe (the
|
|
5706
|
+
// "1-of-42" count) — required so the grader can correct for selection bias.
|
|
5707
|
+
trialCount: external_exports.number().int().positive(),
|
|
5708
|
+
// Track-record length in return observations (e.g. 252 for a year of daily returns) —
|
|
5709
|
+
// the `n` in the Probabilistic/Deflated Sharpe Ratio formula.
|
|
5710
|
+
trackRecordObservations: external_exports.number().int().positive(),
|
|
5711
|
+
returnsFrequency: WitanMetricsManifestReturnsFrequencySchema.default("daily"),
|
|
5712
|
+
// Skew/kurtosis of the returns distribution; default to the normal-distribution values
|
|
5713
|
+
// (0 skew, kurtosis 3) when the repo does not report them.
|
|
5714
|
+
skewness: external_exports.number().default(0),
|
|
5715
|
+
kurtosis: external_exports.number().min(0).default(3),
|
|
5716
|
+
// Whether reportedSharpe is net of trading costs (fees/slippage/borrow/roll).
|
|
5717
|
+
netOfCosts: external_exports.boolean(),
|
|
5718
|
+
costModel: WitanMetricsManifestCostModelSchema.optional(),
|
|
5719
|
+
// Per-fold in-sample vs out-of-sample breakdown, when the repo reports one.
|
|
5720
|
+
folds: external_exports.array(WitanMetricsManifestFoldSchema).default([]),
|
|
5721
|
+
// Per-trial, per-block performance matrix for the CSCV/PBO computation, when available.
|
|
5722
|
+
cscv: WitanMetricsManifestCscvSchema.optional(),
|
|
5723
|
+
// Parameter-sweep breakdown for the run-tier (L3b) parameter-neighborhood robustness
|
|
5724
|
+
// grader, when the run swept a parameter (e.g. a lookback window) and recorded OOS
|
|
5725
|
+
// performance at each swept value.
|
|
5726
|
+
parameterSweep: WitanMetricsManifestParameterSweepSchema.optional(),
|
|
5727
|
+
// Provenance of the labels behind reportedSharpe (labelling-integrity, L1+artifact tier).
|
|
5728
|
+
labelSource: WitanMetricsManifestLabelSourceSchema.optional()
|
|
5729
|
+
}).strict();
|
|
5730
|
+
|
|
5731
|
+
// ../shared/src/schemas/witan-strategy-adapter.ts
|
|
5732
|
+
var WITAN_STRATEGY_ADAPTER_CONFIG_SCHEMA_VERSION = "witan-strategy-adapter-v0";
|
|
5733
|
+
var WitanStrategyAdapterConfigSchema = external_exports.object({
|
|
5734
|
+
schemaVersion: external_exports.literal(WITAN_STRATEGY_ADAPTER_CONFIG_SCHEMA_VERSION),
|
|
5735
|
+
// Argv for the strategy entrypoint, e.g. ["python3", "strategy.py"] or ["node", "run.mjs"].
|
|
5736
|
+
// Command-argv (not a language enum) is what keeps the adapter language-agnostic — most
|
|
5737
|
+
// real targets are Python, but the contract does not assume it.
|
|
5738
|
+
command: external_exports.array(external_exports.string().min(1).max(300)).min(1).max(20),
|
|
5739
|
+
// Relative path (within the target repo) to the data the strategy should backtest against.
|
|
5740
|
+
dataPath: external_exports.string().min(1).max(500).optional(),
|
|
5741
|
+
// Backtest window, as the target repo defines its own date strings (ISO-8601 recommended).
|
|
5742
|
+
// Optional — a strategy may declare its own default window instead.
|
|
5743
|
+
windowStart: external_exports.string().min(1).max(40).optional(),
|
|
5744
|
+
windowEnd: external_exports.string().min(1).max(40).optional(),
|
|
5745
|
+
// Relative path (within the sandboxed workspace) the entrypoint must write its raw result
|
|
5746
|
+
// to — see WitanStrategyRunResultSchema below.
|
|
5747
|
+
outputPath: external_exports.string().min(1).max(300).default("witan-run-result.json"),
|
|
5748
|
+
timeoutMs: external_exports.number().int().positive().max(30 * 60 * 1e3).default(2 * 60 * 1e3),
|
|
5749
|
+
// Explicit opt-in egress allowlist. Empty by default — no network from the sandboxed run
|
|
5750
|
+
// unless the target repo explicitly whitelists hosts here.
|
|
5751
|
+
allowedHosts: external_exports.array(external_exports.string().min(1).max(255)).max(20).default([])
|
|
5752
|
+
}).strict();
|
|
5753
|
+
var WitanStrategyRunResultSchema = WitanMetricsManifestSchema.omit({
|
|
5754
|
+
schemaVersion: true
|
|
5755
|
+
});
|
|
5756
|
+
|
|
5757
|
+
// ../shared/src/types/tactical-action.ts
|
|
5758
|
+
var TacticalActionTypeSchema = external_exports.enum([
|
|
5759
|
+
"merge_pr_auto_merge_safe",
|
|
5760
|
+
"deploy_staging",
|
|
5761
|
+
"acknowledge_canary_alert",
|
|
5762
|
+
"update_status_md",
|
|
5763
|
+
"provision_product",
|
|
5764
|
+
"dispatch_dev_task"
|
|
5765
|
+
]);
|
|
5766
|
+
var TacticalActionStatusSchema = external_exports.enum(["executed", "blocked", "dry_run"]);
|
|
5767
|
+
var TacticalActionPolicySchema = external_exports.object({
|
|
5768
|
+
studioId: external_exports.string().uuid(),
|
|
5769
|
+
productId: external_exports.string().uuid(),
|
|
5770
|
+
actionType: TacticalActionTypeSchema,
|
|
5771
|
+
allowed: external_exports.boolean(),
|
|
5772
|
+
dryRun: external_exports.boolean(),
|
|
5773
|
+
promotedAt: external_exports.coerce.date().nullable(),
|
|
5774
|
+
forceEnableReason: external_exports.string().nullable()
|
|
5775
|
+
});
|
|
5776
|
+
var BaseActionSchema = external_exports.object({
|
|
5777
|
+
actionType: TacticalActionTypeSchema,
|
|
5778
|
+
productId: external_exports.string().uuid(),
|
|
5779
|
+
coordinatorSessionId: external_exports.string().uuid().nullable().optional(),
|
|
5780
|
+
customerFacingProduction: external_exports.boolean().default(false)
|
|
5781
|
+
});
|
|
5782
|
+
var MergePrTacticalActionSchema = BaseActionSchema.extend({
|
|
5783
|
+
actionType: external_exports.literal("merge_pr_auto_merge_safe"),
|
|
5784
|
+
repository: external_exports.string().min(1),
|
|
5785
|
+
pullRequestNumber: external_exports.number().int().positive(),
|
|
5786
|
+
labels: external_exports.array(external_exports.string()),
|
|
5787
|
+
ciStatus: external_exports.enum(["green", "red", "unknown"]),
|
|
5788
|
+
humanApprovals: external_exports.number().int().nonnegative(),
|
|
5789
|
+
coworkClaudeApprovedStatus: external_exports.enum(["green", "red", "unknown"]),
|
|
5790
|
+
// The PR head SHA captured at the SAME live precondition snapshot that
|
|
5791
|
+
// verified the label/CI/approvals/cowork-claude-approved gates. Threaded
|
|
5792
|
+
// through to the GitHub merge call as the conditional `sha` parameter so a
|
|
5793
|
+
// commit that lands between the snapshot and the merge (a fast follow-up
|
|
5794
|
+
// push, or a re-triggered CI run resetting status) can never be
|
|
5795
|
+
// squash-merged unverified — GitHub rejects the merge with 409 instead.
|
|
5796
|
+
headSha: external_exports.string().min(1)
|
|
5797
|
+
});
|
|
5798
|
+
var DeployStagingTacticalActionSchema = BaseActionSchema.extend({
|
|
5799
|
+
actionType: external_exports.literal("deploy_staging"),
|
|
5800
|
+
environment: external_exports.literal("staging"),
|
|
5801
|
+
mainStatus: external_exports.enum(["green", "red", "unknown"]),
|
|
5802
|
+
stagingStatus: external_exports.enum(["green", "red", "unknown"])
|
|
5803
|
+
});
|
|
5804
|
+
var AcknowledgeCanaryAlertTacticalActionSchema = BaseActionSchema.extend({
|
|
5805
|
+
actionType: external_exports.literal("acknowledge_canary_alert"),
|
|
5806
|
+
alertId: external_exports.string().min(1),
|
|
5807
|
+
fingerprint: external_exports.string().min(1),
|
|
5808
|
+
knownFalsePositiveFingerprints: external_exports.array(external_exports.string()).default([])
|
|
5809
|
+
});
|
|
5810
|
+
var UpdateStatusMdTacticalActionSchema = BaseActionSchema.extend({
|
|
5811
|
+
actionType: external_exports.literal("update_status_md"),
|
|
5812
|
+
source: external_exports.literal("daily_brief_synthesis"),
|
|
5813
|
+
statusMarkdown: external_exports.string().min(1).max(2e4)
|
|
5814
|
+
});
|
|
5815
|
+
var ProvisionProductTacticalActionSchema = BaseActionSchema.extend({
|
|
5816
|
+
actionType: external_exports.literal("provision_product"),
|
|
5817
|
+
productName: external_exports.string().min(1).max(80),
|
|
5818
|
+
vertical: external_exports.string().min(1).max(80),
|
|
5819
|
+
repoTarget: external_exports.string().min(1),
|
|
5820
|
+
templateRef: external_exports.string().min(1),
|
|
5821
|
+
scopeNotes: external_exports.string().max(2e3).optional()
|
|
5822
|
+
});
|
|
5823
|
+
var DispatchDevTaskTacticalActionSchema = BaseActionSchema.extend({
|
|
5824
|
+
actionType: external_exports.literal("dispatch_dev_task"),
|
|
5825
|
+
repo: RepoRefSchema,
|
|
5826
|
+
task: external_exports.string().min(1).max(2e4),
|
|
5827
|
+
executor: CodingAgentExecutorSchema
|
|
5828
|
+
});
|
|
5829
|
+
var TacticalActionSchema = external_exports.discriminatedUnion("actionType", [
|
|
5830
|
+
MergePrTacticalActionSchema,
|
|
5831
|
+
DeployStagingTacticalActionSchema,
|
|
5832
|
+
AcknowledgeCanaryAlertTacticalActionSchema,
|
|
5833
|
+
UpdateStatusMdTacticalActionSchema,
|
|
5834
|
+
ProvisionProductTacticalActionSchema,
|
|
5835
|
+
DispatchDevTaskTacticalActionSchema
|
|
5836
|
+
]);
|
|
5837
|
+
var TacticalActionContextSchema = external_exports.object({
|
|
5838
|
+
studioId: external_exports.string().uuid(),
|
|
5839
|
+
actorUserId: external_exports.string().uuid().nullable().optional(),
|
|
5840
|
+
requestedAt: external_exports.coerce.date().optional()
|
|
5841
|
+
});
|
|
5842
|
+
var TacticalActionPermitResultSchema = external_exports.discriminatedUnion("status", [
|
|
5843
|
+
external_exports.object({
|
|
5844
|
+
status: external_exports.literal("executed"),
|
|
5845
|
+
auditLogId: external_exports.string().uuid(),
|
|
5846
|
+
reason: external_exports.literal("permit_allowed")
|
|
5847
|
+
}),
|
|
5848
|
+
external_exports.object({
|
|
5849
|
+
status: external_exports.literal("blocked"),
|
|
5850
|
+
auditLogId: external_exports.string().uuid().optional(),
|
|
5851
|
+
reason: external_exports.string().min(1)
|
|
5852
|
+
}),
|
|
5853
|
+
external_exports.object({
|
|
5854
|
+
status: external_exports.literal("dry_run"),
|
|
5855
|
+
auditLogId: external_exports.string().uuid(),
|
|
5856
|
+
reason: external_exports.literal("dry_run_mode"),
|
|
5857
|
+
wouldHaveDone: external_exports.record(external_exports.unknown())
|
|
5858
|
+
})
|
|
5859
|
+
]);
|
|
5860
|
+
var TacticalActionLogEntrySchema = external_exports.object({
|
|
5861
|
+
id: external_exports.string().uuid(),
|
|
5862
|
+
studioId: external_exports.string().uuid(),
|
|
5863
|
+
productId: external_exports.string().uuid(),
|
|
5864
|
+
product: external_exports.string().nullable().optional(),
|
|
5865
|
+
coordinatorSessionId: external_exports.string().uuid().nullable(),
|
|
5866
|
+
actionType: TacticalActionTypeSchema.or(external_exports.string()),
|
|
5867
|
+
context: external_exports.record(external_exports.unknown()),
|
|
5868
|
+
permitResult: external_exports.record(external_exports.unknown()),
|
|
5869
|
+
status: TacticalActionStatusSchema,
|
|
5870
|
+
outcome: external_exports.string().nullable(),
|
|
5871
|
+
wouldHaveDone: external_exports.record(external_exports.unknown()).nullable(),
|
|
5872
|
+
attemptedAt: external_exports.string(),
|
|
5873
|
+
executedAt: external_exports.string().nullable()
|
|
5874
|
+
});
|
|
5875
|
+
|
|
5876
|
+
// ../shared/src/schemas/index.ts
|
|
5877
|
+
var StudioSchema = external_exports.object({
|
|
5878
|
+
id: external_exports.string().uuid(),
|
|
5879
|
+
name: external_exports.string().min(1).max(100),
|
|
5880
|
+
billingStatus: external_exports.enum(["trial", "active", "past_due", "cancelled"]),
|
|
5881
|
+
planTier: external_exports.enum(["trial", "solo", "studio", "studio_plus", "self_hosted", "enterprise"]),
|
|
5882
|
+
onPrem: external_exports.boolean().default(false),
|
|
5883
|
+
createdAt: external_exports.coerce.date()
|
|
5884
|
+
});
|
|
5885
|
+
var HumanSchema = external_exports.object({
|
|
5886
|
+
id: external_exports.string().uuid(),
|
|
5887
|
+
studioId: external_exports.string().uuid(),
|
|
5888
|
+
email: external_exports.string().email(),
|
|
5889
|
+
name: external_exports.string().min(1).max(120),
|
|
5890
|
+
oauthProviders: external_exports.array(external_exports.enum(["google", "microsoft", "apple"])).default([]),
|
|
5891
|
+
role: external_exports.enum(["owner", "member", "advisor", "per_product"]),
|
|
5892
|
+
timezone: external_exports.string(),
|
|
5893
|
+
briefTime: external_exports.string().regex(/^\d{2}:\d{2}$/),
|
|
5894
|
+
createdAt: external_exports.coerce.date()
|
|
5895
|
+
});
|
|
5896
|
+
var ProductSchema = external_exports.object({
|
|
5897
|
+
id: external_exports.string().uuid(),
|
|
5898
|
+
studioId: external_exports.string().uuid(),
|
|
5899
|
+
name: external_exports.string().min(1).max(80),
|
|
5900
|
+
slug: external_exports.string().regex(/^[a-z0-9][a-z0-9-]*[a-z0-9]$/),
|
|
5901
|
+
status: external_exports.enum(["active", "snoozed", "wound_down", "deleted"]),
|
|
5902
|
+
description: external_exports.string().max(280).optional(),
|
|
5903
|
+
repoUrl: external_exports.string().url().optional(),
|
|
5904
|
+
calendarTag: external_exports.string().optional(),
|
|
5905
|
+
emailLabelPrefix: external_exports.string().optional(),
|
|
5906
|
+
colorHex: external_exports.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
|
|
5907
|
+
scheduleBriefTime: external_exports.string().regex(/^\d{2}:\d{2}$/).optional(),
|
|
5908
|
+
briefTemplateId: external_exports.string().uuid().optional(),
|
|
5909
|
+
regulated: external_exports.boolean().default(false),
|
|
5910
|
+
createdAt: external_exports.coerce.date(),
|
|
5911
|
+
lastTouchedAt: external_exports.coerce.date()
|
|
5912
|
+
});
|
|
5913
|
+
var AgentSchema = external_exports.object({
|
|
5914
|
+
id: external_exports.string().uuid(),
|
|
5915
|
+
studioId: external_exports.string().uuid(),
|
|
5916
|
+
productId: external_exports.string().uuid(),
|
|
5917
|
+
agentType: external_exports.enum(["codex", "claude-code", "cowork", "cursor", "cline", "aider", "other"]),
|
|
5918
|
+
sessionId: external_exports.string().optional(),
|
|
5919
|
+
status: external_exports.enum(["active", "idle", "registered", "archived"]),
|
|
5920
|
+
registeredAt: external_exports.coerce.date(),
|
|
5921
|
+
lastActiveAt: external_exports.coerce.date().optional(),
|
|
5922
|
+
totalCostCentsLifetime: external_exports.number().int().nonnegative().default(0)
|
|
5923
|
+
});
|
|
5924
|
+
var AgentRunSchema = external_exports.object({
|
|
5925
|
+
id: external_exports.string().uuid(),
|
|
5926
|
+
agentId: external_exports.string().uuid(),
|
|
5927
|
+
coordinatorSessionId: external_exports.string().uuid().nullable().optional(),
|
|
5928
|
+
startedAt: external_exports.coerce.date(),
|
|
5929
|
+
completedAt: external_exports.coerce.date().optional(),
|
|
5930
|
+
actionType: external_exports.string(),
|
|
5931
|
+
toolName: external_exports.string().optional(),
|
|
5932
|
+
toolInputSummary: external_exports.string().optional(),
|
|
5933
|
+
toolOutputSummary: external_exports.string().optional(),
|
|
5934
|
+
tokensUsedInput: external_exports.number().int().nonnegative().default(0),
|
|
5935
|
+
tokensUsedOutput: external_exports.number().int().nonnegative().default(0),
|
|
5936
|
+
costCents: external_exports.number().int().nonnegative().default(0),
|
|
5937
|
+
durationMs: external_exports.number().int().nonnegative().default(0),
|
|
5938
|
+
resultStatus: external_exports.enum(["success", "failure", "partial", "timeout"]).optional(),
|
|
5939
|
+
resultSummary: external_exports.string().optional(),
|
|
5940
|
+
filesTouched: external_exports.array(external_exports.string()).default([])
|
|
5941
|
+
});
|
|
5942
|
+
var CoordinatorStatusSchema = external_exports.enum([
|
|
5943
|
+
"draft",
|
|
5944
|
+
"spawned",
|
|
5945
|
+
"in_progress",
|
|
5946
|
+
"reporting",
|
|
5947
|
+
"closed"
|
|
5948
|
+
]);
|
|
5949
|
+
var CoordinatorEscalationPolicySchema = external_exports.object({
|
|
5950
|
+
stuck_after_hours: external_exports.number().int().positive(),
|
|
5951
|
+
method: external_exports.literal("flag_for_human"),
|
|
5952
|
+
urgency: external_exports.enum(["low", "medium", "high", "critical"]).optional()
|
|
5953
|
+
});
|
|
5954
|
+
var CoordinatorSessionSchema = external_exports.object({
|
|
5955
|
+
id: external_exports.string().uuid(),
|
|
5956
|
+
studioId: external_exports.string().uuid(),
|
|
5957
|
+
productId: external_exports.string().uuid(),
|
|
5958
|
+
promptId: external_exports.string().uuid().nullable(),
|
|
5959
|
+
objective: external_exports.string(),
|
|
5960
|
+
status: CoordinatorStatusSchema,
|
|
5961
|
+
spawnedAt: external_exports.coerce.date().nullable(),
|
|
5962
|
+
closedAt: external_exports.coerce.date().nullable(),
|
|
5963
|
+
escalationPolicy: CoordinatorEscalationPolicySchema.nullable(),
|
|
5964
|
+
outcomeSummary: external_exports.string().nullable(),
|
|
5965
|
+
createdAt: external_exports.coerce.date()
|
|
5966
|
+
});
|
|
5967
|
+
var AgentActivityWindowSchema = external_exports.enum(["24h", "7d", "30d"]);
|
|
5968
|
+
var AgentCostBucketSchema = external_exports.object({
|
|
5969
|
+
key: external_exports.string(),
|
|
5970
|
+
name: external_exports.string(),
|
|
5971
|
+
runCount: external_exports.number().int().nonnegative(),
|
|
5972
|
+
costUsd: external_exports.number().nonnegative()
|
|
5973
|
+
});
|
|
5974
|
+
var AgentCostRollupSchema = external_exports.object({
|
|
5975
|
+
window: AgentActivityWindowSchema,
|
|
5976
|
+
studioTotalUsd: external_exports.number().nonnegative(),
|
|
5977
|
+
runCount: external_exports.number().int().nonnegative(),
|
|
5978
|
+
byAgent: external_exports.array(AgentCostBucketSchema),
|
|
5979
|
+
byProduct: external_exports.array(AgentCostBucketSchema)
|
|
5980
|
+
});
|
|
5981
|
+
var AgentConflictRecordSchema = external_exports.object({
|
|
5982
|
+
file: external_exports.string(),
|
|
5983
|
+
agents: external_exports.array(external_exports.string()).min(2),
|
|
5984
|
+
references: external_exports.array(
|
|
5985
|
+
external_exports.object({
|
|
5986
|
+
runId: external_exports.string(),
|
|
5987
|
+
agent: external_exports.string(),
|
|
5988
|
+
product: external_exports.string().nullable(),
|
|
5989
|
+
startedAt: external_exports.string(),
|
|
5990
|
+
sessionRef: external_exports.string().nullable(),
|
|
5991
|
+
prUrl: external_exports.string().nullable()
|
|
5992
|
+
})
|
|
5993
|
+
)
|
|
5994
|
+
});
|
|
5995
|
+
var AgentLeaderboardEntrySchema = external_exports.object({
|
|
5996
|
+
agent: external_exports.string(),
|
|
5997
|
+
product: external_exports.string().nullable(),
|
|
5998
|
+
runCount: external_exports.number().int().nonnegative(),
|
|
5999
|
+
completedRuns: external_exports.number().int().nonnegative(),
|
|
6000
|
+
failedRuns: external_exports.number().int().nonnegative(),
|
|
6001
|
+
costUsd: external_exports.number().nonnegative(),
|
|
6002
|
+
filesTouched: external_exports.number().int().nonnegative(),
|
|
6003
|
+
conflicts: external_exports.number().int().nonnegative(),
|
|
6004
|
+
state: external_exports.enum(["productive", "idle", "duplicating"]),
|
|
6005
|
+
lastActiveAt: external_exports.string().nullable()
|
|
6006
|
+
});
|
|
6007
|
+
var ModelCostEstimateInputSchema = external_exports.object({
|
|
6008
|
+
model: external_exports.string().optional(),
|
|
6009
|
+
inputTokens: external_exports.number().int().nonnegative().default(0),
|
|
6010
|
+
outputTokens: external_exports.number().int().nonnegative().default(0)
|
|
6011
|
+
});
|
|
6012
|
+
var ModelCostEstimateSchema = external_exports.object({
|
|
6013
|
+
costUsd: external_exports.number().nonnegative(),
|
|
6014
|
+
method: external_exports.enum(["estimated_from_model_rate", "unknown_model_rate"]),
|
|
6015
|
+
rateModel: external_exports.enum(["claude-haiku", "claude-sonnet", "claude-opus", "unknown"])
|
|
6016
|
+
});
|
|
6017
|
+
var IntegrationSchema = external_exports.object({
|
|
6018
|
+
id: external_exports.string().uuid(),
|
|
6019
|
+
studioId: external_exports.string().uuid(),
|
|
6020
|
+
productId: external_exports.string().uuid().nullable(),
|
|
6021
|
+
kind: external_exports.string(),
|
|
6022
|
+
oauthTokenEncrypted: external_exports.string().optional(),
|
|
6023
|
+
refreshTokenEncrypted: external_exports.string().optional(),
|
|
6024
|
+
status: external_exports.enum(["active", "broken", "revoked"]),
|
|
6025
|
+
lastSyncAt: external_exports.coerce.date().optional(),
|
|
6026
|
+
errorCount: external_exports.number().int().nonnegative().default(0)
|
|
6027
|
+
});
|
|
6028
|
+
var EmailAccountSchema = external_exports.object({
|
|
6029
|
+
id: external_exports.string().uuid(),
|
|
6030
|
+
studioId: external_exports.string().uuid(),
|
|
6031
|
+
provider: external_exports.enum(["gmail", "m365", "imap"]),
|
|
6032
|
+
oauthTokenEncrypted: external_exports.string().optional(),
|
|
6033
|
+
defaultLabelPrefix: external_exports.string().optional(),
|
|
6034
|
+
triageCadenceMins: external_exports.number().int().positive().default(240)
|
|
6035
|
+
});
|
|
6036
|
+
var RoutineSchema = external_exports.object({
|
|
6037
|
+
id: external_exports.string().uuid(),
|
|
6038
|
+
productId: external_exports.string().uuid().nullable(),
|
|
6039
|
+
name: external_exports.string(),
|
|
6040
|
+
cronExpression: external_exports.string(),
|
|
6041
|
+
promptTemplate: external_exports.string(),
|
|
6042
|
+
model: external_exports.enum(["sonnet", "opus", "haiku"]).default("sonnet"),
|
|
6043
|
+
lastRunAt: external_exports.coerce.date().optional(),
|
|
6044
|
+
nextRunAt: external_exports.coerce.date().optional(),
|
|
6045
|
+
enabled: external_exports.boolean().default(true),
|
|
6046
|
+
retryCount: external_exports.number().int().nonnegative().default(0)
|
|
6047
|
+
});
|
|
6048
|
+
var RoutineRunSchema = external_exports.object({
|
|
6049
|
+
id: external_exports.string().uuid(),
|
|
6050
|
+
routineId: external_exports.string().uuid(),
|
|
6051
|
+
startedAt: external_exports.coerce.date(),
|
|
6052
|
+
completedAt: external_exports.coerce.date().optional(),
|
|
6053
|
+
status: external_exports.enum(["success", "failed", "retried"]),
|
|
6054
|
+
outputBriefId: external_exports.string().uuid().optional(),
|
|
6055
|
+
errorMessage: external_exports.string().optional(),
|
|
6056
|
+
inferenceCostCents: external_exports.number().int().nonnegative().default(0)
|
|
6057
|
+
});
|
|
6058
|
+
var BriefSchema = external_exports.object({
|
|
6059
|
+
id: external_exports.string().uuid(),
|
|
6060
|
+
studioId: external_exports.string().uuid(),
|
|
6061
|
+
generatedAt: external_exports.coerce.date(),
|
|
6062
|
+
type: external_exports.enum(["daily", "weekly", "on_demand"]),
|
|
6063
|
+
html: external_exports.string().optional(),
|
|
6064
|
+
markdown: external_exports.string(),
|
|
6065
|
+
sourceLinks: external_exports.array(external_exports.object({ label: external_exports.string(), url: external_exports.string() })).default([]),
|
|
6066
|
+
shared: external_exports.boolean().default(false),
|
|
6067
|
+
shareToken: external_exports.string().optional(),
|
|
6068
|
+
shareExpiresAt: external_exports.coerce.date().optional(),
|
|
6069
|
+
inferenceCostCents: external_exports.number().int().nonnegative().default(0)
|
|
6070
|
+
});
|
|
6071
|
+
var MemoryEntrySchema = external_exports.object({
|
|
6072
|
+
id: external_exports.string().uuid(),
|
|
6073
|
+
productId: external_exports.string().uuid(),
|
|
6074
|
+
kind: external_exports.enum(["decision", "fact", "customer", "status", "pattern", "thread"]),
|
|
6075
|
+
content: external_exports.string(),
|
|
6076
|
+
// embedding stored separately in pgvector; not modelled in API layer
|
|
6077
|
+
createdAt: external_exports.coerce.date(),
|
|
6078
|
+
lastReferencedAt: external_exports.coerce.date().optional(),
|
|
6079
|
+
referenceCount: external_exports.number().int().nonnegative().default(0),
|
|
6080
|
+
pinned: external_exports.boolean().default(false)
|
|
6081
|
+
});
|
|
6082
|
+
var InboxClassificationSchema = external_exports.object({
|
|
6083
|
+
id: external_exports.string().uuid(),
|
|
6084
|
+
emailAccountId: external_exports.string().uuid(),
|
|
6085
|
+
productId: external_exports.string().uuid().nullable(),
|
|
6086
|
+
messageId: external_exports.string(),
|
|
6087
|
+
sender: external_exports.string(),
|
|
6088
|
+
labelApplied: external_exports.string(),
|
|
6089
|
+
urgency: external_exports.enum(["needs_reply", "fyi", "noise", "escalation"]),
|
|
6090
|
+
confidence: external_exports.number().min(0).max(1),
|
|
6091
|
+
action: external_exports.enum(["labelled", "archived", "drafted_reply"]),
|
|
6092
|
+
userCorrected: external_exports.boolean().default(false),
|
|
6093
|
+
correctedTo: external_exports.string().optional()
|
|
6094
|
+
});
|
|
6095
|
+
var DraftReplySchema = external_exports.object({
|
|
6096
|
+
id: external_exports.string().uuid(),
|
|
6097
|
+
classificationId: external_exports.string().uuid(),
|
|
6098
|
+
draftText: external_exports.string(),
|
|
6099
|
+
confidence: external_exports.number().min(0).max(1),
|
|
6100
|
+
sentAt: external_exports.coerce.date().optional(),
|
|
6101
|
+
sentVia: external_exports.string().optional()
|
|
6102
|
+
});
|
|
6103
|
+
var AlwaysAlertRuleSchema = external_exports.object({
|
|
6104
|
+
id: external_exports.string().uuid(),
|
|
6105
|
+
studioId: external_exports.string().uuid(),
|
|
6106
|
+
ruleType: external_exports.enum(["sender", "subject", "domain"]),
|
|
6107
|
+
value: external_exports.string(),
|
|
6108
|
+
escalationMethod: external_exports.enum(["push", "slack", "email", "brief_pin"]).default("brief_pin")
|
|
6109
|
+
});
|
|
6110
|
+
var AuditEventSchema = external_exports.object({
|
|
6111
|
+
id: external_exports.string().uuid(),
|
|
6112
|
+
studioId: external_exports.string().uuid(),
|
|
6113
|
+
actor: external_exports.enum(["user", "agent", "system"]),
|
|
6114
|
+
action: external_exports.string(),
|
|
6115
|
+
integrationId: external_exports.string().uuid().optional(),
|
|
6116
|
+
productId: external_exports.string().uuid().optional(),
|
|
6117
|
+
timestamp: external_exports.coerce.date(),
|
|
6118
|
+
metadata: external_exports.record(external_exports.unknown()).default({})
|
|
6119
|
+
});
|
|
6120
|
+
var SubscriptionSchema = external_exports.object({
|
|
6121
|
+
id: external_exports.string().uuid(),
|
|
6122
|
+
studioId: external_exports.string().uuid(),
|
|
6123
|
+
stripeSubscriptionId: external_exports.string().optional(),
|
|
6124
|
+
tier: external_exports.enum(["trial", "solo", "studio", "studio_plus", "self_hosted", "enterprise"]),
|
|
6125
|
+
seats: external_exports.number().int().positive(),
|
|
6126
|
+
status: external_exports.string(),
|
|
6127
|
+
currentPeriodEnd: external_exports.coerce.date(),
|
|
6128
|
+
cancelAt: external_exports.coerce.date().optional()
|
|
6129
|
+
});
|
|
6130
|
+
var ProductMembershipSchema = external_exports.object({
|
|
6131
|
+
humanId: external_exports.string().uuid(),
|
|
6132
|
+
productId: external_exports.string().uuid(),
|
|
6133
|
+
role: external_exports.enum(["lead", "contributor", "observer"])
|
|
6134
|
+
});
|
|
6135
|
+
|
|
6136
|
+
// ../witan/src/batch.ts
|
|
6137
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
6138
|
+
import { mkdirSync as mkdirSync2, writeFileSync } from "fs";
|
|
6139
|
+
import { basename as basename2, join as join5 } from "path";
|
|
6140
|
+
|
|
6141
|
+
// ../witan/src/public-scan.ts
|
|
6142
|
+
import { resolve as resolve2 } from "path";
|
|
6143
|
+
|
|
6144
|
+
// ../witan/src/ingest.ts
|
|
6145
|
+
import { readFileSync as readFileSync5, readdirSync as readdirSync2 } from "fs";
|
|
6146
|
+
import { join as join2 } from "path";
|
|
6147
|
+
|
|
6148
|
+
// ../witan/src/finding-limits.ts
|
|
6149
|
+
var RULE_ID_MAX = 200;
|
|
6150
|
+
var MESSAGE_MAX = 500;
|
|
6151
|
+
var LOCATION_MAX = 700;
|
|
6152
|
+
function clamp(value, max) {
|
|
6153
|
+
if (value.length <= max) return value;
|
|
6154
|
+
const ellipsis = "...";
|
|
6155
|
+
return `${value.slice(0, Math.max(max - ellipsis.length, 0))}${ellipsis}`;
|
|
6156
|
+
}
|
|
6157
|
+
function clampFinding(finding) {
|
|
4725
6158
|
return {
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
...headSha ? { headSha } : {}
|
|
4731
|
-
},
|
|
4732
|
-
generatedAt,
|
|
4733
|
-
...options.rubricVersion ? { rubricVersion: options.rubricVersion } : {},
|
|
4734
|
-
archetype: archetype.archetype,
|
|
4735
|
-
...archetype.insufficientSourceReason ? { insufficientSourceReason: archetype.insufficientSourceReason } : {},
|
|
4736
|
-
signals: [
|
|
4737
|
-
...collectRepoSignals(options.repoPath, generatedAt, repoFiles),
|
|
4738
|
-
...(options.domainCollectors ?? []).map((collect) => collect(options.repoPath, repoFiles)),
|
|
4739
|
-
...options.additionalSignals ?? []
|
|
4740
|
-
]
|
|
6159
|
+
...finding,
|
|
6160
|
+
ruleId: clamp(finding.ruleId, RULE_ID_MAX),
|
|
6161
|
+
message: clamp(finding.message, MESSAGE_MAX),
|
|
6162
|
+
...finding.location ? { location: clamp(finding.location, LOCATION_MAX) } : {}
|
|
4741
6163
|
};
|
|
4742
6164
|
}
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
6165
|
+
|
|
6166
|
+
// ../witan/src/generic-adapter.ts
|
|
6167
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
6168
|
+
|
|
6169
|
+
// ../witan/src/json-safe.ts
|
|
6170
|
+
function stripBom(text) {
|
|
6171
|
+
return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
6172
|
+
}
|
|
6173
|
+
|
|
6174
|
+
// ../witan/src/generic-adapter.ts
|
|
6175
|
+
var VALID_DIMENSIONS = /* @__PURE__ */ new Set([
|
|
6176
|
+
"A1",
|
|
6177
|
+
"A2",
|
|
6178
|
+
"A3",
|
|
6179
|
+
"A4",
|
|
6180
|
+
"A5",
|
|
6181
|
+
"B1",
|
|
6182
|
+
"B2",
|
|
6183
|
+
"B3",
|
|
6184
|
+
"B4",
|
|
6185
|
+
"B5",
|
|
6186
|
+
"B6"
|
|
6187
|
+
]);
|
|
6188
|
+
var VALID_SEVERITIES = /* @__PURE__ */ new Set(["critical", "warning", "info"]);
|
|
6189
|
+
function isGenericSignalDocument(raw) {
|
|
6190
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
6191
|
+
const doc = raw;
|
|
6192
|
+
return typeof doc.tool === "string" && doc.tool.length > 0 && Array.isArray(doc.signals);
|
|
6193
|
+
}
|
|
6194
|
+
function parseGenericJson(raw) {
|
|
6195
|
+
if (!isGenericSignalDocument(raw)) return [];
|
|
6196
|
+
const source = raw.tool ?? "unknown";
|
|
6197
|
+
const signals = [];
|
|
6198
|
+
for (const signal of raw.signals ?? []) {
|
|
6199
|
+
const dimension = signal.dimension;
|
|
6200
|
+
if (!dimension || !VALID_DIMENSIONS.has(dimension)) continue;
|
|
6201
|
+
const weight = typeof signal.weight === "number" && Number.isFinite(signal.weight) ? Math.min(Math.max(signal.weight, 0), 1) : 0.5;
|
|
6202
|
+
const findings = [];
|
|
6203
|
+
for (const finding of signal.findings ?? []) {
|
|
6204
|
+
const severity = finding.severity;
|
|
6205
|
+
if (!severity || !VALID_SEVERITIES.has(severity)) continue;
|
|
6206
|
+
const ruleId = finding.ruleId ?? "unknown";
|
|
6207
|
+
findings.push({
|
|
6208
|
+
ruleId,
|
|
6209
|
+
severity,
|
|
6210
|
+
message: finding.message ?? ruleId,
|
|
6211
|
+
...finding.location ? { location: finding.location } : {}
|
|
6212
|
+
});
|
|
6213
|
+
}
|
|
6214
|
+
if (findings.length === 0) continue;
|
|
6215
|
+
signals.push({ source, dimension, weight, findings });
|
|
6216
|
+
}
|
|
6217
|
+
return signals;
|
|
6218
|
+
}
|
|
6219
|
+
|
|
6220
|
+
// ../witan/src/sarif-adapter.ts
|
|
6221
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
6222
|
+
var DIMENSION_RULES = [
|
|
6223
|
+
// A2 — injection / secrets / auth (high weight)
|
|
6224
|
+
{
|
|
6225
|
+
pattern: /sql[- _]?inject|cwe-89|sqli|command[- _]?inject|cwe-78|os[- _]?cmd|rce|remote[- _]?code/i,
|
|
6226
|
+
dimension: "A2",
|
|
6227
|
+
weight: 0.9
|
|
6228
|
+
},
|
|
6229
|
+
{
|
|
6230
|
+
pattern: /secret|credential|api[- _]?key|password[- _]?leak|hardcoded[- _]?(token|key|secret)|cwe-259|cwe-798/i,
|
|
6231
|
+
dimension: "A2",
|
|
6232
|
+
weight: 0.9
|
|
6233
|
+
},
|
|
6234
|
+
{
|
|
6235
|
+
pattern: /path[- _]?traversal|directory[- _]?traversal|cwe-22|lfi|rfi/i,
|
|
6236
|
+
dimension: "A2",
|
|
6237
|
+
weight: 0.8
|
|
6238
|
+
},
|
|
6239
|
+
{
|
|
6240
|
+
pattern: /ssrf|server[- _]?side[- _]?request[- _]?forg|cwe-918/i,
|
|
6241
|
+
dimension: "A2",
|
|
6242
|
+
weight: 0.8
|
|
6243
|
+
},
|
|
6244
|
+
{
|
|
6245
|
+
pattern: /xxe|xml[- _]?external[- _]?entity|cwe-611/i,
|
|
6246
|
+
dimension: "A2",
|
|
6247
|
+
weight: 0.8
|
|
6248
|
+
},
|
|
6249
|
+
{
|
|
6250
|
+
pattern: /auth[- _]?bypass|broken[- _]?auth|missing[- _]?auth|cwe-287|cwe-306|cwe-863|cwe-862/i,
|
|
6251
|
+
dimension: "A2",
|
|
6252
|
+
weight: 0.7
|
|
6253
|
+
},
|
|
6254
|
+
{
|
|
6255
|
+
pattern: /xss|cross[- _]?site[- _]?script|cwe-79/i,
|
|
6256
|
+
dimension: "A2",
|
|
6257
|
+
weight: 0.6
|
|
6258
|
+
},
|
|
6259
|
+
// A4 — dependency vulnerabilities
|
|
6260
|
+
{
|
|
6261
|
+
pattern: /cve-\d{4}-\d+|supply[- _]?chain|depend[a-z]*[- _]?vulner|outdated[- _]?depend|deprecated[- _]?package/i,
|
|
6262
|
+
dimension: "A4",
|
|
6263
|
+
weight: 0.8
|
|
6264
|
+
},
|
|
6265
|
+
{
|
|
6266
|
+
pattern: /npm[- _]?audit|yarn[- _]?audit|pnpm[- _]?audit|pip[- _]?audit|cargo[- _]?audit/i,
|
|
6267
|
+
dimension: "A4",
|
|
6268
|
+
weight: 0.7
|
|
6269
|
+
},
|
|
6270
|
+
// A3 — production readiness / insecure config
|
|
6271
|
+
{
|
|
6272
|
+
pattern: /insecure[- _]?tls|weak[- _]?cipher|tls[- _]?version|http[- _]?strict|hsts|csp[- _]?missing|cwe-326|cwe-327/i,
|
|
6273
|
+
dimension: "A3",
|
|
6274
|
+
weight: 0.5
|
|
6275
|
+
},
|
|
6276
|
+
{
|
|
6277
|
+
pattern: /error[- _]?handl|unhandled[- _]?exception|crash|uncaught|stacktrace[- _]?leak/i,
|
|
6278
|
+
dimension: "A3",
|
|
6279
|
+
weight: 0.4
|
|
6280
|
+
},
|
|
6281
|
+
{
|
|
6282
|
+
pattern: /debug[- _]?mode|dev[- _]?endpoint|staging[- _]?secret/i,
|
|
6283
|
+
dimension: "A3",
|
|
6284
|
+
weight: 0.4
|
|
6285
|
+
},
|
|
6286
|
+
// A1 — test integrity (low weight; SARIF rarely surfaces this)
|
|
6287
|
+
{
|
|
6288
|
+
pattern: /skipped[- _]?test|hollow[- _]?test|empty[- _]?assert|no[- _]?assertion/i,
|
|
6289
|
+
dimension: "A1",
|
|
6290
|
+
weight: 0.2
|
|
6291
|
+
}
|
|
6292
|
+
];
|
|
6293
|
+
var DEFAULT_DIMENSION = "A2";
|
|
6294
|
+
var DEFAULT_WEIGHT = 0.3;
|
|
6295
|
+
var DROP_LEVEL = /* @__PURE__ */ new Set(["none"]);
|
|
6296
|
+
function mapLevel(level) {
|
|
6297
|
+
if (!level || DROP_LEVEL.has(level)) return null;
|
|
6298
|
+
if (level === "error") return "critical";
|
|
6299
|
+
if (level === "warning") return "warning";
|
|
6300
|
+
return "info";
|
|
6301
|
+
}
|
|
6302
|
+
function mapRuleToDimension(ruleId, rules) {
|
|
6303
|
+
for (const rule of rules) {
|
|
6304
|
+
if (rule.pattern.test(ruleId)) {
|
|
6305
|
+
return { dimension: rule.dimension, weight: rule.weight };
|
|
6306
|
+
}
|
|
6307
|
+
}
|
|
6308
|
+
return { dimension: DEFAULT_DIMENSION, weight: DEFAULT_WEIGHT };
|
|
6309
|
+
}
|
|
6310
|
+
function renderLocation(result) {
|
|
6311
|
+
const loc = result.locations?.[0]?.physicalLocation;
|
|
6312
|
+
if (!loc) return void 0;
|
|
6313
|
+
const uri = loc.artifactLocation?.uri;
|
|
6314
|
+
const line = loc.region?.startLine;
|
|
6315
|
+
if (!uri) return void 0;
|
|
6316
|
+
return line != null ? `${uri}:${line}` : uri;
|
|
6317
|
+
}
|
|
6318
|
+
function dedupeFindings(findings) {
|
|
6319
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6320
|
+
return findings.filter((f) => {
|
|
6321
|
+
const key = `${f.ruleId}|${f.severity}|${f.location ?? ""}`;
|
|
6322
|
+
if (seen.has(key)) return false;
|
|
6323
|
+
seen.add(key);
|
|
6324
|
+
return true;
|
|
6325
|
+
});
|
|
6326
|
+
}
|
|
6327
|
+
function parseSarifJson(raw, extraDimensionRules) {
|
|
6328
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return [];
|
|
6329
|
+
const dimensionRules = extraDimensionRules ? [...DIMENSION_RULES, ...extraDimensionRules] : DIMENSION_RULES;
|
|
6330
|
+
const doc = raw;
|
|
6331
|
+
if (!Array.isArray(doc.runs)) return [];
|
|
6332
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
6333
|
+
for (const run of doc.runs) {
|
|
6334
|
+
const driverName = run.tool?.driver?.name ?? "unknown";
|
|
6335
|
+
const source = `sarif:${driverName}`;
|
|
6336
|
+
const ruleDefaultLevels = /* @__PURE__ */ new Map();
|
|
6337
|
+
for (const rule of run.tool?.driver?.rules ?? []) {
|
|
6338
|
+
if (rule.id && rule.defaultConfiguration?.level) {
|
|
6339
|
+
ruleDefaultLevels.set(rule.id, rule.defaultConfiguration.level);
|
|
6340
|
+
}
|
|
6341
|
+
}
|
|
6342
|
+
for (const result of run.results ?? []) {
|
|
6343
|
+
const ruleId = result.ruleId ?? "unknown";
|
|
6344
|
+
const effectiveLevel = result.level ?? ruleDefaultLevels.get(ruleId) ?? "warning";
|
|
6345
|
+
const severity = mapLevel(effectiveLevel);
|
|
6346
|
+
if (!severity) continue;
|
|
6347
|
+
const message = result.message?.text ?? ruleId;
|
|
6348
|
+
const location = renderLocation(result);
|
|
6349
|
+
const { dimension, weight } = mapRuleToDimension(ruleId, dimensionRules);
|
|
6350
|
+
const bucketKey = `${source}|${dimension}`;
|
|
6351
|
+
if (!buckets.has(bucketKey)) {
|
|
6352
|
+
buckets.set(bucketKey, { source, dimension, weight, findings: [] });
|
|
6353
|
+
}
|
|
6354
|
+
buckets.get(bucketKey)?.findings.push({ ruleId, severity, message, ...location ? { location } : {} });
|
|
6355
|
+
}
|
|
6356
|
+
}
|
|
6357
|
+
return Array.from(buckets.values()).map(({ source, dimension, weight, findings }) => ({
|
|
6358
|
+
source,
|
|
6359
|
+
dimension,
|
|
6360
|
+
weight,
|
|
6361
|
+
findings: dedupeFindings(findings)
|
|
6362
|
+
}));
|
|
6363
|
+
}
|
|
6364
|
+
|
|
6365
|
+
// ../witan/src/scorecard-adapter.ts
|
|
6366
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
6367
|
+
var CHECK_RULES = {
|
|
6368
|
+
// B2 — PR outcome traceability
|
|
6369
|
+
"Branch-Protection": { dimension: "B2", weight: 0.8 },
|
|
6370
|
+
"Code-Review": { dimension: "B2", weight: 0.7 },
|
|
6371
|
+
// B3 — CI and QA discipline
|
|
6372
|
+
"Dangerous-Workflow": { dimension: "B3", weight: 0.9 },
|
|
6373
|
+
"Token-Permissions": { dimension: "B3", weight: 0.8 },
|
|
6374
|
+
"CI-Tests": { dimension: "B3", weight: 0.7 },
|
|
6375
|
+
Maintained: { dimension: "B3", weight: 0.3 },
|
|
6376
|
+
// B4 — audit trail / release integrity
|
|
6377
|
+
"Signed-Releases": { dimension: "B4", weight: 0.7 },
|
|
6378
|
+
Packaging: { dimension: "B4", weight: 0.4 },
|
|
6379
|
+
"Security-Policy": { dimension: "B4", weight: 0.4 },
|
|
6380
|
+
// A4 — dependency hygiene
|
|
6381
|
+
Vulnerabilities: { dimension: "A4", weight: 0.9 },
|
|
6382
|
+
"Pinned-Dependencies": { dimension: "A4", weight: 0.8 },
|
|
6383
|
+
"Dependency-Update-Tool": { dimension: "A4", weight: 0.6 },
|
|
6384
|
+
// A2 — data-layer / static analysis
|
|
6385
|
+
SAST: { dimension: "A2", weight: 0.7 },
|
|
6386
|
+
"Binary-Artifacts": { dimension: "A2", weight: 0.6 },
|
|
6387
|
+
// A1 — test integrity
|
|
6388
|
+
Fuzzing: { dimension: "A1", weight: 0.3 }
|
|
6389
|
+
};
|
|
6390
|
+
function mapScoreToSeverity(score) {
|
|
6391
|
+
if (score == null || Number.isNaN(score)) return null;
|
|
6392
|
+
if (score < 0) return null;
|
|
6393
|
+
if (score >= 10) return null;
|
|
6394
|
+
if (score <= 3) return "critical";
|
|
6395
|
+
if (score <= 6) return "warning";
|
|
6396
|
+
return "info";
|
|
6397
|
+
}
|
|
6398
|
+
function dedupeFindings2(findings) {
|
|
6399
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6400
|
+
return findings.filter((f) => {
|
|
6401
|
+
const key = `${f.ruleId}|${f.severity}|${f.location ?? ""}`;
|
|
6402
|
+
if (seen.has(key)) return false;
|
|
6403
|
+
seen.add(key);
|
|
6404
|
+
return true;
|
|
6405
|
+
});
|
|
6406
|
+
}
|
|
6407
|
+
function parseScorecardJson(raw) {
|
|
6408
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return [];
|
|
6409
|
+
const doc = raw;
|
|
6410
|
+
if (!Array.isArray(doc.checks)) return [];
|
|
6411
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
6412
|
+
for (const check of doc.checks) {
|
|
6413
|
+
const name = check.name;
|
|
6414
|
+
if (!name) continue;
|
|
6415
|
+
const rule = CHECK_RULES[name];
|
|
6416
|
+
if (!rule) continue;
|
|
6417
|
+
const severity = mapScoreToSeverity(check.score);
|
|
6418
|
+
if (!severity) continue;
|
|
6419
|
+
const scoreText = typeof check.score === "number" ? `${check.score}/10` : "n/a";
|
|
6420
|
+
const message = `${name} (Scorecard ${scoreText}): ${check.reason ?? "weakness detected"}`.slice(0, 500);
|
|
6421
|
+
const location = check.documentation?.url;
|
|
6422
|
+
const bucket = buckets.get(rule.dimension) ?? { weight: 0, findings: [] };
|
|
6423
|
+
bucket.weight = Math.max(bucket.weight, rule.weight);
|
|
6424
|
+
bucket.findings.push({
|
|
6425
|
+
ruleId: `scorecard:${name}`,
|
|
6426
|
+
severity,
|
|
6427
|
+
message,
|
|
6428
|
+
...location ? { location } : {}
|
|
6429
|
+
});
|
|
6430
|
+
buckets.set(rule.dimension, bucket);
|
|
6431
|
+
}
|
|
6432
|
+
return Array.from(buckets.entries()).map(([dimension, { weight, findings }]) => ({
|
|
6433
|
+
source: "scorecard",
|
|
6434
|
+
dimension,
|
|
6435
|
+
weight,
|
|
6436
|
+
findings: dedupeFindings2(findings)
|
|
6437
|
+
}));
|
|
6438
|
+
}
|
|
6439
|
+
|
|
6440
|
+
// ../witan/src/ingest.ts
|
|
6441
|
+
function looksLikeSarif(raw) {
|
|
6442
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
6443
|
+
return Array.isArray(raw.runs);
|
|
6444
|
+
}
|
|
6445
|
+
function looksLikeScorecard(raw) {
|
|
6446
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
6447
|
+
return Array.isArray(raw.checks);
|
|
6448
|
+
}
|
|
6449
|
+
function countRawEntries(raw) {
|
|
6450
|
+
const obj = raw;
|
|
6451
|
+
if (Array.isArray(obj.runs)) {
|
|
6452
|
+
return obj.runs.reduce((sum, run) => {
|
|
6453
|
+
const results = run.results;
|
|
6454
|
+
return sum + (Array.isArray(results) ? results.length : 0);
|
|
6455
|
+
}, 0);
|
|
6456
|
+
}
|
|
6457
|
+
if (Array.isArray(obj.checks)) return obj.checks.length;
|
|
6458
|
+
if (Array.isArray(obj.signals)) {
|
|
6459
|
+
return obj.signals.reduce((sum, signal) => {
|
|
6460
|
+
const findings = signal.findings;
|
|
6461
|
+
return sum + (Array.isArray(findings) ? findings.length : 0);
|
|
6462
|
+
}, 0);
|
|
6463
|
+
}
|
|
6464
|
+
return 0;
|
|
6465
|
+
}
|
|
6466
|
+
function rawToolName(raw) {
|
|
6467
|
+
const obj = raw;
|
|
6468
|
+
if (Array.isArray(obj.runs)) {
|
|
6469
|
+
const firstRun = obj.runs[0];
|
|
6470
|
+
return firstRun?.tool?.driver?.name ?? "unknown";
|
|
6471
|
+
}
|
|
6472
|
+
if (typeof obj.tool === "string" && obj.tool.length > 0) return obj.tool;
|
|
6473
|
+
return "scorecard";
|
|
6474
|
+
}
|
|
6475
|
+
function parseIngestFile(filePath) {
|
|
6476
|
+
let raw;
|
|
6477
|
+
try {
|
|
6478
|
+
raw = JSON.parse(stripBom(readFileSync5(filePath, "utf8")));
|
|
6479
|
+
} catch (error) {
|
|
6480
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6481
|
+
throw new Error(`Cejel: could not parse ingest file as JSON: ${filePath} (${message})`);
|
|
6482
|
+
}
|
|
6483
|
+
let signals;
|
|
6484
|
+
if (looksLikeSarif(raw)) signals = parseSarifJson(raw);
|
|
6485
|
+
else if (looksLikeScorecard(raw)) signals = parseScorecardJson(raw);
|
|
6486
|
+
else if (isGenericSignalDocument(raw)) signals = parseGenericJson(raw);
|
|
6487
|
+
if (!signals) {
|
|
6488
|
+
throw new Error(
|
|
6489
|
+
`Cejel: unrecognized ingest file format: ${filePath} \u2014 expected SARIF (a "runs" array), OpenSSF Scorecard JSON (a "checks" array), or the generic Cejel external-signal shape (a "tool" string + "signals" array). See the cejel README "Aggregate your scanners".`
|
|
6490
|
+
);
|
|
6491
|
+
}
|
|
6492
|
+
const rawCount = countRawEntries(raw);
|
|
6493
|
+
const mappedCount = signals.reduce((sum, signal) => sum + signal.findings.length, 0);
|
|
6494
|
+
if (rawCount > 0 && mappedCount === 0) {
|
|
6495
|
+
process.stderr.write(
|
|
6496
|
+
`Cejel: ${rawCount} findings from ${rawToolName(raw)} (${filePath}), 0 mapped to trust criteria
|
|
6497
|
+
`
|
|
6498
|
+
);
|
|
6499
|
+
}
|
|
6500
|
+
return signals.map((signal) => ({
|
|
6501
|
+
...signal,
|
|
6502
|
+
findings: signal.findings.map(clampFinding)
|
|
6503
|
+
}));
|
|
6504
|
+
}
|
|
6505
|
+
function expandIngestPattern(pattern) {
|
|
6506
|
+
if (!pattern.includes("*")) return [pattern];
|
|
6507
|
+
const lastSlash = pattern.lastIndexOf("/");
|
|
6508
|
+
const dir = lastSlash === -1 ? "." : pattern.slice(0, lastSlash);
|
|
6509
|
+
const filePattern = lastSlash === -1 ? pattern : pattern.slice(lastSlash + 1);
|
|
6510
|
+
const regexSource = filePattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
6511
|
+
const regex = new RegExp(`^${regexSource}$`);
|
|
6512
|
+
let entries;
|
|
6513
|
+
try {
|
|
6514
|
+
entries = readdirSync2(dir);
|
|
6515
|
+
} catch {
|
|
6516
|
+
return [];
|
|
6517
|
+
}
|
|
6518
|
+
return entries.filter((name) => regex.test(name)).sort().map((name) => join2(dir, name));
|
|
6519
|
+
}
|
|
6520
|
+
function discoverIngestInputs(repoPath) {
|
|
6521
|
+
const inputsDir = join2(repoPath, ".cejel", "inputs");
|
|
6522
|
+
let entries;
|
|
6523
|
+
try {
|
|
6524
|
+
entries = readdirSync2(inputsDir);
|
|
6525
|
+
} catch {
|
|
6526
|
+
return [];
|
|
6527
|
+
}
|
|
6528
|
+
return entries.filter((name) => /\.(sarif|json)$/i.test(name)).sort().map((name) => join2(inputsDir, name));
|
|
6529
|
+
}
|
|
6530
|
+
|
|
6531
|
+
// ../witan/src/repo-signals.ts
|
|
6532
|
+
import { execFileSync } from "child_process";
|
|
6533
|
+
import { createHash } from "crypto";
|
|
6534
|
+
import { readFileSync as readFileSync6, readdirSync as readdirSync3, realpathSync, statSync as statSync2 } from "fs";
|
|
6535
|
+
import { basename, join as join3, relative, resolve, sep } from "path";
|
|
6536
|
+
function buildWitanInputFromRepo(options) {
|
|
6537
|
+
assertRepoPathExists(options.repoPath);
|
|
6538
|
+
const generatedAt = options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
6539
|
+
const headSha = readGitHead(options.repoPath);
|
|
6540
|
+
const repoFiles = listRepoFiles(options.repoPath);
|
|
6541
|
+
const archetype = classifyRepoArchetype(repoFiles);
|
|
6542
|
+
return {
|
|
6543
|
+
productSlug: options.productSlug,
|
|
6544
|
+
productDisplayName: options.productDisplayName,
|
|
6545
|
+
repo: {
|
|
6546
|
+
path: options.repoPath,
|
|
6547
|
+
...headSha ? { headSha } : {}
|
|
6548
|
+
},
|
|
6549
|
+
generatedAt,
|
|
6550
|
+
...options.rubricVersion ? { rubricVersion: options.rubricVersion } : {},
|
|
6551
|
+
archetype: archetype.archetype,
|
|
6552
|
+
...archetype.insufficientSourceReason ? { insufficientSourceReason: archetype.insufficientSourceReason } : {},
|
|
6553
|
+
signals: [
|
|
6554
|
+
...collectRepoSignals(options.repoPath, generatedAt, repoFiles),
|
|
6555
|
+
...(options.domainCollectors ?? []).map((collect) => collect(options.repoPath, repoFiles)),
|
|
6556
|
+
...options.additionalSignals ?? []
|
|
6557
|
+
]
|
|
6558
|
+
};
|
|
6559
|
+
}
|
|
6560
|
+
var SOURCE_LANGUAGES = [
|
|
6561
|
+
{
|
|
6562
|
+
name: "JS/TS",
|
|
6563
|
+
tier: "deep",
|
|
6564
|
+
extensions: ["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"]
|
|
6565
|
+
},
|
|
6566
|
+
{ name: "Python", tier: "deep", extensions: ["py"] },
|
|
6567
|
+
{ name: "Go", tier: "partial", extensions: ["go"] },
|
|
6568
|
+
{ name: "Rust", tier: "partial", extensions: ["rs"] },
|
|
6569
|
+
{ name: "Java", tier: "partial", extensions: ["java"] },
|
|
6570
|
+
{ name: "Ruby", tier: "partial", extensions: ["rb"] },
|
|
6571
|
+
{ name: "PHP", tier: "partial", extensions: ["php"] },
|
|
6572
|
+
{ name: "C#", tier: "partial", extensions: ["cs"] },
|
|
6573
|
+
{ name: "C/C++", tier: "partial", extensions: ["cpp", "cc", "cxx", "c", "h", "hpp"] },
|
|
6574
|
+
{ name: "Swift", tier: "partial", extensions: ["swift"] },
|
|
6575
|
+
{ name: "Kotlin", tier: "partial", extensions: ["kt", "kts"] },
|
|
6576
|
+
{ name: "Dart", tier: "partial", extensions: ["dart"] },
|
|
6577
|
+
{ name: "Elixir", tier: "partial", extensions: ["ex", "exs"] },
|
|
6578
|
+
{ name: "Scala", tier: "partial", extensions: ["scala"] },
|
|
6579
|
+
{ name: "shell", tier: "unmodelled", extensions: ["sh", "bash", "zsh"] },
|
|
6580
|
+
{ name: "R", tier: "unmodelled", extensions: ["r"] },
|
|
6581
|
+
{ name: "Lua", tier: "unmodelled", extensions: ["lua"] },
|
|
6582
|
+
{ name: "Julia", tier: "unmodelled", extensions: ["jl"] },
|
|
6583
|
+
{ name: "Haskell", tier: "unmodelled", extensions: ["hs"] },
|
|
6584
|
+
{ name: "Terraform", tier: "unmodelled", extensions: ["tf", "tfvars"] },
|
|
6585
|
+
{ name: "SQL", tier: "unmodelled", extensions: ["sql"] },
|
|
6586
|
+
{ name: "Perl", tier: "unmodelled", extensions: ["pl", "pm"] },
|
|
6587
|
+
{ name: "OCaml", tier: "unmodelled", extensions: ["ml", "mli"] },
|
|
6588
|
+
{ name: "Clojure", tier: "unmodelled", extensions: ["clj", "cljs", "cljc"] },
|
|
6589
|
+
{ name: "Erlang", tier: "unmodelled", extensions: ["erl", "hrl"] },
|
|
6590
|
+
{ name: "Nim", tier: "unmodelled", extensions: ["nim"] },
|
|
6591
|
+
{ name: "Zig", tier: "unmodelled", extensions: ["zig"] },
|
|
6592
|
+
{ name: "F#", tier: "unmodelled", extensions: ["fs", "fsx"] },
|
|
6593
|
+
{ name: "Groovy", tier: "unmodelled", extensions: ["groovy", "gvy"] }
|
|
6594
|
+
];
|
|
6595
|
+
var SOURCE_EXTENSION_PATTERN = new RegExp(
|
|
6596
|
+
`\\.(${SOURCE_LANGUAGES.flatMap((language) => language.extensions).join("|")})$`,
|
|
6597
|
+
"i"
|
|
6598
|
+
);
|
|
6599
|
+
var BUNDLED_BINARY_EXTENSION_PATTERN = /\.(vsix|zip|tgz|whl|exe|dmg|pkg|msi|jar|war|apk|ipa|dll|dylib)$/i;
|
|
6600
|
+
var DOCS_OR_MEDIA_EXTENSION_PATTERN = /\.(md|mdx|rst|png|jpe?g|gif|svg|webp|ico|pdf)$/i;
|
|
6601
|
+
var KNOWN_NON_SOURCE_EXTENSION_PATTERN = /\.(json|jsonc|json5|ya?ml|toml|txt|lock|xml|csv|tsv|ini|cfg|conf|properties|env|sum|mod|graphql|gql|proto|editorconfig|gitignore|gitattributes|npmrc|nvmrc|dockerignore|log|txt\.license)$/i;
|
|
6602
|
+
var INGEST_POINTER = "To assess a closed/bundled tool, ingest its scanner output via --ingest <sarif|scorecard>.";
|
|
6603
|
+
function classifyRepoArchetype(repoFiles) {
|
|
6604
|
+
const totalFileCount = repoFiles.length;
|
|
6605
|
+
const sourceFileCount = repoFiles.filter((file) => SOURCE_EXTENSION_PATTERN.test(file)).length;
|
|
6606
|
+
if (totalFileCount === 0) {
|
|
6607
|
+
return {
|
|
6608
|
+
archetype: "empty",
|
|
6609
|
+
sourceFileCount: 0,
|
|
6610
|
+
totalFileCount: 0,
|
|
6611
|
+
insufficientSourceReason: "Repository has no tracked files \u2014 there is nothing to certify."
|
|
6612
|
+
};
|
|
6613
|
+
}
|
|
6614
|
+
if (sourceFileCount > 0) {
|
|
6615
|
+
return {
|
|
6616
|
+
archetype: isLikelyMonorepo(repoFiles) ? "monorepo" : "source",
|
|
6617
|
+
sourceFileCount,
|
|
6618
|
+
totalFileCount
|
|
6619
|
+
};
|
|
6620
|
+
}
|
|
6621
|
+
const binaryFiles = repoFiles.filter((file) => BUNDLED_BINARY_EXTENSION_PATTERN.test(file));
|
|
4766
6622
|
if (binaryFiles.length > 0) {
|
|
4767
6623
|
const sample = binaryFiles[0];
|
|
4768
6624
|
return {
|
|
@@ -4781,8 +6637,32 @@ function classifyRepoArchetype(repoFiles) {
|
|
|
4781
6637
|
insufficientSourceReason: `${sourceFileCount} source file(s) found among ${totalFileCount} tracked file(s); repo appears to be a docs/distribution tree (README/markdown/media), not a source tree \u2014 cejel rates source, not docs. ${INGEST_POINTER}`
|
|
4782
6638
|
};
|
|
4783
6639
|
}
|
|
6640
|
+
const unrecognisedExtensions = collectUnrecognisedSourceExtensions(repoFiles);
|
|
6641
|
+
if (unrecognisedExtensions.length > 0) {
|
|
6642
|
+
const sample = unrecognisedExtensions.slice(0, 6).join(", ");
|
|
6643
|
+
return {
|
|
6644
|
+
archetype: "unrecognised_ecosystem",
|
|
6645
|
+
sourceFileCount,
|
|
6646
|
+
totalFileCount,
|
|
6647
|
+
insufficientSourceReason: `Cejel does not yet read this repository's source language(s) (${sample}) \u2014 0 of ${totalFileCount} tracked file(s) matched a recognised source extension. Cejel abstains from a verdict rather than score a language it cannot parse; the Criterion Profile and Measured coverage below show exactly which dimensions were and were not measured. ${INGEST_POINTER}`
|
|
6648
|
+
};
|
|
6649
|
+
}
|
|
4784
6650
|
return { archetype: "source", sourceFileCount, totalFileCount };
|
|
4785
6651
|
}
|
|
6652
|
+
function collectUnrecognisedSourceExtensions(repoFiles) {
|
|
6653
|
+
const found = /* @__PURE__ */ new Set();
|
|
6654
|
+
for (const file of repoFiles) {
|
|
6655
|
+
const base = basename(file);
|
|
6656
|
+
const match = /\.([a-zA-Z0-9_]+)$/.exec(base);
|
|
6657
|
+
const ext = match?.[1];
|
|
6658
|
+
if (!ext) continue;
|
|
6659
|
+
if (KNOWN_NON_SOURCE_EXTENSION_PATTERN.test(base)) continue;
|
|
6660
|
+
if (DOCS_OR_MEDIA_EXTENSION_PATTERN.test(base)) continue;
|
|
6661
|
+
if (BUNDLED_BINARY_EXTENSION_PATTERN.test(base)) continue;
|
|
6662
|
+
found.add(`.${ext.toLowerCase()}`);
|
|
6663
|
+
}
|
|
6664
|
+
return [...found].sort();
|
|
6665
|
+
}
|
|
4786
6666
|
function isLikelyMonorepo(repoFiles) {
|
|
4787
6667
|
const packageRoots = new Set(
|
|
4788
6668
|
repoFiles.filter((file) => /(^|\/)package\.json$/.test(file)).map((file) => file.includes("/") ? file.slice(0, file.lastIndexOf("/")) : "")
|
|
@@ -4792,7 +6672,7 @@ function isLikelyMonorepo(repoFiles) {
|
|
|
4792
6672
|
function assertRepoPathExists(repoPath) {
|
|
4793
6673
|
let stats;
|
|
4794
6674
|
try {
|
|
4795
|
-
stats =
|
|
6675
|
+
stats = statSync2(repoPath);
|
|
4796
6676
|
} catch {
|
|
4797
6677
|
throw new Error(`Cejel: path not found: ${repoPath}`);
|
|
4798
6678
|
}
|
|
@@ -4820,14 +6700,14 @@ function collectRepoSignals(repoPath, generatedAt, repoFiles) {
|
|
|
4820
6700
|
const a5Signal = collectA5ClaimRealityEvidence(repoPath, repoFiles);
|
|
4821
6701
|
const b1Signal = buildNotApplicableSignal(
|
|
4822
6702
|
"B1",
|
|
4823
|
-
"
|
|
6703
|
+
"Repository scans do not evaluate the dispatch-trace process dimension."
|
|
4824
6704
|
);
|
|
4825
6705
|
const b2Signal = collectB2PrTraceEvidence(repoPath, repoFiles);
|
|
4826
6706
|
const b3Signal = collectB3CiDisciplineEvidence(repoPath, repoFiles, mono);
|
|
4827
6707
|
const b4Signal = collectB4AuditEvidence(repoPath, repoFiles, generatedAt);
|
|
4828
6708
|
const b5Signal = buildNotApplicableSignal(
|
|
4829
6709
|
"B5",
|
|
4830
|
-
"
|
|
6710
|
+
"Repository scans do not evaluate the learning-trace process dimension."
|
|
4831
6711
|
);
|
|
4832
6712
|
const b6Signal = collectB6PrivilegedOpsGatingEvidence(repoPath, repoFiles);
|
|
4833
6713
|
for (const signal of [
|
|
@@ -4860,7 +6740,7 @@ function collectA1TestIntegrityEvidence(repoPath, repoFiles) {
|
|
|
4860
6740
|
const runnerFiles = repoFiles.filter(isTestRunnerConfig).slice(0, 6);
|
|
4861
6741
|
const coverageFiles = repoFiles.filter(isCoverageConfig).slice(0, 4);
|
|
4862
6742
|
const packageJson = findRootPackageJson(repoFiles);
|
|
4863
|
-
const packageScripts = packageJson ? readPackageScripts(
|
|
6743
|
+
const packageScripts = packageJson ? readPackageScripts(join3(repoPath, packageJson)) : /* @__PURE__ */ new Map();
|
|
4864
6744
|
const coveragePercent = readCoveragePercent(repoPath, coverageFiles);
|
|
4865
6745
|
const ciWorkflows = repoFiles.filter(isCiWorkflow);
|
|
4866
6746
|
const ciTestWorkflow = ciWorkflows.find(
|
|
@@ -5014,8 +6894,7 @@ function collectA1TestIntegrityEvidence(repoPath, repoFiles) {
|
|
|
5014
6894
|
};
|
|
5015
6895
|
}
|
|
5016
6896
|
function collectA2IsolationEvidence(repoPath, repoFiles) {
|
|
5017
|
-
const
|
|
5018
|
-
const evidence = [...alfredEvidence];
|
|
6897
|
+
const evidence = [];
|
|
5019
6898
|
const findings = [];
|
|
5020
6899
|
const gitignore = repoFiles.find((file) => basename(file) === ".gitignore");
|
|
5021
6900
|
const envExamples = repoFiles.filter((file) => isEnvTemplatePath(file));
|
|
@@ -5031,47 +6910,43 @@ function collectA2IsolationEvidence(repoPath, repoFiles) {
|
|
|
5031
6910
|
repoPath,
|
|
5032
6911
|
repoFiles.filter(isImplementationFile).slice(0, 60)
|
|
5033
6912
|
);
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
6913
|
+
const implFiles = repoFiles.filter(isImplementationFile);
|
|
6914
|
+
const gitignoreHasEnvRule = gitignore != null && fileContains(repoPath, gitignore, /^\.env(\*|\b)|\.env\./m);
|
|
6915
|
+
const committedEnvFilePath = repoFiles.find(
|
|
6916
|
+
(f) => /(?:^|\/)\.env(?:\.|$)/i.test(f) && !isEnvTemplatePath(f)
|
|
6917
|
+
);
|
|
6918
|
+
const hasEnvInHistory = committedEnvFilePath === void 0 && hasEnvPathInGitHistory(repoPath);
|
|
6919
|
+
const dbLayerImportFile = migrationFiles.length === 0 ? implFiles.slice(0, 30).find((f) => fileContains(repoPath, f, DB_CLIENT_PATTERN)) : void 0;
|
|
6920
|
+
const hasDataLayer = migrationFiles.length > 0 || dbLayerImportFile !== void 0;
|
|
6921
|
+
const hasSecretsSurface = envExamples.length > 0 || committedEnvFilePath !== void 0 || gitignoreHasEnvRule || hasEnvInHistory;
|
|
6922
|
+
if (!hasDataLayer && !hasSecretsSurface && !hasConfirmedSecretFinding && !cryptoHygiene.hasSurface) {
|
|
6923
|
+
return buildNotApplicableSignal(
|
|
6924
|
+
"A2",
|
|
6925
|
+
"No data layer (DB/ORM/migrations) or ratable secrets surface detected \u2014 A2 not applicable to this repo archetype. A ratable surface requires .env* files, .gitignore .env rule, committed/history .env path, or detected signing/HMAC/secret-comparison code; bare env reads (process.env / os.environ / std::env::) do not qualify."
|
|
6926
|
+
);
|
|
6927
|
+
}
|
|
6928
|
+
if (committedEnvFilePath) {
|
|
6929
|
+
evidence.push(
|
|
6930
|
+
evidenceForRelative(
|
|
6931
|
+
repoPath,
|
|
6932
|
+
committedEnvFilePath,
|
|
6933
|
+
"secret_scan",
|
|
6934
|
+
"Committed .env file in repository tree"
|
|
6935
|
+
)
|
|
5039
6936
|
);
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
repoPath,
|
|
5054
|
-
committedEnvFilePath,
|
|
5055
|
-
"secret_scan",
|
|
5056
|
-
"Committed .env file in repository tree"
|
|
5057
|
-
)
|
|
5058
|
-
);
|
|
5059
|
-
} else if (hasEnvInHistory) {
|
|
5060
|
-
evidence.push({
|
|
5061
|
-
kind: "secret_scan",
|
|
5062
|
-
label: ".env path detected in git history",
|
|
5063
|
-
path: ".git",
|
|
5064
|
-
contentHash: readGitHead(repoPath) ?? "env-history-scan"
|
|
5065
|
-
});
|
|
5066
|
-
} else if (migrationFiles[0] != null) {
|
|
5067
|
-
evidence.push(
|
|
5068
|
-
evidenceForRelative(repoPath, migrationFiles[0], "artifact", "Data layer migration")
|
|
5069
|
-
);
|
|
5070
|
-
} else if (dbLayerImportFile != null) {
|
|
5071
|
-
evidence.push(
|
|
5072
|
-
evidenceForRelative(repoPath, dbLayerImportFile, "artifact", "DB client import")
|
|
5073
|
-
);
|
|
5074
|
-
}
|
|
6937
|
+
} else if (hasEnvInHistory) {
|
|
6938
|
+
evidence.push({
|
|
6939
|
+
kind: "secret_scan",
|
|
6940
|
+
label: ".env path detected in git history",
|
|
6941
|
+
path: ".git",
|
|
6942
|
+
contentHash: readGitHead(repoPath) ?? "env-history-scan"
|
|
6943
|
+
});
|
|
6944
|
+
} else if (migrationFiles[0] != null) {
|
|
6945
|
+
evidence.push(
|
|
6946
|
+
evidenceForRelative(repoPath, migrationFiles[0], "artifact", "Data layer migration")
|
|
6947
|
+
);
|
|
6948
|
+
} else if (dbLayerImportFile != null) {
|
|
6949
|
+
evidence.push(evidenceForRelative(repoPath, dbLayerImportFile, "artifact", "DB client import"));
|
|
5075
6950
|
}
|
|
5076
6951
|
const rlsMigration = migrationFiles.find((file) => fileContains(repoPath, file, RLS_PATTERN));
|
|
5077
6952
|
const tenantScopedFile = migrationFiles.find(
|
|
@@ -5305,7 +7180,7 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles) {
|
|
|
5305
7180
|
const evidence = [];
|
|
5306
7181
|
const findings = [];
|
|
5307
7182
|
const packageJson = findRootPackageJson(repoFiles);
|
|
5308
|
-
const scripts = packageJson ? readPackageScripts(
|
|
7183
|
+
const scripts = packageJson ? readPackageScripts(join3(repoPath, packageJson)) : /* @__PURE__ */ new Map();
|
|
5309
7184
|
const workflows = repoFiles.filter(isCiWorkflow);
|
|
5310
7185
|
const workflow = workflows[0];
|
|
5311
7186
|
const deployConfigs = repoFiles.filter(isDeployConfig);
|
|
@@ -5579,45 +7454,6 @@ function hasDeclaredVersionConstraint(dependency) {
|
|
|
5579
7454
|
return /^v?\d/.test(trimmed);
|
|
5580
7455
|
}
|
|
5581
7456
|
function collectA5ClaimRealityEvidence(repoPath, repoFiles) {
|
|
5582
|
-
const alfredEvidence = [];
|
|
5583
|
-
if (alfredEvidence.length > 0) {
|
|
5584
|
-
const claimStats = readClaimRealityStats(repoPath);
|
|
5585
|
-
return {
|
|
5586
|
-
criterionId: "A5",
|
|
5587
|
-
positiveEvidence: alfredEvidence,
|
|
5588
|
-
findings: [],
|
|
5589
|
-
metrics: [
|
|
5590
|
-
metric(
|
|
5591
|
-
"claim_match_rate",
|
|
5592
|
-
"Claim match rate",
|
|
5593
|
-
claimStats?.matchRate ?? 0,
|
|
5594
|
-
1,
|
|
5595
|
-
0.6,
|
|
5596
|
-
"ratio",
|
|
5597
|
-
"Measures supported and partially supported claims in the structured reconciliation artifact."
|
|
5598
|
-
),
|
|
5599
|
-
metric(
|
|
5600
|
-
"claim_registry_depth",
|
|
5601
|
-
"Claim registry depth",
|
|
5602
|
-
claimStats?.claimCount ?? 0,
|
|
5603
|
-
Math.max(claimStats?.claimCount ?? 0, 8),
|
|
5604
|
-
0.25,
|
|
5605
|
-
"claims",
|
|
5606
|
-
"Credits the number of concrete claims reconciled without giving unlimited credit for one artifact."
|
|
5607
|
-
),
|
|
5608
|
-
metric(
|
|
5609
|
-
"reconciliation_artifact_depth",
|
|
5610
|
-
"Reconciliation artifact depth",
|
|
5611
|
-
alfredEvidence.length,
|
|
5612
|
-
3,
|
|
5613
|
-
0.15,
|
|
5614
|
-
"artifacts",
|
|
5615
|
-
"Credits implementation, Markdown, and structured reconciliation artifacts."
|
|
5616
|
-
)
|
|
5617
|
-
],
|
|
5618
|
-
notes: "A5 is evidenced by deterministic claim-vs-reality implementation and report artifacts, not a model-opinion verdict."
|
|
5619
|
-
};
|
|
5620
|
-
}
|
|
5621
7457
|
const claimDoc = repoFiles.find((file) => /(^|\/)(README|readme)\.md$/.test(file)) ?? repoFiles.find((file) => /(^|\/)docs\/.*\.(md|mdx)$/.test(file));
|
|
5622
7458
|
if (!claimDoc) {
|
|
5623
7459
|
return buildNotApplicableSignal(
|
|
@@ -5778,7 +7614,7 @@ function collectB2PrTraceEvidence(repoPath, repoFiles) {
|
|
|
5778
7614
|
function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
|
|
5779
7615
|
const evidence = [];
|
|
5780
7616
|
const packageJson = findRootPackageJson(repoFiles);
|
|
5781
|
-
const scripts = packageJson ? readPackageScripts(
|
|
7617
|
+
const scripts = packageJson ? readPackageScripts(join3(repoPath, packageJson)) : /* @__PURE__ */ new Map();
|
|
5782
7618
|
const workflows = repoFiles.filter(isCiWorkflow);
|
|
5783
7619
|
const workflow = workflows[0];
|
|
5784
7620
|
const rootWorkflows = mono ? mono.sharedFiles.filter(isCiWorkflow) : [];
|
|
@@ -6193,13 +8029,13 @@ function listGitTrackedFiles(repoPath) {
|
|
|
6193
8029
|
function visitRepoDir(repoPath, dirPath, files) {
|
|
6194
8030
|
let entries;
|
|
6195
8031
|
try {
|
|
6196
|
-
entries =
|
|
8032
|
+
entries = readdirSync3(dirPath, { withFileTypes: true });
|
|
6197
8033
|
} catch {
|
|
6198
8034
|
return;
|
|
6199
8035
|
}
|
|
6200
8036
|
for (const entry of entries) {
|
|
6201
8037
|
if (shouldSkipDir(entry.name)) continue;
|
|
6202
|
-
const fullPath =
|
|
8038
|
+
const fullPath = join3(dirPath, entry.name);
|
|
6203
8039
|
if (entry.isDirectory()) {
|
|
6204
8040
|
visitRepoDir(repoPath, fullPath, files);
|
|
6205
8041
|
continue;
|
|
@@ -6207,7 +8043,7 @@ function visitRepoDir(repoPath, dirPath, files) {
|
|
|
6207
8043
|
if (!entry.isFile()) continue;
|
|
6208
8044
|
let size;
|
|
6209
8045
|
try {
|
|
6210
|
-
size =
|
|
8046
|
+
size = statSync2(fullPath).size;
|
|
6211
8047
|
} catch {
|
|
6212
8048
|
continue;
|
|
6213
8049
|
}
|
|
@@ -6243,9 +8079,9 @@ function isTestFile(file) {
|
|
|
6243
8079
|
function collectContentBasedCppTestFiles(repoPath, repoFiles) {
|
|
6244
8080
|
const candidates = repoFiles.filter((file) => /\.(cpp|cc|cxx)$/.test(file) && !isTestFile(file)).slice(0, CPP_CONTENT_SCAN_LIMIT);
|
|
6245
8081
|
return candidates.filter((file) => {
|
|
6246
|
-
const fullPath =
|
|
8082
|
+
const fullPath = join3(repoPath, file);
|
|
6247
8083
|
if (!isRegularFile(fullPath)) return false;
|
|
6248
|
-
const contents =
|
|
8084
|
+
const contents = readFileSync6(fullPath, "utf8");
|
|
6249
8085
|
return CPP_TEST_FRAMEWORK_PATTERN.test(contents) || CPP_TEST_MACRO_PATTERN.test(contents);
|
|
6250
8086
|
});
|
|
6251
8087
|
}
|
|
@@ -6264,9 +8100,9 @@ function measureNonHollowTestShare(repoPath, files) {
|
|
|
6264
8100
|
let nonHollowCount = 0;
|
|
6265
8101
|
let ratedCount = 0;
|
|
6266
8102
|
for (const file of files) {
|
|
6267
|
-
const fullPath =
|
|
8103
|
+
const fullPath = join3(repoPath, file);
|
|
6268
8104
|
if (!isRegularFile(fullPath)) continue;
|
|
6269
|
-
const contents =
|
|
8105
|
+
const contents = readFileSync6(fullPath, "utf8");
|
|
6270
8106
|
const nonHollow = (JS_TEST_ASSERTION_PATTERN.test(contents) || CPP_TEST_ASSERTION_PATTERN.test(contents) || MULTI_ECOSYSTEM_TEST_ASSERTION_PATTERN.test(contents)) && !SUITE_LEVEL_SKIP_PATTERN.test(contents);
|
|
6271
8107
|
if (nonHollow) {
|
|
6272
8108
|
nonHollowCount += 1;
|
|
@@ -6285,17 +8121,17 @@ function countPatternMatches(repoPath, files, pattern) {
|
|
|
6285
8121
|
const matcher = new RegExp(pattern.source, flags);
|
|
6286
8122
|
let count = 0;
|
|
6287
8123
|
for (const file of files) {
|
|
6288
|
-
const fullPath =
|
|
8124
|
+
const fullPath = join3(repoPath, file);
|
|
6289
8125
|
if (!isRegularFile(fullPath)) continue;
|
|
6290
|
-
count += [...
|
|
8126
|
+
count += [...readFileSync6(fullPath, "utf8").matchAll(matcher)].length;
|
|
6291
8127
|
}
|
|
6292
8128
|
return count;
|
|
6293
8129
|
}
|
|
6294
8130
|
function readCoveragePercent(repoPath, files) {
|
|
6295
8131
|
for (const file of files) {
|
|
6296
|
-
const fullPath =
|
|
8132
|
+
const fullPath = join3(repoPath, file);
|
|
6297
8133
|
if (!isRegularFile(fullPath)) continue;
|
|
6298
|
-
const contents =
|
|
8134
|
+
const contents = readFileSync6(fullPath, "utf8");
|
|
6299
8135
|
const summaryPercent = parseCoverageSummaryPercent(contents);
|
|
6300
8136
|
if (summaryPercent !== null) return summaryPercent;
|
|
6301
8137
|
const thresholdPercent = parseCoverageThresholdPercent(contents);
|
|
@@ -6339,7 +8175,7 @@ function pickPrimaryDependencyManifest(repoPath, manifests) {
|
|
|
6339
8175
|
function readDependencySpecs(repoPath, manifests) {
|
|
6340
8176
|
const specs = [];
|
|
6341
8177
|
for (const manifest of manifests) {
|
|
6342
|
-
const fullPath =
|
|
8178
|
+
const fullPath = join3(repoPath, manifest);
|
|
6343
8179
|
if (!isRegularFile(fullPath)) continue;
|
|
6344
8180
|
if (manifest.endsWith("package.json")) {
|
|
6345
8181
|
specs.push(...readPackageJsonDependencySpecs(fullPath));
|
|
@@ -6385,7 +8221,7 @@ function readDependencySpecs(repoPath, manifests) {
|
|
|
6385
8221
|
}
|
|
6386
8222
|
function readGoModDependencySpecs(path) {
|
|
6387
8223
|
const specs = [];
|
|
6388
|
-
const contents =
|
|
8224
|
+
const contents = readFileSync6(path, "utf8");
|
|
6389
8225
|
const blockPattern = /require\s*\(([^)]+)\)/gs;
|
|
6390
8226
|
const singlePattern = /^require\s+(\S+)\s+(\S+)/gm;
|
|
6391
8227
|
for (const blockMatch of contents.matchAll(blockPattern)) {
|
|
@@ -6406,7 +8242,7 @@ function readGoModDependencySpecs(path) {
|
|
|
6406
8242
|
}
|
|
6407
8243
|
function readCargoTomlDependencySpecs(path) {
|
|
6408
8244
|
const specs = [];
|
|
6409
|
-
const contents =
|
|
8245
|
+
const contents = readFileSync6(path, "utf8");
|
|
6410
8246
|
const depSectionPattern = /^\[(?:dependencies|dev-dependencies|build-dependencies)\]([\s\S]*?)(?=^\[|(?![\s\S]))/gm;
|
|
6411
8247
|
for (const sectionMatch of contents.matchAll(depSectionPattern)) {
|
|
6412
8248
|
const section = sectionMatch[1] ?? "";
|
|
@@ -6428,7 +8264,7 @@ function readCargoTomlDependencySpecs(path) {
|
|
|
6428
8264
|
}
|
|
6429
8265
|
function readPyprojectDependencySpecs(path) {
|
|
6430
8266
|
const specs = [];
|
|
6431
|
-
const contents =
|
|
8267
|
+
const contents = readFileSync6(path, "utf8");
|
|
6432
8268
|
const poetrySectionPattern = /^\[tool\.poetry\.dependencies\]([\s\S]*?)(?=^\[|(?![\s\S]))/gm;
|
|
6433
8269
|
for (const sectionMatch of contents.matchAll(poetrySectionPattern)) {
|
|
6434
8270
|
const section = sectionMatch[1] ?? "";
|
|
@@ -6462,7 +8298,7 @@ function readPyprojectDependencySpecs(path) {
|
|
|
6462
8298
|
}
|
|
6463
8299
|
function readPipfileDependencySpecs(path) {
|
|
6464
8300
|
const specs = [];
|
|
6465
|
-
const contents =
|
|
8301
|
+
const contents = readFileSync6(path, "utf8");
|
|
6466
8302
|
const sectionPattern = /^\[(?:packages|dev-packages)\]([\s\S]*?)(?=^\[|$(?![\s\S]))/gm;
|
|
6467
8303
|
for (const sectionMatch of contents.matchAll(sectionPattern)) {
|
|
6468
8304
|
for (const line of (sectionMatch[1] ?? "").split("\n")) {
|
|
@@ -6475,7 +8311,7 @@ function readPipfileDependencySpecs(path) {
|
|
|
6475
8311
|
return specs;
|
|
6476
8312
|
}
|
|
6477
8313
|
function readVcpkgJsonDependencySpecs(path) {
|
|
6478
|
-
const parsed = parseJsonObject(
|
|
8314
|
+
const parsed = parseJsonObject(readFileSync6(path, "utf8"));
|
|
6479
8315
|
if (!parsed) return [];
|
|
6480
8316
|
const rawDeps = Array.isArray(parsed.dependencies) ? parsed.dependencies : [];
|
|
6481
8317
|
const specs = [];
|
|
@@ -6491,7 +8327,7 @@ function readVcpkgJsonDependencySpecs(path) {
|
|
|
6491
8327
|
}
|
|
6492
8328
|
function readConanfileTxtDependencySpecs(path) {
|
|
6493
8329
|
const specs = [];
|
|
6494
|
-
const contents =
|
|
8330
|
+
const contents = readFileSync6(path, "utf8");
|
|
6495
8331
|
const requiresMatch = /^\[requires\]([\s\S]*?)(?=^\[|$(?![\s\S]))/m.exec(contents);
|
|
6496
8332
|
if (!requiresMatch) return specs;
|
|
6497
8333
|
for (const line of (requiresMatch[1] ?? "").split("\n")) {
|
|
@@ -6504,7 +8340,7 @@ function readConanfileTxtDependencySpecs(path) {
|
|
|
6504
8340
|
}
|
|
6505
8341
|
function readConanfilePyDependencySpecs(path) {
|
|
6506
8342
|
const specs = [];
|
|
6507
|
-
const contents =
|
|
8343
|
+
const contents = readFileSync6(path, "utf8");
|
|
6508
8344
|
for (const match of contents.matchAll(/self\.requires\s*\(\s*["']([\w.\-]+)\/([\w.\-]+)["']/g)) {
|
|
6509
8345
|
specs.push({ name: match[1] ?? "", version: match[2] ?? "" });
|
|
6510
8346
|
}
|
|
@@ -6518,7 +8354,7 @@ function readConanfilePyDependencySpecs(path) {
|
|
|
6518
8354
|
}
|
|
6519
8355
|
function readCMakeDependencySpecs(path) {
|
|
6520
8356
|
const specs = [];
|
|
6521
|
-
const contents =
|
|
8357
|
+
const contents = readFileSync6(path, "utf8");
|
|
6522
8358
|
for (const match of contents.matchAll(/find_package\s*\(\s*([\w]+)(?:\s+([\d.]+))?/gi)) {
|
|
6523
8359
|
const name = match[1];
|
|
6524
8360
|
if (!name) continue;
|
|
@@ -6533,7 +8369,7 @@ function readCMakeDependencySpecs(path) {
|
|
|
6533
8369
|
return specs;
|
|
6534
8370
|
}
|
|
6535
8371
|
function readPackageJsonDependencySpecs(packageJsonPath) {
|
|
6536
|
-
const parsed = parseJsonObject(
|
|
8372
|
+
const parsed = parseJsonObject(readFileSync6(packageJsonPath, "utf8"));
|
|
6537
8373
|
if (!parsed) return [];
|
|
6538
8374
|
const optionalPeerNames = /* @__PURE__ */ new Set();
|
|
6539
8375
|
const peerDependenciesMeta = parsed.peerDependenciesMeta;
|
|
@@ -6560,7 +8396,7 @@ function readPackageJsonDependencySpecs(packageJsonPath) {
|
|
|
6560
8396
|
return specs;
|
|
6561
8397
|
}
|
|
6562
8398
|
function readRequirementsDependencySpecs(path) {
|
|
6563
|
-
return
|
|
8399
|
+
return readFileSync6(path, "utf8").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).map((line) => {
|
|
6564
8400
|
const [name = line, version = ""] = line.split(/[<>=~!]=?/, 2);
|
|
6565
8401
|
return { name: name.trim(), version: line.includes("==") ? version.trim() : line };
|
|
6566
8402
|
});
|
|
@@ -6575,33 +8411,10 @@ function isPinnedDependencyVersion(version) {
|
|
|
6575
8411
|
if (trimmed === "find") return false;
|
|
6576
8412
|
return /^\d+\.\d+(?:\.\d+)?(?:[-+][0-9A-Za-z.-]+)?$/.test(trimmed);
|
|
6577
8413
|
}
|
|
6578
|
-
function readClaimRealityStats(repoPath) {
|
|
6579
|
-
const path = join(repoPath, "docs/witan/claim_reality_reconciliation.json");
|
|
6580
|
-
if (!isRegularFile(path)) return null;
|
|
6581
|
-
const parsed = parseJsonObject(readFileSync(path, "utf8"));
|
|
6582
|
-
const claims = Array.isArray(parsed?.claims) ? parsed.claims : [];
|
|
6583
|
-
if (claims.length === 0) return null;
|
|
6584
|
-
const totalScore = claims.reduce((sum, claim) => {
|
|
6585
|
-
if (!isRecord(claim) || typeof claim.status !== "string") return sum;
|
|
6586
|
-
return sum + scoreClaimRealityStatus(claim.status);
|
|
6587
|
-
}, 0);
|
|
6588
|
-
return {
|
|
6589
|
-
claimCount: claims.length,
|
|
6590
|
-
matchRate: Math.round(totalScore / claims.length * 1e3) / 1e3
|
|
6591
|
-
};
|
|
6592
|
-
}
|
|
6593
|
-
function scoreClaimRealityStatus(status) {
|
|
6594
|
-
const normalized = status.toLowerCase();
|
|
6595
|
-
if (/supported|verified|matched|true/.test(normalized) && !/unsupported/.test(normalized)) {
|
|
6596
|
-
return 1;
|
|
6597
|
-
}
|
|
6598
|
-
if (/partial|mixed|needs[-_ ]?evidence/.test(normalized)) return 0.5;
|
|
6599
|
-
return 0;
|
|
6600
|
-
}
|
|
6601
8414
|
function workflowTargetsDefaultBranch(repoPath, file) {
|
|
6602
|
-
const fullPath =
|
|
8415
|
+
const fullPath = join3(repoPath, file);
|
|
6603
8416
|
if (!isRegularFile(fullPath)) return false;
|
|
6604
|
-
const contents =
|
|
8417
|
+
const contents = readFileSync6(fullPath, "utf8").toLowerCase();
|
|
6605
8418
|
return /\bpull_request\b/.test(contents) || /\bbranches:\s*\[[^\]]*\b(main|master)\b[^\]]*\]/.test(contents) || /\bbranches:\s*\n\s*-\s*(main|master)\b/.test(contents);
|
|
6606
8419
|
}
|
|
6607
8420
|
function isPrMergeCommit(commit) {
|
|
@@ -6688,15 +8501,15 @@ function isDependencyUpdateConfig(file) {
|
|
|
6688
8501
|
}
|
|
6689
8502
|
function packageJsonHasAuditScript(repoPath, manifest) {
|
|
6690
8503
|
if (!manifest.endsWith("package.json")) return false;
|
|
6691
|
-
const scripts = readPackageScripts(
|
|
8504
|
+
const scripts = readPackageScripts(join3(repoPath, manifest));
|
|
6692
8505
|
return [...scripts.values()].some(
|
|
6693
8506
|
(script) => /\b(audit|npm audit|pnpm audit|yarn audit)\b/i.test(script)
|
|
6694
8507
|
);
|
|
6695
8508
|
}
|
|
6696
8509
|
function packageJsonHasHeavyTestDependency(repoPath, manifest) {
|
|
6697
|
-
const fullPath =
|
|
8510
|
+
const fullPath = join3(repoPath, manifest);
|
|
6698
8511
|
if (!isRegularFile(fullPath)) return false;
|
|
6699
|
-
const parsed = parseJsonObject(
|
|
8512
|
+
const parsed = parseJsonObject(readFileSync6(fullPath, "utf8"));
|
|
6700
8513
|
if (!parsed) return false;
|
|
6701
8514
|
const names = [
|
|
6702
8515
|
...Object.keys(isRecord(parsed.dependencies) ? parsed.dependencies : {}),
|
|
@@ -6735,20 +8548,20 @@ function findRootPackageJson(repoFiles) {
|
|
|
6735
8548
|
}
|
|
6736
8549
|
function isRegularFile(path) {
|
|
6737
8550
|
try {
|
|
6738
|
-
return
|
|
8551
|
+
return statSync2(path).isFile();
|
|
6739
8552
|
} catch {
|
|
6740
8553
|
return false;
|
|
6741
8554
|
}
|
|
6742
8555
|
}
|
|
6743
8556
|
function fileContains(repoPath, file, pattern) {
|
|
6744
|
-
const fullPath =
|
|
8557
|
+
const fullPath = join3(repoPath, file);
|
|
6745
8558
|
if (!isRegularFile(fullPath)) return false;
|
|
6746
|
-
return pattern.test(
|
|
8559
|
+
return pattern.test(readFileSync6(fullPath, "utf8"));
|
|
6747
8560
|
}
|
|
6748
8561
|
function fileContainsCommittedSecret(repoPath, file) {
|
|
6749
|
-
const fullPath =
|
|
8562
|
+
const fullPath = join3(repoPath, file);
|
|
6750
8563
|
if (!isRegularFile(fullPath)) return false;
|
|
6751
|
-
return containsRealSecret(
|
|
8564
|
+
return containsRealSecret(readFileSync6(fullPath, "utf8"));
|
|
6752
8565
|
}
|
|
6753
8566
|
function containsRealSecret(contents) {
|
|
6754
8567
|
SECRET_ASSIGNMENT_PATTERN.lastIndex = 0;
|
|
@@ -6798,1019 +8611,742 @@ function collectHistorySecretEvidence(repoPath) {
|
|
|
6798
8611
|
function readCredentialHistoryEntries(repoPath) {
|
|
6799
8612
|
const entries = [];
|
|
6800
8613
|
const seen = /* @__PURE__ */ new Set();
|
|
6801
|
-
const appendEntry = (entry) => {
|
|
6802
|
-
const key = `${entry.commit}:${entry.path}`;
|
|
6803
|
-
if (seen.has(key)) return;
|
|
6804
|
-
seen.add(key);
|
|
6805
|
-
entries.push(entry);
|
|
6806
|
-
};
|
|
6807
|
-
try {
|
|
6808
|
-
const commits = execFileSync("git", ["rev-list", "--all"], {
|
|
6809
|
-
cwd: repoPath,
|
|
6810
|
-
encoding: "utf8",
|
|
6811
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6812
|
-
});
|
|
6813
|
-
const output = execFileSync(
|
|
6814
|
-
"git",
|
|
6815
|
-
[
|
|
6816
|
-
"diff-tree",
|
|
6817
|
-
"--stdin",
|
|
6818
|
-
"--root",
|
|
6819
|
-
"--name-only",
|
|
6820
|
-
"-r",
|
|
6821
|
-
"--diff-filter=AM",
|
|
6822
|
-
"--pretty=format:commit:%H"
|
|
6823
|
-
],
|
|
6824
|
-
{
|
|
6825
|
-
cwd: repoPath,
|
|
6826
|
-
encoding: "utf8",
|
|
6827
|
-
input: commits,
|
|
6828
|
-
stdio: ["pipe", "pipe", "ignore"]
|
|
6829
|
-
}
|
|
6830
|
-
);
|
|
6831
|
-
let currentCommit = null;
|
|
6832
|
-
for (const line of output.split("\n")) {
|
|
6833
|
-
if (line.startsWith("commit:")) {
|
|
6834
|
-
currentCommit = line.slice("commit:".length);
|
|
6835
|
-
continue;
|
|
6836
|
-
}
|
|
6837
|
-
const path = line.trim();
|
|
6838
|
-
if (!currentCommit || !path) continue;
|
|
6839
|
-
if (!isCredentialHistoryPath(path)) continue;
|
|
6840
|
-
appendEntry({ commit: currentCommit, path });
|
|
6841
|
-
}
|
|
6842
|
-
} catch {
|
|
6843
|
-
}
|
|
6844
|
-
for (const entry of readDeletedCredentialHistoryEntries(repoPath)) {
|
|
6845
|
-
appendEntry(entry);
|
|
6846
|
-
}
|
|
6847
|
-
return entries;
|
|
6848
|
-
}
|
|
6849
|
-
function readDeletedCredentialHistoryEntries(repoPath) {
|
|
6850
|
-
const deletedPaths = readDeletedCredentialHistoryPaths(repoPath);
|
|
6851
|
-
const entries = [];
|
|
6852
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6853
|
-
for (const path of deletedPaths) {
|
|
6854
|
-
for (const commit of readHistoryCommitsForPath(repoPath, path)) {
|
|
6855
|
-
const key = `${commit}:${path}`;
|
|
6856
|
-
if (seen.has(key)) continue;
|
|
6857
|
-
seen.add(key);
|
|
6858
|
-
entries.push({ commit, path });
|
|
6859
|
-
}
|
|
6860
|
-
}
|
|
6861
|
-
return entries;
|
|
6862
|
-
}
|
|
6863
|
-
function readDeletedCredentialHistoryPaths(repoPath) {
|
|
6864
|
-
try {
|
|
6865
|
-
const output = execFileSync(
|
|
6866
|
-
"git",
|
|
6867
|
-
["log", "--all", "--diff-filter=D", "--name-status", "--format=commit:%H"],
|
|
6868
|
-
{
|
|
6869
|
-
cwd: repoPath,
|
|
6870
|
-
encoding: "utf8",
|
|
6871
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6872
|
-
}
|
|
6873
|
-
);
|
|
6874
|
-
const paths = [];
|
|
6875
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6876
|
-
for (const line of output.split("\n")) {
|
|
6877
|
-
if (!line.startsWith("D ")) continue;
|
|
6878
|
-
const path = line.slice(2).trim();
|
|
6879
|
-
if (!path || seen.has(path)) continue;
|
|
6880
|
-
if (!isCredentialHistoryPath(path)) continue;
|
|
6881
|
-
seen.add(path);
|
|
6882
|
-
paths.push(path);
|
|
6883
|
-
}
|
|
6884
|
-
return paths;
|
|
6885
|
-
} catch {
|
|
6886
|
-
return [];
|
|
6887
|
-
}
|
|
6888
|
-
}
|
|
6889
|
-
function readHistoryCommitsForPath(repoPath, path) {
|
|
6890
|
-
try {
|
|
6891
|
-
const output = execFileSync(
|
|
6892
|
-
"git",
|
|
6893
|
-
["log", "--all", "--diff-filter=AM", "--format=%H", "--", path],
|
|
6894
|
-
{
|
|
6895
|
-
cwd: repoPath,
|
|
6896
|
-
encoding: "utf8",
|
|
6897
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6898
|
-
}
|
|
6899
|
-
);
|
|
6900
|
-
return output.split("\n").map((line) => line.trim()).filter((line) => /^[0-9a-f]{40}$/i.test(line));
|
|
6901
|
-
} catch {
|
|
6902
|
-
return [];
|
|
6903
|
-
}
|
|
6904
|
-
}
|
|
6905
|
-
function isCredentialHistoryPath(path) {
|
|
6906
|
-
if (isHardExcludedPath(path)) return false;
|
|
6907
|
-
const lowerPath = path.toLowerCase();
|
|
6908
|
-
const basename3 = lowerPath.split("/").at(-1) ?? lowerPath;
|
|
6909
|
-
if (/\.env(?:\.|$)/.test(basename3)) {
|
|
6910
|
-
return true;
|
|
6911
|
-
}
|
|
6912
|
-
return lowerPath.includes("secret") || lowerPath.includes("credential") || basename3.endsWith(".pem") || basename3.endsWith(".key") || basename3 === "id_rsa" || basename3.endsWith(".p12") || basename3.endsWith(".pfx");
|
|
6913
|
-
}
|
|
6914
|
-
function isEnvHistoryPath(path) {
|
|
6915
|
-
if (isEnvTemplatePath(path)) return false;
|
|
6916
|
-
const basename3 = path.toLowerCase().split("/").at(-1) ?? path.toLowerCase();
|
|
6917
|
-
return /\.env(?:\.|$)/.test(basename3);
|
|
6918
|
-
}
|
|
6919
|
-
function readGitBlob(repoPath, commit, path) {
|
|
6920
|
-
try {
|
|
6921
|
-
return execFileSync("git", ["show", `${commit}:${path}`], {
|
|
6922
|
-
cwd: repoPath,
|
|
6923
|
-
encoding: "utf8",
|
|
6924
|
-
maxBuffer: 512e3,
|
|
6925
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6926
|
-
});
|
|
6927
|
-
} catch {
|
|
6928
|
-
return null;
|
|
6929
|
-
}
|
|
6930
|
-
}
|
|
6931
|
-
var ALL_CAPS_SNAKE_PLACEHOLDER_PATTERN = /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+$/;
|
|
6932
|
-
function isPlaceholderSecretValue(value) {
|
|
6933
|
-
const normalized = value.trim().toLowerCase();
|
|
6934
|
-
return PLACEHOLDER_SECRET_PATTERN.test(normalized) || normalized.includes("your-") || normalized.includes("example") || ALL_CAPS_SNAKE_PLACEHOLDER_PATTERN.test(value.trim()) || isSyntheticFixtureSecretValue(normalized) || isFillerRunSecretValue(normalized);
|
|
6935
|
-
}
|
|
6936
|
-
function isFillerRunSecretValue(value) {
|
|
6937
|
-
const candidates = [value];
|
|
6938
|
-
const sepIdx = Math.max(value.lastIndexOf("_"), value.lastIndexOf("-"));
|
|
6939
|
-
if (sepIdx > 0 && sepIdx < value.length - 1) {
|
|
6940
|
-
candidates.push(value.slice(sepIdx + 1));
|
|
6941
|
-
}
|
|
6942
|
-
for (const body of candidates) {
|
|
6943
|
-
if (body.length < 8) continue;
|
|
6944
|
-
const counts = /* @__PURE__ */ new Map();
|
|
6945
|
-
for (const ch of body) counts.set(ch, (counts.get(ch) ?? 0) + 1);
|
|
6946
|
-
const distinct = counts.size;
|
|
6947
|
-
const maxRun = Math.max(...counts.values());
|
|
6948
|
-
if (distinct <= 2 && maxRun / body.length >= 0.8) return true;
|
|
6949
|
-
}
|
|
6950
|
-
return false;
|
|
6951
|
-
}
|
|
6952
|
-
function isSyntheticFixtureSecretValue(value) {
|
|
6953
|
-
return value.includes("abcdefghijklmnopqrstuvwxyz") || value.includes("0123456789abcdefghijklmnopqrstuvwxyz") || value.includes("abcdefghijklmnopqrstuvwxyz0123456789") || value.includes("abcdefghijklmnopqrst");
|
|
6954
|
-
}
|
|
6955
|
-
function hasSuspiciousDependencies(repoPath, manifest) {
|
|
6956
|
-
if (!manifest.endsWith("package.json")) return false;
|
|
6957
|
-
const fullPath = join(repoPath, manifest);
|
|
6958
|
-
if (!isRegularFile(fullPath)) return false;
|
|
6959
|
-
const parsed = parseJsonObject(readFileSync(fullPath, "utf8"));
|
|
6960
|
-
if (!parsed) return false;
|
|
6961
|
-
const dependencies = isRecord(parsed.dependencies) ? parsed.dependencies : {};
|
|
6962
|
-
const devDependencies = isRecord(parsed.devDependencies) ? parsed.devDependencies : {};
|
|
6963
|
-
const names = [...Object.keys(dependencies), ...Object.keys(devDependencies)];
|
|
6964
|
-
return names.some(
|
|
6965
|
-
(name) => /^(todo|fake|placeholder|example)-|does-not-exist| hallucinated/i.test(name)
|
|
6966
|
-
);
|
|
6967
|
-
}
|
|
6968
|
-
function readRecentCommits(repoPath) {
|
|
6969
|
-
try {
|
|
6970
|
-
const output = execFileSync("git", ["log", "--max-count=12", "--format=%H%x00%s"], {
|
|
6971
|
-
cwd: repoPath,
|
|
6972
|
-
encoding: "utf8",
|
|
6973
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6974
|
-
}).trim();
|
|
6975
|
-
if (!output) return [];
|
|
6976
|
-
return output.split("\n").map((line) => {
|
|
6977
|
-
const [sha = "", subject = ""] = line.split("\0");
|
|
6978
|
-
return { sha, subject };
|
|
6979
|
-
}).filter((commit) => commit.sha.length >= 7);
|
|
6980
|
-
} catch {
|
|
6981
|
-
return [];
|
|
6982
|
-
}
|
|
6983
|
-
}
|
|
6984
|
-
function readPackageScripts(packageJsonPath) {
|
|
6985
|
-
if (!isRegularFile(packageJsonPath)) return /* @__PURE__ */ new Map();
|
|
6986
|
-
const parsed = parseJsonObject(readFileSync(packageJsonPath, "utf8"));
|
|
6987
|
-
const scripts = parsed?.scripts;
|
|
6988
|
-
if (!isRecord(scripts)) return /* @__PURE__ */ new Map();
|
|
6989
|
-
return new Map(
|
|
6990
|
-
Object.entries(scripts).filter(
|
|
6991
|
-
(entry) => typeof entry[1] === "string"
|
|
6992
|
-
)
|
|
6993
|
-
);
|
|
6994
|
-
}
|
|
6995
|
-
function evidenceForRelative(repoPath, path, kind, label) {
|
|
6996
|
-
const fullPath = join(repoPath, path);
|
|
6997
|
-
const contents = isRegularFile(fullPath) ? readFileSync(fullPath, "utf8") : "";
|
|
6998
|
-
return {
|
|
6999
|
-
kind,
|
|
7000
|
-
label,
|
|
7001
|
-
path,
|
|
7002
|
-
...contents ? {
|
|
7003
|
-
line: firstMeaningfulLine(contents),
|
|
7004
|
-
contentHash: createHash("sha256").update(contents).digest("hex")
|
|
7005
|
-
} : {}
|
|
7006
|
-
};
|
|
7007
|
-
}
|
|
7008
|
-
function metric(name, label, value, max, weight, unit, description, kind) {
|
|
7009
|
-
return {
|
|
7010
|
-
name,
|
|
7011
|
-
label,
|
|
7012
|
-
value: Math.max(0, value),
|
|
7013
|
-
max,
|
|
7014
|
-
...kind ? { kind } : {},
|
|
7015
|
-
weight,
|
|
7016
|
-
unit,
|
|
7017
|
-
description
|
|
7018
|
-
};
|
|
7019
|
-
}
|
|
7020
|
-
function firstMeaningfulLine(contents) {
|
|
7021
|
-
const lines = contents.split("\n");
|
|
7022
|
-
const index = lines.findIndex((line) => line.trim().length > 0);
|
|
7023
|
-
return index === -1 ? 1 : index + 1;
|
|
7024
|
-
}
|
|
7025
|
-
function readGitHead(repoPath) {
|
|
8614
|
+
const appendEntry = (entry) => {
|
|
8615
|
+
const key = `${entry.commit}:${entry.path}`;
|
|
8616
|
+
if (seen.has(key)) return;
|
|
8617
|
+
seen.add(key);
|
|
8618
|
+
entries.push(entry);
|
|
8619
|
+
};
|
|
7026
8620
|
try {
|
|
7027
|
-
|
|
8621
|
+
const commits = execFileSync("git", ["rev-list", "--all"], {
|
|
7028
8622
|
cwd: repoPath,
|
|
7029
8623
|
encoding: "utf8",
|
|
7030
8624
|
stdio: ["ignore", "pipe", "ignore"]
|
|
7031
|
-
})
|
|
7032
|
-
} catch {
|
|
7033
|
-
return null;
|
|
7034
|
-
}
|
|
7035
|
-
}
|
|
7036
|
-
function hasEnvPathInGitHistory(repoPath) {
|
|
7037
|
-
try {
|
|
8625
|
+
});
|
|
7038
8626
|
const output = execFileSync(
|
|
7039
8627
|
"git",
|
|
7040
|
-
[
|
|
8628
|
+
[
|
|
8629
|
+
"diff-tree",
|
|
8630
|
+
"--stdin",
|
|
8631
|
+
"--root",
|
|
8632
|
+
"--name-only",
|
|
8633
|
+
"-r",
|
|
8634
|
+
"--diff-filter=AM",
|
|
8635
|
+
"--pretty=format:commit:%H"
|
|
8636
|
+
],
|
|
7041
8637
|
{
|
|
7042
8638
|
cwd: repoPath,
|
|
7043
8639
|
encoding: "utf8",
|
|
7044
|
-
|
|
7045
|
-
|
|
8640
|
+
input: commits,
|
|
8641
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
7046
8642
|
}
|
|
7047
|
-
)
|
|
7048
|
-
|
|
7049
|
-
|
|
8643
|
+
);
|
|
8644
|
+
let currentCommit = null;
|
|
8645
|
+
for (const line of output.split("\n")) {
|
|
8646
|
+
if (line.startsWith("commit:")) {
|
|
8647
|
+
currentCommit = line.slice("commit:".length);
|
|
8648
|
+
continue;
|
|
8649
|
+
}
|
|
8650
|
+
const path = line.trim();
|
|
8651
|
+
if (!currentCommit || !path) continue;
|
|
8652
|
+
if (!isCredentialHistoryPath(path)) continue;
|
|
8653
|
+
appendEntry({ commit: currentCommit, path });
|
|
8654
|
+
}
|
|
7050
8655
|
} catch {
|
|
7051
|
-
return false;
|
|
7052
8656
|
}
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
// src/witan/rubric.ts
|
|
7056
|
-
var WITAN_RUBRIC = [
|
|
7057
|
-
{
|
|
7058
|
-
id: "A1",
|
|
7059
|
-
title: "Test integrity and regression signal",
|
|
7060
|
-
category: "code_trust"
|
|
7061
|
-
},
|
|
7062
|
-
{
|
|
7063
|
-
id: "A2",
|
|
7064
|
-
title: "Data-layer isolation and secrets posture",
|
|
7065
|
-
category: "code_trust"
|
|
7066
|
-
},
|
|
7067
|
-
{
|
|
7068
|
-
id: "A3",
|
|
7069
|
-
title: "Production readiness",
|
|
7070
|
-
category: "code_trust"
|
|
7071
|
-
},
|
|
7072
|
-
{
|
|
7073
|
-
id: "A4",
|
|
7074
|
-
title: "Dependency hygiene",
|
|
7075
|
-
category: "code_trust"
|
|
7076
|
-
},
|
|
7077
|
-
{
|
|
7078
|
-
id: "A5",
|
|
7079
|
-
title: "Claim-vs-reality reconciliation",
|
|
7080
|
-
category: "code_trust"
|
|
7081
|
-
},
|
|
7082
|
-
{
|
|
7083
|
-
id: "B1",
|
|
7084
|
-
title: "Dispatch trace completeness",
|
|
7085
|
-
category: "process_trust"
|
|
7086
|
-
},
|
|
7087
|
-
{
|
|
7088
|
-
id: "B2",
|
|
7089
|
-
title: "PR outcome traceability",
|
|
7090
|
-
category: "process_trust"
|
|
7091
|
-
},
|
|
7092
|
-
{
|
|
7093
|
-
id: "B3",
|
|
7094
|
-
title: "CI and QA discipline",
|
|
7095
|
-
category: "process_trust"
|
|
7096
|
-
},
|
|
7097
|
-
{
|
|
7098
|
-
id: "B4",
|
|
7099
|
-
title: "Audit trail and report-up completeness",
|
|
7100
|
-
category: "process_trust"
|
|
7101
|
-
},
|
|
7102
|
-
{
|
|
7103
|
-
id: "B5",
|
|
7104
|
-
title: "Verified learning trace",
|
|
7105
|
-
category: "process_trust"
|
|
7106
|
-
},
|
|
7107
|
-
{
|
|
7108
|
-
id: "B6",
|
|
7109
|
-
title: "Privileged-operation human gating",
|
|
7110
|
-
category: "process_trust"
|
|
8657
|
+
for (const entry of readDeletedCredentialHistoryEntries(repoPath)) {
|
|
8658
|
+
appendEntry(entry);
|
|
7111
8659
|
}
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
const
|
|
7118
|
-
const
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
bucket.push(signal);
|
|
7125
|
-
inputSignalsByDimension.set(signal.dimension, bucket);
|
|
8660
|
+
return entries;
|
|
8661
|
+
}
|
|
8662
|
+
function readDeletedCredentialHistoryEntries(repoPath) {
|
|
8663
|
+
const deletedPaths = readDeletedCredentialHistoryPaths(repoPath);
|
|
8664
|
+
const entries = [];
|
|
8665
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8666
|
+
for (const path of deletedPaths) {
|
|
8667
|
+
for (const commit of readHistoryCommitsForPath(repoPath, path)) {
|
|
8668
|
+
const key = `${commit}:${path}`;
|
|
8669
|
+
if (seen.has(key)) continue;
|
|
8670
|
+
seen.add(key);
|
|
8671
|
+
entries.push({ commit, path });
|
|
7126
8672
|
}
|
|
7127
8673
|
}
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
const
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
status: scored.status,
|
|
7141
|
-
evidence: scored.evidence,
|
|
7142
|
-
findings: scored.findings,
|
|
7143
|
-
metrics: scored.metrics,
|
|
7144
|
-
...signal?.notes ? { notes: signal.notes } : {}
|
|
7145
|
-
};
|
|
7146
|
-
}
|
|
7147
|
-
const { adjustedScore, adjustment, summaries } = applySignalAdjustment(
|
|
7148
|
-
scored.score,
|
|
7149
|
-
id,
|
|
7150
|
-
dimensionSignals
|
|
8674
|
+
return entries;
|
|
8675
|
+
}
|
|
8676
|
+
function readDeletedCredentialHistoryPaths(repoPath) {
|
|
8677
|
+
try {
|
|
8678
|
+
const output = execFileSync(
|
|
8679
|
+
"git",
|
|
8680
|
+
["log", "--all", "--diff-filter=D", "--name-status", "--format=commit:%H"],
|
|
8681
|
+
{
|
|
8682
|
+
cwd: repoPath,
|
|
8683
|
+
encoding: "utf8",
|
|
8684
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
8685
|
+
}
|
|
7151
8686
|
);
|
|
7152
|
-
|
|
7153
|
-
const
|
|
7154
|
-
const
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
status: finalStatus,
|
|
7162
|
-
evidence: scored.evidence,
|
|
7163
|
-
findings: scored.findings,
|
|
7164
|
-
metrics: scored.metrics,
|
|
7165
|
-
...signal?.notes ? { notes: signal.notes } : {}
|
|
7166
|
-
};
|
|
7167
|
-
});
|
|
7168
|
-
const categoryOrder = [];
|
|
7169
|
-
for (const rubricCriterion of rubric) {
|
|
7170
|
-
if (!categoryOrder.includes(rubricCriterion.category)) {
|
|
7171
|
-
categoryOrder.push(rubricCriterion.category);
|
|
8687
|
+
const paths = [];
|
|
8688
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8689
|
+
for (const line of output.split("\n")) {
|
|
8690
|
+
if (!line.startsWith("D ")) continue;
|
|
8691
|
+
const path = line.slice(2).trim();
|
|
8692
|
+
if (!path || seen.has(path)) continue;
|
|
8693
|
+
if (!isCredentialHistoryPath(path)) continue;
|
|
8694
|
+
seen.add(path);
|
|
8695
|
+
paths.push(path);
|
|
7172
8696
|
}
|
|
8697
|
+
return paths;
|
|
8698
|
+
} catch {
|
|
8699
|
+
return [];
|
|
7173
8700
|
}
|
|
7174
|
-
const categoryScoreMap = {};
|
|
7175
|
-
for (const category of categoryOrder) {
|
|
7176
|
-
categoryScoreMap[category] = averageScore(
|
|
7177
|
-
criteria.filter((criterion) => criterion.category === category)
|
|
7178
|
-
);
|
|
7179
|
-
}
|
|
7180
|
-
const firstCategory = categoryOrder[0];
|
|
7181
|
-
const secondCategory = categoryOrder[1] ?? firstCategory;
|
|
7182
|
-
const codeTrustScore = categoryScoreMap.code_trust ?? (firstCategory ? categoryScoreMap[firstCategory] : void 0) ?? 0;
|
|
7183
|
-
const processTrustScore = categoryScoreMap.process_trust ?? (secondCategory ? categoryScoreMap[secondCategory] : void 0) ?? 0;
|
|
7184
|
-
const overallScore = roundScore(
|
|
7185
|
-
categoryOrder.reduce((sum, category) => sum + (categoryScoreMap[category] ?? 0), 0) / Math.max(categoryOrder.length, 1)
|
|
7186
|
-
);
|
|
7187
|
-
return WitanReportSchema.parse({
|
|
7188
|
-
productSlug: parsedInput.productSlug,
|
|
7189
|
-
productDisplayName: parsedInput.productDisplayName,
|
|
7190
|
-
repo: parsedInput.repo,
|
|
7191
|
-
generatedAt: parsedInput.generatedAt,
|
|
7192
|
-
rubricVersion: parsedInput.rubricVersion,
|
|
7193
|
-
codeTrustScore,
|
|
7194
|
-
processTrustScore,
|
|
7195
|
-
overallScore,
|
|
7196
|
-
criteria,
|
|
7197
|
-
...consumedSignals.length > 0 ? { consumedSignals } : {},
|
|
7198
|
-
// Only surface the full per-category map for rubrics with more than two buckets —
|
|
7199
|
-
// the default two-category rubric is fully represented by codeTrustScore/processTrustScore.
|
|
7200
|
-
...categoryOrder.length > 2 ? { categoryScores: categoryScoreMap } : {},
|
|
7201
|
-
// Pass through repo-archetype metadata verbatim — createWitanReport does not compute or
|
|
7202
|
-
// alter it (see classifyRepoArchetype in repo-signals.ts); per-criterion scoring above is
|
|
7203
|
-
// unaffected by archetype, only presentation layers (badge/terminal/verdict) key off it.
|
|
7204
|
-
...parsedInput.archetype ? { archetype: parsedInput.archetype } : {},
|
|
7205
|
-
...parsedInput.insufficientSourceReason ? { insufficientSourceReason: parsedInput.insufficientSourceReason } : {}
|
|
7206
|
-
});
|
|
7207
8701
|
}
|
|
7208
|
-
function
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
);
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
source: signal.source,
|
|
7223
|
-
dimension,
|
|
7224
|
-
findingCount: signal.findings.length,
|
|
7225
|
-
severityBreakdown: { critical: criticalCount, warning: warningCount, info: infoCount },
|
|
7226
|
-
nativeScore,
|
|
7227
|
-
scoreAdjustment: -roundScore(Math.min(signalAdj, MAX_SIGNAL_ADJUSTMENT)),
|
|
7228
|
-
adjustedScore: roundScore(
|
|
7229
|
-
Math.max(0, nativeScore - Math.min(signalAdj, MAX_SIGNAL_ADJUSTMENT))
|
|
7230
|
-
),
|
|
7231
|
-
findings: [...signal.findings]
|
|
7232
|
-
});
|
|
8702
|
+
function readHistoryCommitsForPath(repoPath, path) {
|
|
8703
|
+
try {
|
|
8704
|
+
const output = execFileSync(
|
|
8705
|
+
"git",
|
|
8706
|
+
["log", "--all", "--diff-filter=AM", "--format=%H", "--", path],
|
|
8707
|
+
{
|
|
8708
|
+
cwd: repoPath,
|
|
8709
|
+
encoding: "utf8",
|
|
8710
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
8711
|
+
}
|
|
8712
|
+
);
|
|
8713
|
+
return output.split("\n").map((line) => line.trim()).filter((line) => /^[0-9a-f]{40}$/i.test(line));
|
|
8714
|
+
} catch {
|
|
8715
|
+
return [];
|
|
7233
8716
|
}
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
8717
|
+
}
|
|
8718
|
+
function isCredentialHistoryPath(path) {
|
|
8719
|
+
if (isHardExcludedPath(path)) return false;
|
|
8720
|
+
const lowerPath = path.toLowerCase();
|
|
8721
|
+
const basename4 = lowerPath.split("/").at(-1) ?? lowerPath;
|
|
8722
|
+
if (/\.env(?:\.|$)/.test(basename4)) {
|
|
8723
|
+
return true;
|
|
7239
8724
|
}
|
|
7240
|
-
return
|
|
8725
|
+
return lowerPath.includes("secret") || lowerPath.includes("credential") || basename4.endsWith(".pem") || basename4.endsWith(".key") || basename4 === "id_rsa" || basename4.endsWith(".p12") || basename4.endsWith(".pfx");
|
|
7241
8726
|
}
|
|
7242
|
-
function
|
|
7243
|
-
if (
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
if (score > 0) return "critical";
|
|
7247
|
-
return "critical";
|
|
8727
|
+
function isEnvHistoryPath(path) {
|
|
8728
|
+
if (isEnvTemplatePath(path)) return false;
|
|
8729
|
+
const basename4 = path.toLowerCase().split("/").at(-1) ?? path.toLowerCase();
|
|
8730
|
+
return /\.env(?:\.|$)/.test(basename4);
|
|
7248
8731
|
}
|
|
7249
|
-
function
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
}
|
|
7257
|
-
merged.set(signal.criterionId, {
|
|
7258
|
-
criterionId: signal.criterionId,
|
|
7259
|
-
positiveEvidence: [...existing.positiveEvidence, ...signal.positiveEvidence],
|
|
7260
|
-
findings: [...existing.findings, ...signal.findings],
|
|
7261
|
-
metrics: [...existing.metrics ?? [], ...signal.metrics ?? []],
|
|
7262
|
-
notes: signal.notes ?? existing.notes,
|
|
7263
|
-
// N/A wins on merge: if either signal is N/A, the criterion is N/A.
|
|
7264
|
-
...existing.notApplicable === true || signal.notApplicable === true ? { notApplicable: true } : {}
|
|
8732
|
+
function readGitBlob(repoPath, commit, path) {
|
|
8733
|
+
try {
|
|
8734
|
+
return execFileSync("git", ["show", `${commit}:${path}`], {
|
|
8735
|
+
cwd: repoPath,
|
|
8736
|
+
encoding: "utf8",
|
|
8737
|
+
maxBuffer: 512e3,
|
|
8738
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
7265
8739
|
});
|
|
8740
|
+
} catch {
|
|
8741
|
+
return null;
|
|
7266
8742
|
}
|
|
7267
|
-
return merged;
|
|
7268
|
-
}
|
|
7269
|
-
function usesMetricScoring(rubricVersion) {
|
|
7270
|
-
return rubricVersion === WITAN_RUBRIC_VERSION_V1 || rubricVersion === WITAN_RUBRIC_VERSION_V2 || rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0;
|
|
7271
8743
|
}
|
|
7272
|
-
|
|
7273
|
-
|
|
8744
|
+
var ALL_CAPS_SNAKE_PLACEHOLDER_PATTERN = /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+$/;
|
|
8745
|
+
function isPlaceholderSecretValue(value) {
|
|
8746
|
+
const normalized = value.trim().toLowerCase();
|
|
8747
|
+
return PLACEHOLDER_SECRET_PATTERN.test(normalized) || normalized.includes("your-") || normalized.includes("example") || ALL_CAPS_SNAKE_PLACEHOLDER_PATTERN.test(value.trim()) || isSyntheticFixtureSecretValue(normalized) || isFillerRunSecretValue(normalized);
|
|
7274
8748
|
}
|
|
7275
|
-
function
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
evidence: [],
|
|
7281
|
-
findings: [],
|
|
7282
|
-
metrics: []
|
|
7283
|
-
};
|
|
7284
|
-
}
|
|
7285
|
-
if (signal.notApplicable === true) {
|
|
7286
|
-
return {
|
|
7287
|
-
score: 0,
|
|
7288
|
-
status: "not_applicable",
|
|
7289
|
-
evidence: [],
|
|
7290
|
-
findings: [],
|
|
7291
|
-
metrics: []
|
|
7292
|
-
};
|
|
7293
|
-
}
|
|
7294
|
-
const evidence = signal.positiveEvidence;
|
|
7295
|
-
const findings = signal.findings;
|
|
7296
|
-
const metrics = signal.metrics ?? [];
|
|
7297
|
-
const evidenceCount = evidence.length + findings.length;
|
|
7298
|
-
if (evidenceCount === 0) {
|
|
7299
|
-
if (!usesMetricScoring(rubricVersion) || metrics.length === 0) {
|
|
7300
|
-
return {
|
|
7301
|
-
score: 0,
|
|
7302
|
-
status: unmeasuredStatus(rubricVersion),
|
|
7303
|
-
evidence,
|
|
7304
|
-
findings,
|
|
7305
|
-
metrics
|
|
7306
|
-
};
|
|
7307
|
-
}
|
|
7308
|
-
}
|
|
7309
|
-
if (usesMetricScoring(rubricVersion)) {
|
|
7310
|
-
const measuredMetrics = metrics.length > 0 ? metrics : fallbackMetricsForEvidence(evidence, findings);
|
|
7311
|
-
const score = capScoreForFindings(scoreMetrics(measuredMetrics), findings);
|
|
7312
|
-
const status = statusForScoreAndFindings(score, findings);
|
|
7313
|
-
return {
|
|
7314
|
-
score,
|
|
7315
|
-
status,
|
|
7316
|
-
evidence,
|
|
7317
|
-
findings: ensureFindingsExplainStatus(signal.criterionId, score, status, findings, evidence),
|
|
7318
|
-
metrics: measuredMetrics
|
|
7319
|
-
};
|
|
7320
|
-
}
|
|
7321
|
-
if (findings.some((finding) => finding.severity === "critical")) {
|
|
7322
|
-
return {
|
|
7323
|
-
score: 1,
|
|
7324
|
-
status: "critical",
|
|
7325
|
-
evidence,
|
|
7326
|
-
findings,
|
|
7327
|
-
metrics
|
|
7328
|
-
};
|
|
7329
|
-
}
|
|
7330
|
-
if (findings.some((finding) => finding.severity === "warning")) {
|
|
7331
|
-
return {
|
|
7332
|
-
score: 2,
|
|
7333
|
-
status: "warning",
|
|
7334
|
-
evidence,
|
|
7335
|
-
findings,
|
|
7336
|
-
metrics
|
|
7337
|
-
};
|
|
8749
|
+
function isFillerRunSecretValue(value) {
|
|
8750
|
+
const candidates = [value];
|
|
8751
|
+
const sepIdx = Math.max(value.lastIndexOf("_"), value.lastIndexOf("-"));
|
|
8752
|
+
if (sepIdx > 0 && sepIdx < value.length - 1) {
|
|
8753
|
+
candidates.push(value.slice(sepIdx + 1));
|
|
7338
8754
|
}
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
};
|
|
8755
|
+
for (const body of candidates) {
|
|
8756
|
+
if (body.length < 8) continue;
|
|
8757
|
+
const counts = /* @__PURE__ */ new Map();
|
|
8758
|
+
for (const ch of body) counts.set(ch, (counts.get(ch) ?? 0) + 1);
|
|
8759
|
+
const distinct = counts.size;
|
|
8760
|
+
const maxRun = Math.max(...counts.values());
|
|
8761
|
+
if (distinct <= 2 && maxRun / body.length >= 0.8) return true;
|
|
7347
8762
|
}
|
|
7348
|
-
return
|
|
7349
|
-
score: 4,
|
|
7350
|
-
status: "verified",
|
|
7351
|
-
evidence,
|
|
7352
|
-
findings,
|
|
7353
|
-
metrics
|
|
7354
|
-
};
|
|
8763
|
+
return false;
|
|
7355
8764
|
}
|
|
7356
|
-
function
|
|
7357
|
-
return
|
|
7358
|
-
{
|
|
7359
|
-
name: "evidence_depth",
|
|
7360
|
-
label: "Evidence depth",
|
|
7361
|
-
value: Math.min(evidence.length + findings.length + 1, 4),
|
|
7362
|
-
max: 4,
|
|
7363
|
-
weight: 1,
|
|
7364
|
-
unit: "signals",
|
|
7365
|
-
description: "Conservative v1 fallback for externally supplied evidence that has not provided criterion-specific depth metrics."
|
|
7366
|
-
}
|
|
7367
|
-
];
|
|
8765
|
+
function isSyntheticFixtureSecretValue(value) {
|
|
8766
|
+
return value.includes("abcdefghijklmnopqrstuvwxyz") || value.includes("0123456789abcdefghijklmnopqrstuvwxyz") || value.includes("abcdefghijklmnopqrstuvwxyz0123456789") || value.includes("abcdefghijklmnopqrst");
|
|
7368
8767
|
}
|
|
7369
|
-
function
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
}
|
|
7377
|
-
|
|
7378
|
-
return
|
|
8768
|
+
function hasSuspiciousDependencies(repoPath, manifest) {
|
|
8769
|
+
if (!manifest.endsWith("package.json")) return false;
|
|
8770
|
+
const fullPath = join3(repoPath, manifest);
|
|
8771
|
+
if (!isRegularFile(fullPath)) return false;
|
|
8772
|
+
const parsed = parseJsonObject(readFileSync6(fullPath, "utf8"));
|
|
8773
|
+
if (!parsed) return false;
|
|
8774
|
+
const dependencies = isRecord(parsed.dependencies) ? parsed.dependencies : {};
|
|
8775
|
+
const devDependencies = isRecord(parsed.devDependencies) ? parsed.devDependencies : {};
|
|
8776
|
+
const names = [...Object.keys(dependencies), ...Object.keys(devDependencies)];
|
|
8777
|
+
return names.some(
|
|
8778
|
+
(name) => /^(todo|fake|placeholder|example)-|does-not-exist| hallucinated/i.test(name)
|
|
8779
|
+
);
|
|
7379
8780
|
}
|
|
7380
|
-
function
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
8781
|
+
function readRecentCommits(repoPath) {
|
|
8782
|
+
try {
|
|
8783
|
+
const output = execFileSync("git", ["log", "--max-count=12", "--format=%H%x00%s"], {
|
|
8784
|
+
cwd: repoPath,
|
|
8785
|
+
encoding: "utf8",
|
|
8786
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
8787
|
+
}).trim();
|
|
8788
|
+
if (!output) return [];
|
|
8789
|
+
return output.split("\n").map((line) => {
|
|
8790
|
+
const [sha = "", subject = ""] = line.split("\0");
|
|
8791
|
+
return { sha, subject };
|
|
8792
|
+
}).filter((commit) => commit.sha.length >= 7);
|
|
8793
|
+
} catch {
|
|
8794
|
+
return [];
|
|
8795
|
+
}
|
|
7385
8796
|
}
|
|
7386
|
-
function
|
|
7387
|
-
if (
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
if (
|
|
7391
|
-
|
|
7392
|
-
|
|
8797
|
+
function readPackageScripts(packageJsonPath) {
|
|
8798
|
+
if (!isRegularFile(packageJsonPath)) return /* @__PURE__ */ new Map();
|
|
8799
|
+
const parsed = parseJsonObject(readFileSync6(packageJsonPath, "utf8"));
|
|
8800
|
+
const scripts = parsed?.scripts;
|
|
8801
|
+
if (!isRecord(scripts)) return /* @__PURE__ */ new Map();
|
|
8802
|
+
return new Map(
|
|
8803
|
+
Object.entries(scripts).filter(
|
|
8804
|
+
(entry) => typeof entry[1] === "string"
|
|
8805
|
+
)
|
|
8806
|
+
);
|
|
7393
8807
|
}
|
|
7394
|
-
function
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
kind
|
|
7399
|
-
label
|
|
7400
|
-
path
|
|
8808
|
+
function evidenceForRelative(repoPath, path, kind, label) {
|
|
8809
|
+
const fullPath = join3(repoPath, path);
|
|
8810
|
+
const contents = isRegularFile(fullPath) ? readFileSync6(fullPath, "utf8") : "";
|
|
8811
|
+
return {
|
|
8812
|
+
kind,
|
|
8813
|
+
label,
|
|
8814
|
+
path,
|
|
8815
|
+
...contents ? {
|
|
8816
|
+
line: firstMeaningfulLine(contents),
|
|
8817
|
+
contentHash: createHash("sha256").update(contents).digest("hex")
|
|
8818
|
+
} : {}
|
|
8819
|
+
};
|
|
8820
|
+
}
|
|
8821
|
+
function metric(name, label, value, max, weight, unit, description, kind) {
|
|
8822
|
+
return {
|
|
8823
|
+
name,
|
|
8824
|
+
label,
|
|
8825
|
+
value: Math.max(0, value),
|
|
8826
|
+
max,
|
|
8827
|
+
...kind ? { kind } : {},
|
|
8828
|
+
weight,
|
|
8829
|
+
unit,
|
|
8830
|
+
description
|
|
7401
8831
|
};
|
|
7402
|
-
return [
|
|
7403
|
-
{
|
|
7404
|
-
severity: status,
|
|
7405
|
-
summary: `${criterionId} metric-derived score is ${score.toFixed(1)}/4.0, in the ${status} band \u2014 no single finding drove this; it reflects the combined metric weighting below.`,
|
|
7406
|
-
evidence: anchor
|
|
7407
|
-
}
|
|
7408
|
-
];
|
|
7409
8832
|
}
|
|
7410
|
-
function
|
|
7411
|
-
const
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
if (applicable.length === 0) return 0;
|
|
7415
|
-
const total = applicable.reduce((sum, criterion) => sum + criterion.score, 0);
|
|
7416
|
-
return roundScore(total / applicable.length);
|
|
8833
|
+
function firstMeaningfulLine(contents) {
|
|
8834
|
+
const lines = contents.split("\n");
|
|
8835
|
+
const index = lines.findIndex((line) => line.trim().length > 0);
|
|
8836
|
+
return index === -1 ? 1 : index + 1;
|
|
7417
8837
|
}
|
|
7418
|
-
function
|
|
7419
|
-
|
|
8838
|
+
function readGitHead(repoPath) {
|
|
8839
|
+
try {
|
|
8840
|
+
return execFileSync("git", ["rev-parse", "HEAD"], {
|
|
8841
|
+
cwd: repoPath,
|
|
8842
|
+
encoding: "utf8",
|
|
8843
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
8844
|
+
}).trim();
|
|
8845
|
+
} catch {
|
|
8846
|
+
return null;
|
|
8847
|
+
}
|
|
8848
|
+
}
|
|
8849
|
+
function hasEnvPathInGitHistory(repoPath) {
|
|
8850
|
+
try {
|
|
8851
|
+
const output = execFileSync(
|
|
8852
|
+
"git",
|
|
8853
|
+
["log", "--all", "--diff-filter=AM", "--name-only", "--format="],
|
|
8854
|
+
{
|
|
8855
|
+
cwd: repoPath,
|
|
8856
|
+
encoding: "utf8",
|
|
8857
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
8858
|
+
maxBuffer: 512e3
|
|
8859
|
+
}
|
|
8860
|
+
).trim();
|
|
8861
|
+
if (!output) return false;
|
|
8862
|
+
return output.split("\n").some((p) => /(?:^|\/)\.env(?:\.|$)/i.test(p.trim()));
|
|
8863
|
+
} catch {
|
|
8864
|
+
return false;
|
|
8865
|
+
}
|
|
7420
8866
|
}
|
|
7421
8867
|
|
|
7422
|
-
// src/
|
|
7423
|
-
|
|
7424
|
-
var DIMENSION_RULES = [
|
|
7425
|
-
// A2 — injection / secrets / auth (high weight)
|
|
7426
|
-
{
|
|
7427
|
-
pattern: /sql[- _]?inject|cwe-89|sqli|command[- _]?inject|cwe-78|os[- _]?cmd|rce|remote[- _]?code/i,
|
|
7428
|
-
dimension: "A2",
|
|
7429
|
-
weight: 0.9
|
|
7430
|
-
},
|
|
7431
|
-
{
|
|
7432
|
-
pattern: /secret|credential|api[- _]?key|password[- _]?leak|hardcoded[- _]?(token|key|secret)|cwe-259|cwe-798/i,
|
|
7433
|
-
dimension: "A2",
|
|
7434
|
-
weight: 0.9
|
|
7435
|
-
},
|
|
8868
|
+
// ../witan/src/rubric.ts
|
|
8869
|
+
var WITAN_RUBRIC = [
|
|
7436
8870
|
{
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
8871
|
+
id: "A1",
|
|
8872
|
+
title: "Test integrity and regression signal",
|
|
8873
|
+
category: "code_trust"
|
|
7440
8874
|
},
|
|
7441
8875
|
{
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
8876
|
+
id: "A2",
|
|
8877
|
+
title: "Data-layer isolation and secrets posture",
|
|
8878
|
+
category: "code_trust"
|
|
7445
8879
|
},
|
|
7446
8880
|
{
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
8881
|
+
id: "A3",
|
|
8882
|
+
title: "Production readiness",
|
|
8883
|
+
category: "code_trust"
|
|
7450
8884
|
},
|
|
7451
8885
|
{
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
8886
|
+
id: "A4",
|
|
8887
|
+
title: "Dependency hygiene",
|
|
8888
|
+
category: "code_trust"
|
|
7455
8889
|
},
|
|
7456
8890
|
{
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
8891
|
+
id: "A5",
|
|
8892
|
+
title: "Claim-vs-reality reconciliation",
|
|
8893
|
+
category: "code_trust"
|
|
7460
8894
|
},
|
|
7461
|
-
// A4 — dependency vulnerabilities
|
|
7462
8895
|
{
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
8896
|
+
id: "B1",
|
|
8897
|
+
title: "Dispatch trace completeness",
|
|
8898
|
+
category: "process_trust"
|
|
7466
8899
|
},
|
|
7467
8900
|
{
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
8901
|
+
id: "B2",
|
|
8902
|
+
title: "PR outcome traceability",
|
|
8903
|
+
category: "process_trust"
|
|
7471
8904
|
},
|
|
7472
|
-
// A3 — production readiness / insecure config
|
|
7473
8905
|
{
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
8906
|
+
id: "B3",
|
|
8907
|
+
title: "CI and QA discipline",
|
|
8908
|
+
category: "process_trust"
|
|
7477
8909
|
},
|
|
7478
8910
|
{
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
8911
|
+
id: "B4",
|
|
8912
|
+
title: "Audit trail and report-up completeness",
|
|
8913
|
+
category: "process_trust"
|
|
7482
8914
|
},
|
|
7483
8915
|
{
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
8916
|
+
id: "B5",
|
|
8917
|
+
title: "Verified learning trace",
|
|
8918
|
+
category: "process_trust"
|
|
7487
8919
|
},
|
|
7488
|
-
// A1 — test integrity (low weight; SARIF rarely surfaces this)
|
|
7489
8920
|
{
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
8921
|
+
id: "B6",
|
|
8922
|
+
title: "Privileged-operation human gating",
|
|
8923
|
+
category: "process_trust"
|
|
7493
8924
|
}
|
|
7494
8925
|
];
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
var
|
|
7498
|
-
function
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
8926
|
+
|
|
8927
|
+
// ../witan/src/scoring.ts
|
|
8928
|
+
var MAX_SIGNAL_ADJUSTMENT = 0.8;
|
|
8929
|
+
function createWitanReport(input, inputSignals, rubric = WITAN_RUBRIC) {
|
|
8930
|
+
const parsedInput = WitanReportInputSchema.parse(input);
|
|
8931
|
+
const signalsByCriterion = mergeSignalsByCriterion(parsedInput.signals);
|
|
8932
|
+
const hasInputSignals = inputSignals != null && inputSignals.length > 0;
|
|
8933
|
+
const inputSignalsByDimension = /* @__PURE__ */ new Map();
|
|
8934
|
+
if (hasInputSignals && inputSignals) {
|
|
8935
|
+
for (const signal of inputSignals) {
|
|
8936
|
+
const bucket = inputSignalsByDimension.get(signal.dimension) ?? [];
|
|
8937
|
+
bucket.push(signal);
|
|
8938
|
+
inputSignalsByDimension.set(signal.dimension, bucket);
|
|
8939
|
+
}
|
|
8940
|
+
}
|
|
8941
|
+
const consumedSignals = [];
|
|
8942
|
+
const criteria = rubric.map((rubricCriterion) => {
|
|
8943
|
+
const id = rubricCriterion.id;
|
|
8944
|
+
const signal = signalsByCriterion.get(id);
|
|
8945
|
+
const scored = scoreCriterion(signal, parsedInput.rubricVersion);
|
|
8946
|
+
const dimensionSignals = inputSignalsByDimension.get(id);
|
|
8947
|
+
if (!dimensionSignals || dimensionSignals.length === 0) {
|
|
8948
|
+
return {
|
|
8949
|
+
id,
|
|
8950
|
+
title: rubricCriterion.title,
|
|
8951
|
+
category: rubricCriterion.category,
|
|
8952
|
+
score: scored.score,
|
|
8953
|
+
status: scored.status,
|
|
8954
|
+
evidence: scored.evidence,
|
|
8955
|
+
findings: scored.findings,
|
|
8956
|
+
metrics: scored.metrics,
|
|
8957
|
+
...signal?.notes ? { notes: signal.notes } : {}
|
|
8958
|
+
};
|
|
8959
|
+
}
|
|
8960
|
+
const { adjustedScore, adjustment, summaries } = applySignalAdjustment(
|
|
8961
|
+
scored.score,
|
|
8962
|
+
id,
|
|
8963
|
+
dimensionSignals
|
|
8964
|
+
);
|
|
8965
|
+
consumedSignals.push(...summaries);
|
|
8966
|
+
const finalScore = adjustment === 0 ? scored.score : adjustedScore;
|
|
8967
|
+
const finalStatus = adjustment === 0 ? scored.status : statusForScore(finalScore);
|
|
8968
|
+
return {
|
|
8969
|
+
id,
|
|
8970
|
+
title: rubricCriterion.title,
|
|
8971
|
+
category: rubricCriterion.category,
|
|
8972
|
+
score: finalScore,
|
|
8973
|
+
...adjustment !== 0 ? { nativeScore: scored.score } : {},
|
|
8974
|
+
status: finalStatus,
|
|
8975
|
+
evidence: scored.evidence,
|
|
8976
|
+
findings: scored.findings,
|
|
8977
|
+
metrics: scored.metrics,
|
|
8978
|
+
...signal?.notes ? { notes: signal.notes } : {}
|
|
8979
|
+
};
|
|
8980
|
+
});
|
|
8981
|
+
const categoryOrder = [];
|
|
8982
|
+
for (const rubricCriterion of rubric) {
|
|
8983
|
+
if (!categoryOrder.includes(rubricCriterion.category)) {
|
|
8984
|
+
categoryOrder.push(rubricCriterion.category);
|
|
7508
8985
|
}
|
|
7509
8986
|
}
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
const
|
|
7517
|
-
|
|
7518
|
-
|
|
8987
|
+
const categoryScoreMap = {};
|
|
8988
|
+
for (const category of categoryOrder) {
|
|
8989
|
+
categoryScoreMap[category] = averageScore(
|
|
8990
|
+
criteria.filter((criterion) => criterion.category === category)
|
|
8991
|
+
);
|
|
8992
|
+
}
|
|
8993
|
+
const firstCategory = categoryOrder[0];
|
|
8994
|
+
const secondCategory = categoryOrder[1] ?? firstCategory;
|
|
8995
|
+
const codeTrustScore = categoryScoreMap.code_trust ?? (firstCategory ? categoryScoreMap[firstCategory] : void 0) ?? 0;
|
|
8996
|
+
const processTrustScore = categoryScoreMap.process_trust ?? (secondCategory ? categoryScoreMap[secondCategory] : void 0) ?? 0;
|
|
8997
|
+
const overallScore = roundScore(
|
|
8998
|
+
categoryOrder.reduce((sum, category) => sum + (categoryScoreMap[category] ?? 0), 0) / Math.max(categoryOrder.length, 1)
|
|
8999
|
+
);
|
|
9000
|
+
return WitanReportSchema.parse({
|
|
9001
|
+
productSlug: parsedInput.productSlug,
|
|
9002
|
+
productDisplayName: parsedInput.productDisplayName,
|
|
9003
|
+
repo: parsedInput.repo,
|
|
9004
|
+
generatedAt: parsedInput.generatedAt,
|
|
9005
|
+
rubricVersion: parsedInput.rubricVersion,
|
|
9006
|
+
codeTrustScore,
|
|
9007
|
+
processTrustScore,
|
|
9008
|
+
overallScore,
|
|
9009
|
+
criteria,
|
|
9010
|
+
...consumedSignals.length > 0 ? { consumedSignals } : {},
|
|
9011
|
+
// Only surface the full per-category map for rubrics with more than two buckets —
|
|
9012
|
+
// the default two-category rubric is fully represented by codeTrustScore/processTrustScore.
|
|
9013
|
+
...categoryOrder.length > 2 ? { categoryScores: categoryScoreMap } : {},
|
|
9014
|
+
// Pass through repo-archetype metadata verbatim — createWitanReport does not compute or
|
|
9015
|
+
// alter it (see classifyRepoArchetype in repo-signals.ts); per-criterion scoring above is
|
|
9016
|
+
// unaffected by archetype, only presentation layers (badge/terminal/verdict) key off it.
|
|
9017
|
+
...parsedInput.archetype ? { archetype: parsedInput.archetype } : {},
|
|
9018
|
+
...parsedInput.insufficientSourceReason ? { insufficientSourceReason: parsedInput.insufficientSourceReason } : {}
|
|
9019
|
+
});
|
|
9020
|
+
}
|
|
9021
|
+
function applySignalAdjustment(nativeScore, dimension, signals) {
|
|
9022
|
+
const summaries = [];
|
|
9023
|
+
let totalRawAdj = 0;
|
|
9024
|
+
for (const signal of signals) {
|
|
9025
|
+
const criticalCount = signal.findings.filter((f) => f.severity === "critical").length;
|
|
9026
|
+
const warningCount = signal.findings.filter((f) => f.severity === "warning").length;
|
|
9027
|
+
const infoCount = signal.findings.filter((f) => f.severity === "info").length;
|
|
9028
|
+
const severityScore = Math.min(
|
|
9029
|
+
criticalCount * 0.2 + warningCount * 0.1 + infoCount * 0.02,
|
|
9030
|
+
1
|
|
9031
|
+
);
|
|
9032
|
+
const signalAdj = signal.weight * severityScore * MAX_SIGNAL_ADJUSTMENT;
|
|
9033
|
+
totalRawAdj += signalAdj;
|
|
9034
|
+
summaries.push({
|
|
9035
|
+
source: signal.source,
|
|
9036
|
+
dimension,
|
|
9037
|
+
findingCount: signal.findings.length,
|
|
9038
|
+
severityBreakdown: { critical: criticalCount, warning: warningCount, info: infoCount },
|
|
9039
|
+
nativeScore,
|
|
9040
|
+
scoreAdjustment: -roundScore(Math.min(signalAdj, MAX_SIGNAL_ADJUSTMENT)),
|
|
9041
|
+
adjustedScore: roundScore(
|
|
9042
|
+
Math.max(0, nativeScore - Math.min(signalAdj, MAX_SIGNAL_ADJUSTMENT))
|
|
9043
|
+
),
|
|
9044
|
+
findings: [...signal.findings]
|
|
9045
|
+
});
|
|
9046
|
+
}
|
|
9047
|
+
const totalAdj = Math.min(totalRawAdj, MAX_SIGNAL_ADJUSTMENT);
|
|
9048
|
+
const adjustedScore = roundScore(Math.max(0, nativeScore - totalAdj));
|
|
9049
|
+
for (const summary of summaries) {
|
|
9050
|
+
summary.adjustedScore = adjustedScore;
|
|
9051
|
+
summary.scoreAdjustment = -roundScore(totalAdj);
|
|
9052
|
+
}
|
|
9053
|
+
return { adjustedScore, adjustment: roundScore(totalAdj), summaries };
|
|
7519
9054
|
}
|
|
7520
|
-
function
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
return true;
|
|
7527
|
-
});
|
|
9055
|
+
function statusForScore(score) {
|
|
9056
|
+
if (score >= 3.5) return "verified";
|
|
9057
|
+
if (score >= 2.5) return "info";
|
|
9058
|
+
if (score >= 1.5) return "warning";
|
|
9059
|
+
if (score > 0) return "critical";
|
|
9060
|
+
return "critical";
|
|
7528
9061
|
}
|
|
7529
|
-
function
|
|
7530
|
-
|
|
7531
|
-
const
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
const driverName = run.tool?.driver?.name ?? "unknown";
|
|
7537
|
-
const source = `sarif:${driverName}`;
|
|
7538
|
-
const ruleDefaultLevels = /* @__PURE__ */ new Map();
|
|
7539
|
-
for (const rule of run.tool?.driver?.rules ?? []) {
|
|
7540
|
-
if (rule.id && rule.defaultConfiguration?.level) {
|
|
7541
|
-
ruleDefaultLevels.set(rule.id, rule.defaultConfiguration.level);
|
|
7542
|
-
}
|
|
7543
|
-
}
|
|
7544
|
-
for (const result of run.results ?? []) {
|
|
7545
|
-
const ruleId = result.ruleId ?? "unknown";
|
|
7546
|
-
const effectiveLevel = result.level ?? ruleDefaultLevels.get(ruleId) ?? "warning";
|
|
7547
|
-
const severity = mapLevel(effectiveLevel);
|
|
7548
|
-
if (!severity) continue;
|
|
7549
|
-
const message = result.message?.text ?? ruleId;
|
|
7550
|
-
const location = renderLocation(result);
|
|
7551
|
-
const { dimension, weight } = mapRuleToDimension(ruleId, dimensionRules);
|
|
7552
|
-
const bucketKey = `${source}|${dimension}`;
|
|
7553
|
-
if (!buckets.has(bucketKey)) {
|
|
7554
|
-
buckets.set(bucketKey, { source, dimension, weight, findings: [] });
|
|
7555
|
-
}
|
|
7556
|
-
buckets.get(bucketKey)?.findings.push({ ruleId, severity, message, ...location ? { location } : {} });
|
|
9062
|
+
function mergeSignalsByCriterion(signals) {
|
|
9063
|
+
const merged = /* @__PURE__ */ new Map();
|
|
9064
|
+
for (const signal of signals) {
|
|
9065
|
+
const existing = merged.get(signal.criterionId);
|
|
9066
|
+
if (!existing) {
|
|
9067
|
+
merged.set(signal.criterionId, signal);
|
|
9068
|
+
continue;
|
|
7557
9069
|
}
|
|
9070
|
+
merged.set(signal.criterionId, {
|
|
9071
|
+
criterionId: signal.criterionId,
|
|
9072
|
+
positiveEvidence: [...existing.positiveEvidence, ...signal.positiveEvidence],
|
|
9073
|
+
findings: [...existing.findings, ...signal.findings],
|
|
9074
|
+
metrics: [...existing.metrics ?? [], ...signal.metrics ?? []],
|
|
9075
|
+
notes: signal.notes ?? existing.notes,
|
|
9076
|
+
// N/A wins on merge: if either signal is N/A, the criterion is N/A.
|
|
9077
|
+
...existing.notApplicable === true || signal.notApplicable === true ? { notApplicable: true } : {}
|
|
9078
|
+
});
|
|
7558
9079
|
}
|
|
7559
|
-
return
|
|
7560
|
-
source,
|
|
7561
|
-
dimension,
|
|
7562
|
-
weight,
|
|
7563
|
-
findings: dedupeFindings(findings)
|
|
7564
|
-
}));
|
|
9080
|
+
return merged;
|
|
7565
9081
|
}
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
import { readFileSync as readFileSync3 } from "fs";
|
|
7569
|
-
var CHECK_RULES = {
|
|
7570
|
-
// B2 — PR outcome traceability
|
|
7571
|
-
"Branch-Protection": { dimension: "B2", weight: 0.8 },
|
|
7572
|
-
"Code-Review": { dimension: "B2", weight: 0.7 },
|
|
7573
|
-
// B3 — CI and QA discipline
|
|
7574
|
-
"Dangerous-Workflow": { dimension: "B3", weight: 0.9 },
|
|
7575
|
-
"Token-Permissions": { dimension: "B3", weight: 0.8 },
|
|
7576
|
-
"CI-Tests": { dimension: "B3", weight: 0.7 },
|
|
7577
|
-
Maintained: { dimension: "B3", weight: 0.3 },
|
|
7578
|
-
// B4 — audit trail / release integrity
|
|
7579
|
-
"Signed-Releases": { dimension: "B4", weight: 0.7 },
|
|
7580
|
-
Packaging: { dimension: "B4", weight: 0.4 },
|
|
7581
|
-
"Security-Policy": { dimension: "B4", weight: 0.4 },
|
|
7582
|
-
// A4 — dependency hygiene
|
|
7583
|
-
Vulnerabilities: { dimension: "A4", weight: 0.9 },
|
|
7584
|
-
"Pinned-Dependencies": { dimension: "A4", weight: 0.8 },
|
|
7585
|
-
"Dependency-Update-Tool": { dimension: "A4", weight: 0.6 },
|
|
7586
|
-
// A2 — data-layer / static analysis
|
|
7587
|
-
SAST: { dimension: "A2", weight: 0.7 },
|
|
7588
|
-
"Binary-Artifacts": { dimension: "A2", weight: 0.6 },
|
|
7589
|
-
// A1 — test integrity
|
|
7590
|
-
Fuzzing: { dimension: "A1", weight: 0.3 }
|
|
7591
|
-
};
|
|
7592
|
-
function mapScoreToSeverity(score) {
|
|
7593
|
-
if (score == null || Number.isNaN(score)) return null;
|
|
7594
|
-
if (score < 0) return null;
|
|
7595
|
-
if (score >= 10) return null;
|
|
7596
|
-
if (score <= 3) return "critical";
|
|
7597
|
-
if (score <= 6) return "warning";
|
|
7598
|
-
return "info";
|
|
9082
|
+
function usesMetricScoring(rubricVersion) {
|
|
9083
|
+
return rubricVersion === WITAN_RUBRIC_VERSION_V1 || rubricVersion === WITAN_RUBRIC_VERSION_V2 || rubricVersion === WITAN_RUBRIC_VERSION_V3 || rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0;
|
|
7599
9084
|
}
|
|
7600
|
-
function
|
|
7601
|
-
|
|
7602
|
-
return findings.filter((f) => {
|
|
7603
|
-
const key = `${f.ruleId}|${f.severity}|${f.location ?? ""}`;
|
|
7604
|
-
if (seen.has(key)) return false;
|
|
7605
|
-
seen.add(key);
|
|
7606
|
-
return true;
|
|
7607
|
-
});
|
|
9085
|
+
function unmeasuredStatus(rubricVersion) {
|
|
9086
|
+
return rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0 ? "unverified" : "insufficient_data";
|
|
7608
9087
|
}
|
|
7609
|
-
function
|
|
7610
|
-
if (!
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
if (!rule) continue;
|
|
7619
|
-
const severity = mapScoreToSeverity(check.score);
|
|
7620
|
-
if (!severity) continue;
|
|
7621
|
-
const scoreText = typeof check.score === "number" ? `${check.score}/10` : "n/a";
|
|
7622
|
-
const message = `${name} (Scorecard ${scoreText}): ${check.reason ?? "weakness detected"}`.slice(0, 500);
|
|
7623
|
-
const location = check.documentation?.url;
|
|
7624
|
-
const bucket = buckets.get(rule.dimension) ?? { weight: 0, findings: [] };
|
|
7625
|
-
bucket.weight = Math.max(bucket.weight, rule.weight);
|
|
7626
|
-
bucket.findings.push({
|
|
7627
|
-
ruleId: `scorecard:${name}`,
|
|
7628
|
-
severity,
|
|
7629
|
-
message,
|
|
7630
|
-
...location ? { location } : {}
|
|
7631
|
-
});
|
|
7632
|
-
buckets.set(rule.dimension, bucket);
|
|
9088
|
+
function scoreCriterion(signal, rubricVersion) {
|
|
9089
|
+
if (!signal) {
|
|
9090
|
+
return {
|
|
9091
|
+
score: 0,
|
|
9092
|
+
status: unmeasuredStatus(rubricVersion),
|
|
9093
|
+
evidence: [],
|
|
9094
|
+
findings: [],
|
|
9095
|
+
metrics: []
|
|
9096
|
+
};
|
|
7633
9097
|
}
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
9098
|
+
if (signal.notApplicable === true) {
|
|
9099
|
+
return {
|
|
9100
|
+
score: 0,
|
|
9101
|
+
status: "not_applicable",
|
|
9102
|
+
evidence: [],
|
|
9103
|
+
findings: [],
|
|
9104
|
+
metrics: []
|
|
9105
|
+
};
|
|
9106
|
+
}
|
|
9107
|
+
const evidence = signal.positiveEvidence;
|
|
9108
|
+
const findings = signal.findings;
|
|
9109
|
+
const metrics = signal.metrics ?? [];
|
|
9110
|
+
const evidenceCount = evidence.length + findings.length;
|
|
9111
|
+
if (evidenceCount === 0) {
|
|
9112
|
+
if (!usesMetricScoring(rubricVersion) || metrics.length === 0) {
|
|
9113
|
+
return {
|
|
9114
|
+
score: 0,
|
|
9115
|
+
status: unmeasuredStatus(rubricVersion),
|
|
9116
|
+
evidence,
|
|
9117
|
+
findings,
|
|
9118
|
+
metrics
|
|
9119
|
+
};
|
|
9120
|
+
}
|
|
9121
|
+
}
|
|
9122
|
+
if (usesMetricScoring(rubricVersion)) {
|
|
9123
|
+
const measuredMetrics = metrics.length > 0 ? metrics : fallbackMetricsForEvidence(evidence, findings);
|
|
9124
|
+
const score = capScoreForFindings(scoreMetrics(measuredMetrics), findings);
|
|
9125
|
+
const status = statusForScoreAndFindings(score, findings);
|
|
9126
|
+
return {
|
|
9127
|
+
score,
|
|
9128
|
+
status,
|
|
9129
|
+
evidence,
|
|
9130
|
+
findings: ensureFindingsExplainStatus(signal.criterionId, score, status, findings, evidence),
|
|
9131
|
+
metrics: measuredMetrics
|
|
9132
|
+
};
|
|
9133
|
+
}
|
|
9134
|
+
if (findings.some((finding) => finding.severity === "critical")) {
|
|
9135
|
+
return {
|
|
9136
|
+
score: 1,
|
|
9137
|
+
status: "critical",
|
|
9138
|
+
evidence,
|
|
9139
|
+
findings,
|
|
9140
|
+
metrics
|
|
9141
|
+
};
|
|
9142
|
+
}
|
|
9143
|
+
if (findings.some((finding) => finding.severity === "warning")) {
|
|
9144
|
+
return {
|
|
9145
|
+
score: 2,
|
|
9146
|
+
status: "warning",
|
|
9147
|
+
evidence,
|
|
9148
|
+
findings,
|
|
9149
|
+
metrics
|
|
9150
|
+
};
|
|
9151
|
+
}
|
|
9152
|
+
if (findings.some((finding) => finding.severity === "info")) {
|
|
9153
|
+
return {
|
|
9154
|
+
score: 3,
|
|
9155
|
+
status: "info",
|
|
9156
|
+
evidence,
|
|
9157
|
+
findings,
|
|
9158
|
+
metrics
|
|
9159
|
+
};
|
|
9160
|
+
}
|
|
9161
|
+
return {
|
|
9162
|
+
score: 4,
|
|
9163
|
+
status: "verified",
|
|
9164
|
+
evidence,
|
|
9165
|
+
findings,
|
|
9166
|
+
metrics
|
|
9167
|
+
};
|
|
7662
9168
|
}
|
|
7663
|
-
function
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
const severity = finding.severity;
|
|
7674
|
-
if (!severity || !VALID_SEVERITIES.has(severity)) continue;
|
|
7675
|
-
const ruleId = finding.ruleId ?? "unknown";
|
|
7676
|
-
findings.push({
|
|
7677
|
-
ruleId,
|
|
7678
|
-
severity,
|
|
7679
|
-
message: finding.message ?? ruleId,
|
|
7680
|
-
...finding.location ? { location: finding.location } : {}
|
|
7681
|
-
});
|
|
9169
|
+
function fallbackMetricsForEvidence(evidence, findings) {
|
|
9170
|
+
return [
|
|
9171
|
+
{
|
|
9172
|
+
name: "evidence_depth",
|
|
9173
|
+
label: "Evidence depth",
|
|
9174
|
+
value: Math.min(evidence.length + findings.length + 1, 4),
|
|
9175
|
+
max: 4,
|
|
9176
|
+
weight: 1,
|
|
9177
|
+
unit: "signals",
|
|
9178
|
+
description: "Conservative v1 fallback for externally supplied evidence that has not provided criterion-specific depth metrics."
|
|
7682
9179
|
}
|
|
7683
|
-
|
|
7684
|
-
signals.push({ source, dimension, weight, findings });
|
|
7685
|
-
}
|
|
7686
|
-
return signals;
|
|
9180
|
+
];
|
|
7687
9181
|
}
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
if (value.length <= max) return value;
|
|
7699
|
-
const ellipsis = "...";
|
|
7700
|
-
return `${value.slice(0, Math.max(max - ellipsis.length, 0))}${ellipsis}`;
|
|
9182
|
+
function scoreMetrics(metrics) {
|
|
9183
|
+
let weightedTotal = 0;
|
|
9184
|
+
let totalWeight = 0;
|
|
9185
|
+
for (const metric2 of metrics) {
|
|
9186
|
+
const normalized = metric2.max ? Math.min(metric2.value / metric2.max, 1) : Math.min(metric2.value, 1);
|
|
9187
|
+
weightedTotal += normalized * metric2.weight;
|
|
9188
|
+
totalWeight += metric2.weight;
|
|
9189
|
+
}
|
|
9190
|
+
if (totalWeight === 0) return 0;
|
|
9191
|
+
return roundScore(weightedTotal / totalWeight * 4);
|
|
7701
9192
|
}
|
|
7702
|
-
function
|
|
7703
|
-
return
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
...finding.location ? { location: clamp(finding.location, LOCATION_MAX) } : {}
|
|
7708
|
-
};
|
|
9193
|
+
function capScoreForFindings(score, findings) {
|
|
9194
|
+
if (findings.some((finding) => finding.severity === "critical")) return 1.4;
|
|
9195
|
+
if (findings.some((finding) => finding.severity === "warning")) return Math.min(score, 2.4);
|
|
9196
|
+
if (findings.some((finding) => finding.severity === "info")) return Math.min(score, 3.4);
|
|
9197
|
+
return score;
|
|
7709
9198
|
}
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
if (
|
|
7714
|
-
|
|
9199
|
+
function statusForScoreAndFindings(score, findings) {
|
|
9200
|
+
if (findings.some((finding) => finding.severity === "critical")) return "critical";
|
|
9201
|
+
if (findings.some((finding) => finding.severity === "warning")) return "warning";
|
|
9202
|
+
if (score >= 3.5 && findings.length === 0) return "verified";
|
|
9203
|
+
if (score >= 2.5) return "info";
|
|
9204
|
+
if (score >= 1.5) return "warning";
|
|
9205
|
+
return "critical";
|
|
7715
9206
|
}
|
|
7716
|
-
function
|
|
7717
|
-
if (
|
|
7718
|
-
|
|
9207
|
+
function ensureFindingsExplainStatus(criterionId, score, status, findings, evidence) {
|
|
9208
|
+
if (findings.length > 0) return [...findings];
|
|
9209
|
+
if (status !== "critical" && status !== "warning") return [...findings];
|
|
9210
|
+
const anchor = evidence[0] ?? {
|
|
9211
|
+
kind: "repository",
|
|
9212
|
+
label: `${criterionId} metric-derived score`,
|
|
9213
|
+
path: "."
|
|
9214
|
+
};
|
|
9215
|
+
return [
|
|
9216
|
+
{
|
|
9217
|
+
severity: status,
|
|
9218
|
+
summary: `${criterionId} metric-derived score is ${score.toFixed(1)}/4.0, in the ${status} band \u2014 no single finding drove this; it reflects the combined metric weighting below.`,
|
|
9219
|
+
evidence: anchor
|
|
9220
|
+
}
|
|
9221
|
+
];
|
|
7719
9222
|
}
|
|
7720
|
-
function
|
|
7721
|
-
const
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
}
|
|
7728
|
-
if (Array.isArray(obj.checks)) return obj.checks.length;
|
|
7729
|
-
if (Array.isArray(obj.signals)) {
|
|
7730
|
-
return obj.signals.reduce((sum, signal) => {
|
|
7731
|
-
const findings = signal.findings;
|
|
7732
|
-
return sum + (Array.isArray(findings) ? findings.length : 0);
|
|
7733
|
-
}, 0);
|
|
7734
|
-
}
|
|
7735
|
-
return 0;
|
|
9223
|
+
function averageScore(criteria) {
|
|
9224
|
+
const applicable = criteria.filter(
|
|
9225
|
+
(criterion) => criterion.status !== "not_applicable" && criterion.status !== "insufficient_data"
|
|
9226
|
+
);
|
|
9227
|
+
if (applicable.length === 0) return 0;
|
|
9228
|
+
const total = applicable.reduce((sum, criterion) => sum + criterion.score, 0);
|
|
9229
|
+
return roundScore(total / applicable.length);
|
|
7736
9230
|
}
|
|
7737
|
-
function
|
|
7738
|
-
|
|
7739
|
-
if (Array.isArray(obj.runs)) {
|
|
7740
|
-
const firstRun = obj.runs[0];
|
|
7741
|
-
return firstRun?.tool?.driver?.name ?? "unknown";
|
|
7742
|
-
}
|
|
7743
|
-
if (typeof obj.tool === "string" && obj.tool.length > 0) return obj.tool;
|
|
7744
|
-
return "scorecard";
|
|
9231
|
+
function roundScore(score) {
|
|
9232
|
+
return Math.round(score * 10) / 10;
|
|
7745
9233
|
}
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
else if (isGenericSignalDocument(raw)) signals = parseGenericJson(raw);
|
|
7758
|
-
if (!signals) {
|
|
7759
|
-
throw new Error(
|
|
7760
|
-
`Cejel: unrecognized ingest file format: ${filePath} \u2014 expected SARIF (a "runs" array), OpenSSF Scorecard JSON (a "checks" array), or the generic Cejel external-signal shape (a "tool" string + "signals" array). See the cejel README "Aggregate your scanners".`
|
|
7761
|
-
);
|
|
7762
|
-
}
|
|
7763
|
-
const rawCount = countRawEntries(raw);
|
|
7764
|
-
const mappedCount = signals.reduce((sum, signal) => sum + signal.findings.length, 0);
|
|
7765
|
-
if (rawCount > 0 && mappedCount === 0) {
|
|
7766
|
-
process.stderr.write(
|
|
7767
|
-
`Cejel: ${rawCount} findings from ${rawToolName(raw)} (${filePath}), 0 mapped to trust criteria
|
|
7768
|
-
`
|
|
7769
|
-
);
|
|
7770
|
-
}
|
|
7771
|
-
return signals.map((signal) => ({
|
|
7772
|
-
...signal,
|
|
7773
|
-
findings: signal.findings.map(clampFinding)
|
|
7774
|
-
}));
|
|
9234
|
+
|
|
9235
|
+
// ../witan/src/public-scan.ts
|
|
9236
|
+
function scoreRepoWithPublicCejel(options) {
|
|
9237
|
+
const input = buildWitanInputFromRepo({
|
|
9238
|
+
productSlug: options.productSlug,
|
|
9239
|
+
productDisplayName: options.productDisplayName,
|
|
9240
|
+
repoPath: options.repoPath,
|
|
9241
|
+
...options.generatedAt ? { generatedAt: options.generatedAt } : {}
|
|
9242
|
+
});
|
|
9243
|
+
const inputSignals = resolvePublicIngestSignals(options);
|
|
9244
|
+
return createWitanReport(input, inputSignals.length > 0 ? inputSignals : void 0);
|
|
7775
9245
|
}
|
|
7776
|
-
function
|
|
7777
|
-
|
|
7778
|
-
const
|
|
7779
|
-
const
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
9246
|
+
function resolvePublicIngestSignals(options) {
|
|
9247
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9248
|
+
const files = [];
|
|
9249
|
+
for (const pattern of options.ingestPatterns ?? []) {
|
|
9250
|
+
const matches = expandIngestPattern(pattern);
|
|
9251
|
+
if (matches.length === 0 && options.warnOnEmptyIngestMatch) {
|
|
9252
|
+
process.stderr.write(`Cejel: --ingest pattern matched no files: ${pattern}
|
|
9253
|
+
`);
|
|
9254
|
+
}
|
|
9255
|
+
for (const match of matches) {
|
|
9256
|
+
const resolved = resolve2(match);
|
|
9257
|
+
if (seen.has(resolved)) continue;
|
|
9258
|
+
seen.add(resolved);
|
|
9259
|
+
files.push(match);
|
|
9260
|
+
}
|
|
7788
9261
|
}
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
try {
|
|
7795
|
-
entries = readdirSync2(inputsDir);
|
|
7796
|
-
} catch {
|
|
7797
|
-
return [];
|
|
9262
|
+
for (const discovered of discoverIngestInputs(options.repoPath)) {
|
|
9263
|
+
const resolved = resolve2(discovered);
|
|
9264
|
+
if (seen.has(resolved)) continue;
|
|
9265
|
+
seen.add(resolved);
|
|
9266
|
+
files.push(discovered);
|
|
7798
9267
|
}
|
|
7799
|
-
return
|
|
9268
|
+
return files.flatMap((file) => parseIngestFile(file));
|
|
7800
9269
|
}
|
|
7801
9270
|
|
|
7802
|
-
// src/
|
|
7803
|
-
import {
|
|
9271
|
+
// ../witan/src/repo-clone.ts
|
|
9272
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
9273
|
+
import { mkdirSync, rmSync } from "fs";
|
|
9274
|
+
import { tmpdir } from "os";
|
|
9275
|
+
import { join as join4 } from "path";
|
|
9276
|
+
|
|
9277
|
+
// ../witan/src/cejel-package-name.ts
|
|
9278
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
9279
|
+
import { fileURLToPath } from "url";
|
|
9280
|
+
|
|
9281
|
+
// ../witan/src/leaderboard.ts
|
|
9282
|
+
var RESERVED_CORPUS_SLUGS = ["biome", "tsconfig", "package"];
|
|
9283
|
+
var LeaderboardCorpusEntrySchema = external_exports.object({
|
|
9284
|
+
// Also the evidence-report slug (reports/<name>.{json,md,svg}) — min length 3
|
|
9285
|
+
// to satisfy the WitanReport productSlug pattern.
|
|
9286
|
+
name: external_exports.string().regex(/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/).refine((value) => !RESERVED_CORPUS_SLUGS.includes(value), {
|
|
9287
|
+
message: "Corpus entry name collides with a tool config filename (reports/<name>.json would be discovered by that tool) \u2014 pick a different slug, e.g. biomejs."
|
|
9288
|
+
}),
|
|
9289
|
+
category: external_exports.string().min(1).max(80),
|
|
9290
|
+
expectedArchetype: external_exports.string().min(1).max(40),
|
|
9291
|
+
license: external_exports.string().min(1).max(80),
|
|
9292
|
+
/**
|
|
9293
|
+
* Repository visibility — the redaction policy's first-class input
|
|
9294
|
+
* (goal_cejel_redaction_policy_is_verifiability_2026-07-12): a path is
|
|
9295
|
+
* published exactly when the reader can check it (public), and withheld
|
|
9296
|
+
* entirely when they can't (private). FAIL CLOSED: absent or unrecognized
|
|
9297
|
+
* resolves to 'private' via `.catch` rather than throwing or defaulting
|
|
9298
|
+
* open, so a corpus entry can never accidentally publish paths by omission.
|
|
9299
|
+
*/
|
|
9300
|
+
visibility: external_exports.enum(["public", "private"]).catch("private"),
|
|
9301
|
+
url: external_exports.string().url().optional(),
|
|
9302
|
+
/**
|
|
9303
|
+
* Immutable source snapshot for URL entries. A rubric rescore always uses
|
|
9304
|
+
* the same commits; changing one is a separate corpus update.
|
|
9305
|
+
*/
|
|
9306
|
+
commit: external_exports.string().regex(/^[0-9a-f]{40}$/).optional(),
|
|
9307
|
+
self: external_exports.literal(true).optional(),
|
|
9308
|
+
/**
|
|
9309
|
+
* A directory inside THIS repository (relative to its root), for internal
|
|
9310
|
+
* entries that are a sub-package rather than the whole repo (e.g. the public
|
|
9311
|
+
* cejel CLI at packages/witan-cli). Scored locally like "self".
|
|
9312
|
+
*/
|
|
9313
|
+
path: external_exports.string().min(1).max(200).regex(/^[A-Za-z0-9._/-]+$/).refine((value) => !value.startsWith("/") && !value.split("/").includes(".."), {
|
|
9314
|
+
message: 'Corpus entry "path" must be relative and must not traverse upward.'
|
|
9315
|
+
}).optional()
|
|
9316
|
+
}).strict().refine((entry) => (entry.url ? 1 : 0) + (entry.self ? 1 : 0) + (entry.path ? 1 : 0) === 1, {
|
|
9317
|
+
message: 'Corpus entry must have exactly one of "url", "self", or "path".'
|
|
9318
|
+
}).refine((entry) => entry.url ? entry.commit !== void 0 : entry.commit === void 0, {
|
|
9319
|
+
message: 'Every URL corpus entry must declare exactly one immutable 40-character "commit".'
|
|
9320
|
+
});
|
|
9321
|
+
var LeaderboardCorpusSchema = external_exports.object({
|
|
9322
|
+
comment: external_exports.string().min(1),
|
|
9323
|
+
entries: external_exports.array(LeaderboardCorpusEntrySchema).min(1)
|
|
9324
|
+
}).strict().refine(
|
|
9325
|
+
(corpus) => new Set(corpus.entries.map((entry) => entry.name)).size === corpus.entries.length,
|
|
9326
|
+
{ message: "Corpus entry names must be unique." }
|
|
9327
|
+
);
|
|
9328
|
+
|
|
9329
|
+
// ../witan/src/quant-integrity.ts
|
|
9330
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
9331
|
+
import { join as join8 } from "path";
|
|
9332
|
+
|
|
9333
|
+
// ../witan/src/quant-metrics-grading.ts
|
|
9334
|
+
import { createHash as createHash2 } from "crypto";
|
|
9335
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
9336
|
+
import { join as join7 } from "path";
|
|
9337
|
+
|
|
9338
|
+
// ../witan/src/quant-run-tier-grading.ts
|
|
9339
|
+
import { createHash as createHash3 } from "crypto";
|
|
7804
9340
|
|
|
7805
9341
|
// src/product-identity.ts
|
|
7806
|
-
import { existsSync, readFileSync as
|
|
7807
|
-
import { basename as
|
|
9342
|
+
import { existsSync as existsSync3, readFileSync as readFileSync11 } from "fs";
|
|
9343
|
+
import { basename as basename3, join as join9 } from "path";
|
|
7808
9344
|
var SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/;
|
|
7809
9345
|
var FALLBACK_SLUG = "repo";
|
|
7810
9346
|
var FALLBACK_DISPLAY_NAME = "Repository";
|
|
7811
9347
|
function deriveProductIdentity(repoPath) {
|
|
7812
|
-
const packageJsonPath =
|
|
7813
|
-
const raw = readPackageName(packageJsonPath) ??
|
|
9348
|
+
const packageJsonPath = join9(repoPath, "package.json");
|
|
9349
|
+
const raw = readPackageName(packageJsonPath) ?? basename3(repoPath);
|
|
7814
9350
|
const displayName = raw.trim().length > 0 ? raw.trim() : FALLBACK_DISPLAY_NAME;
|
|
7815
9351
|
return {
|
|
7816
9352
|
productSlug: slugify(raw),
|
|
@@ -7818,9 +9354,9 @@ function deriveProductIdentity(repoPath) {
|
|
|
7818
9354
|
};
|
|
7819
9355
|
}
|
|
7820
9356
|
function readPackageName(packageJsonPath) {
|
|
7821
|
-
if (!
|
|
9357
|
+
if (!existsSync3(packageJsonPath)) return void 0;
|
|
7822
9358
|
try {
|
|
7823
|
-
const parsed = JSON.parse(
|
|
9359
|
+
const parsed = JSON.parse(readFileSync11(packageJsonPath, "utf8"));
|
|
7824
9360
|
if (typeof parsed === "object" && parsed !== null && "name" in parsed) {
|
|
7825
9361
|
const name = parsed.name;
|
|
7826
9362
|
if (typeof name === "string" && name.trim().length > 0) return name;
|
|
@@ -7881,52 +9417,28 @@ function buildWitanCliSummary(report) {
|
|
|
7881
9417
|
// src/scan.ts
|
|
7882
9418
|
function runCejelScan(options) {
|
|
7883
9419
|
const identity = deriveProductIdentity(options.repoPath);
|
|
7884
|
-
const
|
|
9420
|
+
const report = scoreRepoWithPublicCejel({
|
|
7885
9421
|
productSlug: identity.productSlug,
|
|
7886
9422
|
productDisplayName: identity.productDisplayName,
|
|
7887
|
-
repoPath: options.repoPath
|
|
9423
|
+
repoPath: options.repoPath,
|
|
9424
|
+
ingestPatterns: options.ingestPatterns,
|
|
9425
|
+
warnOnEmptyIngestMatch: options.warnOnEmptyIngestMatch
|
|
7888
9426
|
});
|
|
7889
|
-
const inputSignals = resolveIngestSignals(options);
|
|
7890
|
-
const report = createWitanReport(input, inputSignals.length > 0 ? inputSignals : void 0);
|
|
7891
9427
|
const summary = buildWitanCliSummary(report);
|
|
7892
9428
|
return { report, summary };
|
|
7893
9429
|
}
|
|
7894
|
-
function resolveIngestSignals(options) {
|
|
7895
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7896
|
-
const files = [];
|
|
7897
|
-
for (const pattern of options.ingestPatterns ?? []) {
|
|
7898
|
-
const matches = expandIngestPattern(pattern);
|
|
7899
|
-
if (matches.length === 0 && options.warnOnEmptyIngestMatch) {
|
|
7900
|
-
process.stderr.write(`Cejel: --ingest pattern matched no files: ${pattern}
|
|
7901
|
-
`);
|
|
7902
|
-
}
|
|
7903
|
-
for (const match of matches) {
|
|
7904
|
-
const resolved = resolve2(match);
|
|
7905
|
-
if (seen.has(resolved)) continue;
|
|
7906
|
-
seen.add(resolved);
|
|
7907
|
-
files.push(match);
|
|
7908
|
-
}
|
|
7909
|
-
}
|
|
7910
|
-
for (const discovered of discoverIngestInputs(options.repoPath)) {
|
|
7911
|
-
const resolved = resolve2(discovered);
|
|
7912
|
-
if (seen.has(resolved)) continue;
|
|
7913
|
-
seen.add(resolved);
|
|
7914
|
-
files.push(discovered);
|
|
7915
|
-
}
|
|
7916
|
-
return files.flatMap((file) => parseIngestFile(file));
|
|
7917
|
-
}
|
|
7918
9430
|
|
|
7919
9431
|
export {
|
|
7920
9432
|
__commonJS,
|
|
7921
9433
|
__export,
|
|
7922
9434
|
__toESM,
|
|
7923
|
-
ZodOptional,
|
|
7924
|
-
ZodFirstPartyTypeKind,
|
|
7925
|
-
objectType,
|
|
7926
|
-
external_exports,
|
|
7927
9435
|
formatExternalSourceLine,
|
|
7928
9436
|
renderWitanHtmlReport,
|
|
7929
9437
|
renderWitanBadgeEndpoint,
|
|
7930
9438
|
renderWitanBadgeSvg,
|
|
9439
|
+
ZodOptional,
|
|
9440
|
+
ZodFirstPartyTypeKind,
|
|
9441
|
+
objectType,
|
|
9442
|
+
external_exports,
|
|
7931
9443
|
runCejelScan
|
|
7932
9444
|
};
|