@archpilotlabs/archpilot 0.0.3 → 0.0.5

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 CHANGED
@@ -1,11 +1,31 @@
1
- # ArchPilot
1
+ <p align="center">
2
+ <img src="https://archpilot.org/logo.svg" width="100" />
3
+ </p>
2
4
 
3
- **Executable architecture governance for your codebase.**
5
+ <h1 align="center">ArchPilot</h1>
6
+
7
+ <p align="center">
8
+ Executable architecture governance for your codebase
9
+ </p>
10
+
11
+ <p align="center">
12
+ Validate • Enforce • Measure your architecture - continuously
13
+ </p>
4
14
 
5
15
  ArchPilot is a CLI that validates your repository against architecture rules and helps you keep your system **visible, enforceable, and measurable** as it evolves.
6
16
 
7
17
  ---
8
18
 
19
+ ## 🧭 Why this exists
20
+
21
+ Most teams rely on documentation or tribal knowledge to maintain architecture.
22
+
23
+ Over time, boundaries blur, dependencies leak, and architectural decisions drift without anyone noticing.
24
+
25
+ ArchPilot turns architecture into something you can **actually validate, enforce, and track continuously**.
26
+
27
+ ---
28
+
9
29
  ## 🚀 What it does
10
30
 
11
31
  ArchPilot turns architecture into something you can actually run and verify:
@@ -132,7 +152,7 @@ archpilot governance upload
132
152
 
133
153
  ---
134
154
 
135
- ## 🧩 Features
155
+ ## 🧩 Core Capabilities
136
156
 
137
157
  * Architecture-as-code (`.archpilot/`)
138
158
  * Dependency validation and module contracts
@@ -156,7 +176,7 @@ ArchPilot is built on four principles:
156
176
 
157
177
  ## 📄 License
158
178
 
159
- All rights reserved. This software is proprietary and closed-source.
179
+ Proprietary. See LICENSE file for details.
160
180
 
161
181
  ---
162
182
 
@@ -218290,8 +218290,8 @@ function assessChangeRisk(input2) {
218290
218290
  },
218291
218291
  {
218292
218292
  id: "CRF-015",
218293
- label: "Diff context unavailable",
218294
- description: "Diff-aware scope was unavailable; risk uses fallback signals only.",
218293
+ label: "Full validation mode (no scoped diff provided)",
218294
+ description: "No scoped diff was provided; risk uses full validation context.",
218295
218295
  weight: 2,
218296
218296
  category: "scope"
218297
218297
  }
@@ -218354,7 +218354,7 @@ function assessChangeRisk(input2) {
218354
218354
  trigger("CRF-016", `warningCount=${input2.warningCount}, affectedDependents=${affectedDependentsCount}`);
218355
218355
  }
218356
218356
  if (!diffContextAvailable) {
218357
- trigger("CRF-015", "no changed/diff context available");
218357
+ trigger("CRF-015", "no scoped diff was provided; full validation context used");
218358
218358
  }
218359
218359
  const signals = {
218360
218360
  ...changedModulesCount !== void 0 ? { changedModulesCount } : {},
@@ -222254,7 +222254,7 @@ function renderArchitectureReviewConsole(summary, options) {
222254
222254
  lines.push("ArchPilot Architecture Review");
222255
222255
  lines.push("");
222256
222256
  lines.push(`Result: ${getValidationResultLabel(summary)}`);
222257
- lines.push(`Risk level (Governance Risk): ${summary.risk.level.toUpperCase()}`);
222257
+ lines.push(`Architecture Review Level: ${summary.risk.level.toUpperCase()}`);
222258
222258
  lines.push(`Enforcement (Policy Outcome): ${summary.enforcement.action.toUpperCase()}`);
222259
222259
  if (summary.enforcement.policyLevel) {
222260
222260
  lines.push(`Policy level: ${summary.enforcement.policyLevel.toUpperCase()}`);
@@ -222348,7 +222348,7 @@ function renderArchitectureReviewConsole(summary, options) {
222348
222348
  lines.push(` - ${summary.adrRequirement.suggestedFilenameHint}`);
222349
222349
  }
222350
222350
  if (summary.safetyControls) {
222351
- lines.push("Missing Safety Controls:");
222351
+ lines.push("Recommended Deployment Safety Controls:");
222352
222352
  lines.push(`- Triggered: ${summary.safetyControls.triggered ? "YES" : "NO"}`);
222353
222353
  lines.push(`- Applicable: ${summary.safetyControls.applicable ? "YES" : "NO"}`);
222354
222354
  lines.push(`- Summary: ${summary.safetyControls.summary}`);
@@ -222588,7 +222588,7 @@ ${options.impactAnalysisSection}
222588
222588
  - Quality findings: ${summary.qualityFindings}
222589
222589
  - Setup gaps: ${summary.setupGaps}
222590
222590
  - Guidance findings: ${summary.guidanceFindings}
222591
- - Risk level (governance risk): ${summary.risk.level.toUpperCase()}
222591
+ - Architecture Review Level: ${summary.risk.level.toUpperCase()}
222592
222592
  - Enforcement (policy outcome): ${summary.enforcement.action.toUpperCase()}
222593
222593
  - Change risk (diff-aware PR impact): ${summary.changeRisk.riskLevel.toUpperCase()}
222594
222594
  - Impact radius level: ${summary.impactAnalysis.impactLevel}
@@ -222628,15 +222628,15 @@ ${options?.driftReport ? `- Drift detected: ${options.driftReport.summaryCounts.
222628
222628
  - Dependencies removed: ${options.driftReport.summaryCounts.dependenciesRemoved}` : "- No baseline drift report is available. Run `archpilot baseline check` to generate drift-report.md details."}
222629
222629
 
222630
222630
  ## Governance Summary
222631
- - Governance Risk: ${summary.risk.level.toUpperCase()}
222631
+ - Architecture Review Level: ${summary.risk.level.toUpperCase()}
222632
222632
  - Change Risk: ${summary.changeRisk.riskLevel.toUpperCase()}
222633
222633
  - Enforcement Outcome: ${summary.enforcement.enforcementDecision ?? summary.enforcement.action.toUpperCase()}
222634
222634
  - Policy Level: ${summary.enforcement.policyLevel?.toUpperCase() ?? "N/A"}
222635
222635
  - Approved exceptions: ${summary.counts.exceptions ?? 0}
222636
222636
  - Suppressed findings: ${summary.counts.suppressed}
222637
222637
 
222638
- ## Risk Assessment (Governance Risk)
222639
- - Risk level: ${summary.risk.level.toUpperCase()}
222638
+ ## Architecture Review Level
222639
+ - Level: ${summary.risk.level.toUpperCase()}
222640
222640
  - Reasons:
222641
222641
  ${summary.risk.reasons.map((reason) => ` - ${reason}`).join("\n")}
222642
222642
 
@@ -222664,7 +222664,7 @@ ${adrDisplay.state === "required" && summary.adrRequirement.suggestedCommand ? `
222664
222664
  - Suggested filename hint:
222665
222665
  ${adrDisplay.state === "required" && summary.adrRequirement.suggestedFilenameHint ? ` - ${summary.adrRequirement.suggestedFilenameHint}` : " - (none)"}
222666
222666
 
222667
- ## Missing Safety Controls
222667
+ ## Recommended Deployment Safety Controls
222668
222668
  ${summary.safetyControls ? `- Triggered: ${summary.safetyControls.triggered ? "YES" : "NO"}
222669
222669
  - Applicable: ${summary.safetyControls.applicable ? "YES" : "NO"}
222670
222670
  - Summary: ${summary.safetyControls.summary}
@@ -222812,13 +222812,13 @@ function renderArchitectureReviewCompactMarkdown(summary, options) {
222812
222812
  - Passed: ${summary.counts.passed}
222813
222813
  - Suppressed: ${summary.counts.suppressed}
222814
222814
  - Exceptions: ${summary.counts.exceptions ?? 0}
222815
- - Risk level (Governance Risk): ${summary.risk.level.toUpperCase()}
222815
+ - Architecture Review Level: ${summary.risk.level.toUpperCase()}
222816
222816
  - Enforcement (Policy Outcome): ${summary.enforcement.action.toUpperCase()}
222817
222817
  - Policy Level: ${summary.enforcement.policyLevel?.toUpperCase() ?? "N/A"}
222818
222818
  - ADR Required: ${adrDisplay.requiredLabel}
222819
222819
  - ADR Satisfied: ${adrDisplay.satisfiedLabel}
222820
222820
  - ADR Suggested command: ${adrDisplay.state === "required" ? summary.adrRequirement.suggestedCommand ?? "(none)" : "(none)"}
222821
- - Missing Safety Controls: ${(summary.safetyControls?.findings.length ?? 0) > 0 ? `${summary.safetyControls?.findings.length} finding(s)` : summary.safetyControls?.triggered ? "none" : "not-applicable"}
222821
+ - Recommended Deployment Safety Controls: ${(summary.safetyControls?.findings.length ?? 0) > 0 ? `${summary.safetyControls?.findings.length} finding(s)` : summary.safetyControls?.triggered ? "none" : "not-applicable"}
222822
222822
  - Change Risk (Diff-Aware PR Impact): ${summary.changeRisk.riskLevel.toUpperCase()}
222823
222823
  - Change Risk Summary: ${summary.changeRisk.summary}
222824
222824
  - Impact Analysis: ${summary.impactAnalysis.impactLevel} (radius ${summary.impactAnalysis.impactRadiusScore})
@@ -222843,6 +222843,9 @@ function formatRuleLine(ruleId) {
222843
222843
  const metadata = getValidationRuleMetadataById(ruleId);
222844
222844
  return `${ruleId} ${metadata.title}`;
222845
222845
  }
222846
+ function formatFindingLine(finding) {
222847
+ return `${formatRuleLine(finding.id)} | ${finding.message}`;
222848
+ }
222846
222849
  function parseFindingKind2(value) {
222847
222850
  return value === "violation" || value === "setup-gap" || value === "guidance" ? value : void 0;
222848
222851
  }
@@ -222900,21 +222903,24 @@ function renderArchitecturePrCommentMarkdown(input2) {
222900
222903
  (input2.driftComparison?.resolvedViolations ?? []).filter((entry) => resolveKind(entry) === "setup-gap").map((entry) => formatRuleLine(entry.ruleId))
222901
222904
  );
222902
222905
  const activeQualityViolationLines = sortUniqueLines(
222903
- input2.summary.findings.filter((entry) => resolveKind({ ruleId: entry.id, message: entry.message }) === "violation").map((entry) => formatRuleLine(entry.id))
222906
+ input2.summary.findings.filter((entry) => resolveKind({ ruleId: entry.id, message: entry.message }) === "violation").map((entry) => formatFindingLine(entry))
222904
222907
  );
222905
222908
  const activeSetupGapLines = sortUniqueLines(
222906
- input2.summary.findings.filter((entry) => resolveKind({ ruleId: entry.id, message: entry.message }) === "setup-gap").map((entry) => formatRuleLine(entry.id))
222909
+ input2.summary.findings.filter((entry) => resolveKind({ ruleId: entry.id, message: entry.message }) === "setup-gap").map((entry) => formatFindingLine(entry))
222907
222910
  );
222908
222911
  const activeGuidanceLines = sortUniqueLines(
222909
- input2.summary.findings.filter((entry) => resolveKind({ ruleId: entry.id, message: entry.message }) === "guidance").map((entry) => formatRuleLine(entry.id))
222912
+ input2.summary.findings.filter((entry) => resolveKind({ ruleId: entry.id, message: entry.message }) === "guidance").map((entry) => formatFindingLine(entry))
222910
222913
  );
222914
+ const activeQualityViolationCount = activeQualityViolationLines.length;
222915
+ const activeSetupGapCount = activeSetupGapLines.length;
222916
+ const activeGuidanceCount = activeGuidanceLines.length;
222911
222917
  const summaryWithReadiness = input2.summary;
222912
222918
  const trendLine = input2.healthTrend ? formatArchitectureHealthTrendLine(input2.healthTrend) : "Trend: no previous history";
222913
222919
  const scoreDelta = input2.driftComparison?.scoreDelta ?? 0;
222914
222920
  const isScoreDrop = !!input2.driftComparison?.hasPreviousSnapshot && scoreDelta < 0;
222915
- const hasViolations = activeQualityViolationLines.length > 0;
222916
- const hasSetupGaps = (summaryWithReadiness.setupGaps ?? 0) > 0 || activeSetupGapLines.length > 0;
222917
- const hasGuidance = input2.summary.guidanceFindings > 0 || activeGuidanceLines.length > 0;
222921
+ const hasViolations = activeQualityViolationCount > 0;
222922
+ const hasSetupGaps = activeSetupGapCount > 0;
222923
+ const hasGuidance = activeGuidanceCount > 0;
222918
222924
  const elevatedChangeRisk = input2.summary.changeRisk.riskLevel !== "low";
222919
222925
  const useDetailed = hasViolations || hasSetupGaps || hasGuidance || elevatedChangeRisk || isScoreDrop;
222920
222926
  const changedModulesCount = input2.summary.changeRisk.signals.changedModulesCount;
@@ -222941,8 +222947,8 @@ function renderArchitecturePrCommentMarkdown(input2) {
222941
222947
  lines.push("ArchPilot Review");
222942
222948
  lines.push(`Score: ${input2.summary.healthScore} / 100`);
222943
222949
  lines.push(`Change Risk: ${input2.summary.changeRisk.riskLevel.toUpperCase()}`);
222944
- lines.push(`Violations: ${input2.summary.qualityFindings}`);
222945
- lines.push(`Setup Gaps: ${summaryWithReadiness.setupGaps ?? 0}`);
222950
+ lines.push(`Violations: ${activeQualityViolationCount}`);
222951
+ lines.push(`Setup Gaps: ${activeSetupGapCount}`);
222946
222952
  lines.push("");
222947
222953
  lines.push(`Change Risk (Diff-Aware PR Impact): ${changeRiskSummary}`);
222948
222954
  lines.push(`Change Risk Summary: ${input2.summary.changeRisk.summary}`);
@@ -222963,7 +222969,7 @@ function renderArchitecturePrCommentMarkdown(input2) {
222963
222969
  );
222964
222970
  }
222965
222971
  lines.push("");
222966
- lines.push(`Risk level (Governance Risk): ${input2.summary.risk.level.toUpperCase()}`);
222972
+ lines.push(`Architecture Review Level: ${input2.summary.risk.level.toUpperCase()}`);
222967
222973
  for (const reason of input2.summary.risk.reasons) {
222968
222974
  lines.push(`- ${reason}`);
222969
222975
  }
@@ -223022,7 +223028,7 @@ function renderArchitecturePrCommentMarkdown(input2) {
223022
223028
  }
223023
223029
  if (input2.summary.safetyControls?.triggered && (input2.summary.safetyControls.findings.length ?? 0) > 0) {
223024
223030
  lines.push("");
223025
- lines.push("Missing Safety Controls");
223031
+ lines.push("Recommended Deployment Safety Controls");
223026
223032
  lines.push(`- ${input2.summary.safetyControls.summary}`);
223027
223033
  for (const finding of input2.summary.safetyControls.findings) {
223028
223034
  lines.push(
@@ -223036,7 +223042,7 @@ function renderArchitecturePrCommentMarkdown(input2) {
223036
223042
  lines.push(`Setup Readiness: ${summaryWithReadiness.readinessScore} / 100`);
223037
223043
  }
223038
223044
  if (typeof summaryWithReadiness.setupGaps === "number") {
223039
- lines.push(`Setup gaps: ${summaryWithReadiness.setupGaps}`);
223045
+ lines.push(`Setup gaps: ${activeSetupGapCount}`);
223040
223046
  }
223041
223047
  lines.push(trendLine);
223042
223048
  if (input2.driftComparison?.hasPreviousSnapshot) {
@@ -223064,7 +223070,7 @@ function renderArchitecturePrCommentMarkdown(input2) {
223064
223070
  lines.push("</details>");
223065
223071
  lines.push("");
223066
223072
  lines.push("<details>");
223067
- lines.push(`<summary>Violations (${activeQualityViolationLines.length})</summary>`);
223073
+ lines.push(`<summary>Violations (${activeQualityViolationCount})</summary>`);
223068
223074
  lines.push("");
223069
223075
  lines.push(
223070
223076
  activeQualityViolationLines.length === 0 ? "- (none)" : activeQualityViolationLines.map((line) => `- ${line}`).join("\n")
@@ -223072,7 +223078,7 @@ function renderArchitecturePrCommentMarkdown(input2) {
223072
223078
  lines.push("</details>");
223073
223079
  lines.push("");
223074
223080
  lines.push("<details>");
223075
- lines.push(`<summary>Setup Gaps (${activeSetupGapLines.length})</summary>`);
223081
+ lines.push(`<summary>Setup Gaps (${activeSetupGapCount})</summary>`);
223076
223082
  lines.push("");
223077
223083
  lines.push(
223078
223084
  activeSetupGapLines.length === 0 ? "- (none)" : activeSetupGapLines.map((line) => `- ${line}`).join("\n")
@@ -223080,7 +223086,7 @@ function renderArchitecturePrCommentMarkdown(input2) {
223080
223086
  lines.push("</details>");
223081
223087
  lines.push("");
223082
223088
  lines.push("<details>");
223083
- lines.push(`<summary>Guidance (${activeGuidanceLines.length})</summary>`);
223089
+ lines.push(`<summary>Guidance (${activeGuidanceCount})</summary>`);
223084
223090
  lines.push("");
223085
223091
  lines.push(
223086
223092
  activeGuidanceLines.length === 0 ? "- (none)" : activeGuidanceLines.map((line) => `- ${line}`).join("\n")
@@ -225662,9 +225668,9 @@ function renderArchitecturePrReviewMarkdown(input2) {
225662
225668
  }
225663
225669
  if (input2.validation.kind === "ok" && input2.validation.data.risk) {
225664
225670
  const governanceRisk = input2.validation.data.risk;
225665
- lines.push("## Risk Level (Governance Risk)");
225671
+ lines.push("## Architecture Review Level");
225666
225672
  lines.push("- Purpose: governance severity derived from validation results.");
225667
- lines.push(`- Risk Level: ${governanceRisk.level.toUpperCase()}`);
225673
+ lines.push(`- Architecture Review Level: ${governanceRisk.level.toUpperCase()}`);
225668
225674
  lines.push("- Reasons:");
225669
225675
  lines.push(
225670
225676
  governanceRisk.reasons.length === 0 ? " - (none)" : governanceRisk.reasons.map((reason) => ` - ${reason}`).join("\n")
@@ -225734,7 +225740,7 @@ function renderArchitecturePrReviewMarkdown(input2) {
225734
225740
  if (input2.validation.kind === "ok" && input2.validation.data.safetyControls) {
225735
225741
  const safety = input2.validation.data.safetyControls;
225736
225742
  if (safety.triggered && (safety.findings?.length ?? 0) > 0) {
225737
- lines.push("## Missing Safety Controls");
225743
+ lines.push("## Recommended Deployment Safety Controls");
225738
225744
  lines.push(`- Summary: ${safety.summary ?? "Missing safety controls detected."}`);
225739
225745
  lines.push(
225740
225746
  `- Missing controls: ${(safety.missingControls ?? []).length > 0 ? (safety.missingControls ?? []).join(", ") : "(none)"}`
@@ -228260,7 +228266,7 @@ function renderArchitectureReviewReportMarkdown(input2) {
228260
228266
  - Setup Readiness Score: ${summary.readinessScore} / 100
228261
228267
  - Trend: ${String(payload.summary.postureTrend)}
228262
228268
  - Change Risk: ${summary.changeRisk.riskLevel.toUpperCase()} (${summary.changeRisk.summary})
228263
- - Governance Risk: ${summary.risk.level.toUpperCase()}
228269
+ - Architecture Review Level: ${summary.risk.level.toUpperCase()}
228264
228270
  - Enforcement Outcome: ${summary.enforcement.enforcementDecision ?? summary.enforcement.action.toUpperCase()}
228265
228271
  - ADR Required: ${adrDisplay.requiredLabel}
228266
228272
  - ADR Satisfied: ${adrDisplay.satisfiedLabel}
@@ -228306,7 +228312,7 @@ ${toLines(adrDisplay.reasons)}
228306
228312
  ${adrDisplay.state === "required" && summary.adrRequirement.suggestedCommand ? `- Suggested ADR command: ${summary.adrRequirement.suggestedCommand}` : ""}
228307
228313
  ${adrDisplay.state === "required" && summary.adrRequirement.suggestedFilenameHint ? `- Suggested ADR filename hint: ${summary.adrRequirement.suggestedFilenameHint}` : ""}
228308
228314
 
228309
- ## Missing Safety Controls
228315
+ ## Recommended Deployment Safety Controls
228310
228316
  - Triggered: ${safetyControls.triggered ? "YES" : "NO"}
228311
228317
  - Applicable: ${safetyControls.applicable ? "YES" : "NO"}
228312
228318
  - Summary: ${safetyControls.summary}
@@ -228360,7 +228366,7 @@ function renderArchitectureDriftReportMarkdown(input2) {
228360
228366
  ## Impact Summary
228361
228367
  - Architecture Health Score: ${input2.summary.healthScore} / 100
228362
228368
  - Change Risk: ${input2.summary.changeRisk.riskLevel.toUpperCase()}
228363
- - Governance Risk: ${input2.summary.risk.level.toUpperCase()}
228369
+ - Architecture Review Level: ${input2.summary.risk.level.toUpperCase()}
228364
228370
 
228365
228371
  ## Suggested Actions
228366
228372
  - Create a baseline snapshot if this architecture state is accepted.
@@ -228427,7 +228433,7 @@ function renderArchitectureGovernanceReportMarkdown(input2) {
228427
228433
  - Generated at (UTC): ${summary.generatedAtUtc}
228428
228434
  ${input2.commitSha ? `- Commit SHA: ${input2.commitSha}` : ""}
228429
228435
  - Architecture Score: ${summary.healthScore} / 100
228430
- - Governance Risk: ${summary.risk.level.toUpperCase()}
228436
+ - Architecture Review Level: ${summary.risk.level.toUpperCase()}
228431
228437
  - Change Risk: ${summary.changeRisk.riskLevel.toUpperCase()}
228432
228438
  - Enforcement Outcome: ${enforcementDecision}
228433
228439
  - Policy Level: ${summary.enforcement.policyLevel?.toUpperCase() ?? "N/A"}
@@ -230045,6 +230051,9 @@ function validateGovernanceUploadPayload(payload) {
230045
230051
  if (!isFiniteNumber(typed.schemaVersion)) {
230046
230052
  errors.push("schemaVersion must be a finite number.");
230047
230053
  }
230054
+ if (typed.uploadMode !== "manual" && typed.uploadMode !== "ci") {
230055
+ errors.push('uploadMode must be "manual" or "ci".');
230056
+ }
230048
230057
  const organization = typed.organization;
230049
230058
  const repository = typed.repository;
230050
230059
  const snapshot = typed.snapshot;
@@ -230203,6 +230212,13 @@ function deriveOrganizationSlug(input2) {
230203
230212
  function isCiEnvironment(environment) {
230204
230213
  return environment.CI === "true" || typeof environment.GITHUB_ACTIONS === "string";
230205
230214
  }
230215
+ function resolveRequestedUploadMode(environment) {
230216
+ const explicit = asString(environment.ARCHPILOT_UPLOAD_MODE);
230217
+ if (explicit) {
230218
+ return explicit.toLowerCase();
230219
+ }
230220
+ return void 0;
230221
+ }
230206
230222
  function readEnvironmentIdentity(environment) {
230207
230223
  const branch = asString(environment.GITHUB_REF_NAME) ?? asString(environment.CI_COMMIT_REF_NAME) ?? asString(environment.BRANCH_NAME) ?? null;
230208
230224
  const commitSha = asString(environment.GITHUB_SHA) ?? asString(environment.CI_COMMIT_SHA) ?? asString(environment.COMMIT_SHA) ?? null;
@@ -230296,6 +230312,7 @@ function buildGovernanceUploadPayload(input2) {
230296
230312
  const governanceRisk = asRecord(architectureSummary.risk) ?? {};
230297
230313
  const enforcement = asRecord(architectureSummary.enforcement) ?? {};
230298
230314
  const environment = input2.environment ?? process.env;
230315
+ const requestedUploadMode = resolveRequestedUploadMode(environment);
230299
230316
  const environmentIdentity = readEnvironmentIdentity(environment);
230300
230317
  const repository = resolveRepositoryContract({
230301
230318
  workspaceRoot: input2.workspaceRoot,
@@ -230316,7 +230333,7 @@ function buildGovernanceUploadPayload(input2) {
230316
230333
  environmentIdentity.branch ?? input2.gitMetadata?.branch,
230317
230334
  repository.defaultBranch
230318
230335
  ),
230319
- source: isCiEnvironment(environment) ? "ci" : "cli",
230336
+ source: requestedUploadMode === "ci" || isCiEnvironment(environment) ? "ci" : "cli",
230320
230337
  architectureScore: asNumber(
230321
230338
  validationSummary.healthScore,
230322
230339
  asNumber(architectureSummary.healthScore, 0)
@@ -230344,8 +230361,10 @@ function buildGovernanceUploadPayload(input2) {
230344
230361
  cliVersion: input2.archpilotVersion
230345
230362
  }
230346
230363
  };
230364
+ const uploadMode = requestedUploadMode ?? (snapshot.source === "ci" ? "ci" : "manual");
230347
230365
  const payload = {
230348
230366
  schemaVersion: 1,
230367
+ uploadMode,
230349
230368
  organization: normalizeOrganization({
230350
230369
  projectIdentity: input2.projectIdentity,
230351
230370
  gitMetadata: input2.gitMetadata,
@@ -230471,6 +230490,23 @@ async function buildGovernanceUploadPayloadForWorkspace(input2) {
230471
230490
  }
230472
230491
 
230473
230492
  // ../core/src/governance/governanceUploadClient.ts
230493
+ var GovernanceUploadHttpError = class extends Error {
230494
+ endpoint;
230495
+ statusCode;
230496
+ response;
230497
+ responseMessage;
230498
+ constructor(input2) {
230499
+ const responseMessage = input2.responseMessage?.trim() ?? "";
230500
+ super(
230501
+ `Governance upload failed with status ${input2.statusCode}.${responseMessage ? ` ${responseMessage}` : ""}`
230502
+ );
230503
+ this.name = "GovernanceUploadHttpError";
230504
+ this.endpoint = input2.endpoint;
230505
+ this.statusCode = input2.statusCode;
230506
+ this.response = input2.response;
230507
+ this.responseMessage = responseMessage;
230508
+ }
230509
+ };
230474
230510
  function resolveUploadEndpoint(serverUrl) {
230475
230511
  const trimmed = serverUrl.trim();
230476
230512
  if (trimmed.length === 0) {
@@ -230497,6 +230533,26 @@ function parseResponseBody(raw) {
230497
230533
  return { message: raw };
230498
230534
  }
230499
230535
  }
230536
+ function extractResponseMessage(parsed) {
230537
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
230538
+ return "";
230539
+ }
230540
+ const record = parsed;
230541
+ if (typeof record.message === "string") {
230542
+ return record.message.trim();
230543
+ }
230544
+ if (typeof record.error === "string") {
230545
+ return record.error.trim();
230546
+ }
230547
+ const nestedError = record.error;
230548
+ if (nestedError && typeof nestedError === "object" && !Array.isArray(nestedError)) {
230549
+ const nestedMessage = nestedError.message;
230550
+ if (typeof nestedMessage === "string") {
230551
+ return nestedMessage.trim();
230552
+ }
230553
+ }
230554
+ return "";
230555
+ }
230500
230556
  async function uploadGovernanceSnapshot(input2) {
230501
230557
  const endpoint = resolveUploadEndpoint(input2.serverUrl);
230502
230558
  const timeoutMs = input2.timeoutMs ?? 1e4;
@@ -230523,10 +230579,12 @@ async function uploadGovernanceSnapshot(input2) {
230523
230579
  const raw = await response.text();
230524
230580
  const parsed = parseResponseBody(raw);
230525
230581
  if (!response.ok) {
230526
- const responseMessage = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? typeof parsed.message === "string" ? parsed.message.trim() : "" : "";
230527
- throw new Error(
230528
- `Governance upload failed with status ${response.status}.${responseMessage ? ` ${responseMessage}` : ""}`
230529
- );
230582
+ throw new GovernanceUploadHttpError({
230583
+ endpoint,
230584
+ statusCode: response.status,
230585
+ response: parsed,
230586
+ responseMessage: extractResponseMessage(parsed)
230587
+ });
230530
230588
  }
230531
230589
  return {
230532
230590
  endpoint,
@@ -233717,6 +233775,35 @@ function parseGovernanceUploadFlags(args) {
233717
233775
  ...readFlagValue(args, "--token") ? { token: readFlagValue(args, "--token") } : {}
233718
233776
  };
233719
233777
  }
233778
+ function resolveCliGovernanceUploadMode(environment) {
233779
+ const explicitUploadMode = environment.ARCHPILOT_UPLOAD_MODE?.trim().toLowerCase();
233780
+ if (explicitUploadMode === "ci") {
233781
+ return "ci";
233782
+ }
233783
+ return environment.CI === "true" || typeof environment.GITHUB_ACTIONS === "string" ? "ci" : "manual";
233784
+ }
233785
+ function normalizeApiMessage(value) {
233786
+ return value.trim().toLowerCase().replace(/\s+/gu, " ").replace(/[.]+$/u, "");
233787
+ }
233788
+ function isKnownFreePlanCiGovernanceUploadMessage(message) {
233789
+ const normalized = normalizeApiMessage(message);
233790
+ return normalized === "ci governance upload skipped: current plan supports manual uploads only" || normalized === "automatic ci governance upload is not available on the free plan" || normalized === "automatic ci-to-cloud governance upload is not available on the free plan" || normalized === "ci-to-cloud governance upload is not available on the free plan";
233791
+ }
233792
+ function isFreePlanCiGovernanceUploadSkip(error, uploadMode) {
233793
+ return uploadMode === "ci" && error instanceof GovernanceUploadHttpError && error.statusCode === 403 && isKnownFreePlanCiGovernanceUploadMessage(error.responseMessage);
233794
+ }
233795
+ function renderGovernanceUploadSkippedByPlan() {
233796
+ return [
233797
+ "ArchPilot Governance Upload",
233798
+ "",
233799
+ "Status: Skipped",
233800
+ "CI governance upload skipped: current plan supports manual uploads only.",
233801
+ "",
233802
+ "What you can do:",
233803
+ "- Use manual governance upload from the CLI or Inspector",
233804
+ "- Upgrade your plan to enable CI-to-Cloud upload on main"
233805
+ ].join("\n");
233806
+ }
233720
233807
  function printUsage() {
233721
233808
  console.error("Usage: archpilot init");
233722
233809
  console.error("Usage: archpilot validate [--ci] [--json] [--changed] [--diff] [--base <branch>]");
@@ -236667,12 +236754,20 @@ async function runGovernanceCommand(args) {
236667
236754
  ...flags.server ? { serverUrl: flags.server } : {},
236668
236755
  ...flags.token ? { token: flags.token } : {}
236669
236756
  });
236757
+ console.log("ArchPilot Governance Upload");
236758
+ console.log("");
236759
+ console.log("Status: Uploaded");
236670
236760
  console.log(`Uploaded governance snapshot for ${result.repository} at ${result.commitSha}.`);
236671
236761
  console.log(
236672
236762
  `Findings: ${result.totalFindings} total (${result.errors} errors, ${result.warnings} warnings). Score: ${result.architectureHealth ?? "n/a"}.`
236673
236763
  );
236674
236764
  return 0;
236675
236765
  } catch (error) {
236766
+ const uploadMode = resolveCliGovernanceUploadMode(process.env);
236767
+ if (isFreePlanCiGovernanceUploadSkip(error, uploadMode)) {
236768
+ console.log(renderGovernanceUploadSkippedByPlan());
236769
+ return 0;
236770
+ }
236676
236771
  const message = error instanceof Error ? error.message : "Governance upload failed.";
236677
236772
  console.error(message);
236678
236773
  if (message.includes("Governance upload requires server URL and token")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archpilotlabs/archpilot",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Executable architecture governance CLI",
5
5
  "homepage": "https://archpilot.org",
6
6
  "bugs": {